xref: /openbsd-src/sys/dev/fdt/if_mvpp.c (revision 0f9e9ec23bb2b65cc62a3d17df12827a45dae80c)
1*0f9e9ec2Sjsg /*	$OpenBSD: if_mvpp.c,v 1.53 2024/05/13 01:15:50 jsg Exp $	*/
21a945772Spatrick /*
31a945772Spatrick  * Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org>
41a945772Spatrick  * Copyright (c) 2017, 2020 Patrick Wildt <patrick@blueri.se>
51a945772Spatrick  *
61a945772Spatrick  * Permission to use, copy, modify, and distribute this software for any
71a945772Spatrick  * purpose with or without fee is hereby granted, provided that the above
81a945772Spatrick  * copyright notice and this permission notice appear in all copies.
91a945772Spatrick  *
101a945772Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
111a945772Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
121a945772Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
131a945772Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
141a945772Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
151a945772Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
161a945772Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
171a945772Spatrick  */
181a945772Spatrick /*
191a945772Spatrick  * Copyright (C) 2016 Marvell International Ltd.
201a945772Spatrick  *
211a945772Spatrick  * Marvell BSD License Option
221a945772Spatrick  *
231a945772Spatrick  * If you received this File from Marvell, you may opt to use, redistribute
241a945772Spatrick  * and/or modify this File under the following licensing terms.
251a945772Spatrick  * Redistribution and use in source and binary forms, with or without
261a945772Spatrick  * modification, are permitted provided that the following conditions are met:
271a945772Spatrick  *
281a945772Spatrick  *   * Redistributions of source code must retain the above copyright notice,
291a945772Spatrick  *     this list of conditions and the following disclaimer.
301a945772Spatrick  *
311a945772Spatrick  *   * Redistributions in binary form must reproduce the above copyright
321a945772Spatrick  *     notice, this list of conditions and the following disclaimer in the
331a945772Spatrick  *     documentation and/or other materials provided with the distribution.
341a945772Spatrick  *
351a945772Spatrick  *   * Neither the name of Marvell nor the names of its contributors may be
361a945772Spatrick  *     used to endorse or promote products derived from this software without
371a945772Spatrick  *     specific prior written permission.
381a945772Spatrick  *
391a945772Spatrick  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
401a945772Spatrick  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
411a945772Spatrick  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
421a945772Spatrick  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
431a945772Spatrick  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
441a945772Spatrick  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
451a945772Spatrick  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
461a945772Spatrick  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
471a945772Spatrick  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
481a945772Spatrick  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
491a945772Spatrick  * POSSIBILITY OF SUCH DAMAGE.
501a945772Spatrick  */
511a945772Spatrick 
521a945772Spatrick #include "bpfilter.h"
531a945772Spatrick 
541a945772Spatrick #include <sys/param.h>
551a945772Spatrick #include <sys/systm.h>
561a945772Spatrick #include <sys/device.h>
571a945772Spatrick #include <sys/kernel.h>
581a945772Spatrick #include <sys/malloc.h>
591a945772Spatrick #include <sys/mbuf.h>
601a945772Spatrick #include <sys/queue.h>
611a945772Spatrick #include <sys/socket.h>
621a945772Spatrick #include <sys/sockio.h>
631a945772Spatrick #include <sys/timeout.h>
641a945772Spatrick 
6509e5d825Spatrick #include <uvm/uvm_extern.h>
6609e5d825Spatrick 
6709e5d825Spatrick #include <machine/cpufunc.h>
681a945772Spatrick #include <machine/bus.h>
691a945772Spatrick #include <machine/fdt.h>
701a945772Spatrick 
711a945772Spatrick #include <net/if.h>
721a945772Spatrick #include <net/if_media.h>
73e042150eSpatrick #include <net/ppp_defs.h>
741a945772Spatrick 
751a945772Spatrick #include <dev/ofw/openfirm.h>
761a945772Spatrick #include <dev/ofw/ofw_clock.h>
771a945772Spatrick #include <dev/ofw/ofw_gpio.h>
781a945772Spatrick #include <dev/ofw/ofw_misc.h>
791a945772Spatrick #include <dev/ofw/ofw_pinctrl.h>
801a945772Spatrick #include <dev/ofw/ofw_regulator.h>
811a945772Spatrick #include <dev/ofw/fdt.h>
821a945772Spatrick 
831a945772Spatrick #include <dev/mii/mii.h>
841a945772Spatrick #include <dev/mii/miivar.h>
851a945772Spatrick 
861a945772Spatrick #if NBPFILTER > 0
871a945772Spatrick #include <net/bpf.h>
881a945772Spatrick #endif
891a945772Spatrick 
901a945772Spatrick #include <netinet/in.h>
911a945772Spatrick #include <netinet/ip.h>
921a945772Spatrick #include <netinet/if_ether.h>
931a945772Spatrick 
941a945772Spatrick #include <netinet6/in6_var.h>
951a945772Spatrick #include <netinet/ip6.h>
961a945772Spatrick 
971a945772Spatrick #include <dev/fdt/if_mvppreg.h>
981a945772Spatrick 
991a945772Spatrick struct mvpp2_buf {
1001a945772Spatrick 	bus_dmamap_t		mb_map;
1011a945772Spatrick 	struct mbuf		*mb_m;
1021a945772Spatrick };
1031a945772Spatrick 
1041a945772Spatrick #define MVPP2_NTXDESC	512
1051a945772Spatrick #define MVPP2_NTXSEGS	16
1061a945772Spatrick #define MVPP2_NRXDESC	512
1071a945772Spatrick 
1081a945772Spatrick struct mvpp2_bm_pool {
1091a945772Spatrick 	struct mvpp2_dmamem	*bm_mem;
1101a945772Spatrick 	struct mvpp2_buf	*rxbuf;
111be107da9Spatrick 	uint32_t		*freelist;
112be107da9Spatrick 	int			free_prod;
113be107da9Spatrick 	int			free_cons;
1141a945772Spatrick };
1151a945772Spatrick 
1161a945772Spatrick #define MVPP2_BM_SIZE		64
1171a945772Spatrick #define MVPP2_BM_POOL_PTR_ALIGN	128
1181a945772Spatrick #define MVPP2_BM_POOLS_NUM	8
1191a945772Spatrick #define MVPP2_BM_ALIGN		32
1201a945772Spatrick 
1211a945772Spatrick struct mvpp2_tx_queue {
1221a945772Spatrick 	uint8_t			id;
1231a945772Spatrick 	uint8_t			log_id;
1241a945772Spatrick 	struct mvpp2_dmamem	*ring;
1251a945772Spatrick 	struct mvpp2_buf	*buf;
1261a945772Spatrick 	struct mvpp2_tx_desc	*descs;
1271a945772Spatrick 	int			prod;
1281a945772Spatrick 	int			cons;
1291a945772Spatrick 
1301a945772Spatrick 	uint32_t		done_pkts_coal;
1311a945772Spatrick };
1321a945772Spatrick 
1331a945772Spatrick struct mvpp2_rx_queue {
1341a945772Spatrick 	uint8_t			id;
1351a945772Spatrick 	struct mvpp2_dmamem	*ring;
1361a945772Spatrick 	struct mvpp2_rx_desc	*descs;
1371a945772Spatrick 	int			prod;
1381a945772Spatrick 	struct if_rxring	rxring;
1391a945772Spatrick 	int			cons;
1401a945772Spatrick 
1411a945772Spatrick 	uint32_t		pkts_coal;
1421a945772Spatrick 	uint32_t		time_coal;
1431a945772Spatrick };
1441a945772Spatrick 
1451a945772Spatrick struct mvpp2_dmamem {
1461a945772Spatrick 	bus_dmamap_t		mdm_map;
1471a945772Spatrick 	bus_dma_segment_t	mdm_seg;
1481a945772Spatrick 	size_t			mdm_size;
1491a945772Spatrick 	caddr_t			mdm_kva;
1501a945772Spatrick };
1511a945772Spatrick #define MVPP2_DMA_MAP(_mdm)	((_mdm)->mdm_map)
1521a945772Spatrick #define MVPP2_DMA_LEN(_mdm)	((_mdm)->mdm_size)
1531a945772Spatrick #define MVPP2_DMA_DVA(_mdm)	((_mdm)->mdm_map->dm_segs[0].ds_addr)
1541a945772Spatrick #define MVPP2_DMA_KVA(_mdm)	((void *)(_mdm)->mdm_kva)
1551a945772Spatrick 
1561a945772Spatrick struct mvpp2_port;
1571a945772Spatrick struct mvpp2_softc {
1581a945772Spatrick 	struct device		sc_dev;
1591a945772Spatrick 	int			sc_node;
1601a945772Spatrick 	bus_space_tag_t		sc_iot;
1611a945772Spatrick 	bus_space_handle_t	sc_ioh_base;
1621a945772Spatrick 	bus_space_handle_t	sc_ioh_iface;
16309e5d825Spatrick 	paddr_t			sc_ioh_paddr;
1641a945772Spatrick 	bus_size_t		sc_iosize_base;
1651a945772Spatrick 	bus_size_t		sc_iosize_iface;
1661a945772Spatrick 	bus_dma_tag_t		sc_dmat;
16709e5d825Spatrick 	struct regmap		*sc_rm;
1681a945772Spatrick 
1691a945772Spatrick 	uint32_t		sc_tclk;
1701a945772Spatrick 
171be107da9Spatrick 	struct mvpp2_bm_pool	*sc_bm_pools;
172be107da9Spatrick 	int			sc_npools;
1731a945772Spatrick 
1741a945772Spatrick 	struct mvpp2_prs_shadow	*sc_prs_shadow;
1751a945772Spatrick 	uint8_t			*sc_prs_double_vlans;
1761a945772Spatrick 
1771a945772Spatrick 	int			sc_aggr_ntxq;
1781a945772Spatrick 	struct mvpp2_tx_queue	*sc_aggr_txqs;
1791a945772Spatrick 
1801a945772Spatrick 	struct mvpp2_port	**sc_ports;
1811a945772Spatrick };
1821a945772Spatrick 
1831a945772Spatrick struct mvpp2_port {
1841a945772Spatrick 	struct device		sc_dev;
1851a945772Spatrick 	struct mvpp2_softc	*sc;
1861a945772Spatrick 	int			sc_node;
1871a945772Spatrick 	bus_dma_tag_t		sc_dmat;
1881a945772Spatrick 	int			sc_id;
1891a945772Spatrick 	int			sc_gop_id;
1901a945772Spatrick 
1911a945772Spatrick 	struct arpcom		sc_ac;
1921a945772Spatrick #define sc_lladdr	sc_ac.ac_enaddr
1931a945772Spatrick 	struct mii_data		sc_mii;
1941a945772Spatrick #define sc_media	sc_mii.mii_media
195120fed02Spatrick 	struct mii_bus		*sc_mdio;
1961a945772Spatrick 
1971a945772Spatrick 	enum {
1981a945772Spatrick 		PHY_MODE_XAUI,
1991a945772Spatrick 		PHY_MODE_10GBASER,
2001a945772Spatrick 		PHY_MODE_2500BASEX,
2011a945772Spatrick 		PHY_MODE_1000BASEX,
2021a945772Spatrick 		PHY_MODE_SGMII,
2031a945772Spatrick 		PHY_MODE_RGMII,
2041a945772Spatrick 		PHY_MODE_RGMII_ID,
2051a945772Spatrick 		PHY_MODE_RGMII_RXID,
2061a945772Spatrick 		PHY_MODE_RGMII_TXID,
2071a945772Spatrick 	}			sc_phy_mode;
2081a945772Spatrick 	int			sc_fixed_link;
2091a945772Spatrick 	int			sc_inband_status;
2101a945772Spatrick 	int			sc_link;
2111a945772Spatrick 	int			sc_phyloc;
2121a945772Spatrick 	int			sc_sfp;
2131a945772Spatrick 
2141a945772Spatrick 	int			sc_ntxq;
2151a945772Spatrick 	int			sc_nrxq;
2161a945772Spatrick 
2171a945772Spatrick 	struct mvpp2_tx_queue	*sc_txqs;
2181a945772Spatrick 	struct mvpp2_rx_queue	*sc_rxqs;
2191a945772Spatrick 
2201a945772Spatrick 	struct timeout		sc_tick;
2211a945772Spatrick 
2221a945772Spatrick 	uint32_t		sc_tx_time_coal;
2231a945772Spatrick };
2241a945772Spatrick 
2251a945772Spatrick #define MVPP2_MAX_PORTS		4
2261a945772Spatrick 
2271a945772Spatrick struct mvpp2_attach_args {
2281a945772Spatrick 	int			ma_node;
2291a945772Spatrick 	bus_dma_tag_t		ma_dmat;
2301a945772Spatrick };
2311a945772Spatrick 
2321a945772Spatrick #define DEVNAME(_s)	((_s)->sc_dev.dv_xname)
2331a945772Spatrick 
2341a945772Spatrick static struct rwlock mvpp2_sff_lock = RWLOCK_INITIALIZER("mvpp2sff");
2351a945772Spatrick 
2361a945772Spatrick int	mvpp2_match(struct device *, void *, void *);
2371a945772Spatrick void	mvpp2_attach(struct device *, struct device *, void *);
2381a945772Spatrick void	mvpp2_attach_deferred(struct device *);
2391a945772Spatrick 
240471aeecfSnaddy const struct cfattach mvppc_ca = {
2411a945772Spatrick 	sizeof(struct mvpp2_softc), mvpp2_match, mvpp2_attach
2421a945772Spatrick };
2431a945772Spatrick 
2441a945772Spatrick struct cfdriver mvppc_cd = {
2451a945772Spatrick 	NULL, "mvppc", DV_DULL
2461a945772Spatrick };
2471a945772Spatrick 
2481a945772Spatrick int	mvpp2_port_match(struct device *, void *, void *);
2491a945772Spatrick void	mvpp2_port_attach(struct device *, struct device *, void *);
2501a945772Spatrick 
251471aeecfSnaddy const struct cfattach mvpp_ca = {
2521a945772Spatrick 	sizeof(struct mvpp2_port), mvpp2_port_match, mvpp2_port_attach
2531a945772Spatrick };
2541a945772Spatrick 
2551a945772Spatrick struct cfdriver mvpp_cd = {
2561a945772Spatrick 	NULL, "mvpp", DV_IFNET
2571a945772Spatrick };
2581a945772Spatrick 
259a02f2d56Skettenis void	mvpp2_port_attach_sfp(struct device *);
260a02f2d56Skettenis 
2611a945772Spatrick uint32_t mvpp2_read(struct mvpp2_softc *, bus_addr_t);
2621a945772Spatrick void	mvpp2_write(struct mvpp2_softc *, bus_addr_t, uint32_t);
2631a945772Spatrick uint32_t mvpp2_gmac_read(struct mvpp2_port *, bus_addr_t);
2641a945772Spatrick void	mvpp2_gmac_write(struct mvpp2_port *, bus_addr_t, uint32_t);
2651a945772Spatrick uint32_t mvpp2_xlg_read(struct mvpp2_port *, bus_addr_t);
2661a945772Spatrick void	mvpp2_xlg_write(struct mvpp2_port *, bus_addr_t, uint32_t);
2671a945772Spatrick uint32_t mvpp2_xpcs_read(struct mvpp2_port *, bus_addr_t);
2681a945772Spatrick void	mvpp2_xpcs_write(struct mvpp2_port *, bus_addr_t, uint32_t);
2691a945772Spatrick uint32_t mvpp2_mpcs_read(struct mvpp2_port *, bus_addr_t);
2701a945772Spatrick void	mvpp2_mpcs_write(struct mvpp2_port *, bus_addr_t, uint32_t);
2711a945772Spatrick 
2721a945772Spatrick int	mvpp2_ioctl(struct ifnet *, u_long, caddr_t);
2731a945772Spatrick void	mvpp2_start(struct ifnet *);
2741a945772Spatrick int	mvpp2_rxrinfo(struct mvpp2_port *, struct if_rxrinfo *);
2751a945772Spatrick void	mvpp2_watchdog(struct ifnet *);
2761a945772Spatrick 
2771a945772Spatrick int	mvpp2_media_change(struct ifnet *);
2781a945772Spatrick void	mvpp2_media_status(struct ifnet *, struct ifmediareq *);
2791a945772Spatrick 
2801a945772Spatrick int	mvpp2_mii_readreg(struct device *, int, int);
2811a945772Spatrick void	mvpp2_mii_writereg(struct device *, int, int, int);
2821a945772Spatrick void	mvpp2_mii_statchg(struct device *);
2831a945772Spatrick void	mvpp2_inband_statchg(struct mvpp2_port *);
2841a945772Spatrick void	mvpp2_port_change(struct mvpp2_port *);
2851a945772Spatrick 
2861a945772Spatrick void	mvpp2_tick(void *);
2871a945772Spatrick 
2881a945772Spatrick int	mvpp2_link_intr(void *);
2891a945772Spatrick int	mvpp2_intr(void *);
2901a945772Spatrick void	mvpp2_tx_proc(struct mvpp2_port *, uint8_t);
29163ca77e8Spatrick void	mvpp2_txq_proc(struct mvpp2_port *, struct mvpp2_tx_queue *);
2921a945772Spatrick void	mvpp2_rx_proc(struct mvpp2_port *, uint8_t);
2931a945772Spatrick void	mvpp2_rxq_proc(struct mvpp2_port *, struct mvpp2_rx_queue *);
294be107da9Spatrick void	mvpp2_rx_refill(struct mvpp2_port *);
2951a945772Spatrick 
2961a945772Spatrick void	mvpp2_up(struct mvpp2_port *);
2971a945772Spatrick void	mvpp2_down(struct mvpp2_port *);
2981a945772Spatrick void	mvpp2_iff(struct mvpp2_port *);
2991a945772Spatrick 
3001a945772Spatrick void	mvpp2_aggr_txq_hw_init(struct mvpp2_softc *, struct mvpp2_tx_queue *);
3011a945772Spatrick void	mvpp2_txq_hw_init(struct mvpp2_port *, struct mvpp2_tx_queue *);
3021a945772Spatrick void	mvpp2_rxq_hw_init(struct mvpp2_port *, struct mvpp2_rx_queue *);
3031a945772Spatrick void	mvpp2_txq_hw_deinit(struct mvpp2_port *, struct mvpp2_tx_queue *);
3048801406bSpatrick void	mvpp2_rxq_hw_drop(struct mvpp2_port *, struct mvpp2_rx_queue *);
3051a945772Spatrick void	mvpp2_rxq_hw_deinit(struct mvpp2_port *, struct mvpp2_rx_queue *);
3061a945772Spatrick void	mvpp2_rxq_long_pool_set(struct mvpp2_port *, int, int);
3071a945772Spatrick void	mvpp2_rxq_short_pool_set(struct mvpp2_port *, int, int);
3081a945772Spatrick 
309c56f4c70Spatrick void	mvpp2_mac_reset_assert(struct mvpp2_port *);
310c56f4c70Spatrick void	mvpp2_pcs_reset_assert(struct mvpp2_port *);
311c56f4c70Spatrick void	mvpp2_pcs_reset_deassert(struct mvpp2_port *);
3121a945772Spatrick void	mvpp2_mac_config(struct mvpp2_port *);
3131a945772Spatrick void	mvpp2_xlg_config(struct mvpp2_port *);
3141a945772Spatrick void	mvpp2_gmac_config(struct mvpp2_port *);
315c56f4c70Spatrick void	mvpp2_comphy_config(struct mvpp2_port *, int);
31609e5d825Spatrick void	mvpp2_gop_config(struct mvpp2_port *);
317c56f4c70Spatrick void	mvpp2_gop_intr_mask(struct mvpp2_port *);
318c56f4c70Spatrick void	mvpp2_gop_intr_unmask(struct mvpp2_port *);
3191a945772Spatrick 
3201a945772Spatrick struct mvpp2_dmamem *
3211a945772Spatrick 	mvpp2_dmamem_alloc(struct mvpp2_softc *, bus_size_t, bus_size_t);
3221a945772Spatrick void	mvpp2_dmamem_free(struct mvpp2_softc *, struct mvpp2_dmamem *);
3231a945772Spatrick struct mbuf *mvpp2_alloc_mbuf(struct mvpp2_softc *, bus_dmamap_t);
3241a945772Spatrick 
3251a945772Spatrick void	mvpp2_interrupts_enable(struct mvpp2_port *, int);
3261a945772Spatrick void	mvpp2_interrupts_disable(struct mvpp2_port *, int);
3271a945772Spatrick int	mvpp2_egress_port(struct mvpp2_port *);
3281a945772Spatrick int	mvpp2_txq_phys(int, int);
3291a945772Spatrick void	mvpp2_defaults_set(struct mvpp2_port *);
3301a945772Spatrick void	mvpp2_ingress_enable(struct mvpp2_port *);
3311a945772Spatrick void	mvpp2_ingress_disable(struct mvpp2_port *);
3321a945772Spatrick void	mvpp2_egress_enable(struct mvpp2_port *);
3331a945772Spatrick void	mvpp2_egress_disable(struct mvpp2_port *);
3341a945772Spatrick void	mvpp2_port_enable(struct mvpp2_port *);
3351a945772Spatrick void	mvpp2_port_disable(struct mvpp2_port *);
3361a945772Spatrick void	mvpp2_rxq_status_update(struct mvpp2_port *, int, int, int);
3371a945772Spatrick int	mvpp2_rxq_received(struct mvpp2_port *, int);
3381a945772Spatrick void	mvpp2_rxq_offset_set(struct mvpp2_port *, int, int);
3391a945772Spatrick void	mvpp2_txp_max_tx_size_set(struct mvpp2_port *);
3401a945772Spatrick void	mvpp2_rx_pkts_coal_set(struct mvpp2_port *, struct mvpp2_rx_queue *,
3411a945772Spatrick 	    uint32_t);
3421a945772Spatrick void	mvpp2_tx_pkts_coal_set(struct mvpp2_port *, struct mvpp2_tx_queue *,
3431a945772Spatrick 	    uint32_t);
3441a945772Spatrick void	mvpp2_rx_time_coal_set(struct mvpp2_port *, struct mvpp2_rx_queue *,
3451a945772Spatrick 	    uint32_t);
3461a945772Spatrick void	mvpp2_tx_time_coal_set(struct mvpp2_port *, uint32_t);
3471a945772Spatrick 
3481a945772Spatrick void	mvpp2_axi_config(struct mvpp2_softc *);
3491a945772Spatrick void	mvpp2_bm_pool_init(struct mvpp2_softc *);
3501a945772Spatrick void	mvpp2_rx_fifo_init(struct mvpp2_softc *);
3511a945772Spatrick void	mvpp2_tx_fifo_init(struct mvpp2_softc *);
3521a945772Spatrick int	mvpp2_prs_default_init(struct mvpp2_softc *);
3531a945772Spatrick void	mvpp2_prs_hw_inv(struct mvpp2_softc *, int);
3541a945772Spatrick void	mvpp2_prs_hw_port_init(struct mvpp2_softc *, int, int, int, int);
3551a945772Spatrick void	mvpp2_prs_def_flow_init(struct mvpp2_softc *);
3561a945772Spatrick void	mvpp2_prs_mh_init(struct mvpp2_softc *);
3571a945772Spatrick void	mvpp2_prs_mac_init(struct mvpp2_softc *);
3581a945772Spatrick void	mvpp2_prs_dsa_init(struct mvpp2_softc *);
3591a945772Spatrick int	mvpp2_prs_etype_init(struct mvpp2_softc *);
3601a945772Spatrick int	mvpp2_prs_vlan_init(struct mvpp2_softc *);
3611a945772Spatrick int	mvpp2_prs_pppoe_init(struct mvpp2_softc *);
3621a945772Spatrick int	mvpp2_prs_ip6_init(struct mvpp2_softc *);
3631a945772Spatrick int	mvpp2_prs_ip4_init(struct mvpp2_softc *);
3641a945772Spatrick void	mvpp2_prs_shadow_ri_set(struct mvpp2_softc *, int,
3651a945772Spatrick 	    uint32_t, uint32_t);
3661a945772Spatrick void	mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry *, uint32_t);
3671a945772Spatrick void	mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry *, uint32_t, int);
3681a945772Spatrick void	mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry *, uint32_t);
3691a945772Spatrick uint32_t mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry *);
3701a945772Spatrick void	mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry *, uint32_t,
3711a945772Spatrick 	    uint8_t, uint8_t);
3721a945772Spatrick void	mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry *, uint32_t,
3731a945772Spatrick 	    uint8_t *, uint8_t *);
3741a945772Spatrick int	mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *, int, uint16_t);
3751a945772Spatrick void	mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry *, uint32_t, uint32_t);
3761a945772Spatrick int	mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry *);
3771a945772Spatrick int	mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry *);
3781a945772Spatrick void	mvpp2_prs_tcam_data_word_get(struct mvpp2_prs_entry *, uint32_t,
3791a945772Spatrick 	    uint32_t *, uint32_t *);
3801a945772Spatrick void	mvpp2_prs_match_etype(struct mvpp2_prs_entry *, uint32_t, uint16_t);
3811a945772Spatrick int	mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry *);
3821a945772Spatrick void	mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *, uint32_t, uint32_t);
3831a945772Spatrick void	mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *, uint32_t, uint32_t);
3841a945772Spatrick void	mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *, uint32_t, uint32_t);
3851a945772Spatrick void	mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry *, uint32_t, uint32_t);
3861a945772Spatrick void	mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *, int, uint32_t);
3871a945772Spatrick void	mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *, uint32_t, int,
3881a945772Spatrick 	    uint32_t);
3891a945772Spatrick void	mvpp2_prs_sram_next_lu_set(struct mvpp2_prs_entry *, uint32_t);
3901a945772Spatrick void	mvpp2_prs_shadow_set(struct mvpp2_softc *, int, uint32_t);
3911a945772Spatrick int	mvpp2_prs_hw_write(struct mvpp2_softc *, struct mvpp2_prs_entry *);
392fad015d2Spatrick int	mvpp2_prs_hw_read(struct mvpp2_softc *, struct mvpp2_prs_entry *, int);
393fef01367Spatrick int	mvpp2_prs_flow_find(struct mvpp2_softc *, int);
3941a945772Spatrick int	mvpp2_prs_tcam_first_free(struct mvpp2_softc *, uint8_t, uint8_t);
3951a945772Spatrick void	mvpp2_prs_mac_drop_all_set(struct mvpp2_softc *, uint32_t, int);
39641cd246cSpatrick void	mvpp2_prs_mac_promisc_set(struct mvpp2_softc *, uint32_t, int, int);
3971a945772Spatrick void	mvpp2_prs_dsa_tag_set(struct mvpp2_softc *, uint32_t, int, int, int);
3981a945772Spatrick void	mvpp2_prs_dsa_tag_ethertype_set(struct mvpp2_softc *, uint32_t,
3991a945772Spatrick 	    int, int, int);
4001a945772Spatrick struct mvpp2_prs_entry *mvpp2_prs_vlan_find(struct mvpp2_softc *, uint16_t,
4011a945772Spatrick 	    int);
4021a945772Spatrick int	mvpp2_prs_vlan_add(struct mvpp2_softc *, uint16_t, int, uint32_t);
4031a945772Spatrick int	mvpp2_prs_double_vlan_ai_free_get(struct mvpp2_softc *);
4041a945772Spatrick struct mvpp2_prs_entry *mvpp2_prs_double_vlan_find(struct mvpp2_softc *,
4051a945772Spatrick 	    uint16_t, uint16_t);
4061a945772Spatrick int	mvpp2_prs_double_vlan_add(struct mvpp2_softc *, uint16_t, uint16_t,
4071a945772Spatrick 	    uint32_t);
4081a945772Spatrick int	mvpp2_prs_ip4_proto(struct mvpp2_softc *, uint16_t, uint32_t, uint32_t);
4091a945772Spatrick int	mvpp2_prs_ip4_cast(struct mvpp2_softc *, uint16_t);
4101a945772Spatrick int	mvpp2_prs_ip6_proto(struct mvpp2_softc *, uint16_t, uint32_t, uint32_t);
4111a945772Spatrick int	mvpp2_prs_ip6_cast(struct mvpp2_softc *, uint16_t);
41241cd246cSpatrick int	mvpp2_prs_mac_da_range_find(struct mvpp2_softc *, int, const uint8_t *,
41341cd246cSpatrick 	    uint8_t *, int);
4141a945772Spatrick int	mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry *, const uint8_t *,
4151a945772Spatrick 	    uint8_t *);
41641cd246cSpatrick int	mvpp2_prs_mac_da_accept(struct mvpp2_port *, const uint8_t *, int);
417ce595ab8Spatrick void	mvpp2_prs_mac_del_all(struct mvpp2_port *);
4181a945772Spatrick int	mvpp2_prs_tag_mode_set(struct mvpp2_softc *, int, int);
4191a945772Spatrick int	mvpp2_prs_def_flow(struct mvpp2_port *);
4201a945772Spatrick void	mvpp2_cls_flow_write(struct mvpp2_softc *, struct mvpp2_cls_flow_entry *);
4211a945772Spatrick void	mvpp2_cls_lookup_write(struct mvpp2_softc *, struct mvpp2_cls_lookup_entry *);
4221a945772Spatrick void	mvpp2_cls_init(struct mvpp2_softc *);
4231a945772Spatrick void	mvpp2_cls_port_config(struct mvpp2_port *);
4241a945772Spatrick void	mvpp2_cls_oversize_rxq_set(struct mvpp2_port *);
4251a945772Spatrick 
4261a945772Spatrick int
mvpp2_match(struct device * parent,void * cfdata,void * aux)4271a945772Spatrick mvpp2_match(struct device *parent, void *cfdata, void *aux)
4281a945772Spatrick {
4291a945772Spatrick 	struct fdt_attach_args *faa = aux;
4301a945772Spatrick 
4311a945772Spatrick 	return OF_is_compatible(faa->fa_node, "marvell,armada-7k-pp22");
4321a945772Spatrick }
4331a945772Spatrick 
4341a945772Spatrick void
mvpp2_attach(struct device * parent,struct device * self,void * aux)4351a945772Spatrick mvpp2_attach(struct device *parent, struct device *self, void *aux)
4361a945772Spatrick {
4371a945772Spatrick 	struct mvpp2_softc *sc = (void *)self;
4381a945772Spatrick 	struct fdt_attach_args *faa = aux;
4391a945772Spatrick 
4401a945772Spatrick 	if (faa->fa_nreg < 2) {
4411a945772Spatrick 		printf(": no registers\n");
4421a945772Spatrick 		return;
4431a945772Spatrick 	}
4441a945772Spatrick 
4451a945772Spatrick 	sc->sc_node = faa->fa_node;
4461a945772Spatrick 	sc->sc_iot = faa->fa_iot;
4471a945772Spatrick 	sc->sc_dmat = faa->fa_dmat;
4481a945772Spatrick 
4491a945772Spatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
4501a945772Spatrick 	    faa->fa_reg[0].size, 0, &sc->sc_ioh_base)) {
4511a945772Spatrick 		printf(": can't map registers\n");
4521a945772Spatrick 		return;
4531a945772Spatrick 	}
4541a945772Spatrick 	sc->sc_iosize_base = faa->fa_reg[0].size;
4551a945772Spatrick 
456983593c5Skettenis 	sc->sc_ioh_paddr = bus_space_mmap(sc->sc_iot, faa->fa_reg[0].addr,
457983593c5Skettenis 	    0, PROT_READ | PROT_WRITE, 0);
458983593c5Skettenis 	KASSERT(sc->sc_ioh_paddr != -1);
459983593c5Skettenis 	sc->sc_ioh_paddr &= PMAP_PA_MASK;
46009e5d825Spatrick 
4611a945772Spatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
4621a945772Spatrick 	    faa->fa_reg[1].size, 0, &sc->sc_ioh_iface)) {
4631a945772Spatrick 		printf(": can't map registers\n");
4641a945772Spatrick 		bus_space_unmap(sc->sc_iot, sc->sc_ioh_base,
4651a945772Spatrick 		    sc->sc_iosize_base);
4661a945772Spatrick 		return;
4671a945772Spatrick 	}
4681a945772Spatrick 	sc->sc_iosize_iface = faa->fa_reg[1].size;
4691a945772Spatrick 
47009e5d825Spatrick 	sc->sc_rm = regmap_byphandle(OF_getpropint(faa->fa_node,
47109e5d825Spatrick 	    "marvell,system-controller", 0));
47209e5d825Spatrick 
4731a945772Spatrick 	clock_enable_all(faa->fa_node);
4741a945772Spatrick 	sc->sc_tclk = clock_get_frequency(faa->fa_node, "pp_clk");
4751a945772Spatrick 
4761a945772Spatrick 	printf("\n");
4771a945772Spatrick 
4781a945772Spatrick 	config_defer(self, mvpp2_attach_deferred);
4791a945772Spatrick }
4801a945772Spatrick 
4811a945772Spatrick void
mvpp2_attach_deferred(struct device * self)4821a945772Spatrick mvpp2_attach_deferred(struct device *self)
4831a945772Spatrick {
4841a945772Spatrick 	struct mvpp2_softc *sc = (void *)self;
4851a945772Spatrick 	struct mvpp2_attach_args maa;
4861a945772Spatrick 	struct mvpp2_tx_queue *txq;
4871a945772Spatrick 	int i, node;
4881a945772Spatrick 
4891a945772Spatrick 	mvpp2_axi_config(sc);
4901a945772Spatrick 
491b3a1ec52Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh_iface, MVPP22_SMI_MISC_CFG_REG,
492b3a1ec52Spatrick 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh_iface,
493b3a1ec52Spatrick 	    MVPP22_SMI_MISC_CFG_REG) & ~MVPP22_SMI_POLLING_EN);
494b3a1ec52Spatrick 
4951a945772Spatrick 	sc->sc_aggr_ntxq = 1;
4961a945772Spatrick 	sc->sc_aggr_txqs = mallocarray(sc->sc_aggr_ntxq,
4971a945772Spatrick 	    sizeof(*sc->sc_aggr_txqs), M_DEVBUF, M_WAITOK | M_ZERO);
4981a945772Spatrick 
4991a945772Spatrick 	for (i = 0; i < sc->sc_aggr_ntxq; i++) {
5001a945772Spatrick 		txq = &sc->sc_aggr_txqs[i];
5011a945772Spatrick 		txq->id = i;
5021a945772Spatrick 		mvpp2_aggr_txq_hw_init(sc, txq);
5031a945772Spatrick 	}
5041a945772Spatrick 
5051a945772Spatrick 	mvpp2_rx_fifo_init(sc);
5061a945772Spatrick 	mvpp2_tx_fifo_init(sc);
5071a945772Spatrick 
5081a945772Spatrick 	mvpp2_write(sc, MVPP2_TX_SNOOP_REG, 0x1);
5091a945772Spatrick 
5101a945772Spatrick 	mvpp2_bm_pool_init(sc);
5111a945772Spatrick 
5121a945772Spatrick 	sc->sc_prs_shadow = mallocarray(MVPP2_PRS_TCAM_SRAM_SIZE,
5131a945772Spatrick 	    sizeof(*sc->sc_prs_shadow), M_DEVBUF, M_WAITOK | M_ZERO);
5141a945772Spatrick 
5151a945772Spatrick 	mvpp2_prs_default_init(sc);
5161a945772Spatrick 	mvpp2_cls_init(sc);
5171a945772Spatrick 
5181a945772Spatrick 	memset(&maa, 0, sizeof(maa));
5191a945772Spatrick 	for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) {
5201a945772Spatrick 		maa.ma_node = node;
5211a945772Spatrick 		maa.ma_dmat = sc->sc_dmat;
5221a945772Spatrick 		config_found(self, &maa, NULL);
5231a945772Spatrick 	}
5241a945772Spatrick }
5251a945772Spatrick 
5261a945772Spatrick void
mvpp2_axi_config(struct mvpp2_softc * sc)5271a945772Spatrick mvpp2_axi_config(struct mvpp2_softc *sc)
5281a945772Spatrick {
5291a945772Spatrick 	uint32_t reg;
5301a945772Spatrick 
53113d9cc68Spatrick 	mvpp2_write(sc, MVPP22_BM_ADDR_HIGH_RLS_REG, 0);
5321a945772Spatrick 
5331a945772Spatrick 	reg = (MVPP22_AXI_CODE_CACHE_WR_CACHE << MVPP22_AXI_ATTR_CACHE_OFFS) |
5341a945772Spatrick 	    (MVPP22_AXI_CODE_DOMAIN_OUTER_DOM << MVPP22_AXI_ATTR_DOMAIN_OFFS);
5351a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_BM_WR_ATTR_REG, reg);
5361a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG, reg);
5371a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG, reg);
5381a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_RX_DATA_WR_ATTR_REG, reg);
5391a945772Spatrick 
5401a945772Spatrick 	reg = (MVPP22_AXI_CODE_CACHE_RD_CACHE << MVPP22_AXI_ATTR_CACHE_OFFS) |
5411a945772Spatrick 	    (MVPP22_AXI_CODE_DOMAIN_OUTER_DOM << MVPP22_AXI_ATTR_DOMAIN_OFFS);
5421a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_BM_RD_ATTR_REG, reg);
5431a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG, reg);
5441a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG, reg);
5451a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_TX_DATA_RD_ATTR_REG, reg);
5461a945772Spatrick 
5471a945772Spatrick 	reg = (MVPP22_AXI_CODE_CACHE_NON_CACHE << MVPP22_AXI_CODE_CACHE_OFFS) |
5481a945772Spatrick 	    (MVPP22_AXI_CODE_DOMAIN_SYSTEM << MVPP22_AXI_CODE_DOMAIN_OFFS);
5491a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_RD_NORMAL_CODE_REG, reg);
5501a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_WR_NORMAL_CODE_REG, reg);
5511a945772Spatrick 
5521a945772Spatrick 	reg = (MVPP22_AXI_CODE_CACHE_RD_CACHE << MVPP22_AXI_CODE_CACHE_OFFS) |
5531a945772Spatrick 	    (MVPP22_AXI_CODE_DOMAIN_OUTER_DOM << MVPP22_AXI_CODE_DOMAIN_OFFS);
5541a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_RD_SNOOP_CODE_REG, reg);
5551a945772Spatrick 
5561a945772Spatrick 	reg = (MVPP22_AXI_CODE_CACHE_WR_CACHE << MVPP22_AXI_CODE_CACHE_OFFS) |
5571a945772Spatrick 	    (MVPP22_AXI_CODE_DOMAIN_OUTER_DOM << MVPP22_AXI_CODE_DOMAIN_OFFS);
5581a945772Spatrick 	mvpp2_write(sc, MVPP22_AXI_WR_SNOOP_CODE_REG, reg);
5591a945772Spatrick }
5601a945772Spatrick 
5611a945772Spatrick void
mvpp2_bm_pool_init(struct mvpp2_softc * sc)5621a945772Spatrick mvpp2_bm_pool_init(struct mvpp2_softc *sc)
5631a945772Spatrick {
5641a945772Spatrick 	struct mvpp2_bm_pool *bm;
5651a945772Spatrick 	struct mvpp2_buf *rxb;
5661a945772Spatrick 	uint64_t phys, virt;
5676d508037Spatrick 	int i, j, inuse;
5681a945772Spatrick 
5691a945772Spatrick 	for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) {
5701a945772Spatrick 		mvpp2_write(sc, MVPP2_BM_INTR_MASK_REG(i), 0);
5711a945772Spatrick 		mvpp2_write(sc, MVPP2_BM_INTR_CAUSE_REG(i), 0);
5721a945772Spatrick 	}
5731a945772Spatrick 
574be107da9Spatrick 	sc->sc_npools = ncpus;
575be107da9Spatrick 	sc->sc_npools = min(sc->sc_npools, MVPP2_BM_POOLS_NUM);
576be107da9Spatrick 
577be107da9Spatrick 	sc->sc_bm_pools = mallocarray(sc->sc_npools, sizeof(*sc->sc_bm_pools),
578be107da9Spatrick 	    M_DEVBUF, M_WAITOK | M_ZERO);
579be107da9Spatrick 
580be107da9Spatrick 	for (i = 0; i < sc->sc_npools; i++) {
5811a945772Spatrick 		bm = &sc->sc_bm_pools[i];
5821a945772Spatrick 		bm->bm_mem = mvpp2_dmamem_alloc(sc,
5831a945772Spatrick 		    MVPP2_BM_SIZE * sizeof(uint64_t) * 2,
5841a945772Spatrick 		    MVPP2_BM_POOL_PTR_ALIGN);
5857262ae33Spatrick 		KASSERT(bm->bm_mem != NULL);
5861a945772Spatrick 		bus_dmamap_sync(sc->sc_dmat, MVPP2_DMA_MAP(bm->bm_mem), 0,
5871a945772Spatrick 		    MVPP2_DMA_LEN(bm->bm_mem),
5881a945772Spatrick 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
5891a945772Spatrick 
5906d508037Spatrick 		mvpp2_write(sc, MVPP2_BM_POOL_CTRL_REG(i),
5916d508037Spatrick 		    mvpp2_read(sc, MVPP2_BM_POOL_CTRL_REG(i)) |
5926d508037Spatrick 		    MVPP2_BM_STOP_MASK);
5936d508037Spatrick 
5941a945772Spatrick 		mvpp2_write(sc, MVPP2_BM_POOL_BASE_REG(i),
5954f6c1c9bSpatrick 		    (uint64_t)MVPP2_DMA_DVA(bm->bm_mem) & 0xffffffff);
5961a945772Spatrick 		mvpp2_write(sc, MVPP22_BM_POOL_BASE_HIGH_REG,
5974f6c1c9bSpatrick 		    ((uint64_t)MVPP2_DMA_DVA(bm->bm_mem) >> 32)
5981a945772Spatrick 		    & MVPP22_BM_POOL_BASE_HIGH_MASK);
5991a945772Spatrick 		mvpp2_write(sc, MVPP2_BM_POOL_SIZE_REG(i),
6001a945772Spatrick 		    MVPP2_BM_SIZE);
6011a945772Spatrick 
6021a945772Spatrick 		mvpp2_write(sc, MVPP2_BM_POOL_CTRL_REG(i),
6031a945772Spatrick 		    mvpp2_read(sc, MVPP2_BM_POOL_CTRL_REG(i)) |
6041a945772Spatrick 		    MVPP2_BM_START_MASK);
6051a945772Spatrick 
6066d508037Spatrick 		/*
6076d508037Spatrick 		 * U-Boot might not have cleaned its pools.  The pool needs
6086d508037Spatrick 		 * to be empty before we fill it, otherwise our packets are
6096d508037Spatrick 		 * written to wherever U-Boot allocated memory.  Cleaning it
6106d508037Spatrick 		 * up ourselves is worrying as well, since the BM's pages are
6116d508037Spatrick 		 * probably in our own memory.  Best we can do is stop the BM,
6126d508037Spatrick 		 * set new memory and drain the pool.
6136d508037Spatrick 		 */
6146d508037Spatrick 		inuse = mvpp2_read(sc, MVPP2_BM_POOL_PTRS_NUM_REG(i)) &
6156d508037Spatrick 		    MVPP2_BM_POOL_PTRS_NUM_MASK;
6166d508037Spatrick 		inuse += mvpp2_read(sc, MVPP2_BM_BPPI_PTRS_NUM_REG(i)) &
6176d508037Spatrick 		    MVPP2_BM_BPPI_PTRS_NUM_MASK;
6186d508037Spatrick 		if (inuse)
6196d508037Spatrick 			inuse++;
6206d508037Spatrick 		for (j = 0; j < inuse; j++)
6216d508037Spatrick 			mvpp2_read(sc, MVPP2_BM_PHY_ALLOC_REG(i));
6226d508037Spatrick 
6231a945772Spatrick 		mvpp2_write(sc, MVPP2_POOL_BUF_SIZE_REG(i),
6241a945772Spatrick 		    roundup(MCLBYTES, 1 << MVPP2_POOL_BUF_SIZE_OFFSET));
6251a945772Spatrick 
6261a945772Spatrick 		bm->rxbuf = mallocarray(MVPP2_BM_SIZE, sizeof(struct mvpp2_buf),
6271a945772Spatrick 		    M_DEVBUF, M_WAITOK);
628be107da9Spatrick 		bm->freelist = mallocarray(MVPP2_BM_SIZE, sizeof(*bm->freelist),
629be107da9Spatrick 		    M_DEVBUF, M_WAITOK | M_ZERO);
6301a945772Spatrick 
6311a945772Spatrick 		for (j = 0; j < MVPP2_BM_SIZE; j++) {
6321a945772Spatrick 			rxb = &bm->rxbuf[j];
6331a945772Spatrick 			bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
6341a945772Spatrick 			    MCLBYTES, 0, BUS_DMA_WAITOK, &rxb->mb_map);
635be107da9Spatrick 			rxb->mb_m = NULL;
6361a945772Spatrick 		}
6371a945772Spatrick 
638be107da9Spatrick 		/* Use pool-id and rxbuf index as cookie. */
639be107da9Spatrick 		for (j = 0; j < MVPP2_BM_SIZE; j++)
640be107da9Spatrick 			bm->freelist[j] = (i << 16) | (j << 0);
641be107da9Spatrick 
6421a945772Spatrick 		for (j = 0; j < MVPP2_BM_SIZE; j++) {
6431a945772Spatrick 			rxb = &bm->rxbuf[j];
6441a945772Spatrick 			rxb->mb_m = mvpp2_alloc_mbuf(sc, rxb->mb_map);
6451a945772Spatrick 			if (rxb->mb_m == NULL)
6461a945772Spatrick 				break;
647be107da9Spatrick 
648be107da9Spatrick 			KASSERT(bm->freelist[bm->free_cons] != -1);
649be107da9Spatrick 			virt = bm->freelist[bm->free_cons];
650be107da9Spatrick 			bm->freelist[bm->free_cons] = -1;
651be107da9Spatrick 			bm->free_cons = (bm->free_cons + 1) % MVPP2_BM_SIZE;
652be107da9Spatrick 
6531a945772Spatrick 			phys = rxb->mb_map->dm_segs[0].ds_addr;
65413d9cc68Spatrick 			mvpp2_write(sc, MVPP22_BM_ADDR_HIGH_RLS_REG,
6551a945772Spatrick 			    (((virt >> 32) & MVPP22_ADDR_HIGH_MASK)
65613d9cc68Spatrick 			    << MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) |
65713d9cc68Spatrick 			    ((phys >> 32) & MVPP22_ADDR_HIGH_MASK));
6581a945772Spatrick 			mvpp2_write(sc, MVPP2_BM_VIRT_RLS_REG,
6591a945772Spatrick 			    virt & 0xffffffff);
6601a945772Spatrick 			mvpp2_write(sc, MVPP2_BM_PHY_RLS_REG(i),
6611a945772Spatrick 			    phys & 0xffffffff);
6621a945772Spatrick 		}
6631a945772Spatrick 	}
6641a945772Spatrick }
6651a945772Spatrick 
6661a945772Spatrick void
mvpp2_rx_fifo_init(struct mvpp2_softc * sc)6671a945772Spatrick mvpp2_rx_fifo_init(struct mvpp2_softc *sc)
6681a945772Spatrick {
6691a945772Spatrick 	int i;
6701a945772Spatrick 
6711a945772Spatrick 	mvpp2_write(sc, MVPP2_RX_DATA_FIFO_SIZE_REG(0),
6721a945772Spatrick 	    MVPP2_RX_FIFO_PORT_DATA_SIZE_32KB);
6731a945772Spatrick 	mvpp2_write(sc, MVPP2_RX_ATTR_FIFO_SIZE_REG(0),
6741a945772Spatrick 	    MVPP2_RX_FIFO_PORT_ATTR_SIZE_32KB);
6751a945772Spatrick 
6761a945772Spatrick 	mvpp2_write(sc, MVPP2_RX_DATA_FIFO_SIZE_REG(1),
6771a945772Spatrick 	    MVPP2_RX_FIFO_PORT_DATA_SIZE_8KB);
6781a945772Spatrick 	mvpp2_write(sc, MVPP2_RX_ATTR_FIFO_SIZE_REG(1),
6791a945772Spatrick 	    MVPP2_RX_FIFO_PORT_ATTR_SIZE_8KB);
6801a945772Spatrick 
6811a945772Spatrick 	for (i = 2; i < MVPP2_MAX_PORTS; i++) {
6821a945772Spatrick 		mvpp2_write(sc, MVPP2_RX_DATA_FIFO_SIZE_REG(i),
6831a945772Spatrick 		    MVPP2_RX_FIFO_PORT_DATA_SIZE_4KB);
6841a945772Spatrick 		mvpp2_write(sc, MVPP2_RX_ATTR_FIFO_SIZE_REG(i),
6851a945772Spatrick 		    MVPP2_RX_FIFO_PORT_ATTR_SIZE_4KB);
6861a945772Spatrick 	}
6871a945772Spatrick 
6881a945772Spatrick 	mvpp2_write(sc, MVPP2_RX_MIN_PKT_SIZE_REG, MVPP2_RX_FIFO_PORT_MIN_PKT);
6891a945772Spatrick 	mvpp2_write(sc, MVPP2_RX_FIFO_INIT_REG, 0x1);
6901a945772Spatrick }
6911a945772Spatrick 
6921a945772Spatrick void
mvpp2_tx_fifo_init(struct mvpp2_softc * sc)6931a945772Spatrick mvpp2_tx_fifo_init(struct mvpp2_softc *sc)
6941a945772Spatrick {
6951a945772Spatrick 	int i;
6961a945772Spatrick 
6971a945772Spatrick 	mvpp2_write(sc, MVPP22_TX_FIFO_SIZE_REG(0),
6981a945772Spatrick 	    MVPP22_TX_FIFO_DATA_SIZE_10KB);
6991a945772Spatrick 	mvpp2_write(sc, MVPP22_TX_FIFO_THRESH_REG(0),
7001a945772Spatrick 	    MVPP2_TX_FIFO_THRESHOLD_10KB);
7011a945772Spatrick 
7021a945772Spatrick 	for (i = 1; i < MVPP2_MAX_PORTS; i++) {
7031a945772Spatrick 		mvpp2_write(sc, MVPP22_TX_FIFO_SIZE_REG(i),
7041a945772Spatrick 		    MVPP22_TX_FIFO_DATA_SIZE_3KB);
7051a945772Spatrick 		mvpp2_write(sc, MVPP22_TX_FIFO_THRESH_REG(i),
7061a945772Spatrick 		    MVPP2_TX_FIFO_THRESHOLD_3KB);
7071a945772Spatrick 	}
7081a945772Spatrick }
7091a945772Spatrick 
7101a945772Spatrick int
mvpp2_prs_default_init(struct mvpp2_softc * sc)7111a945772Spatrick mvpp2_prs_default_init(struct mvpp2_softc *sc)
7121a945772Spatrick {
7131a945772Spatrick 	int i, j, ret;
7141a945772Spatrick 
7151a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_TCAM_CTRL_REG, MVPP2_PRS_TCAM_EN_MASK);
7161a945772Spatrick 
7171a945772Spatrick 	for (i = 0; i < MVPP2_PRS_TCAM_SRAM_SIZE; i++) {
7181a945772Spatrick 		mvpp2_write(sc, MVPP2_PRS_TCAM_IDX_REG, i);
7191a945772Spatrick 		for (j = 0; j < MVPP2_PRS_TCAM_WORDS; j++)
7201a945772Spatrick 			mvpp2_write(sc, MVPP2_PRS_TCAM_DATA_REG(j), 0);
7211a945772Spatrick 
7221a945772Spatrick 		mvpp2_write(sc, MVPP2_PRS_SRAM_IDX_REG, i);
7231a945772Spatrick 		for (j = 0; j < MVPP2_PRS_SRAM_WORDS; j++)
7241a945772Spatrick 			mvpp2_write(sc, MVPP2_PRS_SRAM_DATA_REG(j), 0);
7251a945772Spatrick 	}
7261a945772Spatrick 
7271a945772Spatrick 	for (i = 0; i < MVPP2_PRS_TCAM_SRAM_SIZE; i++)
7281a945772Spatrick 		mvpp2_prs_hw_inv(sc, i);
7291a945772Spatrick 
7301a945772Spatrick 	for (i = 0; i < MVPP2_MAX_PORTS; i++)
7311a945772Spatrick 		mvpp2_prs_hw_port_init(sc, i, MVPP2_PRS_LU_MH,
7321a945772Spatrick 		    MVPP2_PRS_PORT_LU_MAX, 0);
7331a945772Spatrick 
7341a945772Spatrick 	mvpp2_prs_def_flow_init(sc);
7351a945772Spatrick 	mvpp2_prs_mh_init(sc);
7361a945772Spatrick 	mvpp2_prs_mac_init(sc);
7371a945772Spatrick 	mvpp2_prs_dsa_init(sc);
7381a945772Spatrick 	ret = mvpp2_prs_etype_init(sc);
7391a945772Spatrick 	if (ret)
7401a945772Spatrick 		return ret;
7411a945772Spatrick 	ret = mvpp2_prs_vlan_init(sc);
7421a945772Spatrick 	if (ret)
7431a945772Spatrick 		return ret;
7441a945772Spatrick 	ret = mvpp2_prs_pppoe_init(sc);
7451a945772Spatrick 	if (ret)
7461a945772Spatrick 		return ret;
7471a945772Spatrick 	ret = mvpp2_prs_ip6_init(sc);
7481a945772Spatrick 	if (ret)
7491a945772Spatrick 		return ret;
7501a945772Spatrick 	ret = mvpp2_prs_ip4_init(sc);
7511a945772Spatrick 	if (ret)
7521a945772Spatrick 		return ret;
7531a945772Spatrick 
7541a945772Spatrick 	return 0;
7551a945772Spatrick }
7561a945772Spatrick 
7571a945772Spatrick void
mvpp2_prs_hw_inv(struct mvpp2_softc * sc,int index)7581a945772Spatrick mvpp2_prs_hw_inv(struct mvpp2_softc *sc, int index)
7591a945772Spatrick {
7601a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_TCAM_IDX_REG, index);
7611a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD),
7621a945772Spatrick 	    MVPP2_PRS_TCAM_INV_MASK);
7631a945772Spatrick }
7641a945772Spatrick 
7651a945772Spatrick void
mvpp2_prs_hw_port_init(struct mvpp2_softc * sc,int port,int lu_first,int lu_max,int offset)7661a945772Spatrick mvpp2_prs_hw_port_init(struct mvpp2_softc *sc, int port,
7671a945772Spatrick     int lu_first, int lu_max, int offset)
7681a945772Spatrick {
7691a945772Spatrick 	uint32_t reg;
7701a945772Spatrick 
7711a945772Spatrick 	reg = mvpp2_read(sc, MVPP2_PRS_INIT_LOOKUP_REG);
7721a945772Spatrick 	reg &= ~MVPP2_PRS_PORT_LU_MASK(port);
7731a945772Spatrick 	reg |=  MVPP2_PRS_PORT_LU_VAL(port, lu_first);
7741a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_INIT_LOOKUP_REG, reg);
7751a945772Spatrick 
7761a945772Spatrick 	reg = mvpp2_read(sc, MVPP2_PRS_MAX_LOOP_REG(port));
7771a945772Spatrick 	reg &= ~MVPP2_PRS_MAX_LOOP_MASK(port);
7781a945772Spatrick 	reg |= MVPP2_PRS_MAX_LOOP_VAL(port, lu_max);
7791a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_MAX_LOOP_REG(port), reg);
7801a945772Spatrick 
7811a945772Spatrick 	reg = mvpp2_read(sc, MVPP2_PRS_INIT_OFFS_REG(port));
7821a945772Spatrick 	reg &= ~MVPP2_PRS_INIT_OFF_MASK(port);
7831a945772Spatrick 	reg |= MVPP2_PRS_INIT_OFF_VAL(port, offset);
7841a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_INIT_OFFS_REG(port), reg);
7851a945772Spatrick }
7861a945772Spatrick 
7871a945772Spatrick void
mvpp2_prs_def_flow_init(struct mvpp2_softc * sc)7881a945772Spatrick mvpp2_prs_def_flow_init(struct mvpp2_softc *sc)
7891a945772Spatrick {
7901a945772Spatrick 	struct mvpp2_prs_entry pe;
7911a945772Spatrick 	int i;
7921a945772Spatrick 
7931a945772Spatrick 	for (i = 0; i < MVPP2_MAX_PORTS; i++) {
7941a945772Spatrick 		memset(&pe, 0, sizeof(pe));
7951a945772Spatrick 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
7961a945772Spatrick 		pe.index = MVPP2_PE_FIRST_DEFAULT_FLOW - i;
7971a945772Spatrick 		mvpp2_prs_tcam_port_map_set(&pe, 0);
7981a945772Spatrick 		mvpp2_prs_sram_ai_update(&pe, i, MVPP2_PRS_FLOW_ID_MASK);
7991a945772Spatrick 		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
8001a945772Spatrick 		mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_FLOWS);
8011a945772Spatrick 		mvpp2_prs_hw_write(sc, &pe);
8021a945772Spatrick 	}
8031a945772Spatrick }
8041a945772Spatrick 
8051a945772Spatrick void
mvpp2_prs_mh_init(struct mvpp2_softc * sc)8061a945772Spatrick mvpp2_prs_mh_init(struct mvpp2_softc *sc)
8071a945772Spatrick {
8081a945772Spatrick 	struct mvpp2_prs_entry pe;
8091a945772Spatrick 
8101a945772Spatrick 	memset(&pe, 0, sizeof(pe));
8111a945772Spatrick 	pe.index = MVPP2_PE_MH_DEFAULT;
8121a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MH);
8131a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, MVPP2_MH_SIZE,
8141a945772Spatrick 	    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
8151a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_MAC);
8161a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
8171a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_MH);
8181a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
8191a945772Spatrick }
8201a945772Spatrick 
8211a945772Spatrick void
mvpp2_prs_mac_init(struct mvpp2_softc * sc)8221a945772Spatrick mvpp2_prs_mac_init(struct mvpp2_softc *sc)
8231a945772Spatrick {
8241a945772Spatrick 	struct mvpp2_prs_entry pe;
8251a945772Spatrick 
8261a945772Spatrick 	memset(&pe, 0, sizeof(pe));
8271a945772Spatrick 	pe.index = MVPP2_PE_MAC_NON_PROMISCUOUS;
8281a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
8291a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
8301a945772Spatrick 	    MVPP2_PRS_RI_DROP_MASK);
8311a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
8321a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
8331a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
8341a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_MAC);
8351a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
8361a945772Spatrick 	mvpp2_prs_mac_drop_all_set(sc, 0, 0);
83741cd246cSpatrick 	mvpp2_prs_mac_promisc_set(sc, 0, MVPP2_PRS_L2_UNI_CAST, 0);
83841cd246cSpatrick 	mvpp2_prs_mac_promisc_set(sc, 0, MVPP2_PRS_L2_MULTI_CAST, 0);
8391a945772Spatrick }
8401a945772Spatrick 
8411a945772Spatrick void
mvpp2_prs_dsa_init(struct mvpp2_softc * sc)8421a945772Spatrick mvpp2_prs_dsa_init(struct mvpp2_softc *sc)
8431a945772Spatrick {
8441a945772Spatrick 	struct mvpp2_prs_entry pe;
8451a945772Spatrick 
8461a945772Spatrick 	mvpp2_prs_dsa_tag_set(sc, 0, 0, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
8471a945772Spatrick 	mvpp2_prs_dsa_tag_set(sc, 0, 0, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
8481a945772Spatrick 	mvpp2_prs_dsa_tag_set(sc, 0, 0, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
8491a945772Spatrick 	mvpp2_prs_dsa_tag_set(sc, 0, 0, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
8501a945772Spatrick 	mvpp2_prs_dsa_tag_ethertype_set(sc, 0, 0, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
8511a945772Spatrick 	mvpp2_prs_dsa_tag_ethertype_set(sc, 0, 0, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
8521a945772Spatrick 	mvpp2_prs_dsa_tag_ethertype_set(sc, 0, 1, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
8531a945772Spatrick 	mvpp2_prs_dsa_tag_ethertype_set(sc, 0, 1, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
8541a945772Spatrick 	memset(&pe, 0, sizeof(pe));
8551a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
8561a945772Spatrick 	pe.index = MVPP2_PE_DSA_DEFAULT;
8571a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
8581a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, 0, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
8591a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_MAC);
8601a945772Spatrick 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
8611a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
8621a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
8631a945772Spatrick }
8641a945772Spatrick 
8651a945772Spatrick int
mvpp2_prs_etype_init(struct mvpp2_softc * sc)8661a945772Spatrick mvpp2_prs_etype_init(struct mvpp2_softc *sc)
8671a945772Spatrick {
8681a945772Spatrick 	struct mvpp2_prs_entry pe;
8691a945772Spatrick 	int tid;
8701a945772Spatrick 
8711a945772Spatrick 	/* Ethertype: PPPoE */
8721a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
8731a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
8741a945772Spatrick 	if (tid < 0)
8751a945772Spatrick 		return tid;
8761a945772Spatrick 	memset(&pe, 0, sizeof(pe));
8771a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
8781a945772Spatrick 	pe.index = tid;
879e042150eSpatrick 	mvpp2_prs_match_etype(&pe, 0, ETHERTYPE_PPPOE);
8801a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, MVPP2_PPPOE_HDR_SIZE,
8811a945772Spatrick 	    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
8821a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
8831a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_PPPOE_MASK,
8841a945772Spatrick 	    MVPP2_PRS_RI_PPPOE_MASK);
8851a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_L2);
8861a945772Spatrick 	sc->sc_prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
8871a945772Spatrick 	sc->sc_prs_shadow[pe.index].finish = 0;
8881a945772Spatrick 	mvpp2_prs_shadow_ri_set(sc, pe.index, MVPP2_PRS_RI_PPPOE_MASK,
8891a945772Spatrick 	    MVPP2_PRS_RI_PPPOE_MASK);
8901a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
8911a945772Spatrick 
8921a945772Spatrick 	/* Ethertype: ARP */
8931a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
8941a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
8951a945772Spatrick 	if (tid < 0)
8961a945772Spatrick 		return tid;
8971a945772Spatrick 	memset(&pe, 0, sizeof(pe));
8981a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
8991a945772Spatrick 	pe.index = tid;
900e042150eSpatrick 	mvpp2_prs_match_etype(&pe, 0, ETHERTYPE_ARP);
9011a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
9021a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
9031a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_ARP,
9041a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
9051a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
9061a945772Spatrick 	    MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
9071a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_L2);
9081a945772Spatrick 	sc->sc_prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
9091a945772Spatrick 	sc->sc_prs_shadow[pe.index].finish = 1;
9101a945772Spatrick 	mvpp2_prs_shadow_ri_set(sc, pe.index, MVPP2_PRS_RI_L3_ARP,
9111a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
9121a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
9131a945772Spatrick 
9141a945772Spatrick 	/* Ethertype: LBTD */
9151a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
9161a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
9171a945772Spatrick 	if (tid < 0)
9181a945772Spatrick 		return tid;
9191a945772Spatrick 	memset(&pe, 0, sizeof(pe));
9201a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
9211a945772Spatrick 	pe.index = tid;
9221a945772Spatrick 	mvpp2_prs_match_etype(&pe, 0, MVPP2_IP_LBDT_TYPE);
9231a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
9241a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
9251a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
9261a945772Spatrick 	    MVPP2_PRS_RI_UDF3_RX_SPECIAL, MVPP2_PRS_RI_CPU_CODE_MASK |
9271a945772Spatrick 	    MVPP2_PRS_RI_UDF3_MASK);
9281a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
9291a945772Spatrick 	    MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
9301a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_L2);
9311a945772Spatrick 	sc->sc_prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
9321a945772Spatrick 	sc->sc_prs_shadow[pe.index].finish = 1;
9331a945772Spatrick 	mvpp2_prs_shadow_ri_set(sc, pe.index, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
9341a945772Spatrick 	    MVPP2_PRS_RI_UDF3_RX_SPECIAL, MVPP2_PRS_RI_CPU_CODE_MASK |
9351a945772Spatrick 	    MVPP2_PRS_RI_UDF3_MASK);
9361a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
9371a945772Spatrick 
9381a945772Spatrick 	/* Ethertype: IPv4 without options */
9391a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
9401a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
9411a945772Spatrick 	if (tid < 0)
9421a945772Spatrick 		return tid;
9431a945772Spatrick 	memset(&pe, 0, sizeof(pe));
9441a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
9451a945772Spatrick 	pe.index = tid;
946e042150eSpatrick 	mvpp2_prs_match_etype(&pe, 0, ETHERTYPE_IP);
9471a945772Spatrick 	mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
9481a945772Spatrick 	    MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
9491a945772Spatrick 	    MVPP2_PRS_IPV4_HEAD_MASK | MVPP2_PRS_IPV4_IHL_MASK);
9501a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
9511a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
9521a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
9531a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4,
9541a945772Spatrick 	    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
9551a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
9561a945772Spatrick 	    MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
9571a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_L2);
9581a945772Spatrick 	sc->sc_prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
9591a945772Spatrick 	sc->sc_prs_shadow[pe.index].finish = 0;
9601a945772Spatrick 	mvpp2_prs_shadow_ri_set(sc, pe.index, MVPP2_PRS_RI_L3_IP4,
9611a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
9621a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
9631a945772Spatrick 
9641a945772Spatrick 	/* Ethertype: IPv4 with options */
9651a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
9661a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
9671a945772Spatrick 	if (tid < 0)
9681a945772Spatrick 		return tid;
9691a945772Spatrick 	pe.index = tid;
9701a945772Spatrick 
9711a945772Spatrick 	pe.tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(MVPP2_ETH_TYPE_LEN)] = 0x0;
9721a945772Spatrick 	pe.tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(MVPP2_ETH_TYPE_LEN)] = 0x0;
9731a945772Spatrick 	mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
9741a945772Spatrick 	    MVPP2_PRS_IPV4_HEAD, MVPP2_PRS_IPV4_HEAD_MASK);
9751a945772Spatrick 	pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
9761a945772Spatrick 	pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
9771a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT,
9781a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
9791a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_L2);
9801a945772Spatrick 	sc->sc_prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
9811a945772Spatrick 	sc->sc_prs_shadow[pe.index].finish = 0;
9821a945772Spatrick 	mvpp2_prs_shadow_ri_set(sc, pe.index, MVPP2_PRS_RI_L3_IP4_OPT,
9831a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
9841a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
9851a945772Spatrick 
9861a945772Spatrick 	/* Ethertype: IPv6 without options */
9871a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
9881a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
9891a945772Spatrick 	if (tid < 0)
9901a945772Spatrick 		return tid;
9911a945772Spatrick 	memset(&pe, 0, sizeof(pe));
9921a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
9931a945772Spatrick 	pe.index = tid;
994e042150eSpatrick 	mvpp2_prs_match_etype(&pe, 0, ETHERTYPE_IPV6);
9951a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 +
9961a945772Spatrick 	    MVPP2_MAX_L3_ADDR_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
9971a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
9981a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
9991a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
10001a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
10011a945772Spatrick 	    MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
10021a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_L2);
10031a945772Spatrick 	sc->sc_prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
10041a945772Spatrick 	sc->sc_prs_shadow[pe.index].finish = 0;
10051a945772Spatrick 	mvpp2_prs_shadow_ri_set(sc, pe.index, MVPP2_PRS_RI_L3_IP6,
10061a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
10071a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
10081a945772Spatrick 
10091a945772Spatrick 	/* Default entry for MVPP2_PRS_LU_L2 - Unknown ethtype */
1010ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
10111a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
10121a945772Spatrick 	pe.index = MVPP2_PE_ETH_TYPE_UN;
10131a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
10141a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
10151a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
10161a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
10171a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
10181a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
10191a945772Spatrick 	    MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
10201a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_L2);
10211a945772Spatrick 	sc->sc_prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
10221a945772Spatrick 	sc->sc_prs_shadow[pe.index].finish = 1;
10231a945772Spatrick 	mvpp2_prs_shadow_ri_set(sc, pe.index, MVPP2_PRS_RI_L3_UN,
10241a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
10251a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
10261a945772Spatrick 
10271a945772Spatrick 	return 0;
10281a945772Spatrick }
10291a945772Spatrick 
10301a945772Spatrick int
mvpp2_prs_vlan_init(struct mvpp2_softc * sc)10311a945772Spatrick mvpp2_prs_vlan_init(struct mvpp2_softc *sc)
10321a945772Spatrick {
10331a945772Spatrick 	struct mvpp2_prs_entry pe;
10341a945772Spatrick 	int ret;
10351a945772Spatrick 
10361a945772Spatrick 	sc->sc_prs_double_vlans = mallocarray(MVPP2_PRS_DBL_VLANS_MAX,
10371a945772Spatrick 	    sizeof(*sc->sc_prs_double_vlans), M_DEVBUF, M_WAITOK | M_ZERO);
10381a945772Spatrick 
1039e042150eSpatrick 	ret = mvpp2_prs_double_vlan_add(sc, ETHERTYPE_VLAN, ETHERTYPE_QINQ,
10401a945772Spatrick 	    MVPP2_PRS_PORT_MASK);
10411a945772Spatrick 	if (ret)
10421a945772Spatrick 		return ret;
1043e042150eSpatrick 	ret = mvpp2_prs_double_vlan_add(sc, ETHERTYPE_VLAN, ETHERTYPE_VLAN,
10441a945772Spatrick 	    MVPP2_PRS_PORT_MASK);
10451a945772Spatrick 	if (ret)
10461a945772Spatrick 		return ret;
1047e042150eSpatrick 	ret = mvpp2_prs_vlan_add(sc, ETHERTYPE_QINQ, MVPP2_PRS_SINGLE_VLAN_AI,
10481a945772Spatrick 	    MVPP2_PRS_PORT_MASK);
10491a945772Spatrick 	if (ret)
10501a945772Spatrick 		return ret;
1051e042150eSpatrick 	ret = mvpp2_prs_vlan_add(sc, ETHERTYPE_VLAN, MVPP2_PRS_SINGLE_VLAN_AI,
10521a945772Spatrick 	    MVPP2_PRS_PORT_MASK);
10531a945772Spatrick 	if (ret)
10541a945772Spatrick 		return ret;
10551a945772Spatrick 
1056ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
10571a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
10581a945772Spatrick 	pe.index = MVPP2_PE_VLAN_DBL;
10591a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
10601a945772Spatrick 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
10611a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
10621a945772Spatrick 	    MVPP2_PRS_RI_VLAN_MASK);
10631a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_DBL_VLAN_AI_BIT,
10641a945772Spatrick 	    MVPP2_PRS_DBL_VLAN_AI_BIT);
10651a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
10661a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_VLAN);
10671a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
10681a945772Spatrick 
1069ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
10701a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
10711a945772Spatrick 	pe.index = MVPP2_PE_VLAN_NONE;
10721a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
1073e7c76d8bSpatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
1074e7c76d8bSpatrick 	    MVPP2_PRS_RI_VLAN_MASK);
10751a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
10761a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_VLAN);
10771a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
10781a945772Spatrick 
10791a945772Spatrick 	return 0;
10801a945772Spatrick }
10811a945772Spatrick 
10821a945772Spatrick int
mvpp2_prs_pppoe_init(struct mvpp2_softc * sc)10831a945772Spatrick mvpp2_prs_pppoe_init(struct mvpp2_softc *sc)
10841a945772Spatrick {
10851a945772Spatrick 	struct mvpp2_prs_entry pe;
10861a945772Spatrick 	int tid;
10871a945772Spatrick 
10881a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
10891a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
10901a945772Spatrick 	if (tid < 0)
10911a945772Spatrick 		return tid;
10921a945772Spatrick 
1093ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
10941a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
10951a945772Spatrick 	pe.index = tid;
1096e042150eSpatrick 	mvpp2_prs_match_etype(&pe, 0, PPP_IP);
10971a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
10981a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT,
10991a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
11001a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4,
11011a945772Spatrick 	    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
11021a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
11031a945772Spatrick 	    MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
11041a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_PPPOE);
11051a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
11061a945772Spatrick 
11071a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
11081a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
11091a945772Spatrick 	if (tid < 0)
11101a945772Spatrick 		return tid;
11111a945772Spatrick 
11121a945772Spatrick 	pe.index = tid;
11131a945772Spatrick 	mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
11141a945772Spatrick 	    MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
11151a945772Spatrick 	    MVPP2_PRS_IPV4_HEAD_MASK | MVPP2_PRS_IPV4_IHL_MASK);
11161a945772Spatrick 	pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
11171a945772Spatrick 	pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
11181a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK);
11191a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_PPPOE);
11201a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
11211a945772Spatrick 
11221a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
11231a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
11241a945772Spatrick 	if (tid < 0)
11251a945772Spatrick 		return tid;
11261a945772Spatrick 
1127ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
11281a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
11291a945772Spatrick 	pe.index = tid;
1130e042150eSpatrick 	mvpp2_prs_match_etype(&pe, 0, PPP_IPV6);
11311a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
11321a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
11331a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
11341a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4,
11351a945772Spatrick 	    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
11361a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
11371a945772Spatrick 	    MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
11381a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_PPPOE);
11391a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
11401a945772Spatrick 
11411a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
11421a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
11431a945772Spatrick 	if (tid < 0)
11441a945772Spatrick 		return tid;
11451a945772Spatrick 
1146ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
11471a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
11481a945772Spatrick 	pe.index = tid;
11491a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
11501a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK);
11511a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
11521a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
11531a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
11541a945772Spatrick 	    MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
11551a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_PPPOE);
11561a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
11571a945772Spatrick 
11581a945772Spatrick 	return 0;
11591a945772Spatrick }
11601a945772Spatrick 
11611a945772Spatrick int
mvpp2_prs_ip6_init(struct mvpp2_softc * sc)11621a945772Spatrick mvpp2_prs_ip6_init(struct mvpp2_softc *sc)
11631a945772Spatrick {
11641a945772Spatrick 	struct mvpp2_prs_entry pe;
11651a945772Spatrick 	int tid, ret;
11661a945772Spatrick 
1167e042150eSpatrick 	ret = mvpp2_prs_ip6_proto(sc, IPPROTO_TCP, MVPP2_PRS_RI_L4_TCP,
11681a945772Spatrick 	    MVPP2_PRS_RI_L4_PROTO_MASK);
11691a945772Spatrick 	if (ret)
11701a945772Spatrick 		return ret;
1171e042150eSpatrick 	ret = mvpp2_prs_ip6_proto(sc, IPPROTO_UDP, MVPP2_PRS_RI_L4_UDP,
11721a945772Spatrick 	    MVPP2_PRS_RI_L4_PROTO_MASK);
11731a945772Spatrick 	if (ret)
11741a945772Spatrick 		return ret;
1175e042150eSpatrick 	ret = mvpp2_prs_ip6_proto(sc, IPPROTO_ICMPV6,
11761a945772Spatrick 	    MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
11771a945772Spatrick 	    MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK);
11781a945772Spatrick 	if (ret)
11791a945772Spatrick 		return ret;
1180e042150eSpatrick 	ret = mvpp2_prs_ip6_proto(sc, IPPROTO_IPIP, MVPP2_PRS_RI_UDF7_IP6_LITE,
11811a945772Spatrick 	    MVPP2_PRS_RI_UDF7_MASK);
11821a945772Spatrick 	if (ret)
11831a945772Spatrick 		return ret;
11841a945772Spatrick 	ret = mvpp2_prs_ip6_cast(sc, MVPP2_PRS_L3_MULTI_CAST);
11851a945772Spatrick 	if (ret)
11861a945772Spatrick 		return ret;
11871a945772Spatrick 
11881a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
11891a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
11901a945772Spatrick 	if (tid < 0)
11911a945772Spatrick 		return tid;
11921a945772Spatrick 
1193ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
11941a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
11951a945772Spatrick 	pe.index = tid;
11961a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
11971a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
11981a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe,
11991a945772Spatrick 	    MVPP2_PRS_RI_L3_UN | MVPP2_PRS_RI_DROP_MASK,
12001a945772Spatrick 	    MVPP2_PRS_RI_L3_PROTO_MASK | MVPP2_PRS_RI_DROP_MASK);
12011a945772Spatrick 	mvpp2_prs_tcam_data_byte_set(&pe, 1, 0x00, MVPP2_PRS_IPV6_HOP_MASK);
12021a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
12031a945772Spatrick 	    MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
12041a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP4);
12051a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
12061a945772Spatrick 
1207ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
12081a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
12091a945772Spatrick 	pe.index = MVPP2_PE_IP6_PROTO_UN;
12101a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
12111a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
12121a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
12131a945772Spatrick 	    MVPP2_PRS_RI_L4_PROTO_MASK);
12141a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
12151a945772Spatrick 	    sizeof(struct ip6_hdr) - 6, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
12161a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
12171a945772Spatrick 	    MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
12181a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
12191a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP4);
12201a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
12211a945772Spatrick 
1222ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
12231a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
12241a945772Spatrick 	pe.index = MVPP2_PE_IP6_EXT_PROTO_UN;
12251a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
12261a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
12271a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
12281a945772Spatrick 	    MVPP2_PRS_RI_L4_PROTO_MASK);
12291a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_EXT_AI_BIT,
12301a945772Spatrick 	    MVPP2_PRS_IPV6_EXT_AI_BIT);
12311a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
12321a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP4);
12331a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
12341a945772Spatrick 
1235ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
12361a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
12371a945772Spatrick 	pe.index = MVPP2_PE_IP6_ADDR_UN;
12381a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
12391a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
12401a945772Spatrick 	    MVPP2_PRS_RI_L3_ADDR_MASK);
12411a945772Spatrick 	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
12421a945772Spatrick 	    MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
12431a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
12441a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
12451a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
12461a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP6);
12471a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
12481a945772Spatrick 
12491a945772Spatrick 	return 0;
12501a945772Spatrick }
12511a945772Spatrick 
12521a945772Spatrick int
mvpp2_prs_ip4_init(struct mvpp2_softc * sc)12531a945772Spatrick mvpp2_prs_ip4_init(struct mvpp2_softc *sc)
12541a945772Spatrick {
12551a945772Spatrick 	struct mvpp2_prs_entry pe;
12561a945772Spatrick 	int ret;
12571a945772Spatrick 
1258e042150eSpatrick 	ret = mvpp2_prs_ip4_proto(sc, IPPROTO_TCP, MVPP2_PRS_RI_L4_TCP,
12591a945772Spatrick 	    MVPP2_PRS_RI_L4_PROTO_MASK);
12601a945772Spatrick 	if (ret)
12611a945772Spatrick 		return ret;
1262e042150eSpatrick 	ret = mvpp2_prs_ip4_proto(sc, IPPROTO_UDP, MVPP2_PRS_RI_L4_UDP,
12631a945772Spatrick 	    MVPP2_PRS_RI_L4_PROTO_MASK);
12641a945772Spatrick 	if (ret)
12651a945772Spatrick 		return ret;
1266e042150eSpatrick 	ret = mvpp2_prs_ip4_proto(sc, IPPROTO_IGMP,
12671a945772Spatrick 	    MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
12681a945772Spatrick 	    MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK);
12691a945772Spatrick 	if (ret)
12701a945772Spatrick 		return ret;
12711a945772Spatrick 	ret = mvpp2_prs_ip4_cast(sc, MVPP2_PRS_L3_BROAD_CAST);
12721a945772Spatrick 	if (ret)
12731a945772Spatrick 		return ret;
12741a945772Spatrick 	ret = mvpp2_prs_ip4_cast(sc, MVPP2_PRS_L3_MULTI_CAST);
12751a945772Spatrick 	if (ret)
12761a945772Spatrick 		return ret;
12771a945772Spatrick 
1278ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
12791a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
12801a945772Spatrick 	pe.index = MVPP2_PE_IP4_PROTO_UN;
12811a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
12821a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
12831a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
12841a945772Spatrick 	    sizeof(struct ip) - 4, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
12851a945772Spatrick 	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
12861a945772Spatrick 	    MVPP2_PRS_IPV4_DIP_AI_BIT);
12871a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
12881a945772Spatrick 	    MVPP2_PRS_RI_L4_PROTO_MASK);
12891a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
12901a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
12911a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP4);
12921a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
12931a945772Spatrick 
1294ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
12951a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
12961a945772Spatrick 	pe.index = MVPP2_PE_IP4_ADDR_UN;
12971a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
12981a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
12991a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
13001a945772Spatrick 	    MVPP2_PRS_RI_L3_ADDR_MASK);
13011a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
13021a945772Spatrick 	    MVPP2_PRS_IPV4_DIP_AI_BIT);
13031a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
13041a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP4);
13051a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
13061a945772Spatrick 
13071a945772Spatrick 	return 0;
13081a945772Spatrick }
13091a945772Spatrick 
13101a945772Spatrick int
mvpp2_port_match(struct device * parent,void * cfdata,void * aux)13111a945772Spatrick mvpp2_port_match(struct device *parent, void *cfdata, void *aux)
13121a945772Spatrick {
13131a945772Spatrick 	struct mvpp2_attach_args *maa = aux;
13141a945772Spatrick 	char buf[32];
13151a945772Spatrick 
13161a945772Spatrick 	if (OF_getprop(maa->ma_node, "status", buf, sizeof(buf)) > 0 &&
13171a945772Spatrick 	    strcmp(buf, "disabled") == 0)
13181a945772Spatrick 		return 0;
13191a945772Spatrick 
13201a945772Spatrick 	return 1;
13211a945772Spatrick }
13221a945772Spatrick 
13231a945772Spatrick void
mvpp2_port_attach(struct device * parent,struct device * self,void * aux)13241a945772Spatrick mvpp2_port_attach(struct device *parent, struct device *self, void *aux)
13251a945772Spatrick {
13261a945772Spatrick 	struct mvpp2_port *sc = (void *)self;
13271a945772Spatrick 	struct mvpp2_attach_args *maa = aux;
13281a945772Spatrick 	struct mvpp2_tx_queue *txq;
13291a945772Spatrick 	struct mvpp2_rx_queue *rxq;
13301a945772Spatrick 	struct ifnet *ifp;
13311a945772Spatrick 	uint32_t phy, reg;
13321a945772Spatrick 	int i, idx, len, node;
1333755c7aeaSpatrick 	int mii_flags = 0;
13341a945772Spatrick 	char *phy_mode;
13351a945772Spatrick 	char *managed;
13361a945772Spatrick 
13371a945772Spatrick 	sc->sc = (void *)parent;
13381a945772Spatrick 	sc->sc_node = maa->ma_node;
13391a945772Spatrick 	sc->sc_dmat = maa->ma_dmat;
13401a945772Spatrick 
13411a945772Spatrick 	sc->sc_id = OF_getpropint(sc->sc_node, "port-id", 0);
13421a945772Spatrick 	sc->sc_gop_id = OF_getpropint(sc->sc_node, "gop-port-id", 0);
13431a945772Spatrick 	sc->sc_sfp = OF_getpropint(sc->sc_node, "sfp", 0);
13441a945772Spatrick 
13451a945772Spatrick 	len = OF_getproplen(sc->sc_node, "phy-mode");
13461a945772Spatrick 	if (len <= 0) {
13471a945772Spatrick 		printf("%s: cannot extract phy-mode\n", self->dv_xname);
13481a945772Spatrick 		return;
13491a945772Spatrick 	}
13501a945772Spatrick 
13511a945772Spatrick 	phy_mode = malloc(len, M_TEMP, M_WAITOK);
13521a945772Spatrick 	OF_getprop(sc->sc_node, "phy-mode", phy_mode, len);
13537d13f3eaSkettenis 	if (!strncmp(phy_mode, "10gbase-r", strlen("10gbase-r")))
13547d13f3eaSkettenis 		sc->sc_phy_mode = PHY_MODE_10GBASER;
13557d13f3eaSkettenis 	else if (!strncmp(phy_mode, "10gbase-kr", strlen("10gbase-kr")))
13561a945772Spatrick 		sc->sc_phy_mode = PHY_MODE_10GBASER;
13571a945772Spatrick 	else if (!strncmp(phy_mode, "2500base-x", strlen("2500base-x")))
13581a945772Spatrick 		sc->sc_phy_mode = PHY_MODE_2500BASEX;
13591a945772Spatrick 	else if (!strncmp(phy_mode, "1000base-x", strlen("1000base-x")))
13601a945772Spatrick 		sc->sc_phy_mode = PHY_MODE_1000BASEX;
13611a945772Spatrick 	else if (!strncmp(phy_mode, "sgmii", strlen("sgmii")))
13621a945772Spatrick 		sc->sc_phy_mode = PHY_MODE_SGMII;
13631a945772Spatrick 	else if (!strncmp(phy_mode, "rgmii-rxid", strlen("rgmii-rxid")))
13641a945772Spatrick 		sc->sc_phy_mode = PHY_MODE_RGMII_RXID;
13651a945772Spatrick 	else if (!strncmp(phy_mode, "rgmii-txid", strlen("rgmii-txid")))
13661a945772Spatrick 		sc->sc_phy_mode = PHY_MODE_RGMII_TXID;
13671a945772Spatrick 	else if (!strncmp(phy_mode, "rgmii-id", strlen("rgmii-id")))
13681a945772Spatrick 		sc->sc_phy_mode = PHY_MODE_RGMII_ID;
13691a945772Spatrick 	else if (!strncmp(phy_mode, "rgmii", strlen("rgmii")))
13701a945772Spatrick 		sc->sc_phy_mode = PHY_MODE_RGMII;
13711a945772Spatrick 	else {
13721a945772Spatrick 		printf("%s: cannot use phy-mode %s\n", self->dv_xname,
13731a945772Spatrick 		    phy_mode);
13741a945772Spatrick 		return;
13751a945772Spatrick 	}
13761a945772Spatrick 	free(phy_mode, M_TEMP, len);
13771a945772Spatrick 
13781a945772Spatrick 	/* Lookup PHY. */
13791a945772Spatrick 	phy = OF_getpropint(sc->sc_node, "phy", 0);
13801a945772Spatrick 	if (phy) {
13811a945772Spatrick 		node = OF_getnodebyphandle(phy);
13821a945772Spatrick 		if (!node) {
13831a945772Spatrick 			printf(": no phy\n");
13841a945772Spatrick 			return;
13851a945772Spatrick 		}
13861a945772Spatrick 		sc->sc_mdio = mii_byphandle(phy);
13871a945772Spatrick 		sc->sc_phyloc = OF_getpropint(node, "reg", MII_PHY_ANY);
13881a945772Spatrick 		sc->sc_sfp = OF_getpropint(node, "sfp", sc->sc_sfp);
1389a69db676Spatrick 		sc->sc_mii.mii_node = node;
13901a945772Spatrick 	}
13911a945772Spatrick 
1392a02f2d56Skettenis 	if (sc->sc_sfp)
1393a02f2d56Skettenis 		config_mountroot(self, mvpp2_port_attach_sfp);
1394a02f2d56Skettenis 
13951a945772Spatrick 	if ((len = OF_getproplen(sc->sc_node, "managed")) >= 0) {
13961a945772Spatrick 		managed = malloc(len, M_TEMP, M_WAITOK);
13971a945772Spatrick 		OF_getprop(sc->sc_node, "managed", managed, len);
13981a945772Spatrick 		if (!strncmp(managed, "in-band-status",
13991a945772Spatrick 		    strlen("in-band-status")))
14001a945772Spatrick 			sc->sc_inband_status = 1;
14011a945772Spatrick 		free(managed, M_TEMP, len);
14021a945772Spatrick 	}
14031a945772Spatrick 
14041a945772Spatrick 	if (OF_getprop(sc->sc_node, "local-mac-address",
14051a945772Spatrick 	    &sc->sc_lladdr, ETHER_ADDR_LEN) != ETHER_ADDR_LEN)
14061a945772Spatrick 		memset(sc->sc_lladdr, 0xff, sizeof(sc->sc_lladdr));
14071a945772Spatrick 	printf(": address %s\n", ether_sprintf(sc->sc_lladdr));
14081a945772Spatrick 
14091a945772Spatrick 	sc->sc_ntxq = sc->sc_nrxq = 1;
14101a945772Spatrick 	sc->sc_txqs = mallocarray(sc->sc_ntxq, sizeof(*sc->sc_txqs),
14111a945772Spatrick 	    M_DEVBUF, M_WAITOK | M_ZERO);
14121a945772Spatrick 	sc->sc_rxqs = mallocarray(sc->sc_nrxq, sizeof(*sc->sc_rxqs),
14131a945772Spatrick 	    M_DEVBUF, M_WAITOK | M_ZERO);
14141a945772Spatrick 
14151a945772Spatrick 	for (i = 0; i < sc->sc_ntxq; i++) {
14161a945772Spatrick 		txq = &sc->sc_txqs[i];
14171a945772Spatrick 		txq->id = mvpp2_txq_phys(sc->sc_id, i);
14181a945772Spatrick 		txq->log_id = i;
14191a945772Spatrick 		txq->done_pkts_coal = MVPP2_TXDONE_COAL_PKTS_THRESH;
14201a945772Spatrick 	}
14211a945772Spatrick 
14221a945772Spatrick 	sc->sc_tx_time_coal = MVPP2_TXDONE_COAL_USEC;
14231a945772Spatrick 
14241a945772Spatrick 	for (i = 0; i < sc->sc_nrxq; i++) {
14251a945772Spatrick 		rxq = &sc->sc_rxqs[i];
14261a945772Spatrick 		rxq->id = sc->sc_id * 32 + i;
14271a945772Spatrick 		rxq->pkts_coal = MVPP2_RX_COAL_PKTS;
14281a945772Spatrick 		rxq->time_coal = MVPP2_RX_COAL_USEC;
14291a945772Spatrick 	}
14301a945772Spatrick 
14311a945772Spatrick 	mvpp2_egress_disable(sc);
14321a945772Spatrick 	mvpp2_port_disable(sc);
14331a945772Spatrick 
14341a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_ISR_RXQ_GROUP_INDEX_REG,
14351a945772Spatrick 	    sc->sc_id << MVPP2_ISR_RXQ_GROUP_INDEX_GROUP_SHIFT |
14361a945772Spatrick 	    0 /* queue vector id */);
14371a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_ISR_RXQ_SUB_GROUP_CONFIG_REG,
14381a945772Spatrick 	    sc->sc_nrxq << MVPP2_ISR_RXQ_SUB_GROUP_CONFIG_SIZE_SHIFT |
14391a945772Spatrick 	    0 /* first rxq */);
14401a945772Spatrick 
14411a945772Spatrick 	mvpp2_ingress_disable(sc);
14421a945772Spatrick 	mvpp2_defaults_set(sc);
14431a945772Spatrick 
14441a945772Spatrick 	mvpp2_cls_oversize_rxq_set(sc);
14451a945772Spatrick 	mvpp2_cls_port_config(sc);
14461a945772Spatrick 
1447be107da9Spatrick 	/*
1448be107da9Spatrick 	 * We have one pool per core, so all RX queues on a specific
1449be107da9Spatrick 	 * core share that pool.  Also long and short uses the same
1450be107da9Spatrick 	 * pool.
1451be107da9Spatrick 	 */
14521a945772Spatrick 	for (i = 0; i < sc->sc_nrxq; i++) {
1453be107da9Spatrick 		mvpp2_rxq_long_pool_set(sc, i, i);
1454be107da9Spatrick 		mvpp2_rxq_short_pool_set(sc, i, i);
14551a945772Spatrick 	}
14561a945772Spatrick 
1457c56f4c70Spatrick 	mvpp2_mac_reset_assert(sc);
1458c56f4c70Spatrick 	mvpp2_pcs_reset_assert(sc);
14591a945772Spatrick 
14601a945772Spatrick 	timeout_set(&sc->sc_tick, mvpp2_tick, sc);
14611a945772Spatrick 
14621a945772Spatrick 	ifp = &sc->sc_ac.ac_if;
14631a945772Spatrick 	ifp->if_softc = sc;
14641a945772Spatrick 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
14651a945772Spatrick 	ifp->if_ioctl = mvpp2_ioctl;
14661a945772Spatrick 	ifp->if_start = mvpp2_start;
14671a945772Spatrick 	ifp->if_watchdog = mvpp2_watchdog;
1468cf96265bSbluhm 	ifq_init_maxlen(&ifp->if_snd, MVPP2_NTXDESC - 1);
14691a945772Spatrick 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
14701a945772Spatrick 
14711a945772Spatrick 	ifp->if_capabilities = IFCAP_VLAN_MTU;
14721a945772Spatrick 
14731a945772Spatrick 	sc->sc_mii.mii_ifp = ifp;
14741a945772Spatrick 	sc->sc_mii.mii_readreg = mvpp2_mii_readreg;
14751a945772Spatrick 	sc->sc_mii.mii_writereg = mvpp2_mii_writereg;
14761a945772Spatrick 	sc->sc_mii.mii_statchg = mvpp2_mii_statchg;
14771a945772Spatrick 
14781a945772Spatrick 	ifmedia_init(&sc->sc_media, 0, mvpp2_media_change, mvpp2_media_status);
14791a945772Spatrick 
14801a945772Spatrick 	if (sc->sc_mdio) {
1481755c7aeaSpatrick 		switch (sc->sc_phy_mode) {
1482755c7aeaSpatrick 		case PHY_MODE_1000BASEX:
1483755c7aeaSpatrick 			mii_flags |= MIIF_IS_1000X;
1484755c7aeaSpatrick 			break;
1485755c7aeaSpatrick 		case PHY_MODE_SGMII:
1486755c7aeaSpatrick 			mii_flags |= MIIF_SGMII;
1487755c7aeaSpatrick 			break;
1488755c7aeaSpatrick 		case PHY_MODE_RGMII_ID:
1489755c7aeaSpatrick 			mii_flags |= MIIF_RXID | MIIF_TXID;
1490755c7aeaSpatrick 			break;
1491755c7aeaSpatrick 		case PHY_MODE_RGMII_RXID:
1492755c7aeaSpatrick 			mii_flags |= MIIF_RXID;
1493755c7aeaSpatrick 			break;
1494755c7aeaSpatrick 		case PHY_MODE_RGMII_TXID:
1495755c7aeaSpatrick 			mii_flags |= MIIF_TXID;
1496755c7aeaSpatrick 			break;
1497755c7aeaSpatrick 		default:
1498755c7aeaSpatrick 			break;
1499755c7aeaSpatrick 		}
15001a945772Spatrick 		mii_attach(self, &sc->sc_mii, 0xffffffff, sc->sc_phyloc,
1501755c7aeaSpatrick 		    (sc->sc_phyloc == MII_PHY_ANY) ? 0 : MII_OFFSET_ANY,
1502755c7aeaSpatrick 		    mii_flags);
15031a945772Spatrick 		if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
15041a945772Spatrick 			printf("%s: no PHY found!\n", self->dv_xname);
15051a945772Spatrick 			ifmedia_add(&sc->sc_mii.mii_media,
15061a945772Spatrick 			    IFM_ETHER|IFM_MANUAL, 0, NULL);
15071a945772Spatrick 			ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL);
15081a945772Spatrick 		} else
15091a945772Spatrick 			ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
15101a945772Spatrick 	} else {
15111a945772Spatrick 		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO, 0, NULL);
15121a945772Spatrick 		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
15131a945772Spatrick 
15141a945772Spatrick 		if (sc->sc_inband_status) {
15159b4ffe48Skettenis 			switch (sc->sc_phy_mode) {
15169b4ffe48Skettenis 			case PHY_MODE_1000BASEX:
15179b4ffe48Skettenis 				sc->sc_mii.mii_media_active =
15189b4ffe48Skettenis 				    IFM_ETHER|IFM_1000_KX|IFM_FDX;
15199b4ffe48Skettenis 				break;
15209b4ffe48Skettenis 			case PHY_MODE_2500BASEX:
15219b4ffe48Skettenis 				sc->sc_mii.mii_media_active =
15229b4ffe48Skettenis 				    IFM_ETHER|IFM_2500_KX|IFM_FDX;
15239b4ffe48Skettenis 				break;
15249b4ffe48Skettenis 			case PHY_MODE_10GBASER:
15259b4ffe48Skettenis 				sc->sc_mii.mii_media_active =
15269b4ffe48Skettenis 				    IFM_ETHER|IFM_10G_KR|IFM_FDX;
15279b4ffe48Skettenis 				break;
15289b4ffe48Skettenis 			default:
15299b4ffe48Skettenis 				break;
15309b4ffe48Skettenis 			}
15311a945772Spatrick 			mvpp2_inband_statchg(sc);
15321a945772Spatrick 		} else {
15331a945772Spatrick 			sc->sc_mii.mii_media_status = IFM_AVALID|IFM_ACTIVE;
15341a945772Spatrick 			sc->sc_mii.mii_media_active = IFM_ETHER|IFM_1000_T|IFM_FDX;
15351a945772Spatrick 			mvpp2_mii_statchg(self);
15361a945772Spatrick 		}
15371a945772Spatrick 
15381a945772Spatrick 		ifp->if_baudrate = ifmedia_baudrate(sc->sc_mii.mii_media_active);
15391a945772Spatrick 		ifp->if_link_state = LINK_STATE_FULL_DUPLEX;
15401a945772Spatrick 	}
15411a945772Spatrick 
15421a945772Spatrick 	if_attach(ifp);
15431a945772Spatrick 	ether_ifattach(ifp);
15441a945772Spatrick 
15451a945772Spatrick 	if (sc->sc_phy_mode == PHY_MODE_2500BASEX ||
15461a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_1000BASEX ||
15471a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_SGMII ||
15481a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII ||
15491a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII_ID ||
15501a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII_RXID ||
15511a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII_TXID) {
1552b137aaecSpatrick 		reg = mvpp2_gmac_read(sc, MVPP2_GMAC_INT_MASK_REG);
1553b137aaecSpatrick 		reg |= MVPP2_GMAC_INT_CAUSE_LINK_CHANGE;
1554b137aaecSpatrick 		mvpp2_gmac_write(sc, MVPP2_GMAC_INT_MASK_REG, reg);
15551a945772Spatrick 	}
15561a945772Spatrick 
15571a945772Spatrick 	if (sc->sc_gop_id == 0) {
15581a945772Spatrick 		reg = mvpp2_xlg_read(sc, MV_XLG_INTERRUPT_MASK_REG);
15594d0a0269Spatrick 		reg |= MV_XLG_INTERRUPT_LINK_CHANGE;
15601a945772Spatrick 		mvpp2_xlg_write(sc, MV_XLG_INTERRUPT_MASK_REG, reg);
15611a945772Spatrick 	}
15621a945772Spatrick 
1563c56f4c70Spatrick 	mvpp2_gop_intr_unmask(sc);
1564c56f4c70Spatrick 
15651a945772Spatrick 	idx = OF_getindex(sc->sc_node, "link", "interrupt-names");
15661a945772Spatrick 	if (idx >= 0)
15671a945772Spatrick 		fdt_intr_establish_idx(sc->sc_node, idx, IPL_NET,
15681a945772Spatrick 		    mvpp2_link_intr, sc, sc->sc_dev.dv_xname);
15691a945772Spatrick 	idx = OF_getindex(sc->sc_node, "hif0", "interrupt-names");
15701a945772Spatrick 	if (idx < 0)
15711a945772Spatrick 		idx = OF_getindex(sc->sc_node, "tx-cpu0", "interrupt-names");
15721a945772Spatrick 	if (idx >= 0)
15731a945772Spatrick 		fdt_intr_establish_idx(sc->sc_node, idx, IPL_NET,
15741a945772Spatrick 		    mvpp2_intr, sc, sc->sc_dev.dv_xname);
15751a945772Spatrick }
15761a945772Spatrick 
1577a02f2d56Skettenis void
mvpp2_port_attach_sfp(struct device * self)1578a02f2d56Skettenis mvpp2_port_attach_sfp(struct device *self)
1579a02f2d56Skettenis {
1580a02f2d56Skettenis 	struct mvpp2_port *sc = (struct mvpp2_port *)self;
1581d2cd8f33Skettenis 	uint32_t reg;
1582a02f2d56Skettenis 
1583a02f2d56Skettenis 	rw_enter(&mvpp2_sff_lock, RW_WRITE);
158488474739Skettenis 	sfp_disable(sc->sc_sfp);
1585a02f2d56Skettenis 	sfp_add_media(sc->sc_sfp, &sc->sc_mii);
1586a02f2d56Skettenis 	rw_exit(&mvpp2_sff_lock);
1587d2cd8f33Skettenis 
1588d2cd8f33Skettenis 	switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) {
15899e9e5947Skettenis 	case IFM_10G_SR:
15909e9e5947Skettenis 	case IFM_10G_LR:
15919e9e5947Skettenis 	case IFM_10G_LRM:
15929e9e5947Skettenis 	case IFM_10G_ER:
15939e9e5947Skettenis 	case IFM_10G_SFP_CU:
15949e9e5947Skettenis 		sc->sc_phy_mode = PHY_MODE_10GBASER;
15959e9e5947Skettenis 		sc->sc_mii.mii_media_status = IFM_AVALID;
15969e9e5947Skettenis 		sc->sc_inband_status = 1;
15979e9e5947Skettenis 		break;
1598d2cd8f33Skettenis 	case IFM_2500_SX:
1599d2cd8f33Skettenis 		sc->sc_phy_mode = PHY_MODE_2500BASEX;
1600d2cd8f33Skettenis 		sc->sc_mii.mii_media_status = IFM_AVALID;
1601d2cd8f33Skettenis 		sc->sc_inband_status = 1;
1602d2cd8f33Skettenis 		break;
1603d2cd8f33Skettenis 	case IFM_1000_CX:
1604d2cd8f33Skettenis 	case IFM_1000_LX:
1605d2cd8f33Skettenis 	case IFM_1000_SX:
1606d2cd8f33Skettenis 	case IFM_1000_T:
1607d2cd8f33Skettenis 		sc->sc_phy_mode = PHY_MODE_1000BASEX;
1608d2cd8f33Skettenis 		sc->sc_mii.mii_media_status = IFM_AVALID;
1609d2cd8f33Skettenis 		sc->sc_inband_status = 1;
1610d2cd8f33Skettenis 		break;
1611d2cd8f33Skettenis 	}
1612d2cd8f33Skettenis 
1613d2cd8f33Skettenis 	if (sc->sc_inband_status) {
1614d2cd8f33Skettenis 		reg = mvpp2_gmac_read(sc, MVPP2_GMAC_INT_MASK_REG);
1615d2cd8f33Skettenis 		reg |= MVPP2_GMAC_INT_CAUSE_LINK_CHANGE;
1616d2cd8f33Skettenis 		mvpp2_gmac_write(sc, MVPP2_GMAC_INT_MASK_REG, reg);
1617d2cd8f33Skettenis 	}
1618a02f2d56Skettenis }
1619a02f2d56Skettenis 
16201a945772Spatrick uint32_t
mvpp2_read(struct mvpp2_softc * sc,bus_addr_t addr)16211a945772Spatrick mvpp2_read(struct mvpp2_softc *sc, bus_addr_t addr)
16221a945772Spatrick {
16231a945772Spatrick 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh_base, addr);
16241a945772Spatrick }
16251a945772Spatrick 
16261a945772Spatrick void
mvpp2_write(struct mvpp2_softc * sc,bus_addr_t addr,uint32_t data)16271a945772Spatrick mvpp2_write(struct mvpp2_softc *sc, bus_addr_t addr, uint32_t data)
16281a945772Spatrick {
16291a945772Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh_base, addr, data);
16301a945772Spatrick }
16311a945772Spatrick 
16321a945772Spatrick uint32_t
mvpp2_gmac_read(struct mvpp2_port * sc,bus_addr_t addr)16331a945772Spatrick mvpp2_gmac_read(struct mvpp2_port *sc, bus_addr_t addr)
16341a945772Spatrick {
16351a945772Spatrick 	return bus_space_read_4(sc->sc->sc_iot, sc->sc->sc_ioh_iface,
16361a945772Spatrick 	    MVPP22_GMAC_OFFSET + sc->sc_gop_id * MVPP22_GMAC_REG_SIZE + addr);
16371a945772Spatrick }
16381a945772Spatrick 
16391a945772Spatrick void
mvpp2_gmac_write(struct mvpp2_port * sc,bus_addr_t addr,uint32_t data)16401a945772Spatrick mvpp2_gmac_write(struct mvpp2_port *sc, bus_addr_t addr, uint32_t data)
16411a945772Spatrick {
16421a945772Spatrick 	bus_space_write_4(sc->sc->sc_iot, sc->sc->sc_ioh_iface,
16431a945772Spatrick 	    MVPP22_GMAC_OFFSET + sc->sc_gop_id * MVPP22_GMAC_REG_SIZE + addr,
16441a945772Spatrick 	    data);
16451a945772Spatrick }
16461a945772Spatrick 
16471a945772Spatrick uint32_t
mvpp2_xlg_read(struct mvpp2_port * sc,bus_addr_t addr)16481a945772Spatrick mvpp2_xlg_read(struct mvpp2_port *sc, bus_addr_t addr)
16491a945772Spatrick {
16501a945772Spatrick 	return bus_space_read_4(sc->sc->sc_iot, sc->sc->sc_ioh_iface,
16511a945772Spatrick 	    MVPP22_XLG_OFFSET + sc->sc_gop_id * MVPP22_XLG_REG_SIZE + addr);
16521a945772Spatrick }
16531a945772Spatrick 
16541a945772Spatrick void
mvpp2_xlg_write(struct mvpp2_port * sc,bus_addr_t addr,uint32_t data)16551a945772Spatrick mvpp2_xlg_write(struct mvpp2_port *sc, bus_addr_t addr, uint32_t data)
16561a945772Spatrick {
16571a945772Spatrick 	bus_space_write_4(sc->sc->sc_iot, sc->sc->sc_ioh_iface,
16581a945772Spatrick 	    MVPP22_XLG_OFFSET + sc->sc_gop_id * MVPP22_XLG_REG_SIZE + addr,
16591a945772Spatrick 	    data);
16601a945772Spatrick }
16611a945772Spatrick 
16621a945772Spatrick uint32_t
mvpp2_mpcs_read(struct mvpp2_port * sc,bus_addr_t addr)16631a945772Spatrick mvpp2_mpcs_read(struct mvpp2_port *sc, bus_addr_t addr)
16641a945772Spatrick {
16651a945772Spatrick 	return bus_space_read_4(sc->sc->sc_iot, sc->sc->sc_ioh_iface,
16661a945772Spatrick 	    MVPP22_MPCS_OFFSET + sc->sc_gop_id * MVPP22_MPCS_REG_SIZE + addr);
16671a945772Spatrick }
16681a945772Spatrick 
16691a945772Spatrick void
mvpp2_mpcs_write(struct mvpp2_port * sc,bus_addr_t addr,uint32_t data)16701a945772Spatrick mvpp2_mpcs_write(struct mvpp2_port *sc, bus_addr_t addr, uint32_t data)
16711a945772Spatrick {
16721a945772Spatrick 	bus_space_write_4(sc->sc->sc_iot, sc->sc->sc_ioh_iface,
16731a945772Spatrick 	    MVPP22_MPCS_OFFSET + sc->sc_gop_id * MVPP22_MPCS_REG_SIZE + addr,
16741a945772Spatrick 	    data);
16751a945772Spatrick }
16761a945772Spatrick 
16771a945772Spatrick uint32_t
mvpp2_xpcs_read(struct mvpp2_port * sc,bus_addr_t addr)16781a945772Spatrick mvpp2_xpcs_read(struct mvpp2_port *sc, bus_addr_t addr)
16791a945772Spatrick {
16801a945772Spatrick 	return bus_space_read_4(sc->sc->sc_iot, sc->sc->sc_ioh_iface,
16811a945772Spatrick 	    MVPP22_XPCS_OFFSET + sc->sc_gop_id * MVPP22_XPCS_REG_SIZE + addr);
16821a945772Spatrick }
16831a945772Spatrick 
16841a945772Spatrick void
mvpp2_xpcs_write(struct mvpp2_port * sc,bus_addr_t addr,uint32_t data)16851a945772Spatrick mvpp2_xpcs_write(struct mvpp2_port *sc, bus_addr_t addr, uint32_t data)
16861a945772Spatrick {
16871a945772Spatrick 	bus_space_write_4(sc->sc->sc_iot, sc->sc->sc_ioh_iface,
16881a945772Spatrick 	    MVPP22_XPCS_OFFSET + sc->sc_gop_id * MVPP22_XPCS_REG_SIZE + addr,
16891a945772Spatrick 	    data);
16901a945772Spatrick }
16911a945772Spatrick 
169253d582d1Spatrick static inline int
mvpp2_load_mbuf(bus_dma_tag_t dmat,bus_dmamap_t map,struct mbuf * m)169353d582d1Spatrick mvpp2_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m)
169453d582d1Spatrick {
169553d582d1Spatrick 	int error;
169653d582d1Spatrick 
169753d582d1Spatrick 	error = bus_dmamap_load_mbuf(dmat, map, m, BUS_DMA_NOWAIT);
169853d582d1Spatrick 	if (error != EFBIG)
169953d582d1Spatrick 		return (error);
170053d582d1Spatrick 
170153d582d1Spatrick 	error = m_defrag(m, M_DONTWAIT);
170253d582d1Spatrick 	if (error != 0)
170353d582d1Spatrick 		return (error);
170453d582d1Spatrick 
170553d582d1Spatrick 	return bus_dmamap_load_mbuf(dmat, map, m, BUS_DMA_NOWAIT);
170653d582d1Spatrick }
170753d582d1Spatrick 
17081a945772Spatrick void
mvpp2_start(struct ifnet * ifp)17091a945772Spatrick mvpp2_start(struct ifnet *ifp)
17101a945772Spatrick {
17111a945772Spatrick 	struct mvpp2_port *sc = ifp->if_softc;
17121a945772Spatrick 	struct mvpp2_tx_queue *txq = &sc->sc->sc_aggr_txqs[0];
171353d582d1Spatrick 	struct mvpp2_tx_desc *txd;
17141a945772Spatrick 	struct mbuf *m;
171553d582d1Spatrick 	bus_dmamap_t map;
171653d582d1Spatrick 	uint32_t command;
171753d582d1Spatrick 	int i, current, first, last;
171853d582d1Spatrick 	int free, prod, used;
17191a945772Spatrick 
17201a945772Spatrick 	if (!(ifp->if_flags & IFF_RUNNING))
17211a945772Spatrick 		return;
17221a945772Spatrick 	if (ifq_is_oactive(&ifp->if_snd))
17231a945772Spatrick 		return;
17240cae21bdSpatrick 	if (ifq_empty(&ifp->if_snd))
17251a945772Spatrick 		return;
17261a945772Spatrick 	if (!sc->sc_link)
17271a945772Spatrick 		return;
17281a945772Spatrick 
172953d582d1Spatrick 	used = 0;
173053d582d1Spatrick 	prod = txq->prod;
173153d582d1Spatrick 	free = txq->cons;
173253d582d1Spatrick 	if (free <= prod)
173353d582d1Spatrick 		free += MVPP2_AGGR_TXQ_SIZE;
173453d582d1Spatrick 	free -= prod;
173553d582d1Spatrick 
173653d582d1Spatrick 	for (;;) {
173753d582d1Spatrick 		if (free <= MVPP2_NTXSEGS) {
173853d582d1Spatrick 			ifq_set_oactive(&ifp->if_snd);
173953d582d1Spatrick 			break;
174053d582d1Spatrick 		}
174153d582d1Spatrick 
17421a945772Spatrick 		m = ifq_dequeue(&ifp->if_snd);
17431a945772Spatrick 		if (m == NULL)
17441a945772Spatrick 			break;
17451a945772Spatrick 
174653d582d1Spatrick 		first = last = current = prod;
17471a945772Spatrick 		map = txq->buf[current].mb_map;
17481a945772Spatrick 
174953d582d1Spatrick 		if (mvpp2_load_mbuf(sc->sc_dmat, map, m) != 0) {
175053d582d1Spatrick 			ifp->if_oerrors++;
175153d582d1Spatrick 			m_freem(m);
175253d582d1Spatrick 			continue;
17531a945772Spatrick 		}
17541a945772Spatrick 
17551a945772Spatrick 		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
17561a945772Spatrick 		    BUS_DMASYNC_PREWRITE);
17571a945772Spatrick 
17581a945772Spatrick 		command = MVPP2_TXD_L4_CSUM_NOT |
17591a945772Spatrick 		    MVPP2_TXD_IP_CSUM_DISABLE;
17601a945772Spatrick 		for (i = 0; i < map->dm_nsegs; i++) {
17611a945772Spatrick 			txd = &txq->descs[current];
17621a945772Spatrick 			memset(txd, 0, sizeof(*txd));
17631a945772Spatrick 			txd->buf_phys_addr_hw_cmd2 =
17641a945772Spatrick 			    map->dm_segs[i].ds_addr & ~0x1f;
17651a945772Spatrick 			txd->packet_offset =
17661a945772Spatrick 			    map->dm_segs[i].ds_addr & 0x1f;
17671a945772Spatrick 			txd->data_size = map->dm_segs[i].ds_len;
17681a945772Spatrick 			txd->phys_txq = sc->sc_txqs[0].id;
17691a945772Spatrick 			txd->command = command |
17701a945772Spatrick 			    MVPP2_TXD_PADDING_DISABLE;
17711a945772Spatrick 			if (i == 0)
17721a945772Spatrick 				txd->command |= MVPP2_TXD_F_DESC;
17731a945772Spatrick 			if (i == (map->dm_nsegs - 1))
17741a945772Spatrick 				txd->command |= MVPP2_TXD_L_DESC;
17751a945772Spatrick 
17761a945772Spatrick 			bus_dmamap_sync(sc->sc_dmat, MVPP2_DMA_MAP(txq->ring),
17771a945772Spatrick 			    current * sizeof(*txd), sizeof(*txd),
17781a945772Spatrick 			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
17791a945772Spatrick 
17801a945772Spatrick 			last = current;
1781f230dab5Spatrick 			current = (current + 1) % MVPP2_AGGR_TXQ_SIZE;
17821a945772Spatrick 			KASSERT(current != txq->cons);
17831a945772Spatrick 		}
17841a945772Spatrick 
17851a945772Spatrick 		KASSERT(txq->buf[last].mb_m == NULL);
17861a945772Spatrick 		txq->buf[first].mb_map = txq->buf[last].mb_map;
17871a945772Spatrick 		txq->buf[last].mb_map = map;
17881a945772Spatrick 		txq->buf[last].mb_m = m;
17891a945772Spatrick 
179053d582d1Spatrick #if NBPFILTER > 0
179153d582d1Spatrick 		if (ifp->if_bpf)
179253d582d1Spatrick 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
179353d582d1Spatrick #endif
17941a945772Spatrick 
179553d582d1Spatrick 		free -= map->dm_nsegs;
179653d582d1Spatrick 		used += map->dm_nsegs;
179753d582d1Spatrick 		prod = current;
179853d582d1Spatrick 	}
17991a945772Spatrick 
180053d582d1Spatrick 	if (used)
180153d582d1Spatrick 		mvpp2_write(sc->sc, MVPP2_AGGR_TXQ_UPDATE_REG, used);
180253d582d1Spatrick 
180353d582d1Spatrick 	if (txq->prod != prod)
180453d582d1Spatrick 		txq->prod = prod;
18051a945772Spatrick }
18061a945772Spatrick 
18071a945772Spatrick int
mvpp2_ioctl(struct ifnet * ifp,u_long cmd,caddr_t addr)18081a945772Spatrick mvpp2_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
18091a945772Spatrick {
18101a945772Spatrick 	struct mvpp2_port *sc = ifp->if_softc;
18111a945772Spatrick 	struct ifreq *ifr = (struct ifreq *)addr;
18121a945772Spatrick 	int error = 0, s;
18131a945772Spatrick 
18141a945772Spatrick 	s = splnet();
18151a945772Spatrick 
18161a945772Spatrick 	switch (cmd) {
18171a945772Spatrick 	case SIOCSIFADDR:
18181a945772Spatrick 		ifp->if_flags |= IFF_UP;
18191a945772Spatrick 		/* FALLTHROUGH */
18201a945772Spatrick 	case SIOCSIFFLAGS:
18211a945772Spatrick 		if (ifp->if_flags & IFF_UP) {
18221a945772Spatrick 			if (ifp->if_flags & IFF_RUNNING)
18231a945772Spatrick 				error = ENETRESET;
18241a945772Spatrick 			else
18251a945772Spatrick 				mvpp2_up(sc);
18261a945772Spatrick 		} else {
18271a945772Spatrick 			if (ifp->if_flags & IFF_RUNNING)
18281a945772Spatrick 				mvpp2_down(sc);
18291a945772Spatrick 		}
18301a945772Spatrick 		break;
18311a945772Spatrick 
18321a945772Spatrick 	case SIOCGIFMEDIA:
18331a945772Spatrick 	case SIOCSIFMEDIA:
18341a945772Spatrick 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
18351a945772Spatrick 		break;
18361a945772Spatrick 
18371a945772Spatrick 	case SIOCGIFRXR:
18381a945772Spatrick 		error = mvpp2_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data);
18391a945772Spatrick 		break;
18401a945772Spatrick 
18411a945772Spatrick 	case SIOCGIFSFFPAGE:
18421a945772Spatrick 		error = rw_enter(&mvpp2_sff_lock, RW_WRITE|RW_INTR);
18431a945772Spatrick 		if (error != 0)
18441a945772Spatrick 			break;
18451a945772Spatrick 
18461a945772Spatrick 		error = sfp_get_sffpage(sc->sc_sfp, (struct if_sffpage *)addr);
18471a945772Spatrick 		rw_exit(&mvpp2_sff_lock);
18481a945772Spatrick 		break;
18491a945772Spatrick 
18501a945772Spatrick 	default:
18511a945772Spatrick 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr);
18521a945772Spatrick 		break;
18531a945772Spatrick 	}
18541a945772Spatrick 
18551a945772Spatrick 	if (error == ENETRESET) {
18561a945772Spatrick 		if (ifp->if_flags & IFF_RUNNING)
18571a945772Spatrick 			mvpp2_iff(sc);
18581a945772Spatrick 		error = 0;
18591a945772Spatrick 	}
18601a945772Spatrick 
18611a945772Spatrick 	splx(s);
18621a945772Spatrick 	return (error);
18631a945772Spatrick }
18641a945772Spatrick 
18651a945772Spatrick int
mvpp2_rxrinfo(struct mvpp2_port * sc,struct if_rxrinfo * ifri)18661a945772Spatrick mvpp2_rxrinfo(struct mvpp2_port *sc, struct if_rxrinfo *ifri)
18671a945772Spatrick {
18681a945772Spatrick 	struct mvpp2_rx_queue *rxq;
18691a945772Spatrick 	struct if_rxring_info *ifrs, *ifr;
18701a945772Spatrick 	unsigned int i;
18711a945772Spatrick 	int error;
18721a945772Spatrick 
18731a945772Spatrick 	ifrs = mallocarray(sc->sc_nrxq, sizeof(*ifrs), M_TEMP,
18741a945772Spatrick 	    M_WAITOK|M_ZERO|M_CANFAIL);
18751a945772Spatrick 	if (ifrs == NULL)
18761a945772Spatrick 		return (ENOMEM);
18771a945772Spatrick 
18781a945772Spatrick 	for (i = 0; i < sc->sc_nrxq; i++) {
18791a945772Spatrick 		rxq = &sc->sc_rxqs[i];
18801a945772Spatrick 		ifr = &ifrs[i];
18811a945772Spatrick 
18821a945772Spatrick 		snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), "%u", i);
18831a945772Spatrick 		ifr->ifr_size = MCLBYTES;
18841a945772Spatrick 		ifr->ifr_info = rxq->rxring;
18851a945772Spatrick 	}
18861a945772Spatrick 
18871a945772Spatrick 	error = if_rxr_info_ioctl(ifri, i, ifrs);
18881a945772Spatrick 	free(ifrs, M_TEMP, i * sizeof(*ifrs));
18891a945772Spatrick 
18901a945772Spatrick 	return (error);
18911a945772Spatrick }
18921a945772Spatrick 
18931a945772Spatrick void
mvpp2_watchdog(struct ifnet * ifp)18941a945772Spatrick mvpp2_watchdog(struct ifnet *ifp)
18951a945772Spatrick {
18961a945772Spatrick 	printf("%s\n", __func__);
18971a945772Spatrick }
18981a945772Spatrick 
18991a945772Spatrick int
mvpp2_media_change(struct ifnet * ifp)19001a945772Spatrick mvpp2_media_change(struct ifnet *ifp)
19011a945772Spatrick {
19021a945772Spatrick 	struct mvpp2_port *sc = ifp->if_softc;
19031a945772Spatrick 
19041a945772Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys))
19051a945772Spatrick 		mii_mediachg(&sc->sc_mii);
19061a945772Spatrick 
19071a945772Spatrick 	return (0);
19081a945772Spatrick }
19091a945772Spatrick 
19101a945772Spatrick void
mvpp2_media_status(struct ifnet * ifp,struct ifmediareq * ifmr)19111a945772Spatrick mvpp2_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
19121a945772Spatrick {
19131a945772Spatrick 	struct mvpp2_port *sc = ifp->if_softc;
19141a945772Spatrick 
19151a945772Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys))
19161a945772Spatrick 		mii_pollstat(&sc->sc_mii);
19171a945772Spatrick 
19181a945772Spatrick 	ifmr->ifm_active = sc->sc_mii.mii_media_active;
19191a945772Spatrick 	ifmr->ifm_status = sc->sc_mii.mii_media_status;
19201a945772Spatrick }
19211a945772Spatrick 
19221a945772Spatrick int
mvpp2_mii_readreg(struct device * self,int phy,int reg)19231a945772Spatrick mvpp2_mii_readreg(struct device *self, int phy, int reg)
19241a945772Spatrick {
19251a945772Spatrick 	struct mvpp2_port *sc = (void *)self;
19261a945772Spatrick 	return sc->sc_mdio->md_readreg(sc->sc_mdio->md_cookie, phy, reg);
19271a945772Spatrick }
19281a945772Spatrick 
19291a945772Spatrick void
mvpp2_mii_writereg(struct device * self,int phy,int reg,int val)19301a945772Spatrick mvpp2_mii_writereg(struct device *self, int phy, int reg, int val)
19311a945772Spatrick {
19321a945772Spatrick 	struct mvpp2_port *sc = (void *)self;
19331a945772Spatrick 	return sc->sc_mdio->md_writereg(sc->sc_mdio->md_cookie, phy, reg, val);
19341a945772Spatrick }
19351a945772Spatrick 
19361a945772Spatrick void
mvpp2_mii_statchg(struct device * self)19371a945772Spatrick mvpp2_mii_statchg(struct device *self)
19381a945772Spatrick {
19391a945772Spatrick 	struct mvpp2_port *sc = (void *)self;
19401a945772Spatrick 	mvpp2_port_change(sc);
19411a945772Spatrick }
19421a945772Spatrick 
19431a945772Spatrick void
mvpp2_inband_statchg(struct mvpp2_port * sc)19441a945772Spatrick mvpp2_inband_statchg(struct mvpp2_port *sc)
19451a945772Spatrick {
1946d2cd8f33Skettenis 	uint64_t subtype = IFM_SUBTYPE(sc->sc_mii.mii_media_active);
19471a945772Spatrick 	uint32_t reg;
19481a945772Spatrick 
19491a945772Spatrick 	sc->sc_mii.mii_media_status = IFM_AVALID;
19501a945772Spatrick 	sc->sc_mii.mii_media_active = IFM_ETHER;
19511a945772Spatrick 
19521a945772Spatrick 	if (sc->sc_gop_id == 0 && (sc->sc_phy_mode == PHY_MODE_10GBASER ||
19531a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_XAUI)) {
19541a945772Spatrick 		reg = mvpp2_xlg_read(sc, MV_XLG_MAC_PORT_STATUS_REG);
19554d0a0269Spatrick 		if (reg & MV_XLG_MAC_PORT_STATUS_LINKSTATUS)
19561a945772Spatrick 			sc->sc_mii.mii_media_status |= IFM_ACTIVE;
19571a945772Spatrick 		sc->sc_mii.mii_media_active |= IFM_FDX;
19589e9e5947Skettenis 		sc->sc_mii.mii_media_active |= subtype;
19591a945772Spatrick 	} else {
19601a945772Spatrick 		reg = mvpp2_gmac_read(sc, MVPP2_PORT_STATUS0_REG);
19614d0a0269Spatrick 		if (reg & MVPP2_PORT_STATUS0_LINKUP)
19621a945772Spatrick 			sc->sc_mii.mii_media_status |= IFM_ACTIVE;
19634d0a0269Spatrick 		if (reg & MVPP2_PORT_STATUS0_FULLDX)
19641a945772Spatrick 			sc->sc_mii.mii_media_active |= IFM_FDX;
19651a945772Spatrick 		if (sc->sc_phy_mode == PHY_MODE_2500BASEX)
1966d2cd8f33Skettenis 			sc->sc_mii.mii_media_active |= subtype;
19671a945772Spatrick 		else if (sc->sc_phy_mode == PHY_MODE_1000BASEX)
1968d2cd8f33Skettenis 			sc->sc_mii.mii_media_active |= subtype;
19694d0a0269Spatrick 		else if (reg & MVPP2_PORT_STATUS0_GMIISPEED)
19701a945772Spatrick 			sc->sc_mii.mii_media_active |= IFM_1000_T;
19714d0a0269Spatrick 		else if (reg & MVPP2_PORT_STATUS0_MIISPEED)
19721a945772Spatrick 			sc->sc_mii.mii_media_active |= IFM_100_TX;
19731a945772Spatrick 		else
19741a945772Spatrick 			sc->sc_mii.mii_media_active |= IFM_10_T;
19751a945772Spatrick 	}
19761a945772Spatrick 
19771a945772Spatrick 	mvpp2_port_change(sc);
19781a945772Spatrick }
19791a945772Spatrick 
19801a945772Spatrick void
mvpp2_port_change(struct mvpp2_port * sc)19811a945772Spatrick mvpp2_port_change(struct mvpp2_port *sc)
19821a945772Spatrick {
19831a945772Spatrick 	uint32_t reg;
19841a945772Spatrick 
1985c56f4c70Spatrick 	sc->sc_link = !!(sc->sc_mii.mii_media_status & IFM_ACTIVE);
19861a945772Spatrick 
19871a945772Spatrick 	if (sc->sc_inband_status)
19881a945772Spatrick 		return;
19891a945772Spatrick 
19901a945772Spatrick 	if (sc->sc_link) {
19911a945772Spatrick 		if (sc->sc_phy_mode == PHY_MODE_10GBASER ||
19921a945772Spatrick 		    sc->sc_phy_mode == PHY_MODE_XAUI) {
19931a945772Spatrick 			reg = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG);
19944d0a0269Spatrick 			reg &= ~MV_XLG_MAC_CTRL0_FORCELINKDOWN;
19954d0a0269Spatrick 			reg |= MV_XLG_MAC_CTRL0_FORCELINKPASS;
19961a945772Spatrick 			mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG, reg);
19971a945772Spatrick 		} else {
19981a945772Spatrick 			reg = mvpp2_gmac_read(sc, MVPP2_GMAC_AUTONEG_CONFIG);
19991a945772Spatrick 			reg &= ~MVPP2_GMAC_FORCE_LINK_DOWN;
20001a945772Spatrick 			reg |= MVPP2_GMAC_FORCE_LINK_PASS;
20011a945772Spatrick 			reg &= ~MVPP2_GMAC_CONFIG_MII_SPEED;
20021a945772Spatrick 			reg &= ~MVPP2_GMAC_CONFIG_GMII_SPEED;
20031a945772Spatrick 			reg &= ~MVPP2_GMAC_CONFIG_FULL_DUPLEX;
20049b4ffe48Skettenis 			if (IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_2500_KX ||
20059b4ffe48Skettenis 			    IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_2500_SX ||
2006d2cd8f33Skettenis 			    IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_1000_CX ||
2007d2cd8f33Skettenis 			    IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_1000_LX ||
20089b4ffe48Skettenis 			    IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_1000_KX ||
20091a945772Spatrick 			    IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_1000_SX ||
20101a945772Spatrick 			    IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_1000_T)
20111a945772Spatrick 				reg |= MVPP2_GMAC_CONFIG_GMII_SPEED;
20121a945772Spatrick 			if (IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_100_TX)
20131a945772Spatrick 				reg |= MVPP2_GMAC_CONFIG_MII_SPEED;
20141a945772Spatrick 			if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX)
20151a945772Spatrick 				reg |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
20161a945772Spatrick 			mvpp2_gmac_write(sc, MVPP2_GMAC_AUTONEG_CONFIG, reg);
20171a945772Spatrick 		}
20181a945772Spatrick 	} else {
20191a945772Spatrick 		if (sc->sc_phy_mode == PHY_MODE_10GBASER ||
20201a945772Spatrick 		    sc->sc_phy_mode == PHY_MODE_XAUI) {
20211a945772Spatrick 			reg = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG);
20224d0a0269Spatrick 			reg &= ~MV_XLG_MAC_CTRL0_FORCELINKPASS;
20234d0a0269Spatrick 			reg |= MV_XLG_MAC_CTRL0_FORCELINKDOWN;
20241a945772Spatrick 			mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG, reg);
20251a945772Spatrick 		} else {
20261a945772Spatrick 			reg = mvpp2_gmac_read(sc, MVPP2_GMAC_AUTONEG_CONFIG);
20271a945772Spatrick 			reg &= ~MVPP2_GMAC_FORCE_LINK_PASS;
20281a945772Spatrick 			reg |= MVPP2_GMAC_FORCE_LINK_DOWN;
20291a945772Spatrick 			mvpp2_gmac_write(sc, MVPP2_GMAC_AUTONEG_CONFIG, reg);
20301a945772Spatrick 		}
20311a945772Spatrick 	}
20321a945772Spatrick }
20331a945772Spatrick 
20341a945772Spatrick void
mvpp2_tick(void * arg)20351a945772Spatrick mvpp2_tick(void *arg)
20361a945772Spatrick {
20371a945772Spatrick 	struct mvpp2_port *sc = arg;
20381a945772Spatrick 	int s;
20391a945772Spatrick 
20401a945772Spatrick 	s = splnet();
20411a945772Spatrick 	mii_tick(&sc->sc_mii);
20421a945772Spatrick 	splx(s);
20431a945772Spatrick 
20441a945772Spatrick 	timeout_add_sec(&sc->sc_tick, 1);
20451a945772Spatrick }
20461a945772Spatrick 
20471a945772Spatrick int
mvpp2_link_intr(void * arg)20481a945772Spatrick mvpp2_link_intr(void *arg)
20491a945772Spatrick {
20501a945772Spatrick 	struct mvpp2_port *sc = arg;
20511a945772Spatrick 	uint32_t reg;
20521a945772Spatrick 	int event = 0;
20531a945772Spatrick 
20541a945772Spatrick 	if (sc->sc_gop_id == 0 && (sc->sc_phy_mode == PHY_MODE_10GBASER ||
20551a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_XAUI)) {
20561a945772Spatrick 		reg = mvpp2_xlg_read(sc, MV_XLG_INTERRUPT_CAUSE_REG);
20574d0a0269Spatrick 		if (reg & MV_XLG_INTERRUPT_LINK_CHANGE)
20581a945772Spatrick 			event = 1;
20591a945772Spatrick 	} else if (sc->sc_phy_mode == PHY_MODE_2500BASEX ||
20601a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_1000BASEX ||
20611a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_SGMII ||
20621a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII ||
20631a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII_ID ||
20641a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII_RXID ||
20651a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII_TXID) {
2066b137aaecSpatrick 		reg = mvpp2_gmac_read(sc, MVPP2_GMAC_INT_CAUSE_REG);
2067b137aaecSpatrick 		if (reg & MVPP2_GMAC_INT_CAUSE_LINK_CHANGE)
20681a945772Spatrick 			event = 1;
20691a945772Spatrick 	}
20701a945772Spatrick 
20711a945772Spatrick 	if (event && sc->sc_inband_status)
20721a945772Spatrick 		mvpp2_inband_statchg(sc);
20731a945772Spatrick 
20741a945772Spatrick 	return (1);
20751a945772Spatrick }
20761a945772Spatrick 
20771a945772Spatrick int
mvpp2_intr(void * arg)20781a945772Spatrick mvpp2_intr(void *arg)
20791a945772Spatrick {
20801a945772Spatrick 	struct mvpp2_port *sc = arg;
20811a945772Spatrick 	uint32_t reg;
20821a945772Spatrick 
20831a945772Spatrick 	reg = mvpp2_read(sc->sc, MVPP2_ISR_RX_TX_CAUSE_REG(sc->sc_id));
20841a945772Spatrick 	if (reg & MVPP2_CAUSE_MISC_SUM_MASK) {
20851a945772Spatrick 		mvpp2_write(sc->sc, MVPP2_ISR_MISC_CAUSE_REG, 0);
20861a945772Spatrick 		mvpp2_write(sc->sc, MVPP2_ISR_RX_TX_CAUSE_REG(sc->sc_id),
20871a945772Spatrick 		    reg & ~MVPP2_CAUSE_MISC_SUM_MASK);
20881a945772Spatrick 	}
20891a945772Spatrick 	if (reg & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK)
20901a945772Spatrick 		mvpp2_tx_proc(sc,
20911a945772Spatrick 		    (reg & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK) >>
20921a945772Spatrick 		    MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_OFFSET);
20931a945772Spatrick 
20941a945772Spatrick 	if (reg & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK)
20951a945772Spatrick 		mvpp2_rx_proc(sc,
20961a945772Spatrick 		    reg & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK);
20971a945772Spatrick 
20981a945772Spatrick 	return (1);
20991a945772Spatrick }
21001a945772Spatrick 
21011a945772Spatrick void
mvpp2_tx_proc(struct mvpp2_port * sc,uint8_t queues)21021a945772Spatrick mvpp2_tx_proc(struct mvpp2_port *sc, uint8_t queues)
21031a945772Spatrick {
21041a945772Spatrick 	struct mvpp2_tx_queue *txq;
21051a945772Spatrick 	int i;
21061a945772Spatrick 
21071a945772Spatrick 	for (i = 0; i < sc->sc_ntxq; i++) {
21081a945772Spatrick 		txq = &sc->sc_txqs[i];
21091a945772Spatrick 		if ((queues & (1 << i)) == 0)
21101a945772Spatrick 			continue;
211163ca77e8Spatrick 		mvpp2_txq_proc(sc, txq);
211263ca77e8Spatrick 	}
21131a945772Spatrick }
21141a945772Spatrick 
211563ca77e8Spatrick void
mvpp2_txq_proc(struct mvpp2_port * sc,struct mvpp2_tx_queue * txq)211663ca77e8Spatrick mvpp2_txq_proc(struct mvpp2_port *sc, struct mvpp2_tx_queue *txq)
211763ca77e8Spatrick {
211863ca77e8Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
211963ca77e8Spatrick 	struct mvpp2_tx_queue *aggr_txq = &sc->sc->sc_aggr_txqs[0];
212063ca77e8Spatrick 	struct mvpp2_buf *txb;
212163ca77e8Spatrick 	int i, idx, nsent;
212263ca77e8Spatrick 
212353d582d1Spatrick 	/* XXX: this is a percpu register! */
212463ca77e8Spatrick 	nsent = (mvpp2_read(sc->sc, MVPP2_TXQ_SENT_REG(txq->id)) &
212563ca77e8Spatrick 	    MVPP2_TRANSMITTED_COUNT_MASK) >>
212663ca77e8Spatrick 	    MVPP2_TRANSMITTED_COUNT_OFFSET;
212763ca77e8Spatrick 
212863ca77e8Spatrick 	for (i = 0; i < nsent; i++) {
212963ca77e8Spatrick 		idx = aggr_txq->cons;
213063ca77e8Spatrick 		KASSERT(idx < MVPP2_AGGR_TXQ_SIZE);
213163ca77e8Spatrick 
213263ca77e8Spatrick 		txb = &aggr_txq->buf[idx];
213363ca77e8Spatrick 		if (txb->mb_m) {
213463ca77e8Spatrick 			bus_dmamap_sync(sc->sc_dmat, txb->mb_map, 0,
213563ca77e8Spatrick 			    txb->mb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
213663ca77e8Spatrick 			bus_dmamap_unload(sc->sc_dmat, txb->mb_map);
213763ca77e8Spatrick 
213863ca77e8Spatrick 			m_freem(txb->mb_m);
213963ca77e8Spatrick 			txb->mb_m = NULL;
214063ca77e8Spatrick 		}
214163ca77e8Spatrick 
214263ca77e8Spatrick 		aggr_txq->cons = (aggr_txq->cons + 1) % MVPP2_AGGR_TXQ_SIZE;
214363ca77e8Spatrick 	}
214463ca77e8Spatrick 
214563ca77e8Spatrick 	if (ifq_is_oactive(&ifp->if_snd))
214663ca77e8Spatrick 		ifq_restart(&ifp->if_snd);
21471a945772Spatrick }
21481a945772Spatrick 
21491a945772Spatrick void
mvpp2_rx_proc(struct mvpp2_port * sc,uint8_t queues)21501a945772Spatrick mvpp2_rx_proc(struct mvpp2_port *sc, uint8_t queues)
21511a945772Spatrick {
21521a945772Spatrick 	struct mvpp2_rx_queue *rxq;
21531a945772Spatrick 	int i;
21541a945772Spatrick 
21551a945772Spatrick 	for (i = 0; i < sc->sc_nrxq; i++) {
21561a945772Spatrick 		rxq = &sc->sc_rxqs[i];
21571a945772Spatrick 		if ((queues & (1 << i)) == 0)
21581a945772Spatrick 			continue;
21591a945772Spatrick 		mvpp2_rxq_proc(sc, rxq);
21601a945772Spatrick 	}
2161be107da9Spatrick 
2162be107da9Spatrick 	mvpp2_rx_refill(sc);
21631a945772Spatrick }
21641a945772Spatrick 
21651a945772Spatrick void
mvpp2_rxq_proc(struct mvpp2_port * sc,struct mvpp2_rx_queue * rxq)21661a945772Spatrick mvpp2_rxq_proc(struct mvpp2_port *sc, struct mvpp2_rx_queue *rxq)
21671a945772Spatrick {
21681a945772Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
21691a945772Spatrick 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
21701a945772Spatrick 	struct mvpp2_rx_desc *rxd;
21711a945772Spatrick 	struct mvpp2_bm_pool *bm;
21721a945772Spatrick 	struct mvpp2_buf *rxb;
21731a945772Spatrick 	struct mbuf *m;
21741a945772Spatrick 	uint64_t virt;
2175be107da9Spatrick 	uint32_t i, nrecv, pool;
21761a945772Spatrick 
21771a945772Spatrick 	nrecv = mvpp2_rxq_received(sc, rxq->id);
21781a945772Spatrick 	if (!nrecv)
21791a945772Spatrick 		return;
21801a945772Spatrick 
2181be107da9Spatrick 	pool = curcpu()->ci_cpuid;
2182be107da9Spatrick 	KASSERT(pool < sc->sc->sc_npools);
2183be107da9Spatrick 	bm = &sc->sc->sc_bm_pools[pool];
21841a945772Spatrick 
21851a945772Spatrick 	bus_dmamap_sync(sc->sc_dmat, MVPP2_DMA_MAP(rxq->ring), 0,
21861a945772Spatrick 	    MVPP2_DMA_LEN(rxq->ring),
21871a945772Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
21881a945772Spatrick 
21891a945772Spatrick 	for (i = 0; i < nrecv; i++) {
21901a945772Spatrick 		rxd = &rxq->descs[rxq->cons];
21911a945772Spatrick 		virt = rxd->buf_cookie_bm_qset_cls_info;
2192be107da9Spatrick 		KASSERT(((virt >> 16) & 0xffff) == pool);
2193be107da9Spatrick 		KASSERT((virt & 0xffff) < MVPP2_BM_SIZE);
21941a945772Spatrick 		rxb = &bm->rxbuf[virt & 0xffff];
2195be107da9Spatrick 		KASSERT(rxb->mb_m != NULL);
21961a945772Spatrick 
21971a945772Spatrick 		bus_dmamap_sync(sc->sc_dmat, rxb->mb_map, 0,
21981a945772Spatrick 		    rxd->data_size, BUS_DMASYNC_POSTREAD);
21991a945772Spatrick 		bus_dmamap_unload(sc->sc_dmat, rxb->mb_map);
22001a945772Spatrick 
22011a945772Spatrick 		m = rxb->mb_m;
22021a945772Spatrick 		rxb->mb_m = NULL;
22031a945772Spatrick 
22041a945772Spatrick 		m->m_pkthdr.len = m->m_len = rxd->data_size;
22051a945772Spatrick 		m_adj(m, MVPP2_MH_SIZE);
22061a945772Spatrick 		ml_enqueue(&ml, m);
22071a945772Spatrick 
2208be107da9Spatrick 		KASSERT(bm->freelist[bm->free_prod] == -1);
2209be107da9Spatrick 		bm->freelist[bm->free_prod] = virt & 0xffffffff;
2210be107da9Spatrick 		bm->free_prod = (bm->free_prod + 1) % MVPP2_BM_SIZE;
2211be107da9Spatrick 
22121a945772Spatrick 		rxq->cons = (rxq->cons + 1) % MVPP2_NRXDESC;
22131a945772Spatrick 	}
22141a945772Spatrick 
22151a945772Spatrick 	bus_dmamap_sync(sc->sc_dmat, MVPP2_DMA_MAP(rxq->ring), 0,
22161a945772Spatrick 	    MVPP2_DMA_LEN(rxq->ring),
22171a945772Spatrick 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
22181a945772Spatrick 
22191a945772Spatrick 	mvpp2_rxq_status_update(sc, rxq->id, nrecv, nrecv);
22201a945772Spatrick 
22211a945772Spatrick 	if_input(ifp, &ml);
22221a945772Spatrick }
22231a945772Spatrick 
2224be107da9Spatrick /*
2225be107da9Spatrick  * We have a pool per core, and since we should not assume that
2226be107da9Spatrick  * RX buffers are always used in order, keep a list of rxbuf[]
2227be107da9Spatrick  * indices that should be filled with an mbuf, if possible.
2228be107da9Spatrick  */
2229be107da9Spatrick void
mvpp2_rx_refill(struct mvpp2_port * sc)2230be107da9Spatrick mvpp2_rx_refill(struct mvpp2_port *sc)
2231be107da9Spatrick {
2232be107da9Spatrick 	struct mvpp2_bm_pool *bm;
2233be107da9Spatrick 	struct mvpp2_buf *rxb;
2234be107da9Spatrick 	uint64_t phys, virt;
2235be107da9Spatrick 	int pool;
2236be107da9Spatrick 
2237be107da9Spatrick 	pool = curcpu()->ci_cpuid;
2238be107da9Spatrick 	KASSERT(pool < sc->sc->sc_npools);
2239be107da9Spatrick 	bm = &sc->sc->sc_bm_pools[pool];
2240be107da9Spatrick 
224181fd8658Spatrick 	while (bm->freelist[bm->free_cons] != -1) {
2242be107da9Spatrick 		virt = bm->freelist[bm->free_cons];
2243be107da9Spatrick 		KASSERT(((virt >> 16) & 0xffff) == pool);
2244be107da9Spatrick 		KASSERT((virt & 0xffff) < MVPP2_BM_SIZE);
2245be107da9Spatrick 		rxb = &bm->rxbuf[virt & 0xffff];
2246be107da9Spatrick 		KASSERT(rxb->mb_m == NULL);
2247be107da9Spatrick 
2248be107da9Spatrick 		rxb->mb_m = mvpp2_alloc_mbuf(sc->sc, rxb->mb_map);
2249be107da9Spatrick 		if (rxb->mb_m == NULL)
2250be107da9Spatrick 			break;
2251be107da9Spatrick 
2252be107da9Spatrick 		bm->freelist[bm->free_cons] = -1;
2253be107da9Spatrick 		bm->free_cons = (bm->free_cons + 1) % MVPP2_BM_SIZE;
2254be107da9Spatrick 
2255be107da9Spatrick 		phys = rxb->mb_map->dm_segs[0].ds_addr;
225613d9cc68Spatrick 		mvpp2_write(sc->sc, MVPP22_BM_ADDR_HIGH_RLS_REG,
2257be107da9Spatrick 		    (((virt >> 32) & MVPP22_ADDR_HIGH_MASK)
225813d9cc68Spatrick 		    << MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) |
225913d9cc68Spatrick 		    ((phys >> 32) & MVPP22_ADDR_HIGH_MASK));
2260be107da9Spatrick 		mvpp2_write(sc->sc, MVPP2_BM_VIRT_RLS_REG,
2261be107da9Spatrick 		    virt & 0xffffffff);
2262be107da9Spatrick 		mvpp2_write(sc->sc, MVPP2_BM_PHY_RLS_REG(pool),
2263be107da9Spatrick 		    phys & 0xffffffff);
2264be107da9Spatrick 	}
2265be107da9Spatrick }
2266be107da9Spatrick 
22671a945772Spatrick void
mvpp2_up(struct mvpp2_port * sc)22681a945772Spatrick mvpp2_up(struct mvpp2_port *sc)
22691a945772Spatrick {
22701a945772Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
22711a945772Spatrick 	int i;
22721a945772Spatrick 
227388474739Skettenis 	if (sc->sc_sfp) {
227488474739Skettenis 		rw_enter(&mvpp2_sff_lock, RW_WRITE);
227588474739Skettenis 		sfp_enable(sc->sc_sfp);
227688474739Skettenis 		rw_exit(&mvpp2_sff_lock);
227788474739Skettenis 	}
227888474739Skettenis 
227941cd246cSpatrick 	mvpp2_prs_mac_da_accept(sc, etherbroadcastaddr, 1);
2280ce595ab8Spatrick 	mvpp2_prs_mac_da_accept(sc, sc->sc_lladdr, 1);
22811a945772Spatrick 	mvpp2_prs_tag_mode_set(sc->sc, sc->sc_id, MVPP2_TAG_TYPE_MH);
22821a945772Spatrick 	mvpp2_prs_def_flow(sc);
22831a945772Spatrick 
22841a945772Spatrick 	for (i = 0; i < sc->sc_ntxq; i++)
22851a945772Spatrick 		mvpp2_txq_hw_init(sc, &sc->sc_txqs[i]);
22861a945772Spatrick 
22871a945772Spatrick 	mvpp2_tx_time_coal_set(sc, sc->sc_tx_time_coal);
22881a945772Spatrick 
22891a945772Spatrick 	for (i = 0; i < sc->sc_nrxq; i++)
22901a945772Spatrick 		mvpp2_rxq_hw_init(sc, &sc->sc_rxqs[i]);
22911a945772Spatrick 
22921a945772Spatrick 	/* FIXME: rx buffer fill */
22931a945772Spatrick 
22941a945772Spatrick 	/* Configure media. */
22951a945772Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys))
22961a945772Spatrick 		mii_mediachg(&sc->sc_mii);
22971a945772Spatrick 
22981a945772Spatrick 	/* Program promiscuous mode and multicast filters. */
22991a945772Spatrick 	mvpp2_iff(sc);
23001a945772Spatrick 
23011a945772Spatrick 	ifp->if_flags |= IFF_RUNNING;
23021a945772Spatrick 	ifq_clr_oactive(&ifp->if_snd);
23031a945772Spatrick 
23041a945772Spatrick 	mvpp2_txp_max_tx_size_set(sc);
23051a945772Spatrick 
23061a945772Spatrick 	/* XXX: single vector */
23071a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_ISR_RX_TX_MASK_REG(sc->sc_id),
23081a945772Spatrick 	    MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK |
23091a945772Spatrick 	    MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK |
23101a945772Spatrick 	    MVPP2_CAUSE_MISC_SUM_MASK);
23111a945772Spatrick 	mvpp2_interrupts_enable(sc, (1 << 0));
23121a945772Spatrick 
23131a945772Spatrick 	mvpp2_mac_config(sc);
23141a945772Spatrick 	mvpp2_egress_enable(sc);
23151a945772Spatrick 	mvpp2_ingress_enable(sc);
23161a945772Spatrick 
23171a945772Spatrick 	timeout_add_sec(&sc->sc_tick, 1);
23181a945772Spatrick }
23191a945772Spatrick 
23201a945772Spatrick void
mvpp2_aggr_txq_hw_init(struct mvpp2_softc * sc,struct mvpp2_tx_queue * txq)23211a945772Spatrick mvpp2_aggr_txq_hw_init(struct mvpp2_softc *sc, struct mvpp2_tx_queue *txq)
23221a945772Spatrick {
23231a945772Spatrick 	struct mvpp2_buf *txb;
23241a945772Spatrick 	int i;
23251a945772Spatrick 
23261a945772Spatrick 	txq->ring = mvpp2_dmamem_alloc(sc,
23271a945772Spatrick 	    MVPP2_AGGR_TXQ_SIZE * sizeof(struct mvpp2_tx_desc), 32);
23287262ae33Spatrick 	KASSERT(txq->ring != NULL);
23291a945772Spatrick 	txq->descs = MVPP2_DMA_KVA(txq->ring);
23301a945772Spatrick 
23311a945772Spatrick 	txq->buf = mallocarray(MVPP2_AGGR_TXQ_SIZE, sizeof(struct mvpp2_buf),
23321a945772Spatrick 	    M_DEVBUF, M_WAITOK);
23331a945772Spatrick 
23341a945772Spatrick 	for (i = 0; i < MVPP2_AGGR_TXQ_SIZE; i++) {
23351a945772Spatrick 		txb = &txq->buf[i];
23361a945772Spatrick 		bus_dmamap_create(sc->sc_dmat, MCLBYTES, MVPP2_NTXSEGS,
23371a945772Spatrick 		    MCLBYTES, 0, BUS_DMA_WAITOK, &txb->mb_map);
23381a945772Spatrick 		txb->mb_m = NULL;
23391a945772Spatrick 	}
23401a945772Spatrick 
23411a945772Spatrick 	bus_dmamap_sync(sc->sc_dmat, MVPP2_DMA_MAP(txq->ring), 0,
23421a945772Spatrick 	    MVPP2_DMA_LEN(txq->ring), BUS_DMASYNC_PREWRITE);
23431a945772Spatrick 
23441a945772Spatrick 	txq->prod = mvpp2_read(sc, MVPP2_AGGR_TXQ_INDEX_REG(txq->id));
23451a945772Spatrick 	mvpp2_write(sc, MVPP2_AGGR_TXQ_DESC_ADDR_REG(txq->id),
23464d0a0269Spatrick 	    MVPP2_DMA_DVA(txq->ring) >> MVPP22_DESC_ADDR_OFFS);
23471a945772Spatrick 	mvpp2_write(sc, MVPP2_AGGR_TXQ_DESC_SIZE_REG(txq->id),
23481a945772Spatrick 	    MVPP2_AGGR_TXQ_SIZE);
23491a945772Spatrick }
23501a945772Spatrick 
23511a945772Spatrick void
mvpp2_txq_hw_init(struct mvpp2_port * sc,struct mvpp2_tx_queue * txq)23521a945772Spatrick mvpp2_txq_hw_init(struct mvpp2_port *sc, struct mvpp2_tx_queue *txq)
23531a945772Spatrick {
23541a945772Spatrick 	struct mvpp2_buf *txb;
23551a945772Spatrick 	int desc, desc_per_txq;
23561a945772Spatrick 	uint32_t reg;
23571a945772Spatrick 	int i;
23581a945772Spatrick 
235953d582d1Spatrick 	txq->prod = txq->cons = 0;
23601a945772Spatrick //	txq->last_desc = txq->size - 1;
23611a945772Spatrick 
23621a945772Spatrick 	txq->ring = mvpp2_dmamem_alloc(sc->sc,
23631a945772Spatrick 	    MVPP2_NTXDESC * sizeof(struct mvpp2_tx_desc), 32);
23647262ae33Spatrick 	KASSERT(txq->ring != NULL);
23651a945772Spatrick 	txq->descs = MVPP2_DMA_KVA(txq->ring);
23661a945772Spatrick 
23671a945772Spatrick 	txq->buf = mallocarray(MVPP2_NTXDESC, sizeof(struct mvpp2_buf),
23681a945772Spatrick 	    M_DEVBUF, M_WAITOK);
23691a945772Spatrick 
23701a945772Spatrick 	for (i = 0; i < MVPP2_NTXDESC; i++) {
23711a945772Spatrick 		txb = &txq->buf[i];
23721a945772Spatrick 		bus_dmamap_create(sc->sc_dmat, MCLBYTES, MVPP2_NTXSEGS,
23731a945772Spatrick 		    MCLBYTES, 0, BUS_DMA_WAITOK, &txb->mb_map);
23741a945772Spatrick 		txb->mb_m = NULL;
23751a945772Spatrick 	}
23761a945772Spatrick 
23771a945772Spatrick 	bus_dmamap_sync(sc->sc_dmat, MVPP2_DMA_MAP(txq->ring), 0,
23781a945772Spatrick 	    MVPP2_DMA_LEN(txq->ring), BUS_DMASYNC_PREWRITE);
23791a945772Spatrick 
23801a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_NUM_REG, txq->id);
23811a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_DESC_ADDR_REG,
23821a945772Spatrick 	    MVPP2_DMA_DVA(txq->ring));
23831a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_DESC_SIZE_REG,
23841a945772Spatrick 	    MVPP2_NTXDESC & MVPP2_TXQ_DESC_SIZE_MASK);
23851a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_INDEX_REG, 0);
23861a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_RSVD_CLR_REG,
23871a945772Spatrick 	    txq->id << MVPP2_TXQ_RSVD_CLR_OFFSET);
23881a945772Spatrick 	reg = mvpp2_read(sc->sc, MVPP2_TXQ_PENDING_REG);
23891a945772Spatrick 	reg &= ~MVPP2_TXQ_PENDING_MASK;
23901a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_PENDING_REG, reg);
23911a945772Spatrick 
23921a945772Spatrick 	desc_per_txq = 16;
23931a945772Spatrick 	desc = (sc->sc_id * MVPP2_MAX_TXQ * desc_per_txq) +
23941a945772Spatrick 	    (txq->log_id * desc_per_txq);
23951a945772Spatrick 
23961a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_PREF_BUF_REG,
23971a945772Spatrick 	    MVPP2_PREF_BUF_PTR(desc) | MVPP2_PREF_BUF_SIZE_16 |
23981a945772Spatrick 	    MVPP2_PREF_BUF_THRESH(desc_per_txq / 2));
23991a945772Spatrick 
24001a945772Spatrick 	/* WRR / EJP configuration - indirect access */
24011a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXP_SCHED_PORT_INDEX_REG,
24021a945772Spatrick 	    mvpp2_egress_port(sc));
24031a945772Spatrick 
24041a945772Spatrick 	reg = mvpp2_read(sc->sc, MVPP2_TXQ_SCHED_REFILL_REG(txq->log_id));
24051a945772Spatrick 	reg &= ~MVPP2_TXQ_REFILL_PERIOD_ALL_MASK;
24061a945772Spatrick 	reg |= MVPP2_TXQ_REFILL_PERIOD_MASK(1);
24071a945772Spatrick 	reg |= MVPP2_TXQ_REFILL_TOKENS_ALL_MASK;
24081a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_SCHED_REFILL_REG(txq->log_id), reg);
24091a945772Spatrick 
24101a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq->log_id),
24111a945772Spatrick 	    MVPP2_TXQ_TOKEN_SIZE_MAX);
24121a945772Spatrick 
24131a945772Spatrick 	mvpp2_tx_pkts_coal_set(sc, txq, txq->done_pkts_coal);
2414af1bab90Spatrick 
2415af1bab90Spatrick 	mvpp2_read(sc->sc, MVPP2_TXQ_SENT_REG(txq->id));
24161a945772Spatrick }
24171a945772Spatrick 
24181a945772Spatrick void
mvpp2_rxq_hw_init(struct mvpp2_port * sc,struct mvpp2_rx_queue * rxq)24191a945772Spatrick mvpp2_rxq_hw_init(struct mvpp2_port *sc, struct mvpp2_rx_queue *rxq)
24201a945772Spatrick {
24211a945772Spatrick 	rxq->prod = rxq->cons = 0;
24221a945772Spatrick 
24231a945772Spatrick 	rxq->ring = mvpp2_dmamem_alloc(sc->sc,
24241a945772Spatrick 	    MVPP2_NRXDESC * sizeof(struct mvpp2_rx_desc), 32);
24257262ae33Spatrick 	KASSERT(rxq->ring != NULL);
24261a945772Spatrick 	rxq->descs = MVPP2_DMA_KVA(rxq->ring);
24271a945772Spatrick 
24281a945772Spatrick 	bus_dmamap_sync(sc->sc_dmat, MVPP2_DMA_MAP(rxq->ring),
24291a945772Spatrick 	    0, MVPP2_DMA_LEN(rxq->ring),
24301a945772Spatrick 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
24311a945772Spatrick 
24321a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_RXQ_STATUS_REG(rxq->id), 0);
24331a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_RXQ_NUM_REG, rxq->id);
24341a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_RXQ_DESC_ADDR_REG,
24354d0a0269Spatrick 	    MVPP2_DMA_DVA(rxq->ring) >> MVPP22_DESC_ADDR_OFFS);
24361a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_RXQ_DESC_SIZE_REG, MVPP2_NRXDESC);
24371a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_RXQ_INDEX_REG, 0);
24381a945772Spatrick 	mvpp2_rxq_offset_set(sc, rxq->id, 0);
24391a945772Spatrick 	mvpp2_rx_pkts_coal_set(sc, rxq, rxq->pkts_coal);
24401a945772Spatrick 	mvpp2_rx_time_coal_set(sc, rxq, rxq->time_coal);
24411a945772Spatrick 	mvpp2_rxq_status_update(sc, rxq->id, 0, MVPP2_NRXDESC);
24421a945772Spatrick }
24431a945772Spatrick 
24441a945772Spatrick void
mvpp2_mac_reset_assert(struct mvpp2_port * sc)2445c56f4c70Spatrick mvpp2_mac_reset_assert(struct mvpp2_port *sc)
24461a945772Spatrick {
24471a945772Spatrick 	mvpp2_gmac_write(sc, MVPP2_PORT_CTRL2_REG,
24481a945772Spatrick 	    mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG) |
24494d0a0269Spatrick 	    MVPP2_PORT_CTRL2_PORTMACRESET);
2450c56f4c70Spatrick 	if (sc->sc_gop_id == 0)
24511a945772Spatrick 		mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG,
24521a945772Spatrick 		    mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG) &
24534d0a0269Spatrick 		    ~MV_XLG_MAC_CTRL0_MACRESETN);
2454c56f4c70Spatrick }
2455c56f4c70Spatrick 
2456c56f4c70Spatrick void
mvpp2_pcs_reset_assert(struct mvpp2_port * sc)2457c56f4c70Spatrick mvpp2_pcs_reset_assert(struct mvpp2_port *sc)
2458c56f4c70Spatrick {
2459c56f4c70Spatrick 	uint32_t reg;
2460c56f4c70Spatrick 
2461c56f4c70Spatrick 	if (sc->sc_gop_id != 0)
2462c56f4c70Spatrick 		return;
2463c56f4c70Spatrick 
24641a945772Spatrick 	reg = mvpp2_mpcs_read(sc, MVPP22_MPCS_CLOCK_RESET);
24654d0a0269Spatrick 	reg |= MVPP22_MPCS_CLK_DIV_PHASE_SET;
24664d0a0269Spatrick 	reg &= ~MVPP22_MPCS_TX_SD_CLK_RESET;
24674d0a0269Spatrick 	reg &= ~MVPP22_MPCS_RX_SD_CLK_RESET;
24684d0a0269Spatrick 	reg &= ~MVPP22_MPCS_MAC_CLK_RESET;
24691a945772Spatrick 	mvpp2_mpcs_write(sc, MVPP22_MPCS_CLOCK_RESET, reg);
247009e5d825Spatrick 	reg = mvpp2_xpcs_read(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG);
247109e5d825Spatrick 	reg &= ~MVPP22_XPCS_PCSRESET;
247209e5d825Spatrick 	mvpp2_xpcs_write(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG, reg);
24731a945772Spatrick }
24741a945772Spatrick 
2475c56f4c70Spatrick void
mvpp2_pcs_reset_deassert(struct mvpp2_port * sc)2476c56f4c70Spatrick mvpp2_pcs_reset_deassert(struct mvpp2_port *sc)
2477c56f4c70Spatrick {
2478c56f4c70Spatrick 	uint32_t reg;
247909e5d825Spatrick 
2480c56f4c70Spatrick 	if (sc->sc_gop_id != 0)
2481c56f4c70Spatrick 		return;
2482c56f4c70Spatrick 
24831a945772Spatrick 	if (sc->sc_phy_mode == PHY_MODE_10GBASER) {
24841a945772Spatrick 		reg = mvpp2_mpcs_read(sc, MVPP22_MPCS_CLOCK_RESET);
24854d0a0269Spatrick 		reg &= ~MVPP22_MPCS_CLK_DIV_PHASE_SET;
24864d0a0269Spatrick 		reg |= MVPP22_MPCS_TX_SD_CLK_RESET;
24874d0a0269Spatrick 		reg |= MVPP22_MPCS_RX_SD_CLK_RESET;
24884d0a0269Spatrick 		reg |= MVPP22_MPCS_MAC_CLK_RESET;
24891a945772Spatrick 		mvpp2_mpcs_write(sc, MVPP22_MPCS_CLOCK_RESET, reg);
249009e5d825Spatrick 	} else if (sc->sc_phy_mode == PHY_MODE_XAUI) {
249109e5d825Spatrick 		reg = mvpp2_xpcs_read(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG);
249209e5d825Spatrick 		reg |= MVPP22_XPCS_PCSRESET;
249309e5d825Spatrick 		mvpp2_xpcs_write(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG, reg);
249409e5d825Spatrick 	}
2495c56f4c70Spatrick }
24961a945772Spatrick 
2497c56f4c70Spatrick void
mvpp2_mac_config(struct mvpp2_port * sc)2498c56f4c70Spatrick mvpp2_mac_config(struct mvpp2_port *sc)
2499c56f4c70Spatrick {
2500c56f4c70Spatrick 	uint32_t reg;
2501c56f4c70Spatrick 
2502c56f4c70Spatrick 	reg = mvpp2_gmac_read(sc, MVPP2_GMAC_AUTONEG_CONFIG);
2503c56f4c70Spatrick 	reg &= ~MVPP2_GMAC_FORCE_LINK_PASS;
2504c56f4c70Spatrick 	reg |= MVPP2_GMAC_FORCE_LINK_DOWN;
2505c56f4c70Spatrick 	mvpp2_gmac_write(sc, MVPP2_GMAC_AUTONEG_CONFIG, reg);
2506c56f4c70Spatrick 	if (sc->sc_gop_id == 0) {
2507c56f4c70Spatrick 		reg = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG);
2508c56f4c70Spatrick 		reg &= ~MV_XLG_MAC_CTRL0_FORCELINKPASS;
2509c56f4c70Spatrick 		reg |= MV_XLG_MAC_CTRL0_FORCELINKDOWN;
2510c56f4c70Spatrick 		mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG, reg);
2511c56f4c70Spatrick 	}
2512c56f4c70Spatrick 
2513c56f4c70Spatrick 	mvpp2_port_disable(sc);
2514c56f4c70Spatrick 
251595237283Skettenis 	mvpp2_mac_reset_assert(sc);
251695237283Skettenis 	mvpp2_pcs_reset_assert(sc);
251795237283Skettenis 
2518c56f4c70Spatrick 	mvpp2_gop_intr_mask(sc);
2519c56f4c70Spatrick 	mvpp2_comphy_config(sc, 0);
2520c56f4c70Spatrick 
2521c56f4c70Spatrick 	if (sc->sc_gop_id == 0 && (sc->sc_phy_mode == PHY_MODE_10GBASER ||
2522c56f4c70Spatrick 	    sc->sc_phy_mode == PHY_MODE_XAUI))
2523c56f4c70Spatrick 		mvpp2_xlg_config(sc);
2524c56f4c70Spatrick 	else
2525c56f4c70Spatrick 		mvpp2_gmac_config(sc);
2526c56f4c70Spatrick 
2527c56f4c70Spatrick 	mvpp2_comphy_config(sc, 1);
2528c56f4c70Spatrick 	mvpp2_gop_config(sc);
2529c56f4c70Spatrick 
2530c56f4c70Spatrick 	mvpp2_pcs_reset_deassert(sc);
2531c56f4c70Spatrick 
2532c56f4c70Spatrick 	if (sc->sc_gop_id == 0) {
25331a945772Spatrick 		reg = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL3_REG);
25341a945772Spatrick 		reg &= ~MV_XLG_MAC_CTRL3_MACMODESELECT_MASK;
25351a945772Spatrick 		if (sc->sc_phy_mode == PHY_MODE_10GBASER ||
25361a945772Spatrick 		    sc->sc_phy_mode == PHY_MODE_XAUI)
25371a945772Spatrick 			reg |= MV_XLG_MAC_CTRL3_MACMODESELECT_10G;
25381a945772Spatrick 		else
25391a945772Spatrick 			reg |= MV_XLG_MAC_CTRL3_MACMODESELECT_GMAC;
25401a945772Spatrick 		mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL3_REG, reg);
25411a945772Spatrick 	}
25421a945772Spatrick 
25431a945772Spatrick 	if (sc->sc_gop_id == 0 && (sc->sc_phy_mode == PHY_MODE_10GBASER ||
25441a945772Spatrick 	    sc->sc_phy_mode == PHY_MODE_XAUI)) {
25451a945772Spatrick 		reg = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL1_REG);
25461a945772Spatrick 		reg &= ~MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_MASK;
25471a945772Spatrick 		reg |= ((MCLBYTES - MVPP2_MH_SIZE) / 2) <<
25481a945772Spatrick 		    MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_OFFS;
25491a945772Spatrick 		mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL1_REG, reg);
25501a945772Spatrick 	} else {
25511a945772Spatrick 		reg = mvpp2_gmac_read(sc, MVPP2_GMAC_CTRL_0_REG);
25521a945772Spatrick 		reg &= ~MVPP2_GMAC_MAX_RX_SIZE_MASK;
25531a945772Spatrick 		reg |= ((MCLBYTES - MVPP2_MH_SIZE) / 2) <<
25541a945772Spatrick 		    MVPP2_GMAC_MAX_RX_SIZE_OFFS;
25551a945772Spatrick 		mvpp2_gmac_write(sc, MVPP2_GMAC_CTRL_0_REG, reg);
25561a945772Spatrick 	}
25571a945772Spatrick 
2558c56f4c70Spatrick 	mvpp2_gop_intr_unmask(sc);
2559c56f4c70Spatrick 
2560c56f4c70Spatrick 	if (!(sc->sc_phy_mode == PHY_MODE_10GBASER ||
2561c56f4c70Spatrick 	    sc->sc_phy_mode == PHY_MODE_XAUI)) {
2562c56f4c70Spatrick 		mvpp2_gmac_write(sc, MVPP2_PORT_CTRL2_REG,
2563c56f4c70Spatrick 		    mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG) &
2564c56f4c70Spatrick 		    ~MVPP2_PORT_CTRL2_PORTMACRESET);
2565c56f4c70Spatrick 		while (mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG) &
2566c56f4c70Spatrick 		    MVPP2_PORT_CTRL2_PORTMACRESET)
2567c56f4c70Spatrick 			;
2568c56f4c70Spatrick 	}
25691a945772Spatrick 
25701a945772Spatrick 	mvpp2_port_enable(sc);
2571c56f4c70Spatrick 
2572c56f4c70Spatrick 	if (sc->sc_inband_status) {
2573c56f4c70Spatrick 		reg = mvpp2_gmac_read(sc, MVPP2_GMAC_AUTONEG_CONFIG);
2574c56f4c70Spatrick 		reg &= ~MVPP2_GMAC_FORCE_LINK_PASS;
2575c56f4c70Spatrick 		reg &= ~MVPP2_GMAC_FORCE_LINK_DOWN;
2576c56f4c70Spatrick 		mvpp2_gmac_write(sc, MVPP2_GMAC_AUTONEG_CONFIG, reg);
2577c56f4c70Spatrick 		if (sc->sc_gop_id == 0) {
2578c56f4c70Spatrick 			reg = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG);
2579c56f4c70Spatrick 			reg &= ~MV_XLG_MAC_CTRL0_FORCELINKPASS;
2580c56f4c70Spatrick 			reg &= ~MV_XLG_MAC_CTRL0_FORCELINKDOWN;
2581c56f4c70Spatrick 			mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG, reg);
2582c56f4c70Spatrick 		}
2583c56f4c70Spatrick 	} else
2584c56f4c70Spatrick 		mvpp2_port_change(sc);
25851a945772Spatrick }
25861a945772Spatrick 
25871a945772Spatrick void
mvpp2_xlg_config(struct mvpp2_port * sc)25881a945772Spatrick mvpp2_xlg_config(struct mvpp2_port *sc)
25891a945772Spatrick {
25901a945772Spatrick 	uint32_t ctl0, ctl4;
25911a945772Spatrick 
25921a945772Spatrick 	ctl0 = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG);
25931a945772Spatrick 	ctl4 = mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL4_REG);
25941a945772Spatrick 
25954d0a0269Spatrick 	ctl0 |= MV_XLG_MAC_CTRL0_MACRESETN;
25961a945772Spatrick 	ctl4 &= ~MV_XLG_MAC_CTRL4_EN_IDLE_CHECK_FOR_LINK;
25974d0a0269Spatrick 	ctl4 |= MV_XLG_MAC_CTRL4_FORWARD_PFC_EN;
25984d0a0269Spatrick 	ctl4 |= MV_XLG_MAC_CTRL4_FORWARD_802_3X_FC_EN;
25991a945772Spatrick 
26001a945772Spatrick 	mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL0_REG, ctl0);
2601256d46b8Sjsg 	mvpp2_xlg_write(sc, MV_XLG_PORT_MAC_CTRL4_REG, ctl4);
26021a945772Spatrick 
26031a945772Spatrick 	/* Port reset */
26041a945772Spatrick 	while ((mvpp2_xlg_read(sc, MV_XLG_PORT_MAC_CTRL0_REG) &
26054d0a0269Spatrick 	    MV_XLG_MAC_CTRL0_MACRESETN) == 0)
26061a945772Spatrick 		;
26071a945772Spatrick }
26081a945772Spatrick 
26091a945772Spatrick void
mvpp2_gmac_config(struct mvpp2_port * sc)26101a945772Spatrick mvpp2_gmac_config(struct mvpp2_port *sc)
26111a945772Spatrick {
26121a945772Spatrick 	uint32_t ctl0, ctl2, ctl4, panc;
26131a945772Spatrick 
26141a945772Spatrick 	/* Setup phy. */
26151a945772Spatrick 	ctl0 = mvpp2_gmac_read(sc, MVPP2_PORT_CTRL0_REG);
26161a945772Spatrick 	ctl2 = mvpp2_gmac_read(sc, MVPP2_PORT_CTRL2_REG);
26171a945772Spatrick 	ctl4 = mvpp2_gmac_read(sc, MVPP2_PORT_CTRL4_REG);
26181a945772Spatrick 	panc = mvpp2_gmac_read(sc, MVPP2_GMAC_AUTONEG_CONFIG);
26191a945772Spatrick 
26201a945772Spatrick 	ctl0 &= ~MVPP2_GMAC_PORT_TYPE_MASK;
26211a945772Spatrick 	ctl2 &= ~(MVPP2_GMAC_PORT_RESET_MASK | MVPP2_GMAC_PCS_ENABLE_MASK |
26221a945772Spatrick 	    MVPP2_GMAC_INBAND_AN_MASK);
26231a945772Spatrick 	panc &= ~(MVPP2_GMAC_AN_DUPLEX_EN | MVPP2_GMAC_FLOW_CTRL_AUTONEG |
26241a945772Spatrick 	    MVPP2_GMAC_FC_ADV_ASM_EN | MVPP2_GMAC_FC_ADV_EN |
26251a945772Spatrick 	    MVPP2_GMAC_AN_SPEED_EN | MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS |
26261a945772Spatrick 	    MVPP2_GMAC_IN_BAND_AUTONEG);
26271a945772Spatrick 
26281a945772Spatrick 	switch (sc->sc_phy_mode) {
26291a945772Spatrick 	case PHY_MODE_XAUI:
26301a945772Spatrick 	case PHY_MODE_10GBASER:
26311a945772Spatrick 		break;
26321a945772Spatrick 	case PHY_MODE_2500BASEX:
26331a945772Spatrick 	case PHY_MODE_1000BASEX:
26341a945772Spatrick 		ctl2 |= MVPP2_GMAC_PCS_ENABLE_MASK;
26354d0a0269Spatrick 		ctl4 &= ~MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL;
26364d0a0269Spatrick 		ctl4 |= MVPP2_PORT_CTRL4_SYNC_BYPASS;
26374d0a0269Spatrick 		ctl4 |= MVPP2_PORT_CTRL4_DP_CLK_SEL;
26384d0a0269Spatrick 		ctl4 |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE;
26391a945772Spatrick 		break;
26401a945772Spatrick 	case PHY_MODE_SGMII:
26411a945772Spatrick 		ctl2 |= MVPP2_GMAC_PCS_ENABLE_MASK;
26421a945772Spatrick 		ctl2 |= MVPP2_GMAC_INBAND_AN_MASK;
26434d0a0269Spatrick 		ctl4 &= ~MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL;
26444d0a0269Spatrick 		ctl4 |= MVPP2_PORT_CTRL4_SYNC_BYPASS;
26454d0a0269Spatrick 		ctl4 |= MVPP2_PORT_CTRL4_DP_CLK_SEL;
26464d0a0269Spatrick 		ctl4 |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE;
26471a945772Spatrick 		break;
26481a945772Spatrick 	case PHY_MODE_RGMII:
26491a945772Spatrick 	case PHY_MODE_RGMII_ID:
26501a945772Spatrick 	case PHY_MODE_RGMII_RXID:
26511a945772Spatrick 	case PHY_MODE_RGMII_TXID:
26524d0a0269Spatrick 		ctl4 &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL;
26534d0a0269Spatrick 		ctl4 |= MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL;
26544d0a0269Spatrick 		ctl4 |= MVPP2_PORT_CTRL4_SYNC_BYPASS;
26554d0a0269Spatrick 		ctl4 |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE;
26561a945772Spatrick 		break;
26571a945772Spatrick 	}
26581a945772Spatrick 
26591a945772Spatrick 	/* Use Auto-Negotiation for Inband Status only */
26601a945772Spatrick 	if (sc->sc_inband_status) {
26611a945772Spatrick 		panc &= ~MVPP2_GMAC_CONFIG_MII_SPEED;
26621a945772Spatrick 		panc &= ~MVPP2_GMAC_CONFIG_GMII_SPEED;
26631a945772Spatrick 		panc &= ~MVPP2_GMAC_CONFIG_FULL_DUPLEX;
26641a945772Spatrick 		panc |= MVPP2_GMAC_IN_BAND_AUTONEG;
26651a945772Spatrick 		/* TODO: read mode from SFP */
2666c56f4c70Spatrick 		if (sc->sc_phy_mode == PHY_MODE_SGMII) {
2667c56f4c70Spatrick 			/* SGMII */
2668c56f4c70Spatrick 			panc |= MVPP2_GMAC_AN_SPEED_EN;
2669c56f4c70Spatrick 			panc |= MVPP2_GMAC_AN_DUPLEX_EN;
2670c56f4c70Spatrick 		} else {
26711a945772Spatrick 			/* 802.3z */
26721a945772Spatrick 			ctl0 |= MVPP2_GMAC_PORT_TYPE_MASK;
26731a945772Spatrick 			panc |= MVPP2_GMAC_CONFIG_GMII_SPEED;
26741a945772Spatrick 			panc |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
26751a945772Spatrick 		}
26761a945772Spatrick 	}
26771a945772Spatrick 
26781a945772Spatrick 	mvpp2_gmac_write(sc, MVPP2_PORT_CTRL0_REG, ctl0);
26791a945772Spatrick 	mvpp2_gmac_write(sc, MVPP2_PORT_CTRL2_REG, ctl2);
26801a945772Spatrick 	mvpp2_gmac_write(sc, MVPP2_PORT_CTRL4_REG, ctl4);
26811a945772Spatrick 	mvpp2_gmac_write(sc, MVPP2_GMAC_AUTONEG_CONFIG, panc);
26821a945772Spatrick }
26831a945772Spatrick 
268409e5d825Spatrick #define COMPHY_BASE		0x120000
268509e5d825Spatrick #define COMPHY_SIP_POWER_ON	0x82000001
268609e5d825Spatrick #define COMPHY_SIP_POWER_OFF	0x82000002
268709e5d825Spatrick #define COMPHY_SPEED(x)		((x) << 2)
268809e5d825Spatrick #define  COMPHY_SPEED_1_25G		0 /* SGMII 1G */
268909e5d825Spatrick #define  COMPHY_SPEED_2_5G		1
269009e5d825Spatrick #define  COMPHY_SPEED_3_125G		2 /* SGMII 2.5G */
269109e5d825Spatrick #define  COMPHY_SPEED_5G		3
269209e5d825Spatrick #define  COMPHY_SPEED_5_15625G		4 /* XFI 5G */
269309e5d825Spatrick #define  COMPHY_SPEED_6G		5
269409e5d825Spatrick #define  COMPHY_SPEED_10_3125G		6 /* XFI 10G */
269509e5d825Spatrick #define COMPHY_UNIT(x)		((x) << 8)
269609e5d825Spatrick #define COMPHY_MODE(x)		((x) << 12)
269709e5d825Spatrick #define  COMPHY_MODE_SATA		1
269809e5d825Spatrick #define  COMPHY_MODE_SGMII		2 /* SGMII 1G */
269909e5d825Spatrick #define  COMPHY_MODE_HS_SGMII		3 /* SGMII 2.5G */
270009e5d825Spatrick #define  COMPHY_MODE_USB3H		4
270109e5d825Spatrick #define  COMPHY_MODE_USB3D		5
270209e5d825Spatrick #define  COMPHY_MODE_PCIE		6
270309e5d825Spatrick #define  COMPHY_MODE_RXAUI		7
270409e5d825Spatrick #define  COMPHY_MODE_XFI		8
270509e5d825Spatrick #define  COMPHY_MODE_SFI		9
270609e5d825Spatrick #define  COMPHY_MODE_USB3		10
270709e5d825Spatrick #define  COMPHY_MODE_AP			11
270809e5d825Spatrick 
270909e5d825Spatrick void
mvpp2_comphy_config(struct mvpp2_port * sc,int on)2710c56f4c70Spatrick mvpp2_comphy_config(struct mvpp2_port *sc, int on)
271109e5d825Spatrick {
271209e5d825Spatrick 	int node, phys[2], lane, unit;
271309e5d825Spatrick 	uint32_t mode;
271409e5d825Spatrick 
271509e5d825Spatrick 	if (OF_getpropintarray(sc->sc_node, "phys", phys, sizeof(phys)) !=
271609e5d825Spatrick 	    sizeof(phys))
271709e5d825Spatrick 		return;
271809e5d825Spatrick 	node = OF_getnodebyphandle(phys[0]);
271909e5d825Spatrick 	if (!node)
272009e5d825Spatrick 		return;
272109e5d825Spatrick 
272209e5d825Spatrick 	lane = OF_getpropint(node, "reg", 0);
272309e5d825Spatrick 	unit = phys[1];
272409e5d825Spatrick 
272509e5d825Spatrick 	switch (sc->sc_phy_mode) {
272609e5d825Spatrick 	case PHY_MODE_XAUI:
272709e5d825Spatrick 		mode = COMPHY_MODE(COMPHY_MODE_RXAUI) |
272809e5d825Spatrick 		    COMPHY_UNIT(unit);
272909e5d825Spatrick 		break;
273009e5d825Spatrick 	case PHY_MODE_10GBASER:
273109e5d825Spatrick 		mode = COMPHY_MODE(COMPHY_MODE_XFI) |
273209e5d825Spatrick 		    COMPHY_SPEED(COMPHY_SPEED_10_3125G) |
273309e5d825Spatrick 		    COMPHY_UNIT(unit);
273409e5d825Spatrick 		break;
273509e5d825Spatrick 	case PHY_MODE_2500BASEX:
273609e5d825Spatrick 		mode = COMPHY_MODE(COMPHY_MODE_HS_SGMII) |
273709e5d825Spatrick 		    COMPHY_SPEED(COMPHY_SPEED_3_125G) |
273809e5d825Spatrick 		    COMPHY_UNIT(unit);
273909e5d825Spatrick 		break;
274009e5d825Spatrick 	case PHY_MODE_1000BASEX:
274109e5d825Spatrick 	case PHY_MODE_SGMII:
274209e5d825Spatrick 		mode = COMPHY_MODE(COMPHY_MODE_SGMII) |
274309e5d825Spatrick 		    COMPHY_SPEED(COMPHY_SPEED_1_25G) |
274409e5d825Spatrick 		    COMPHY_UNIT(unit);
274509e5d825Spatrick 		break;
274609e5d825Spatrick 	default:
274709e5d825Spatrick 		return;
274809e5d825Spatrick 	}
274909e5d825Spatrick 
2750c56f4c70Spatrick 	if (on)
275109e5d825Spatrick 		smc_call(COMPHY_SIP_POWER_ON, sc->sc->sc_ioh_paddr + COMPHY_BASE,
275209e5d825Spatrick 		    lane, mode);
2753c56f4c70Spatrick 	else
2754c56f4c70Spatrick 		smc_call(COMPHY_SIP_POWER_OFF, sc->sc->sc_ioh_paddr + COMPHY_BASE,
2755c56f4c70Spatrick 		    lane, 0);
275609e5d825Spatrick }
275709e5d825Spatrick 
275809e5d825Spatrick void
mvpp2_gop_config(struct mvpp2_port * sc)275909e5d825Spatrick mvpp2_gop_config(struct mvpp2_port *sc)
276009e5d825Spatrick {
276109e5d825Spatrick 	uint32_t reg;
276209e5d825Spatrick 
276309e5d825Spatrick 	if (sc->sc->sc_rm == NULL)
276409e5d825Spatrick 		return;
276509e5d825Spatrick 
276609e5d825Spatrick 	if (sc->sc_phy_mode == PHY_MODE_RGMII ||
276709e5d825Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII_ID ||
276809e5d825Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII_RXID ||
276909e5d825Spatrick 	    sc->sc_phy_mode == PHY_MODE_RGMII_TXID) {
277009e5d825Spatrick 		if (sc->sc_gop_id == 0)
277109e5d825Spatrick 			return;
277209e5d825Spatrick 		reg = regmap_read_4(sc->sc->sc_rm, GENCONF_PORT_CTRL0);
277309e5d825Spatrick 		reg |= GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT;
277409e5d825Spatrick 		regmap_write_4(sc->sc->sc_rm, GENCONF_PORT_CTRL0, reg);
277509e5d825Spatrick 		reg = regmap_read_4(sc->sc->sc_rm, GENCONF_CTRL0);
277609e5d825Spatrick 		if (sc->sc_gop_id == 2)
277709e5d825Spatrick 			reg |= GENCONF_CTRL0_PORT0_RGMII |
277809e5d825Spatrick 			    GENCONF_CTRL0_PORT1_RGMII;
277909e5d825Spatrick 		else if (sc->sc_gop_id == 3)
278009e5d825Spatrick 			reg |= GENCONF_CTRL0_PORT1_RGMII_MII;
278109e5d825Spatrick 		regmap_write_4(sc->sc->sc_rm, GENCONF_CTRL0, reg);
278209e5d825Spatrick 	} else if (sc->sc_phy_mode == PHY_MODE_2500BASEX ||
278309e5d825Spatrick 	    sc->sc_phy_mode == PHY_MODE_1000BASEX ||
278409e5d825Spatrick 	    sc->sc_phy_mode == PHY_MODE_SGMII) {
278509e5d825Spatrick 		reg = regmap_read_4(sc->sc->sc_rm, GENCONF_PORT_CTRL0);
278609e5d825Spatrick 		reg |= GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT |
278709e5d825Spatrick 		    GENCONF_PORT_CTRL0_RX_DATA_SAMPLE;
278809e5d825Spatrick 		regmap_write_4(sc->sc->sc_rm, GENCONF_PORT_CTRL0, reg);
278909e5d825Spatrick 		if (sc->sc_gop_id > 1) {
279009e5d825Spatrick 			reg = regmap_read_4(sc->sc->sc_rm, GENCONF_CTRL0);
279109e5d825Spatrick 			if (sc->sc_gop_id == 2)
279209e5d825Spatrick 				reg &= ~GENCONF_CTRL0_PORT0_RGMII;
279309e5d825Spatrick 			else if (sc->sc_gop_id == 3)
279409e5d825Spatrick 				reg &= ~GENCONF_CTRL0_PORT1_RGMII_MII;
279509e5d825Spatrick 			regmap_write_4(sc->sc->sc_rm, GENCONF_CTRL0, reg);
279609e5d825Spatrick 		}
279709e5d825Spatrick 	} else if (sc->sc_phy_mode == PHY_MODE_10GBASER) {
279809e5d825Spatrick 		if (sc->sc_gop_id != 0)
279909e5d825Spatrick 			return;
280009e5d825Spatrick 		reg = mvpp2_xpcs_read(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG);
280109e5d825Spatrick 		reg &= ~MVPP22_XPCS_PCSMODE_MASK;
280209e5d825Spatrick 		reg &= ~MVPP22_XPCS_LANEACTIVE_MASK;
280309e5d825Spatrick 		reg |= 2 << MVPP22_XPCS_LANEACTIVE_OFFS;
280409e5d825Spatrick 		mvpp2_xpcs_write(sc, MVPP22_XPCS_GLOBAL_CFG_0_REG, reg);
280509e5d825Spatrick 		reg = mvpp2_mpcs_read(sc, MVPP22_MPCS40G_COMMON_CONTROL);
280609e5d825Spatrick 		reg &= ~MVPP22_MPCS_FORWARD_ERROR_CORRECTION_MASK;
280709e5d825Spatrick 		mvpp2_mpcs_write(sc, MVPP22_MPCS40G_COMMON_CONTROL, reg);
280809e5d825Spatrick 		reg = mvpp2_mpcs_read(sc, MVPP22_MPCS_CLOCK_RESET);
280909e5d825Spatrick 		reg &= ~MVPP22_MPCS_CLK_DIVISION_RATIO_MASK;
281009e5d825Spatrick 		reg |= MVPP22_MPCS_CLK_DIVISION_RATIO_DEFAULT;
281109e5d825Spatrick 		mvpp2_mpcs_write(sc, MVPP22_MPCS_CLOCK_RESET, reg);
281209e5d825Spatrick 	} else
281309e5d825Spatrick 		return;
281409e5d825Spatrick 
281509e5d825Spatrick 	reg = regmap_read_4(sc->sc->sc_rm, GENCONF_PORT_CTRL1);
281609e5d825Spatrick 	reg |= GENCONF_PORT_CTRL1_RESET(sc->sc_gop_id) |
281709e5d825Spatrick 	    GENCONF_PORT_CTRL1_EN(sc->sc_gop_id);
281809e5d825Spatrick 	regmap_write_4(sc->sc->sc_rm, GENCONF_PORT_CTRL1, reg);
281909e5d825Spatrick 
282009e5d825Spatrick 	reg = regmap_read_4(sc->sc->sc_rm, GENCONF_PORT_CTRL0);
282109e5d825Spatrick 	reg |= GENCONF_PORT_CTRL0_CLK_DIV_PHASE_CLR;
282209e5d825Spatrick 	regmap_write_4(sc->sc->sc_rm, GENCONF_PORT_CTRL0, reg);
282309e5d825Spatrick 
282409e5d825Spatrick 	reg = regmap_read_4(sc->sc->sc_rm, GENCONF_SOFT_RESET1);
282509e5d825Spatrick 	reg |= GENCONF_SOFT_RESET1_GOP;
282609e5d825Spatrick 	regmap_write_4(sc->sc->sc_rm, GENCONF_SOFT_RESET1, reg);
282709e5d825Spatrick }
282809e5d825Spatrick 
28291a945772Spatrick void
mvpp2_gop_intr_mask(struct mvpp2_port * sc)2830c56f4c70Spatrick mvpp2_gop_intr_mask(struct mvpp2_port *sc)
2831c56f4c70Spatrick {
2832c56f4c70Spatrick 	uint32_t reg;
2833c56f4c70Spatrick 
2834c56f4c70Spatrick 	if (sc->sc_gop_id == 0) {
2835c56f4c70Spatrick 		reg = mvpp2_xlg_read(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG);
2836c56f4c70Spatrick 		reg &= ~MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_XLG;
2837c56f4c70Spatrick 		reg &= ~MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_GIG;
2838c56f4c70Spatrick 		mvpp2_xlg_write(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG, reg);
2839c56f4c70Spatrick 	}
2840c56f4c70Spatrick 
2841c56f4c70Spatrick 	reg = mvpp2_gmac_read(sc, MVPP2_GMAC_INT_SUM_MASK_REG);
2842c56f4c70Spatrick 	reg &= ~MVPP2_GMAC_INT_SUM_CAUSE_LINK_CHANGE;
2843c56f4c70Spatrick 	mvpp2_gmac_write(sc, MVPP2_GMAC_INT_SUM_MASK_REG, reg);
2844c56f4c70Spatrick }
2845c56f4c70Spatrick 
2846c56f4c70Spatrick void
mvpp2_gop_intr_unmask(struct mvpp2_port * sc)2847c56f4c70Spatrick mvpp2_gop_intr_unmask(struct mvpp2_port *sc)
2848c56f4c70Spatrick {
2849c56f4c70Spatrick 	uint32_t reg;
2850c56f4c70Spatrick 
2851c56f4c70Spatrick 	reg = mvpp2_gmac_read(sc, MVPP2_GMAC_INT_SUM_MASK_REG);
2852c56f4c70Spatrick 	reg |= MVPP2_GMAC_INT_SUM_CAUSE_LINK_CHANGE;
2853c56f4c70Spatrick 	mvpp2_gmac_write(sc, MVPP2_GMAC_INT_SUM_MASK_REG, reg);
2854c56f4c70Spatrick 
2855c56f4c70Spatrick 	if (sc->sc_gop_id == 0) {
2856c56f4c70Spatrick 		reg = mvpp2_xlg_read(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG);
2857c56f4c70Spatrick 		if (sc->sc_phy_mode == PHY_MODE_10GBASER ||
2858c56f4c70Spatrick 		    sc->sc_phy_mode == PHY_MODE_XAUI)
2859c56f4c70Spatrick 			reg |= MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_XLG;
2860c56f4c70Spatrick 		else
2861c56f4c70Spatrick 			reg |= MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_GIG;
2862c56f4c70Spatrick 		mvpp2_xlg_write(sc, MV_XLG_EXTERNAL_INTERRUPT_MASK_REG, reg);
2863c56f4c70Spatrick 	}
2864c56f4c70Spatrick }
2865c56f4c70Spatrick 
2866c56f4c70Spatrick void
mvpp2_down(struct mvpp2_port * sc)28671a945772Spatrick mvpp2_down(struct mvpp2_port *sc)
28681a945772Spatrick {
28691a945772Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
28701a945772Spatrick 	uint32_t reg;
28711a945772Spatrick 	int i;
28721a945772Spatrick 
28731a945772Spatrick 	timeout_del(&sc->sc_tick);
28741a945772Spatrick 
28751a945772Spatrick 	ifp->if_flags &= ~IFF_RUNNING;
28761a945772Spatrick 	ifq_clr_oactive(&ifp->if_snd);
28771a945772Spatrick 
28781a945772Spatrick 	mvpp2_egress_disable(sc);
28791a945772Spatrick 	mvpp2_ingress_disable(sc);
2880c56f4c70Spatrick 
2881c56f4c70Spatrick 	mvpp2_mac_reset_assert(sc);
2882c56f4c70Spatrick 	mvpp2_pcs_reset_assert(sc);
28831a945772Spatrick 
28841a945772Spatrick 	/* XXX: single vector */
28851a945772Spatrick 	mvpp2_interrupts_disable(sc, (1 << 0));
28861a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_ISR_RX_TX_MASK_REG(sc->sc_id), 0);
28871a945772Spatrick 
28881a945772Spatrick 	reg = mvpp2_read(sc->sc, MVPP2_TX_PORT_FLUSH_REG);
28891a945772Spatrick 	reg |= MVPP2_TX_PORT_FLUSH_MASK(sc->sc_id);
28901a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TX_PORT_FLUSH_REG, reg);
28911a945772Spatrick 
28921a945772Spatrick 	for (i = 0; i < sc->sc_ntxq; i++)
28931a945772Spatrick 		mvpp2_txq_hw_deinit(sc, &sc->sc_txqs[i]);
28941a945772Spatrick 
28951a945772Spatrick 	reg &= ~MVPP2_TX_PORT_FLUSH_MASK(sc->sc_id);
28961a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TX_PORT_FLUSH_REG, reg);
28971a945772Spatrick 
28981a945772Spatrick 	for (i = 0; i < sc->sc_nrxq; i++)
28991a945772Spatrick 		mvpp2_rxq_hw_deinit(sc, &sc->sc_rxqs[i]);
29001a945772Spatrick 
290188474739Skettenis 	if (sc->sc_sfp) {
290288474739Skettenis 		rw_enter(&mvpp2_sff_lock, RW_WRITE);
290388474739Skettenis 		sfp_disable(sc->sc_sfp);
290488474739Skettenis 		rw_exit(&mvpp2_sff_lock);
290588474739Skettenis 	}
29061a945772Spatrick }
29071a945772Spatrick 
29081a945772Spatrick void
mvpp2_txq_hw_deinit(struct mvpp2_port * sc,struct mvpp2_tx_queue * txq)29091a945772Spatrick mvpp2_txq_hw_deinit(struct mvpp2_port *sc, struct mvpp2_tx_queue *txq)
29101a945772Spatrick {
29111a945772Spatrick 	struct mvpp2_buf *txb;
29121a945772Spatrick 	int i, pending;
29131a945772Spatrick 	uint32_t reg;
29141a945772Spatrick 
29151a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_NUM_REG, txq->id);
29161a945772Spatrick 	reg = mvpp2_read(sc->sc, MVPP2_TXQ_PREF_BUF_REG);
29171a945772Spatrick 	reg |= MVPP2_TXQ_DRAIN_EN_MASK;
29181a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_PREF_BUF_REG, reg);
29191a945772Spatrick 
29201a945772Spatrick 	/*
29211a945772Spatrick 	 * the queue has been stopped so wait for all packets
29221a945772Spatrick 	 * to be transmitted.
29231a945772Spatrick 	 */
29241a945772Spatrick 	i = 0;
29251a945772Spatrick 	do {
29261a945772Spatrick 		if (i >= MVPP2_TX_PENDING_TIMEOUT_MSEC) {
29271a945772Spatrick 			printf("%s: port %d: cleaning queue %d timed out\n",
29281a945772Spatrick 			    sc->sc_dev.dv_xname, sc->sc_id, txq->log_id);
29291a945772Spatrick 			break;
29301a945772Spatrick 		}
29311a945772Spatrick 		delay(1000);
29321a945772Spatrick 		i++;
29331a945772Spatrick 
29341a945772Spatrick 		pending = mvpp2_read(sc->sc, MVPP2_TXQ_PENDING_REG) &
29351a945772Spatrick 		    MVPP2_TXQ_PENDING_MASK;
29361a945772Spatrick 	} while (pending);
29371a945772Spatrick 
29381a945772Spatrick 	reg &= ~MVPP2_TXQ_DRAIN_EN_MASK;
29391a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_PREF_BUF_REG, reg);
29401a945772Spatrick 
2941385d82b1Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->log_id), 0);
29421a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_NUM_REG, txq->id);
29431a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_DESC_ADDR_REG, 0);
29441a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_TXQ_DESC_SIZE_REG, 0);
2945af1bab90Spatrick 	mvpp2_read(sc->sc, MVPP2_TXQ_SENT_REG(txq->id));
29461a945772Spatrick 
29471a945772Spatrick 	for (i = 0; i < MVPP2_NTXDESC; i++) {
29481a945772Spatrick 		txb = &txq->buf[i];
29491a945772Spatrick 		if (txb->mb_m) {
29501a945772Spatrick 			bus_dmamap_sync(sc->sc_dmat, txb->mb_map, 0,
29511a945772Spatrick 			    txb->mb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
29521a945772Spatrick 			bus_dmamap_unload(sc->sc_dmat, txb->mb_map);
29531a945772Spatrick 			m_freem(txb->mb_m);
29541a945772Spatrick 		}
29551a945772Spatrick 		bus_dmamap_destroy(sc->sc_dmat, txb->mb_map);
29561a945772Spatrick 	}
29571a945772Spatrick 
29581a945772Spatrick 	mvpp2_dmamem_free(sc->sc, txq->ring);
29591a945772Spatrick 	free(txq->buf, M_DEVBUF, sizeof(struct mvpp2_buf) *
29601a945772Spatrick 	    MVPP2_NTXDESC);
29611a945772Spatrick }
29621a945772Spatrick 
29631a945772Spatrick void
mvpp2_rxq_hw_drop(struct mvpp2_port * sc,struct mvpp2_rx_queue * rxq)29648801406bSpatrick mvpp2_rxq_hw_drop(struct mvpp2_port *sc, struct mvpp2_rx_queue *rxq)
29651a945772Spatrick {
29668801406bSpatrick 	struct mvpp2_rx_desc *rxd;
29678801406bSpatrick 	struct mvpp2_bm_pool *bm;
29688801406bSpatrick 	uint64_t phys, virt;
29698801406bSpatrick 	uint32_t i, nrecv, pool;
29708801406bSpatrick 	struct mvpp2_buf *rxb;
29711a945772Spatrick 
29721a945772Spatrick 	nrecv = mvpp2_rxq_received(sc, rxq->id);
29738801406bSpatrick 	if (!nrecv)
29748801406bSpatrick 		return;
29758801406bSpatrick 
29768801406bSpatrick 	bus_dmamap_sync(sc->sc_dmat, MVPP2_DMA_MAP(rxq->ring), 0,
29778801406bSpatrick 	    MVPP2_DMA_LEN(rxq->ring),
29788801406bSpatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
29798801406bSpatrick 
29808801406bSpatrick 	for (i = 0; i < nrecv; i++) {
29818801406bSpatrick 		rxd = &rxq->descs[rxq->cons];
29828801406bSpatrick 		virt = rxd->buf_cookie_bm_qset_cls_info;
29838801406bSpatrick 		pool = (virt >> 16) & 0xffff;
29848801406bSpatrick 		KASSERT(pool < sc->sc->sc_npools);
29858801406bSpatrick 		bm = &sc->sc->sc_bm_pools[pool];
29868801406bSpatrick 		KASSERT((virt & 0xffff) < MVPP2_BM_SIZE);
29878801406bSpatrick 		rxb = &bm->rxbuf[virt & 0xffff];
29888801406bSpatrick 		KASSERT(rxb->mb_m != NULL);
29898801406bSpatrick 		virt &= 0xffffffff;
29908801406bSpatrick 		phys = rxb->mb_map->dm_segs[0].ds_addr;
29918801406bSpatrick 		mvpp2_write(sc->sc, MVPP22_BM_ADDR_HIGH_RLS_REG,
29928801406bSpatrick 		    (((virt >> 32) & MVPP22_ADDR_HIGH_MASK)
29938801406bSpatrick 		    << MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) |
29948801406bSpatrick 		    ((phys >> 32) & MVPP22_ADDR_HIGH_MASK));
29958801406bSpatrick 		mvpp2_write(sc->sc, MVPP2_BM_VIRT_RLS_REG,
29968801406bSpatrick 		    virt & 0xffffffff);
29978801406bSpatrick 		mvpp2_write(sc->sc, MVPP2_BM_PHY_RLS_REG(pool),
29988801406bSpatrick 		    phys & 0xffffffff);
29998801406bSpatrick 		rxq->cons = (rxq->cons + 1) % MVPP2_NRXDESC;
30008801406bSpatrick 	}
30018801406bSpatrick 
30028801406bSpatrick 	bus_dmamap_sync(sc->sc_dmat, MVPP2_DMA_MAP(rxq->ring), 0,
30038801406bSpatrick 	    MVPP2_DMA_LEN(rxq->ring),
30048801406bSpatrick 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
30058801406bSpatrick 
30061a945772Spatrick 	mvpp2_rxq_status_update(sc, rxq->id, nrecv, nrecv);
30078801406bSpatrick }
30088801406bSpatrick 
30098801406bSpatrick void
mvpp2_rxq_hw_deinit(struct mvpp2_port * sc,struct mvpp2_rx_queue * rxq)30108801406bSpatrick mvpp2_rxq_hw_deinit(struct mvpp2_port *sc, struct mvpp2_rx_queue *rxq)
30118801406bSpatrick {
30128801406bSpatrick 	mvpp2_rxq_hw_drop(sc, rxq);
30131a945772Spatrick 
30141a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_RXQ_STATUS_REG(rxq->id), 0);
30151a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_RXQ_NUM_REG, rxq->id);
30161a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_RXQ_DESC_ADDR_REG, 0);
30171a945772Spatrick 	mvpp2_write(sc->sc, MVPP2_RXQ_DESC_SIZE_REG, 0);
30181a945772Spatrick 
30191a945772Spatrick 	mvpp2_dmamem_free(sc->sc, rxq->ring);
30201a945772Spatrick }
30211a945772Spatrick 
30221a945772Spatrick void
mvpp2_rxq_long_pool_set(struct mvpp2_port * port,int lrxq,int pool)30231a945772Spatrick mvpp2_rxq_long_pool_set(struct mvpp2_port *port, int lrxq, int pool)
30241a945772Spatrick {
30251a945772Spatrick 	uint32_t val;
30261a945772Spatrick 	int prxq;
30271a945772Spatrick 
30281a945772Spatrick 	/* get queue physical ID */
30291a945772Spatrick 	prxq = port->sc_rxqs[lrxq].id;
30301a945772Spatrick 
30311a945772Spatrick 	val = mvpp2_read(port->sc, MVPP2_RXQ_CONFIG_REG(prxq));
30321a945772Spatrick 	val &= ~MVPP2_RXQ_POOL_LONG_MASK;
30331a945772Spatrick 	val |= ((pool << MVPP2_RXQ_POOL_LONG_OFFS) & MVPP2_RXQ_POOL_LONG_MASK);
30341a945772Spatrick 
30351a945772Spatrick 	mvpp2_write(port->sc, MVPP2_RXQ_CONFIG_REG(prxq), val);
30361a945772Spatrick }
30371a945772Spatrick 
30381a945772Spatrick void
mvpp2_rxq_short_pool_set(struct mvpp2_port * port,int lrxq,int pool)30391a945772Spatrick mvpp2_rxq_short_pool_set(struct mvpp2_port *port, int lrxq, int pool)
30401a945772Spatrick {
30411a945772Spatrick 	uint32_t val;
30421a945772Spatrick 	int prxq;
30431a945772Spatrick 
30441a945772Spatrick 	/* get queue physical ID */
30451a945772Spatrick 	prxq = port->sc_rxqs[lrxq].id;
30461a945772Spatrick 
30471a945772Spatrick 	val = mvpp2_read(port->sc, MVPP2_RXQ_CONFIG_REG(prxq));
30481a945772Spatrick 	val &= ~MVPP2_RXQ_POOL_SHORT_MASK;
30491a945772Spatrick 	val |= ((pool << MVPP2_RXQ_POOL_SHORT_OFFS) & MVPP2_RXQ_POOL_SHORT_MASK);
30501a945772Spatrick 
30511a945772Spatrick 	mvpp2_write(port->sc, MVPP2_RXQ_CONFIG_REG(prxq), val);
30521a945772Spatrick }
30531a945772Spatrick 
30541a945772Spatrick void
mvpp2_iff(struct mvpp2_port * sc)30551a945772Spatrick mvpp2_iff(struct mvpp2_port *sc)
30561a945772Spatrick {
3057ce595ab8Spatrick 	struct arpcom *ac = &sc->sc_ac;
3058ce595ab8Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
3059ce595ab8Spatrick 	struct ether_multi *enm;
3060ce595ab8Spatrick 	struct ether_multistep step;
30611a945772Spatrick 
3062ce595ab8Spatrick 	ifp->if_flags &= ~IFF_ALLMULTI;
3063ce595ab8Spatrick 
3064ce595ab8Spatrick 	/* Removes all but broadcast and (new) lladdr */
3065ce595ab8Spatrick 	mvpp2_prs_mac_del_all(sc);
3066ce595ab8Spatrick 
3067ce595ab8Spatrick 	if (ifp->if_flags & IFF_PROMISC) {
3068ce595ab8Spatrick 		mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
3069ce595ab8Spatrick 		    MVPP2_PRS_L2_UNI_CAST, 1);
3070ce595ab8Spatrick 		mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
3071ce595ab8Spatrick 		    MVPP2_PRS_L2_MULTI_CAST, 1);
3072ce595ab8Spatrick 		return;
3073ce595ab8Spatrick 	}
3074ce595ab8Spatrick 
3075ce595ab8Spatrick 	mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
3076ce595ab8Spatrick 	    MVPP2_PRS_L2_UNI_CAST, 0);
3077ce595ab8Spatrick 	mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
3078ce595ab8Spatrick 	    MVPP2_PRS_L2_MULTI_CAST, 0);
3079ce595ab8Spatrick 
3080ce595ab8Spatrick 	if (ac->ac_multirangecnt > 0 ||
3081ce595ab8Spatrick 	    ac->ac_multicnt > MVPP2_PRS_MAC_MC_FILT_MAX) {
3082ce595ab8Spatrick 		ifp->if_flags |= IFF_ALLMULTI;
3083ce595ab8Spatrick 		mvpp2_prs_mac_promisc_set(sc->sc, sc->sc_id,
3084ce595ab8Spatrick 		    MVPP2_PRS_L2_MULTI_CAST, 1);
3085ce595ab8Spatrick 	} else {
3086ce595ab8Spatrick 		ETHER_FIRST_MULTI(step, ac, enm);
3087ce595ab8Spatrick 		while (enm != NULL) {
3088ce595ab8Spatrick 			mvpp2_prs_mac_da_accept(sc, enm->enm_addrlo, 1);
3089ce595ab8Spatrick 			ETHER_NEXT_MULTI(step, enm);
3090ce595ab8Spatrick 		}
309141cd246cSpatrick 	}
30921a945772Spatrick }
30931a945772Spatrick 
30941a945772Spatrick struct mvpp2_dmamem *
mvpp2_dmamem_alloc(struct mvpp2_softc * sc,bus_size_t size,bus_size_t align)30951a945772Spatrick mvpp2_dmamem_alloc(struct mvpp2_softc *sc, bus_size_t size, bus_size_t align)
30961a945772Spatrick {
30971a945772Spatrick 	struct mvpp2_dmamem *mdm;
30981a945772Spatrick 	int nsegs;
30991a945772Spatrick 
31001a945772Spatrick 	mdm = malloc(sizeof(*mdm), M_DEVBUF, M_WAITOK | M_ZERO);
31011a945772Spatrick 	mdm->mdm_size = size;
31021a945772Spatrick 
31031a945772Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
31041a945772Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &mdm->mdm_map) != 0)
31051a945772Spatrick 		goto mdmfree;
31061a945772Spatrick 
31071a945772Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &mdm->mdm_seg, 1,
31081a945772Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
31091a945772Spatrick 		goto destroy;
31101a945772Spatrick 
31111a945772Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &mdm->mdm_seg, nsegs, size,
31121a945772Spatrick 	    &mdm->mdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
31131a945772Spatrick 		goto free;
31141a945772Spatrick 
31151a945772Spatrick 	if (bus_dmamap_load(sc->sc_dmat, mdm->mdm_map, mdm->mdm_kva, size,
31161a945772Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
31171a945772Spatrick 		goto unmap;
31181a945772Spatrick 
31191a945772Spatrick 	bzero(mdm->mdm_kva, size);
31201a945772Spatrick 
31211a945772Spatrick 	return (mdm);
31221a945772Spatrick 
31231a945772Spatrick unmap:
31241a945772Spatrick 	bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, size);
31251a945772Spatrick free:
31261a945772Spatrick 	bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1);
31271a945772Spatrick destroy:
31281a945772Spatrick 	bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map);
31291a945772Spatrick mdmfree:
31301a945772Spatrick 	free(mdm, M_DEVBUF, 0);
31311a945772Spatrick 
31321a945772Spatrick 	return (NULL);
31331a945772Spatrick }
31341a945772Spatrick 
31351a945772Spatrick void
mvpp2_dmamem_free(struct mvpp2_softc * sc,struct mvpp2_dmamem * mdm)31361a945772Spatrick mvpp2_dmamem_free(struct mvpp2_softc *sc, struct mvpp2_dmamem *mdm)
31371a945772Spatrick {
31381a945772Spatrick 	bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, mdm->mdm_size);
31391a945772Spatrick 	bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1);
31401a945772Spatrick 	bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map);
31411a945772Spatrick 	free(mdm, M_DEVBUF, 0);
31421a945772Spatrick }
31431a945772Spatrick 
31441a945772Spatrick struct mbuf *
mvpp2_alloc_mbuf(struct mvpp2_softc * sc,bus_dmamap_t map)31451a945772Spatrick mvpp2_alloc_mbuf(struct mvpp2_softc *sc, bus_dmamap_t map)
31461a945772Spatrick {
31471a945772Spatrick 	struct mbuf *m = NULL;
31481a945772Spatrick 
3149471f2571Sjan 	m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES);
31501a945772Spatrick 	if (!m)
31511a945772Spatrick 		return (NULL);
31521a945772Spatrick 	m->m_len = m->m_pkthdr.len = MCLBYTES;
31531a945772Spatrick 
31541a945772Spatrick 	if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) {
31551a945772Spatrick 		printf("%s: could not load mbuf DMA map", DEVNAME(sc));
31561a945772Spatrick 		m_freem(m);
31571a945772Spatrick 		return (NULL);
31581a945772Spatrick 	}
31591a945772Spatrick 
31601a945772Spatrick 	bus_dmamap_sync(sc->sc_dmat, map, 0,
31611a945772Spatrick 	    m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
31621a945772Spatrick 
31631a945772Spatrick 	return (m);
31641a945772Spatrick }
31651a945772Spatrick 
31661a945772Spatrick void
mvpp2_interrupts_enable(struct mvpp2_port * port,int cpu_mask)31671a945772Spatrick mvpp2_interrupts_enable(struct mvpp2_port *port, int cpu_mask)
31681a945772Spatrick {
31691a945772Spatrick 	mvpp2_write(port->sc, MVPP2_ISR_ENABLE_REG(port->sc_id),
31701a945772Spatrick 	    MVPP2_ISR_ENABLE_INTERRUPT(cpu_mask));
31711a945772Spatrick }
31721a945772Spatrick 
31731a945772Spatrick void
mvpp2_interrupts_disable(struct mvpp2_port * port,int cpu_mask)31741a945772Spatrick mvpp2_interrupts_disable(struct mvpp2_port *port, int cpu_mask)
31751a945772Spatrick {
31761a945772Spatrick 	mvpp2_write(port->sc, MVPP2_ISR_ENABLE_REG(port->sc_id),
31771a945772Spatrick 	    MVPP2_ISR_DISABLE_INTERRUPT(cpu_mask));
31781a945772Spatrick }
31791a945772Spatrick 
31801a945772Spatrick int
mvpp2_egress_port(struct mvpp2_port * port)31811a945772Spatrick mvpp2_egress_port(struct mvpp2_port *port)
31821a945772Spatrick {
31831a945772Spatrick 	return MVPP2_MAX_TCONT + port->sc_id;
31841a945772Spatrick }
31851a945772Spatrick 
31861a945772Spatrick int
mvpp2_txq_phys(int port,int txq)31871a945772Spatrick mvpp2_txq_phys(int port, int txq)
31881a945772Spatrick {
31891a945772Spatrick 	return (MVPP2_MAX_TCONT + port) * MVPP2_MAX_TXQ + txq;
31901a945772Spatrick }
31911a945772Spatrick 
31921a945772Spatrick void
mvpp2_defaults_set(struct mvpp2_port * port)31931a945772Spatrick mvpp2_defaults_set(struct mvpp2_port *port)
31941a945772Spatrick {
3195385d82b1Spatrick 	int val, queue;
31961a945772Spatrick 
31971a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_PORT_INDEX_REG,
31981a945772Spatrick 	    mvpp2_egress_port(port));
31991a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_CMD_1_REG, 0);
32001a945772Spatrick 
3201385d82b1Spatrick 	for (queue = 0; queue < MVPP2_MAX_TXQ; queue++)
3202385d82b1Spatrick 		mvpp2_write(port->sc, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(queue), 0);
32031a945772Spatrick 
32041a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_PERIOD_REG, port->sc->sc_tclk /
32051a945772Spatrick 	    (1000 * 1000));
32061a945772Spatrick 	val = mvpp2_read(port->sc, MVPP2_TXP_SCHED_REFILL_REG);
32071a945772Spatrick 	val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK;
32081a945772Spatrick 	val |= MVPP2_TXP_REFILL_PERIOD_MASK(1);
32091a945772Spatrick 	val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK;
32101a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_REFILL_REG, val);
32111a945772Spatrick 	val = MVPP2_TXP_TOKEN_SIZE_MAX;
32121a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val);
32131a945772Spatrick 
32141a945772Spatrick 	/* set maximum_low_latency_packet_size value to 256 */
32151a945772Spatrick 	mvpp2_write(port->sc, MVPP2_RX_CTRL_REG(port->sc_id),
32161a945772Spatrick 	    MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK |
32171a945772Spatrick 	    MVPP2_RX_LOW_LATENCY_PKT_SIZE(256));
32181a945772Spatrick 
32191a945772Spatrick 	/* mask all interrupts to all present cpus */
32201a945772Spatrick 	mvpp2_interrupts_disable(port, (0xf << 0));
32211a945772Spatrick }
32221a945772Spatrick 
32231a945772Spatrick void
mvpp2_ingress_enable(struct mvpp2_port * port)32241a945772Spatrick mvpp2_ingress_enable(struct mvpp2_port *port)
32251a945772Spatrick {
32261a945772Spatrick 	uint32_t val;
32271a945772Spatrick 	int lrxq, queue;
32281a945772Spatrick 
32291a945772Spatrick 	for (lrxq = 0; lrxq < port->sc_nrxq; lrxq++) {
32301a945772Spatrick 		queue = port->sc_rxqs[lrxq].id;
32311a945772Spatrick 		val = mvpp2_read(port->sc, MVPP2_RXQ_CONFIG_REG(queue));
32321a945772Spatrick 		val &= ~MVPP2_RXQ_DISABLE_MASK;
32331a945772Spatrick 		mvpp2_write(port->sc, MVPP2_RXQ_CONFIG_REG(queue), val);
32341a945772Spatrick 	}
32351a945772Spatrick }
32361a945772Spatrick 
32371a945772Spatrick void
mvpp2_ingress_disable(struct mvpp2_port * port)32381a945772Spatrick mvpp2_ingress_disable(struct mvpp2_port *port)
32391a945772Spatrick {
32401a945772Spatrick 	uint32_t val;
32411a945772Spatrick 	int lrxq, queue;
32421a945772Spatrick 
32431a945772Spatrick 	for (lrxq = 0; lrxq < port->sc_nrxq; lrxq++) {
32441a945772Spatrick 		queue = port->sc_rxqs[lrxq].id;
32451a945772Spatrick 		val = mvpp2_read(port->sc, MVPP2_RXQ_CONFIG_REG(queue));
32461a945772Spatrick 		val |= MVPP2_RXQ_DISABLE_MASK;
32471a945772Spatrick 		mvpp2_write(port->sc, MVPP2_RXQ_CONFIG_REG(queue), val);
32481a945772Spatrick 	}
32491a945772Spatrick }
32501a945772Spatrick 
32511a945772Spatrick void
mvpp2_egress_enable(struct mvpp2_port * port)32521a945772Spatrick mvpp2_egress_enable(struct mvpp2_port *port)
32531a945772Spatrick {
32541a945772Spatrick 	struct mvpp2_tx_queue *txq;
32551a945772Spatrick 	uint32_t qmap;
32561a945772Spatrick 	int queue;
32571a945772Spatrick 
32581a945772Spatrick 	qmap = 0;
32591a945772Spatrick 	for (queue = 0; queue < port->sc_ntxq; queue++) {
32601a945772Spatrick 		txq = &port->sc_txqs[queue];
32611a945772Spatrick 
32621a945772Spatrick 		if (txq->descs != NULL) {
32631a945772Spatrick 			qmap |= (1 << queue);
32641a945772Spatrick 		}
32651a945772Spatrick 	}
32661a945772Spatrick 
32671a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_PORT_INDEX_REG,
32681a945772Spatrick 	    mvpp2_egress_port(port));
32691a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_Q_CMD_REG, qmap);
32701a945772Spatrick }
32711a945772Spatrick 
32721a945772Spatrick void
mvpp2_egress_disable(struct mvpp2_port * port)32731a945772Spatrick mvpp2_egress_disable(struct mvpp2_port *port)
32741a945772Spatrick {
32751a945772Spatrick 	uint32_t reg_data;
32761a945772Spatrick 	int i;
32771a945772Spatrick 
32781a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_PORT_INDEX_REG,
32791a945772Spatrick 	    mvpp2_egress_port(port));
32801a945772Spatrick 	reg_data = (mvpp2_read(port->sc, MVPP2_TXP_SCHED_Q_CMD_REG)) &
32811a945772Spatrick 	    MVPP2_TXP_SCHED_ENQ_MASK;
32821a945772Spatrick 	if (reg_data)
3283687cc71bSpatrick 		mvpp2_write(port->sc, MVPP2_TXP_SCHED_Q_CMD_REG,
3284687cc71bSpatrick 		    reg_data << MVPP2_TXP_SCHED_DISQ_OFFSET);
32851a945772Spatrick 
32861a945772Spatrick 	i = 0;
32871a945772Spatrick 	do {
32881a945772Spatrick 		if (i >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) {
32891a945772Spatrick 			printf("%s: tx stop timed out, status=0x%08x\n",
32901a945772Spatrick 			    port->sc_dev.dv_xname, reg_data);
32911a945772Spatrick 			break;
32921a945772Spatrick 		}
32931a945772Spatrick 		delay(1000);
32941a945772Spatrick 		i++;
32951a945772Spatrick 		reg_data = mvpp2_read(port->sc, MVPP2_TXP_SCHED_Q_CMD_REG);
32961a945772Spatrick 	} while (reg_data & MVPP2_TXP_SCHED_ENQ_MASK);
32971a945772Spatrick }
32981a945772Spatrick 
32991a945772Spatrick void
mvpp2_port_enable(struct mvpp2_port * port)33001a945772Spatrick mvpp2_port_enable(struct mvpp2_port *port)
33011a945772Spatrick {
33021a945772Spatrick 	uint32_t val;
33031a945772Spatrick 
33041a945772Spatrick 	if (port->sc_gop_id == 0 && (port->sc_phy_mode == PHY_MODE_10GBASER ||
33051a945772Spatrick 	    port->sc_phy_mode == PHY_MODE_XAUI)) {
33061a945772Spatrick 		val = mvpp2_xlg_read(port, MV_XLG_PORT_MAC_CTRL0_REG);
33074d0a0269Spatrick 		val |= MV_XLG_MAC_CTRL0_PORTEN;
33084d0a0269Spatrick 		val &= ~MV_XLG_MAC_CTRL0_MIBCNTDIS;
33091a945772Spatrick 		mvpp2_xlg_write(port, MV_XLG_PORT_MAC_CTRL0_REG, val);
33101a945772Spatrick 	} else {
33111a945772Spatrick 		val = mvpp2_gmac_read(port, MVPP2_GMAC_CTRL_0_REG);
33121a945772Spatrick 		val |= MVPP2_GMAC_PORT_EN_MASK;
33131a945772Spatrick 		val |= MVPP2_GMAC_MIB_CNTR_EN_MASK;
33141a945772Spatrick 		mvpp2_gmac_write(port, MVPP2_GMAC_CTRL_0_REG, val);
33151a945772Spatrick 	}
33161a945772Spatrick }
33171a945772Spatrick 
33181a945772Spatrick void
mvpp2_port_disable(struct mvpp2_port * port)33191a945772Spatrick mvpp2_port_disable(struct mvpp2_port *port)
33201a945772Spatrick {
33211a945772Spatrick 	uint32_t val;
33221a945772Spatrick 
33231a945772Spatrick 	if (port->sc_gop_id == 0 && (port->sc_phy_mode == PHY_MODE_10GBASER ||
33241a945772Spatrick 	    port->sc_phy_mode == PHY_MODE_XAUI)) {
33251a945772Spatrick 		val = mvpp2_xlg_read(port, MV_XLG_PORT_MAC_CTRL0_REG);
33264d0a0269Spatrick 		val &= ~MV_XLG_MAC_CTRL0_PORTEN;
33271a945772Spatrick 		mvpp2_xlg_write(port, MV_XLG_PORT_MAC_CTRL0_REG, val);
33281a945772Spatrick 	}
33291a945772Spatrick 
33301a945772Spatrick 	val = mvpp2_gmac_read(port, MVPP2_GMAC_CTRL_0_REG);
33311a945772Spatrick 	val &= ~MVPP2_GMAC_PORT_EN_MASK;
33321a945772Spatrick 	mvpp2_gmac_write(port, MVPP2_GMAC_CTRL_0_REG, val);
33331a945772Spatrick }
33341a945772Spatrick 
33351a945772Spatrick int
mvpp2_rxq_received(struct mvpp2_port * port,int rxq_id)33361a945772Spatrick mvpp2_rxq_received(struct mvpp2_port *port, int rxq_id)
33371a945772Spatrick {
33381a945772Spatrick 	uint32_t val = mvpp2_read(port->sc, MVPP2_RXQ_STATUS_REG(rxq_id));
33391a945772Spatrick 
33401a945772Spatrick 	return val & MVPP2_RXQ_OCCUPIED_MASK;
33411a945772Spatrick }
33421a945772Spatrick 
33431a945772Spatrick void
mvpp2_rxq_status_update(struct mvpp2_port * port,int rxq_id,int used_count,int free_count)33441a945772Spatrick mvpp2_rxq_status_update(struct mvpp2_port *port, int rxq_id,
33451a945772Spatrick     int used_count, int free_count)
33461a945772Spatrick {
33471a945772Spatrick 	uint32_t val = used_count | (free_count << MVPP2_RXQ_NUM_NEW_OFFSET);
33481a945772Spatrick 	mvpp2_write(port->sc, MVPP2_RXQ_STATUS_UPDATE_REG(rxq_id), val);
33491a945772Spatrick }
33501a945772Spatrick 
33511a945772Spatrick void
mvpp2_rxq_offset_set(struct mvpp2_port * port,int prxq,int offset)33521a945772Spatrick mvpp2_rxq_offset_set(struct mvpp2_port *port, int prxq, int offset)
33531a945772Spatrick {
33541a945772Spatrick 	uint32_t val;
33551a945772Spatrick 
33561a945772Spatrick 	offset = offset >> 5;
33571a945772Spatrick 	val = mvpp2_read(port->sc, MVPP2_RXQ_CONFIG_REG(prxq));
33581a945772Spatrick 	val &= ~MVPP2_RXQ_PACKET_OFFSET_MASK;
33591a945772Spatrick 	val |= ((offset << MVPP2_RXQ_PACKET_OFFSET_OFFS) &
33601a945772Spatrick 	    MVPP2_RXQ_PACKET_OFFSET_MASK);
33611a945772Spatrick 	mvpp2_write(port->sc, MVPP2_RXQ_CONFIG_REG(prxq), val);
33621a945772Spatrick }
33631a945772Spatrick 
33641a945772Spatrick void
mvpp2_txp_max_tx_size_set(struct mvpp2_port * port)33651a945772Spatrick mvpp2_txp_max_tx_size_set(struct mvpp2_port *port)
33661a945772Spatrick {
33671a945772Spatrick 	uint32_t val, size, mtu;
33681a945772Spatrick 	int txq;
33691a945772Spatrick 
33701a945772Spatrick 	mtu = MCLBYTES * 8;
33711a945772Spatrick 	if (mtu > MVPP2_TXP_MTU_MAX)
33721a945772Spatrick 		mtu = MVPP2_TXP_MTU_MAX;
33731a945772Spatrick 
33741a945772Spatrick 	/* WA for wrong token bucket update: set MTU value = 3*real MTU value */
33751a945772Spatrick 	mtu = 3 * mtu;
33761a945772Spatrick 
33771a945772Spatrick 	/* indirect access to reg_valisters */
33781a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_PORT_INDEX_REG,
33791a945772Spatrick 	    mvpp2_egress_port(port));
33801a945772Spatrick 
33811a945772Spatrick 	/* set MTU */
33821a945772Spatrick 	val = mvpp2_read(port->sc, MVPP2_TXP_SCHED_MTU_REG);
33831a945772Spatrick 	val &= ~MVPP2_TXP_MTU_MAX;
33841a945772Spatrick 	val |= mtu;
33851a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXP_SCHED_MTU_REG, val);
33861a945772Spatrick 
33871a945772Spatrick 	/* TXP token size and all TXqs token size must be larger that MTU */
33881a945772Spatrick 	val = mvpp2_read(port->sc, MVPP2_TXP_SCHED_TOKEN_SIZE_REG);
33891a945772Spatrick 	size = val & MVPP2_TXP_TOKEN_SIZE_MAX;
33901a945772Spatrick 	if (size < mtu) {
33911a945772Spatrick 		size = mtu;
33921a945772Spatrick 		val &= ~MVPP2_TXP_TOKEN_SIZE_MAX;
33931a945772Spatrick 		val |= size;
33941a945772Spatrick 		mvpp2_write(port->sc, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val);
33951a945772Spatrick 	}
33961a945772Spatrick 
33971a945772Spatrick 	for (txq = 0; txq < port->sc_ntxq; txq++) {
33981a945772Spatrick 		val = mvpp2_read(port->sc, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq));
33991a945772Spatrick 		size = val & MVPP2_TXQ_TOKEN_SIZE_MAX;
34001a945772Spatrick 
34011a945772Spatrick 		if (size < mtu) {
34021a945772Spatrick 			size = mtu;
34031a945772Spatrick 			val &= ~MVPP2_TXQ_TOKEN_SIZE_MAX;
34041a945772Spatrick 			val |= size;
34051a945772Spatrick 			mvpp2_write(port->sc, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq), val);
34061a945772Spatrick 		}
34071a945772Spatrick 	}
34081a945772Spatrick }
34091a945772Spatrick 
34101a945772Spatrick void
mvpp2_rx_pkts_coal_set(struct mvpp2_port * port,struct mvpp2_rx_queue * rxq,uint32_t pkts)34111a945772Spatrick mvpp2_rx_pkts_coal_set(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq,
34121a945772Spatrick     uint32_t pkts)
34131a945772Spatrick {
34141a945772Spatrick 	rxq->pkts_coal =
34151a945772Spatrick 	    pkts <= MVPP2_OCCUPIED_THRESH_MASK ?
34161a945772Spatrick 	    pkts : MVPP2_OCCUPIED_THRESH_MASK;
34171a945772Spatrick 
34181a945772Spatrick 	mvpp2_write(port->sc, MVPP2_RXQ_NUM_REG, rxq->id);
34191a945772Spatrick 	mvpp2_write(port->sc, MVPP2_RXQ_THRESH_REG, rxq->pkts_coal);
34201a945772Spatrick 
34211a945772Spatrick }
34221a945772Spatrick 
34231a945772Spatrick void
mvpp2_tx_pkts_coal_set(struct mvpp2_port * port,struct mvpp2_tx_queue * txq,uint32_t pkts)34241a945772Spatrick mvpp2_tx_pkts_coal_set(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
34251a945772Spatrick     uint32_t pkts)
34261a945772Spatrick {
34271a945772Spatrick 	txq->done_pkts_coal =
34281a945772Spatrick 	    pkts <= MVPP2_TRANSMITTED_THRESH_MASK ?
34291a945772Spatrick 	    pkts : MVPP2_TRANSMITTED_THRESH_MASK;
34301a945772Spatrick 
34311a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXQ_NUM_REG, txq->id);
34321a945772Spatrick 	mvpp2_write(port->sc, MVPP2_TXQ_THRESH_REG,
34331a945772Spatrick 	    txq->done_pkts_coal << MVPP2_TRANSMITTED_THRESH_OFFSET);
34341a945772Spatrick }
34351a945772Spatrick 
34361a945772Spatrick void
mvpp2_rx_time_coal_set(struct mvpp2_port * port,struct mvpp2_rx_queue * rxq,uint32_t usec)34371a945772Spatrick mvpp2_rx_time_coal_set(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq,
34381a945772Spatrick     uint32_t usec)
34391a945772Spatrick {
34401a945772Spatrick 	uint32_t val;
34411a945772Spatrick 
34421a945772Spatrick 	val = (port->sc->sc_tclk / (1000 * 1000)) * usec;
34431a945772Spatrick 	mvpp2_write(port->sc, MVPP2_ISR_RX_THRESHOLD_REG(rxq->id), val);
34441a945772Spatrick 
34451a945772Spatrick 	rxq->time_coal = usec;
34461a945772Spatrick }
34471a945772Spatrick 
34481a945772Spatrick void
mvpp2_tx_time_coal_set(struct mvpp2_port * port,uint32_t usec)34491a945772Spatrick mvpp2_tx_time_coal_set(struct mvpp2_port *port, uint32_t usec)
34501a945772Spatrick {
34511a945772Spatrick 	uint32_t val;
34521a945772Spatrick 
34531a945772Spatrick 	val = (port->sc->sc_tclk / (1000 * 1000)) * usec;
34541a945772Spatrick 	mvpp2_write(port->sc, MVPP2_ISR_TX_THRESHOLD_REG(port->sc_id), val);
34551a945772Spatrick 
34561a945772Spatrick 	port->sc_tx_time_coal = usec;
34571a945772Spatrick }
34581a945772Spatrick 
34591a945772Spatrick void
mvpp2_prs_shadow_ri_set(struct mvpp2_softc * sc,int index,uint32_t ri,uint32_t ri_mask)34601a945772Spatrick mvpp2_prs_shadow_ri_set(struct mvpp2_softc *sc, int index,
34611a945772Spatrick     uint32_t ri, uint32_t ri_mask)
34621a945772Spatrick {
34631a945772Spatrick 	sc->sc_prs_shadow[index].ri_mask = ri_mask;
34641a945772Spatrick 	sc->sc_prs_shadow[index].ri = ri;
34651a945772Spatrick }
34661a945772Spatrick 
34671a945772Spatrick void
mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry * pe,uint32_t lu)34681a945772Spatrick mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry *pe, uint32_t lu)
34691a945772Spatrick {
34701a945772Spatrick 	int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_LU_BYTE);
34711a945772Spatrick 
34721a945772Spatrick 	pe->tcam.byte[MVPP2_PRS_TCAM_LU_BYTE] = lu;
34731a945772Spatrick 	pe->tcam.byte[enable_off] = MVPP2_PRS_LU_MASK;
34741a945772Spatrick }
34751a945772Spatrick 
34761a945772Spatrick void
mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry * pe,uint32_t port,int add)34771a945772Spatrick mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry *pe, uint32_t port, int add)
34781a945772Spatrick {
34791a945772Spatrick 	int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE);
34801a945772Spatrick 
34811a945772Spatrick 	if (add)
34821a945772Spatrick 		pe->tcam.byte[enable_off] &= ~(1 << port);
34831a945772Spatrick 	else
34841a945772Spatrick 		pe->tcam.byte[enable_off] |= (1 << port);
34851a945772Spatrick }
34861a945772Spatrick 
34871a945772Spatrick void
mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry * pe,uint32_t port_mask)34881a945772Spatrick mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry *pe, uint32_t port_mask)
34891a945772Spatrick {
34901a945772Spatrick 	int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE);
34911a945772Spatrick 	uint8_t mask = MVPP2_PRS_PORT_MASK;
34921a945772Spatrick 
34931a945772Spatrick 	pe->tcam.byte[MVPP2_PRS_TCAM_PORT_BYTE] = 0;
34941a945772Spatrick 	pe->tcam.byte[enable_off] &= ~mask;
34951a945772Spatrick 	pe->tcam.byte[enable_off] |= ~port_mask & MVPP2_PRS_PORT_MASK;
34961a945772Spatrick }
34971a945772Spatrick 
34981a945772Spatrick uint32_t
mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry * pe)34991a945772Spatrick mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry *pe)
35001a945772Spatrick {
35011a945772Spatrick 	int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE);
35021a945772Spatrick 
35031a945772Spatrick 	return ~(pe->tcam.byte[enable_off]) & MVPP2_PRS_PORT_MASK;
35041a945772Spatrick }
35051a945772Spatrick 
35061a945772Spatrick void
mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry * pe,uint32_t offs,uint8_t byte,uint8_t enable)35071a945772Spatrick mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry *pe, uint32_t offs,
35081a945772Spatrick     uint8_t byte, uint8_t enable)
35091a945772Spatrick {
35101a945772Spatrick 	pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(offs)] = byte;
35111a945772Spatrick 	pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(offs)] = enable;
35121a945772Spatrick }
35131a945772Spatrick 
35141a945772Spatrick void
mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry * pe,uint32_t offs,uint8_t * byte,uint8_t * enable)35151a945772Spatrick mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry *pe, uint32_t offs,
35161a945772Spatrick     uint8_t *byte, uint8_t *enable)
35171a945772Spatrick {
35181a945772Spatrick 	*byte = pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(offs)];
35191a945772Spatrick 	*enable = pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(offs)];
35201a945772Spatrick }
35211a945772Spatrick 
35221a945772Spatrick int
mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry * pe,int offset,uint16_t data)35231a945772Spatrick mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *pe, int offset, uint16_t data)
35241a945772Spatrick {
35251a945772Spatrick 	int byte_offset = MVPP2_PRS_TCAM_DATA_BYTE(offset);
35261a945772Spatrick 	uint16_t tcam_data;
35271a945772Spatrick 
35281a945772Spatrick 	tcam_data = (pe->tcam.byte[byte_offset + 1] << 8) |
35291a945772Spatrick 	    pe->tcam.byte[byte_offset];
353047d131caSpatrick 	return tcam_data == data;
35311a945772Spatrick }
35321a945772Spatrick 
35331a945772Spatrick void
mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry * pe,uint32_t bits,uint32_t enable)35341a945772Spatrick mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry *pe, uint32_t bits, uint32_t enable)
35351a945772Spatrick {
35361a945772Spatrick 	int i, ai_idx = MVPP2_PRS_TCAM_AI_BYTE;
35371a945772Spatrick 
35381a945772Spatrick 	for (i = 0; i < MVPP2_PRS_AI_BITS; i++) {
35394896f12aSpatrick 		if (!(enable & BIT(i)))
35401a945772Spatrick 			continue;
35411a945772Spatrick 
35424896f12aSpatrick 		if (bits & BIT(i))
35434896f12aSpatrick 			pe->tcam.byte[ai_idx] |= BIT(i);
35441a945772Spatrick 		else
35454896f12aSpatrick 			pe->tcam.byte[ai_idx] &= ~BIT(i);
35461a945772Spatrick 	}
35471a945772Spatrick 
35481a945772Spatrick 	pe->tcam.byte[MVPP2_PRS_TCAM_EN_OFFS(ai_idx)] |= enable;
35491a945772Spatrick }
35501a945772Spatrick 
35511a945772Spatrick int
mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry * pe)35521a945772Spatrick mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry *pe)
35531a945772Spatrick {
35541a945772Spatrick 	return pe->tcam.byte[MVPP2_PRS_TCAM_AI_BYTE];
35551a945772Spatrick }
35561a945772Spatrick 
35571a945772Spatrick void
mvpp2_prs_tcam_data_word_get(struct mvpp2_prs_entry * pe,uint32_t data_offset,uint32_t * word,uint32_t * enable)35581a945772Spatrick mvpp2_prs_tcam_data_word_get(struct mvpp2_prs_entry *pe, uint32_t data_offset,
35591a945772Spatrick     uint32_t *word, uint32_t *enable)
35601a945772Spatrick {
35611a945772Spatrick 	int index, position;
35621a945772Spatrick 	uint8_t byte, mask;
35631a945772Spatrick 
35641a945772Spatrick 	for (index = 0; index < 4; index++) {
35651a945772Spatrick 		position = (data_offset * sizeof(int)) + index;
35661a945772Spatrick 		mvpp2_prs_tcam_data_byte_get(pe, position, &byte, &mask);
35671a945772Spatrick 		((uint8_t *)word)[index] = byte;
35681a945772Spatrick 		((uint8_t *)enable)[index] = mask;
35691a945772Spatrick 	}
35701a945772Spatrick }
35711a945772Spatrick 
35721a945772Spatrick void
mvpp2_prs_match_etype(struct mvpp2_prs_entry * pe,uint32_t offs,uint16_t ether_type)35731a945772Spatrick mvpp2_prs_match_etype(struct mvpp2_prs_entry *pe, uint32_t offs,
35741a945772Spatrick     uint16_t ether_type)
35751a945772Spatrick {
35761a945772Spatrick 	mvpp2_prs_tcam_data_byte_set(pe, offs + 0, ether_type >> 8, 0xff);
35771a945772Spatrick 	mvpp2_prs_tcam_data_byte_set(pe, offs + 1, ether_type & 0xff, 0xff);
35781a945772Spatrick }
35791a945772Spatrick 
35801a945772Spatrick void
mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry * pe,uint32_t bit,uint32_t val)35811a945772Spatrick mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, uint32_t bit, uint32_t val)
35821a945772Spatrick {
35831a945772Spatrick 	pe->sram.byte[bit / 8] |= (val << (bit % 8));
35841a945772Spatrick }
35851a945772Spatrick 
35861a945772Spatrick void
mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry * pe,uint32_t bit,uint32_t val)35871a945772Spatrick mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry *pe, uint32_t bit, uint32_t val)
35881a945772Spatrick {
35891a945772Spatrick 	pe->sram.byte[bit / 8] &= ~(val << (bit % 8));
35901a945772Spatrick }
35911a945772Spatrick 
35921a945772Spatrick void
mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry * pe,uint32_t bits,uint32_t mask)35931a945772Spatrick mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe, uint32_t bits, uint32_t mask)
35941a945772Spatrick {
35951a945772Spatrick 	int i;
35961a945772Spatrick 
35971a945772Spatrick 	for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) {
3598af1244a6Spatrick 		if (!(mask & BIT(i)))
35991a945772Spatrick 			continue;
36001a945772Spatrick 
3601af1244a6Spatrick 		if (bits & BIT(i))
360298c4121bSpatrick 			mvpp2_prs_sram_bits_set(pe,
360398c4121bSpatrick 			    MVPP2_PRS_SRAM_RI_OFFS + i, 1);
36041a945772Spatrick 		else
360598c4121bSpatrick 			mvpp2_prs_sram_bits_clear(pe,
360698c4121bSpatrick 			    MVPP2_PRS_SRAM_RI_OFFS + i, 1);
36071a945772Spatrick 
36081a945772Spatrick 		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1);
36091a945772Spatrick 	}
36101a945772Spatrick }
36111a945772Spatrick 
36121a945772Spatrick int
mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry * pe)36131a945772Spatrick mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry *pe)
36141a945772Spatrick {
36151a945772Spatrick 	return pe->sram.word[MVPP2_PRS_SRAM_RI_WORD];
36161a945772Spatrick }
36171a945772Spatrick 
36181a945772Spatrick void
mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry * pe,uint32_t bits,uint32_t mask)36191a945772Spatrick mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe, uint32_t bits, uint32_t mask)
36201a945772Spatrick {
36211a945772Spatrick 	int i;
36221a945772Spatrick 
36231a945772Spatrick 	for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) {
3624af1244a6Spatrick 		if (!(mask & BIT(i)))
36251a945772Spatrick 			continue;
36261a945772Spatrick 
3627af1244a6Spatrick 		if (bits & BIT(i))
362898c4121bSpatrick 			mvpp2_prs_sram_bits_set(pe,
362998c4121bSpatrick 			    MVPP2_PRS_SRAM_AI_OFFS + i, 1);
36301a945772Spatrick 		else
363198c4121bSpatrick 			mvpp2_prs_sram_bits_clear(pe,
363298c4121bSpatrick 			    MVPP2_PRS_SRAM_AI_OFFS + i, 1);
36331a945772Spatrick 
36341a945772Spatrick 		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1);
36351a945772Spatrick 	}
36361a945772Spatrick }
36371a945772Spatrick 
36381a945772Spatrick int
mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry * pe)36391a945772Spatrick mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry *pe)
36401a945772Spatrick {
36411a945772Spatrick 	uint8_t bits;
36421a945772Spatrick 	int ai_off = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_AI_OFFS);
36431a945772Spatrick 	int ai_en_off = ai_off + 1;
36441a945772Spatrick 	int ai_shift = MVPP2_PRS_SRAM_AI_OFFS % 8;
36451a945772Spatrick 
36461a945772Spatrick 	bits = (pe->sram.byte[ai_off] >> ai_shift) |
36471a945772Spatrick 	    (pe->sram.byte[ai_en_off] << (8 - ai_shift));
36481a945772Spatrick 
36491a945772Spatrick 	return bits;
36501a945772Spatrick }
36511a945772Spatrick 
36521a945772Spatrick void
mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry * pe,int shift,uint32_t op)36531a945772Spatrick mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift, uint32_t op)
36541a945772Spatrick {
36551a945772Spatrick 	if (shift < 0) {
36561a945772Spatrick 		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
36571a945772Spatrick 		shift = -shift;
36581a945772Spatrick 	} else {
36591a945772Spatrick 		mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
36601a945772Spatrick 	}
36611a945772Spatrick 
36621a945772Spatrick 	pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_SHIFT_OFFS)] |=
36631a945772Spatrick 	    shift & MVPP2_PRS_SRAM_SHIFT_MASK;
36641a945772Spatrick 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS,
36651a945772Spatrick 	    MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK);
36661a945772Spatrick 	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, op);
36671a945772Spatrick 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
36681a945772Spatrick }
36691a945772Spatrick 
36701a945772Spatrick void
mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry * pe,uint32_t type,int offset,uint32_t op)36711a945772Spatrick mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe, uint32_t type, int offset,
36721a945772Spatrick     uint32_t op)
36731a945772Spatrick {
36741a945772Spatrick 	uint8_t udf_byte, udf_byte_offset;
36751a945772Spatrick 	uint8_t op_sel_udf_byte, op_sel_udf_byte_offset;
36761a945772Spatrick 
36771a945772Spatrick 	udf_byte = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS +
36781a945772Spatrick 	    MVPP2_PRS_SRAM_UDF_BITS);
36791a945772Spatrick 	udf_byte_offset = (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8));
36801a945772Spatrick 	op_sel_udf_byte = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS +
36811a945772Spatrick 	    MVPP2_PRS_SRAM_OP_SEL_UDF_BITS);
36821a945772Spatrick 	op_sel_udf_byte_offset = (8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8));
36831a945772Spatrick 
36841a945772Spatrick 	if (offset < 0) {
36851a945772Spatrick 		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
36861a945772Spatrick 		offset = -offset;
36871a945772Spatrick 	} else {
36881a945772Spatrick 		mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
36891a945772Spatrick 	}
36901a945772Spatrick 
36911a945772Spatrick 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_OFFS,
36921a945772Spatrick 	    MVPP2_PRS_SRAM_UDF_MASK);
36931a945772Spatrick 	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_OFFS, offset);
36941a945772Spatrick 	pe->sram.byte[udf_byte] &= ~(MVPP2_PRS_SRAM_UDF_MASK >> udf_byte_offset);
36951a945772Spatrick 	pe->sram.byte[udf_byte] |= (offset >> udf_byte_offset);
36961a945772Spatrick 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS,
36971a945772Spatrick 	    MVPP2_PRS_SRAM_UDF_TYPE_MASK);
36981a945772Spatrick 	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, type);
36991a945772Spatrick 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
37001a945772Spatrick 	    MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
37011a945772Spatrick 	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, op);
37021a945772Spatrick 	pe->sram.byte[op_sel_udf_byte] &= ~(MVPP2_PRS_SRAM_OP_SEL_UDF_MASK >>
37031a945772Spatrick 	    op_sel_udf_byte_offset);
37041a945772Spatrick 	pe->sram.byte[op_sel_udf_byte] |= (op >> op_sel_udf_byte_offset);
37051a945772Spatrick 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
37061a945772Spatrick }
37071a945772Spatrick 
37081a945772Spatrick void
mvpp2_prs_sram_next_lu_set(struct mvpp2_prs_entry * pe,uint32_t lu)37091a945772Spatrick mvpp2_prs_sram_next_lu_set(struct mvpp2_prs_entry *pe, uint32_t lu)
37101a945772Spatrick {
37111a945772Spatrick 	int sram_next_off = MVPP2_PRS_SRAM_NEXT_LU_OFFS;
37121a945772Spatrick 
37131a945772Spatrick 	mvpp2_prs_sram_bits_clear(pe, sram_next_off, MVPP2_PRS_SRAM_NEXT_LU_MASK);
37141a945772Spatrick 	mvpp2_prs_sram_bits_set(pe, sram_next_off, lu);
37151a945772Spatrick }
37161a945772Spatrick 
37171a945772Spatrick void
mvpp2_prs_shadow_set(struct mvpp2_softc * sc,int index,uint32_t lu)37181a945772Spatrick mvpp2_prs_shadow_set(struct mvpp2_softc *sc, int index, uint32_t lu)
37191a945772Spatrick {
37201a945772Spatrick 	sc->sc_prs_shadow[index].valid = 1;
37211a945772Spatrick 	sc->sc_prs_shadow[index].lu = lu;
37221a945772Spatrick }
37231a945772Spatrick 
37241a945772Spatrick int
mvpp2_prs_hw_write(struct mvpp2_softc * sc,struct mvpp2_prs_entry * pe)37251a945772Spatrick mvpp2_prs_hw_write(struct mvpp2_softc *sc, struct mvpp2_prs_entry *pe)
37261a945772Spatrick {
37271a945772Spatrick 	int i;
37281a945772Spatrick 
37291a945772Spatrick 	if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
37301a945772Spatrick 		return EINVAL;
37311a945772Spatrick 
37321a945772Spatrick 	pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
37331a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_TCAM_IDX_REG, pe->index);
37341a945772Spatrick 	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
37351a945772Spatrick 		mvpp2_write(sc, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam.word[i]);
37361a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_SRAM_IDX_REG, pe->index);
37371a945772Spatrick 	for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
37381a945772Spatrick 		mvpp2_write(sc, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram.word[i]);
37391a945772Spatrick 
37401a945772Spatrick 	return 0;
37411a945772Spatrick }
37421a945772Spatrick 
37431a945772Spatrick int
mvpp2_prs_hw_read(struct mvpp2_softc * sc,struct mvpp2_prs_entry * pe,int tid)3744fad015d2Spatrick mvpp2_prs_hw_read(struct mvpp2_softc *sc, struct mvpp2_prs_entry *pe, int tid)
37451a945772Spatrick {
37461a945772Spatrick 	int i;
37471a945772Spatrick 
3748fad015d2Spatrick 	if (tid > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
37491a945772Spatrick 		return EINVAL;
37501a945772Spatrick 
3751fad015d2Spatrick 	memset(pe, 0, sizeof(*pe));
3752fad015d2Spatrick 	pe->index = tid;
3753fad015d2Spatrick 
37541a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_TCAM_IDX_REG, pe->index);
37551a945772Spatrick 	pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] =
37561a945772Spatrick 	    mvpp2_read(sc, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD));
37571a945772Spatrick 	if (pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK)
37581a945772Spatrick 		return EINVAL;
37591a945772Spatrick 	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
37601a945772Spatrick 		pe->tcam.word[i] =
37611a945772Spatrick 		    mvpp2_read(sc, MVPP2_PRS_TCAM_DATA_REG(i));
37621a945772Spatrick 
37631a945772Spatrick 	mvpp2_write(sc, MVPP2_PRS_SRAM_IDX_REG, pe->index);
37641a945772Spatrick 	for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
37651a945772Spatrick 		pe->sram.word[i] =
37661a945772Spatrick 		    mvpp2_read(sc, MVPP2_PRS_SRAM_DATA_REG(i));
37671a945772Spatrick 
37681a945772Spatrick 	return 0;
37691a945772Spatrick }
37701a945772Spatrick 
3771fef01367Spatrick int
mvpp2_prs_flow_find(struct mvpp2_softc * sc,int flow)37721a945772Spatrick mvpp2_prs_flow_find(struct mvpp2_softc *sc, int flow)
37731a945772Spatrick {
3774fef01367Spatrick 	struct mvpp2_prs_entry pe;
37751a945772Spatrick 	uint8_t bits;
37761a945772Spatrick 	int tid;
37771a945772Spatrick 
37781a945772Spatrick 	for (tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; tid >= 0; tid--) {
37791a945772Spatrick 		if (!sc->sc_prs_shadow[tid].valid ||
37801a945772Spatrick 		    sc->sc_prs_shadow[tid].lu != MVPP2_PRS_LU_FLOWS)
37811a945772Spatrick 			continue;
37821a945772Spatrick 
3783fad015d2Spatrick 		mvpp2_prs_hw_read(sc, &pe, tid);
3784fef01367Spatrick 		bits = mvpp2_prs_sram_ai_get(&pe);
37851a945772Spatrick 
37861a945772Spatrick 		if ((bits & MVPP2_PRS_FLOW_ID_MASK) == flow)
3787fef01367Spatrick 			return tid;
37881a945772Spatrick 	}
37891a945772Spatrick 
3790fef01367Spatrick 	return -1;
37911a945772Spatrick }
37921a945772Spatrick 
37931a945772Spatrick int
mvpp2_prs_tcam_first_free(struct mvpp2_softc * sc,uint8_t start,uint8_t end)37941a945772Spatrick mvpp2_prs_tcam_first_free(struct mvpp2_softc *sc, uint8_t start, uint8_t end)
37951a945772Spatrick {
37961a945772Spatrick 	uint8_t tmp;
37971a945772Spatrick 	int tid;
37981a945772Spatrick 
37991a945772Spatrick 	if (start > end) {
38001a945772Spatrick 		tmp = end;
38011a945772Spatrick 		end = start;
38021a945772Spatrick 		start = tmp;
38031a945772Spatrick 	}
38041a945772Spatrick 
38051a945772Spatrick 	for (tid = start; tid <= end; tid++) {
38061a945772Spatrick 		if (!sc->sc_prs_shadow[tid].valid)
38071a945772Spatrick 			return tid;
38081a945772Spatrick 	}
38091a945772Spatrick 
38109da20cfaSpatrick 	return -1;
38111a945772Spatrick }
38121a945772Spatrick 
38131a945772Spatrick void
mvpp2_prs_mac_drop_all_set(struct mvpp2_softc * sc,uint32_t port,int add)38141a945772Spatrick mvpp2_prs_mac_drop_all_set(struct mvpp2_softc *sc, uint32_t port, int add)
38151a945772Spatrick {
38161a945772Spatrick 	struct mvpp2_prs_entry pe;
38171a945772Spatrick 
38181a945772Spatrick 	if (sc->sc_prs_shadow[MVPP2_PE_DROP_ALL].valid) {
3819fad015d2Spatrick 		mvpp2_prs_hw_read(sc, &pe, MVPP2_PE_DROP_ALL);
38201a945772Spatrick 	} else {
38211a945772Spatrick 		memset(&pe, 0, sizeof(pe));
38221a945772Spatrick 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
38231a945772Spatrick 		pe.index = MVPP2_PE_DROP_ALL;
38241a945772Spatrick 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
38251a945772Spatrick 		    MVPP2_PRS_RI_DROP_MASK);
38261a945772Spatrick 		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
38271a945772Spatrick 		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
38281a945772Spatrick 		mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_MAC);
38291a945772Spatrick 		mvpp2_prs_tcam_port_map_set(&pe, 0);
38301a945772Spatrick 	}
38311a945772Spatrick 
38321a945772Spatrick 	mvpp2_prs_tcam_port_set(&pe, port, add);
38331a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
38341a945772Spatrick }
38351a945772Spatrick 
38361a945772Spatrick void
mvpp2_prs_mac_promisc_set(struct mvpp2_softc * sc,uint32_t port,int l2_cast,int add)383741cd246cSpatrick mvpp2_prs_mac_promisc_set(struct mvpp2_softc *sc, uint32_t port, int l2_cast,
383841cd246cSpatrick     int add)
38391a945772Spatrick {
38401a945772Spatrick 	struct mvpp2_prs_entry pe;
384141cd246cSpatrick 	uint8_t cast_match;
384241cd246cSpatrick 	uint32_t ri;
384341cd246cSpatrick 	int tid;
38441a945772Spatrick 
384541cd246cSpatrick 	if (l2_cast == MVPP2_PRS_L2_UNI_CAST) {
384641cd246cSpatrick 		cast_match = MVPP2_PRS_UCAST_VAL;
384741cd246cSpatrick 		tid = MVPP2_PE_MAC_UC_PROMISCUOUS;
384841cd246cSpatrick 		ri = MVPP2_PRS_RI_L2_UCAST;
384941cd246cSpatrick 	} else {
385041cd246cSpatrick 		cast_match = MVPP2_PRS_MCAST_VAL;
385141cd246cSpatrick 		tid = MVPP2_PE_MAC_MC_PROMISCUOUS;
385241cd246cSpatrick 		ri = MVPP2_PRS_RI_L2_MCAST;
385341cd246cSpatrick 	}
385441cd246cSpatrick 
385541cd246cSpatrick 	if (sc->sc_prs_shadow[tid].valid) {
385641cd246cSpatrick 		mvpp2_prs_hw_read(sc, &pe, tid);
38571a945772Spatrick 	} else {
38581a945772Spatrick 		memset(&pe, 0, sizeof(pe));
38591a945772Spatrick 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
386041cd246cSpatrick 		pe.index = tid;
38611a945772Spatrick 		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
386241cd246cSpatrick 		mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK);
386341cd246cSpatrick 		mvpp2_prs_tcam_data_byte_set(&pe, 0, cast_match,
386441cd246cSpatrick 		    MVPP2_PRS_CAST_MASK);
38651a945772Spatrick 		mvpp2_prs_sram_shift_set(&pe, 2 * ETHER_ADDR_LEN,
38661a945772Spatrick 		    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
38671a945772Spatrick 		mvpp2_prs_tcam_port_map_set(&pe, 0);
38681a945772Spatrick 		mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_MAC);
38691a945772Spatrick 	}
38701a945772Spatrick 
38711a945772Spatrick 	mvpp2_prs_tcam_port_set(&pe, port, add);
38721a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
38731a945772Spatrick }
38741a945772Spatrick 
38751a945772Spatrick void
mvpp2_prs_dsa_tag_set(struct mvpp2_softc * sc,uint32_t port,int add,int tagged,int extend)38761a945772Spatrick mvpp2_prs_dsa_tag_set(struct mvpp2_softc *sc, uint32_t port, int add,
38771a945772Spatrick     int tagged, int extend)
38781a945772Spatrick {
38791a945772Spatrick 	struct mvpp2_prs_entry pe;
38801a945772Spatrick 	int32_t tid, shift;
38811a945772Spatrick 
38821a945772Spatrick 	if (extend) {
38831a945772Spatrick 		tid = tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED;
38841a945772Spatrick 		shift = 8;
38851a945772Spatrick 	} else {
38861a945772Spatrick 		tid = tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED;
38871a945772Spatrick 		shift = 4;
38881a945772Spatrick 	}
38891a945772Spatrick 
38901a945772Spatrick 	if (sc->sc_prs_shadow[tid].valid) {
3891fad015d2Spatrick 		mvpp2_prs_hw_read(sc, &pe, tid);
38921a945772Spatrick 	} else {
38931a945772Spatrick 		memset(&pe, 0, sizeof(pe));
38941a945772Spatrick 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
38951a945772Spatrick 		pe.index = tid;
38961a945772Spatrick 		mvpp2_prs_sram_shift_set(&pe, shift,
38971a945772Spatrick 		    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
38981a945772Spatrick 		mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_DSA);
38991a945772Spatrick 		if (tagged) {
39001a945772Spatrick 			mvpp2_prs_tcam_data_byte_set(&pe, 0,
39011a945772Spatrick 			    MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
39021a945772Spatrick 			    MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
39031a945772Spatrick 			mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
39041a945772Spatrick 			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
39051a945772Spatrick 		} else {
39061a945772Spatrick 			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
39071a945772Spatrick 			    MVPP2_PRS_RI_VLAN_MASK);
39081a945772Spatrick 			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
39091a945772Spatrick 		}
39101a945772Spatrick 		mvpp2_prs_tcam_port_map_set(&pe, 0);
39111a945772Spatrick 	}
39121a945772Spatrick 
39131a945772Spatrick 	mvpp2_prs_tcam_port_set(&pe, port, add);
39141a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
39151a945772Spatrick }
39161a945772Spatrick 
39171a945772Spatrick void
mvpp2_prs_dsa_tag_ethertype_set(struct mvpp2_softc * sc,uint32_t port,int add,int tagged,int extend)39181a945772Spatrick mvpp2_prs_dsa_tag_ethertype_set(struct mvpp2_softc *sc, uint32_t port,
39191a945772Spatrick     int add, int tagged, int extend)
39201a945772Spatrick {
39211a945772Spatrick 	struct mvpp2_prs_entry pe;
39221a945772Spatrick 	int32_t tid, shift, port_mask;
39231a945772Spatrick 
39241a945772Spatrick 	if (extend) {
39251a945772Spatrick 		tid = tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED;
39261a945772Spatrick 		port_mask = 0;
39271a945772Spatrick 		shift = 8;
39281a945772Spatrick 	} else {
39291a945772Spatrick 		tid = tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED;
39301a945772Spatrick 		port_mask = MVPP2_PRS_PORT_MASK;
39311a945772Spatrick 		shift = 4;
39321a945772Spatrick 	}
39331a945772Spatrick 
39341a945772Spatrick 	if (sc->sc_prs_shadow[tid].valid) {
3935fad015d2Spatrick 		mvpp2_prs_hw_read(sc, &pe, tid);
39361a945772Spatrick 	} else {
39371a945772Spatrick 		memset(&pe, 0, sizeof(pe));
39381a945772Spatrick 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
39391a945772Spatrick 		pe.index = tid;
3940e042150eSpatrick 		mvpp2_prs_match_etype(&pe, 0, 0xdada);
39411a945772Spatrick 		mvpp2_prs_match_etype(&pe, 2, 0);
39421a945772Spatrick 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DSA_MASK,
39431a945772Spatrick 		    MVPP2_PRS_RI_DSA_MASK);
39441a945772Spatrick 		mvpp2_prs_sram_shift_set(&pe, 2 * ETHER_ADDR_LEN + shift,
39451a945772Spatrick 		    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
39461a945772Spatrick 		mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_DSA);
39471a945772Spatrick 		if (tagged) {
39481a945772Spatrick 			mvpp2_prs_tcam_data_byte_set(&pe,
39491a945772Spatrick 			    MVPP2_ETH_TYPE_LEN + 2 + 3,
39501a945772Spatrick 			    MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
39511a945772Spatrick 			    MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
39521a945772Spatrick 			mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
39531a945772Spatrick 			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
39541a945772Spatrick 		} else {
39551a945772Spatrick 			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
39561a945772Spatrick 			    MVPP2_PRS_RI_VLAN_MASK);
39571a945772Spatrick 			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
39581a945772Spatrick 		}
39591a945772Spatrick 		mvpp2_prs_tcam_port_map_set(&pe, port_mask);
39601a945772Spatrick 	}
39611a945772Spatrick 
39621a945772Spatrick 	mvpp2_prs_tcam_port_set(&pe, port, add);
39631a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
39641a945772Spatrick }
39651a945772Spatrick 
39661a945772Spatrick struct mvpp2_prs_entry *
mvpp2_prs_vlan_find(struct mvpp2_softc * sc,uint16_t tpid,int ai)39671a945772Spatrick mvpp2_prs_vlan_find(struct mvpp2_softc *sc, uint16_t tpid, int ai)
39681a945772Spatrick {
39691a945772Spatrick 	struct mvpp2_prs_entry *pe;
39701a945772Spatrick 	uint32_t ri_bits, ai_bits;
39711a945772Spatrick 	int match, tid;
39721a945772Spatrick 
39731a945772Spatrick 	pe = malloc(sizeof(*pe), M_TEMP, M_NOWAIT);
39741a945772Spatrick 	if (pe == NULL)
39751a945772Spatrick 		return NULL;
39761a945772Spatrick 
39771a945772Spatrick 	mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN);
39781a945772Spatrick 
39791a945772Spatrick 	for (tid = MVPP2_PE_FIRST_FREE_TID; tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
39801a945772Spatrick 		if (!sc->sc_prs_shadow[tid].valid ||
39811a945772Spatrick 		    sc->sc_prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
39821a945772Spatrick 			continue;
3983fad015d2Spatrick 		mvpp2_prs_hw_read(sc, pe, tid);
39841a945772Spatrick 		match = mvpp2_prs_tcam_data_cmp(pe, 0, swap16(tpid));
39851a945772Spatrick 		if (!match)
39861a945772Spatrick 			continue;
39871a945772Spatrick 		ri_bits = mvpp2_prs_sram_ri_get(pe);
39881a945772Spatrick 		ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
39891a945772Spatrick 		ai_bits = mvpp2_prs_tcam_ai_get(pe);
39901a945772Spatrick 		ai_bits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT;
39911a945772Spatrick 		if (ai != ai_bits)
39921a945772Spatrick 			continue;
39931a945772Spatrick 		if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
39941a945772Spatrick 		    ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
39951a945772Spatrick 			return pe;
39961a945772Spatrick 	}
39971a945772Spatrick 
39981a945772Spatrick 	free(pe, M_TEMP, sizeof(*pe));
39991a945772Spatrick 	return NULL;
40001a945772Spatrick }
40011a945772Spatrick 
40021a945772Spatrick int
mvpp2_prs_vlan_add(struct mvpp2_softc * sc,uint16_t tpid,int ai,uint32_t port_map)40031a945772Spatrick mvpp2_prs_vlan_add(struct mvpp2_softc *sc, uint16_t tpid, int ai, uint32_t port_map)
40041a945772Spatrick {
40051a945772Spatrick 	struct mvpp2_prs_entry *pe;
40061a945772Spatrick 	uint32_t ri_bits;
40071a945772Spatrick 	int tid_aux, tid;
40081a945772Spatrick 	int ret = 0;
40091a945772Spatrick 
40101a945772Spatrick 	pe = mvpp2_prs_vlan_find(sc, tpid, ai);
40111a945772Spatrick 	if (pe == NULL) {
40121a945772Spatrick 		tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_LAST_FREE_TID,
40131a945772Spatrick 		    MVPP2_PE_FIRST_FREE_TID);
40141a945772Spatrick 		if (tid < 0)
40151a945772Spatrick 			return tid;
40161a945772Spatrick 
40171a945772Spatrick 		pe = malloc(sizeof(*pe), M_TEMP, M_NOWAIT);
40181a945772Spatrick 		if (pe == NULL)
40191a945772Spatrick 			return ENOMEM;
40201a945772Spatrick 
40211a945772Spatrick 		/* get last double vlan tid */
40221a945772Spatrick 		for (tid_aux = MVPP2_PE_LAST_FREE_TID;
40231a945772Spatrick 		    tid_aux >= MVPP2_PE_FIRST_FREE_TID; tid_aux--) {
40241a945772Spatrick 			if (!sc->sc_prs_shadow[tid_aux].valid ||
40251a945772Spatrick 			    sc->sc_prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
40261a945772Spatrick 				continue;
4027fad015d2Spatrick 			mvpp2_prs_hw_read(sc, pe, tid_aux);
40281a945772Spatrick 			ri_bits = mvpp2_prs_sram_ri_get(pe);
40291a945772Spatrick 			if ((ri_bits & MVPP2_PRS_RI_VLAN_MASK) ==
40301a945772Spatrick 			    MVPP2_PRS_RI_VLAN_DOUBLE)
40311a945772Spatrick 				break;
40321a945772Spatrick 		}
40331a945772Spatrick 
40341a945772Spatrick 		if (tid <= tid_aux) {
40351a945772Spatrick 			ret = EINVAL;
40361a945772Spatrick 			goto error;
40371a945772Spatrick 		}
40381a945772Spatrick 
4039ce2a9341Spatrick 		memset(pe, 0, sizeof(*pe));
40401a945772Spatrick 		mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN);
40411a945772Spatrick 		pe->index = tid;
40421a945772Spatrick 		mvpp2_prs_match_etype(pe, 0, tpid);
40431a945772Spatrick 		mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_L2);
40441a945772Spatrick 		mvpp2_prs_sram_shift_set(pe, MVPP2_VLAN_TAG_LEN,
40451a945772Spatrick 				   MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
40461a945772Spatrick 		mvpp2_prs_sram_ai_update(pe, 0, MVPP2_PRS_SRAM_AI_MASK);
40471a945772Spatrick 		if (ai == MVPP2_PRS_SINGLE_VLAN_AI) {
40481a945772Spatrick 			mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_SINGLE,
40491a945772Spatrick 			    MVPP2_PRS_RI_VLAN_MASK);
40501a945772Spatrick 		} else {
40511a945772Spatrick 			ai |= MVPP2_PRS_DBL_VLAN_AI_BIT;
40521a945772Spatrick 			mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_TRIPLE,
40531a945772Spatrick 			    MVPP2_PRS_RI_VLAN_MASK);
40541a945772Spatrick 		}
40551a945772Spatrick 		mvpp2_prs_tcam_ai_update(pe, ai, MVPP2_PRS_SRAM_AI_MASK);
40561a945772Spatrick 		mvpp2_prs_shadow_set(sc, pe->index, MVPP2_PRS_LU_VLAN);
40571a945772Spatrick 	}
40581a945772Spatrick 
40591a945772Spatrick 	mvpp2_prs_tcam_port_map_set(pe, port_map);
40601a945772Spatrick 	mvpp2_prs_hw_write(sc, pe);
40611a945772Spatrick 
40621a945772Spatrick error:
40631a945772Spatrick 	free(pe, M_TEMP, sizeof(*pe));
40641a945772Spatrick 	return ret;
40651a945772Spatrick }
40661a945772Spatrick 
40671a945772Spatrick int
mvpp2_prs_double_vlan_ai_free_get(struct mvpp2_softc * sc)40681a945772Spatrick mvpp2_prs_double_vlan_ai_free_get(struct mvpp2_softc *sc)
40691a945772Spatrick {
40701a945772Spatrick 	int i;
40711a945772Spatrick 
40721a945772Spatrick 	for (i = 1; i < MVPP2_PRS_DBL_VLANS_MAX; i++)
40731a945772Spatrick 		if (!sc->sc_prs_double_vlans[i])
40741a945772Spatrick 			return i;
40751a945772Spatrick 
40769da20cfaSpatrick 	return -1;
40771a945772Spatrick }
40781a945772Spatrick 
40791a945772Spatrick struct mvpp2_prs_entry *
mvpp2_prs_double_vlan_find(struct mvpp2_softc * sc,uint16_t tpid1,uint16_t tpid2)40801a945772Spatrick mvpp2_prs_double_vlan_find(struct mvpp2_softc *sc, uint16_t tpid1, uint16_t tpid2)
40811a945772Spatrick {
40821a945772Spatrick 	struct mvpp2_prs_entry *pe;
40831a945772Spatrick 	uint32_t ri_mask;
40841a945772Spatrick 	int match, tid;
40851a945772Spatrick 
40861a945772Spatrick 	pe = malloc(sizeof(*pe), M_TEMP, M_NOWAIT);
40871a945772Spatrick 	if (pe == NULL)
40881a945772Spatrick 		return NULL;
40891a945772Spatrick 
40901a945772Spatrick 	mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN);
40911a945772Spatrick 
40921a945772Spatrick 	for (tid = MVPP2_PE_FIRST_FREE_TID; tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
40931a945772Spatrick 		if (!sc->sc_prs_shadow[tid].valid ||
40941a945772Spatrick 		    sc->sc_prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
40951a945772Spatrick 			continue;
40961a945772Spatrick 
4097fad015d2Spatrick 		mvpp2_prs_hw_read(sc, pe, tid);
40981a945772Spatrick 		match = mvpp2_prs_tcam_data_cmp(pe, 0, swap16(tpid1)) &&
40991a945772Spatrick 		    mvpp2_prs_tcam_data_cmp(pe, 4, swap16(tpid2));
41001a945772Spatrick 		if (!match)
41011a945772Spatrick 			continue;
41021a945772Spatrick 		ri_mask = mvpp2_prs_sram_ri_get(pe) & MVPP2_PRS_RI_VLAN_MASK;
41031a945772Spatrick 		if (ri_mask == MVPP2_PRS_RI_VLAN_DOUBLE)
41041a945772Spatrick 			return pe;
41051a945772Spatrick 	}
41061a945772Spatrick 
41071a945772Spatrick 	free(pe, M_TEMP, sizeof(*pe));
41081a945772Spatrick 	return NULL;
41091a945772Spatrick }
41101a945772Spatrick 
41111a945772Spatrick int
mvpp2_prs_double_vlan_add(struct mvpp2_softc * sc,uint16_t tpid1,uint16_t tpid2,uint32_t port_map)41121a945772Spatrick mvpp2_prs_double_vlan_add(struct mvpp2_softc *sc, uint16_t tpid1, uint16_t tpid2,
41131a945772Spatrick     uint32_t port_map)
41141a945772Spatrick {
41151a945772Spatrick 	struct mvpp2_prs_entry *pe;
41161a945772Spatrick 	int tid_aux, tid, ai, ret = 0;
41171a945772Spatrick 	uint32_t ri_bits;
41181a945772Spatrick 
41191a945772Spatrick 	pe = mvpp2_prs_double_vlan_find(sc, tpid1, tpid2);
41201a945772Spatrick 	if (pe == NULL) {
41211a945772Spatrick 		tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
41221a945772Spatrick 		    MVPP2_PE_LAST_FREE_TID);
41231a945772Spatrick 		if (tid < 0)
41241a945772Spatrick 			return tid;
41251a945772Spatrick 
41261a945772Spatrick 		pe = malloc(sizeof(*pe), M_TEMP, M_NOWAIT);
41271a945772Spatrick 		if (pe == NULL)
41281a945772Spatrick 			return ENOMEM;
41291a945772Spatrick 
41301a945772Spatrick 		ai = mvpp2_prs_double_vlan_ai_free_get(sc);
41311a945772Spatrick 		if (ai < 0) {
41321a945772Spatrick 			ret = ai;
41331a945772Spatrick 			goto error;
41341a945772Spatrick 		}
41351a945772Spatrick 
41361a945772Spatrick 		for (tid_aux = MVPP2_PE_FIRST_FREE_TID;
41371a945772Spatrick 		    tid_aux <= MVPP2_PE_LAST_FREE_TID; tid_aux++) {
41381a945772Spatrick 			if (!sc->sc_prs_shadow[tid_aux].valid ||
41391a945772Spatrick 			    sc->sc_prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
41401a945772Spatrick 				continue;
4141fad015d2Spatrick 			mvpp2_prs_hw_read(sc, pe, tid_aux);
41421a945772Spatrick 			ri_bits = mvpp2_prs_sram_ri_get(pe);
41431a945772Spatrick 			ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
41441a945772Spatrick 			if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
41451a945772Spatrick 			    ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
41461a945772Spatrick 				break;
41471a945772Spatrick 		}
41481a945772Spatrick 
41491a945772Spatrick 		if (tid >= tid_aux) {
41501a945772Spatrick 			ret = ERANGE;
41511a945772Spatrick 			goto error;
41521a945772Spatrick 		}
41531a945772Spatrick 
4154ce2a9341Spatrick 		memset(pe, 0, sizeof(*pe));
41551a945772Spatrick 		mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_VLAN);
41561a945772Spatrick 		pe->index = tid;
41571a945772Spatrick 		sc->sc_prs_double_vlans[ai] = 1;
41581a945772Spatrick 		mvpp2_prs_match_etype(pe, 0, tpid1);
41591a945772Spatrick 		mvpp2_prs_match_etype(pe, 4, tpid2);
41601a945772Spatrick 		mvpp2_prs_sram_next_lu_set(pe, MVPP2_PRS_LU_VLAN);
41611a945772Spatrick 		mvpp2_prs_sram_shift_set(pe, 2 * MVPP2_VLAN_TAG_LEN,
41621a945772Spatrick 		    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
41631a945772Spatrick 		mvpp2_prs_sram_ri_update(pe, MVPP2_PRS_RI_VLAN_DOUBLE,
41641a945772Spatrick 		    MVPP2_PRS_RI_VLAN_MASK);
41651a945772Spatrick 		mvpp2_prs_sram_ai_update(pe, ai | MVPP2_PRS_DBL_VLAN_AI_BIT,
41661a945772Spatrick 		    MVPP2_PRS_SRAM_AI_MASK);
41671a945772Spatrick 		mvpp2_prs_shadow_set(sc, pe->index, MVPP2_PRS_LU_VLAN);
41681a945772Spatrick 	}
41691a945772Spatrick 
41701a945772Spatrick 	mvpp2_prs_tcam_port_map_set(pe, port_map);
41711a945772Spatrick 	mvpp2_prs_hw_write(sc, pe);
41721a945772Spatrick 
41731a945772Spatrick error:
41741a945772Spatrick 	free(pe, M_TEMP, sizeof(*pe));
41751a945772Spatrick 	return ret;
41761a945772Spatrick }
41771a945772Spatrick 
41781a945772Spatrick int
mvpp2_prs_ip4_proto(struct mvpp2_softc * sc,uint16_t proto,uint32_t ri,uint32_t ri_mask)41791a945772Spatrick mvpp2_prs_ip4_proto(struct mvpp2_softc *sc, uint16_t proto, uint32_t ri,
41801a945772Spatrick     uint32_t ri_mask)
41811a945772Spatrick {
41821a945772Spatrick 	struct mvpp2_prs_entry pe;
41831a945772Spatrick 	int tid;
41841a945772Spatrick 
4185e042150eSpatrick 	if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
4186e042150eSpatrick 	    (proto != IPPROTO_IGMP))
41871a945772Spatrick 		return EINVAL;
41881a945772Spatrick 
41891a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
41901a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
41911a945772Spatrick 	if (tid < 0)
41921a945772Spatrick 		return tid;
41931a945772Spatrick 
4194ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
41951a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
41961a945772Spatrick 	pe.index = tid;
41971a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
41981a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
41991a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
42001a945772Spatrick 	    sizeof(struct ip) - 4, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
42011a945772Spatrick 	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
42021a945772Spatrick 	    MVPP2_PRS_IPV4_DIP_AI_BIT);
4203e7c76d8bSpatrick 	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
4204e7c76d8bSpatrick 	mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00, MVPP2_PRS_TCAM_PROTO_MASK_L);
4205e7c76d8bSpatrick 	mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00, MVPP2_PRS_TCAM_PROTO_MASK);
42061a945772Spatrick 	mvpp2_prs_tcam_data_byte_set(&pe, 5, proto, MVPP2_PRS_TCAM_PROTO_MASK);
42071a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
42081a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
42091a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP4);
42101a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
42111a945772Spatrick 
42121a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
42131a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
42141a945772Spatrick 	if (tid < 0)
42151a945772Spatrick 		return tid;
42161a945772Spatrick 
42171a945772Spatrick 	pe.index = tid;
42181a945772Spatrick 	pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
42191a945772Spatrick 	pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
42201a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
4221e7c76d8bSpatrick 	mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_MASK,
4222e7c76d8bSpatrick 	    ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
4223e7c76d8bSpatrick 	mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00, 0x0);
4224e7c76d8bSpatrick 	mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00, 0x0);
42251a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP4);
42261a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
42271a945772Spatrick 
42281a945772Spatrick 	return 0;
42291a945772Spatrick }
42301a945772Spatrick 
42311a945772Spatrick int
mvpp2_prs_ip4_cast(struct mvpp2_softc * sc,uint16_t l3_cast)42321a945772Spatrick mvpp2_prs_ip4_cast(struct mvpp2_softc *sc, uint16_t l3_cast)
42331a945772Spatrick {
42341a945772Spatrick 	struct mvpp2_prs_entry pe;
42351a945772Spatrick 	int mask, tid;
42361a945772Spatrick 
42371a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
42381a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
42391a945772Spatrick 	if (tid < 0)
42401a945772Spatrick 		return tid;
42411a945772Spatrick 
4242ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
42431a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
42441a945772Spatrick 	pe.index = tid;
42451a945772Spatrick 
42461a945772Spatrick 	switch (l3_cast) {
42471a945772Spatrick 	case MVPP2_PRS_L3_MULTI_CAST:
42481a945772Spatrick 		mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV4_MC,
42491a945772Spatrick 		    MVPP2_PRS_IPV4_MC_MASK);
42501a945772Spatrick 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
42511a945772Spatrick 		    MVPP2_PRS_RI_L3_ADDR_MASK);
42521a945772Spatrick 		break;
42531a945772Spatrick 	case  MVPP2_PRS_L3_BROAD_CAST:
42541a945772Spatrick 		mask = MVPP2_PRS_IPV4_BC_MASK;
42551a945772Spatrick 		mvpp2_prs_tcam_data_byte_set(&pe, 0, mask, mask);
42561a945772Spatrick 		mvpp2_prs_tcam_data_byte_set(&pe, 1, mask, mask);
42571a945772Spatrick 		mvpp2_prs_tcam_data_byte_set(&pe, 2, mask, mask);
42581a945772Spatrick 		mvpp2_prs_tcam_data_byte_set(&pe, 3, mask, mask);
42591a945772Spatrick 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_BCAST,
42601a945772Spatrick 		    MVPP2_PRS_RI_L3_ADDR_MASK);
42611a945772Spatrick 		break;
42621a945772Spatrick 	default:
42631a945772Spatrick 		return EINVAL;
42641a945772Spatrick 	}
42651a945772Spatrick 
42661a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
42671a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
42681a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
42691a945772Spatrick 	    MVPP2_PRS_IPV4_DIP_AI_BIT);
42701a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
42711a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP4);
42721a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
42731a945772Spatrick 
42741a945772Spatrick 	return 0;
42751a945772Spatrick }
42761a945772Spatrick 
42771a945772Spatrick int
mvpp2_prs_ip6_proto(struct mvpp2_softc * sc,uint16_t proto,uint32_t ri,uint32_t ri_mask)42781a945772Spatrick mvpp2_prs_ip6_proto(struct mvpp2_softc *sc, uint16_t proto, uint32_t ri,
42791a945772Spatrick     uint32_t ri_mask)
42801a945772Spatrick {
42811a945772Spatrick 	struct mvpp2_prs_entry pe;
42821a945772Spatrick 	int tid;
42831a945772Spatrick 
4284e042150eSpatrick 	if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
4285e042150eSpatrick 	    (proto != IPPROTO_ICMPV6) && (proto != IPPROTO_IPIP))
42861a945772Spatrick 		return EINVAL;
42871a945772Spatrick 
42881a945772Spatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
42891a945772Spatrick 	    MVPP2_PE_LAST_FREE_TID);
42901a945772Spatrick 	if (tid < 0)
42911a945772Spatrick 		return tid;
42921a945772Spatrick 
4293ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
42941a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
42951a945772Spatrick 	pe.index = tid;
42961a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
42971a945772Spatrick 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
42981a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
42991a945772Spatrick 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
43001a945772Spatrick 	    sizeof(struct ip6_hdr) - 6, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
43011a945772Spatrick 	mvpp2_prs_tcam_data_byte_set(&pe, 0, proto, MVPP2_PRS_TCAM_PROTO_MASK);
43021a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
43031a945772Spatrick 	    MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
43041a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
43051a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP6);
43061a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
43071a945772Spatrick 
43081a945772Spatrick 	return 0;
43091a945772Spatrick }
43101a945772Spatrick 
43111a945772Spatrick int
mvpp2_prs_ip6_cast(struct mvpp2_softc * sc,uint16_t l3_cast)43121a945772Spatrick mvpp2_prs_ip6_cast(struct mvpp2_softc *sc, uint16_t l3_cast)
43131a945772Spatrick {
43141a945772Spatrick 	struct mvpp2_prs_entry pe;
43151a945772Spatrick 	int tid;
43161a945772Spatrick 
43171a945772Spatrick 	if (l3_cast != MVPP2_PRS_L3_MULTI_CAST)
43181a945772Spatrick 		return EINVAL;
43191a945772Spatrick 
4320e7c76d8bSpatrick 	tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_FIRST_FREE_TID,
4321e7c76d8bSpatrick 	    MVPP2_PE_LAST_FREE_TID);
43221a945772Spatrick 	if (tid < 0)
43231a945772Spatrick 		return tid;
43241a945772Spatrick 
4325ce2a9341Spatrick 	memset(&pe, 0, sizeof(pe));
43261a945772Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
43271a945772Spatrick 	pe.index = tid;
43281a945772Spatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
43291a945772Spatrick 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
43301a945772Spatrick 	    MVPP2_PRS_RI_L3_ADDR_MASK);
43311a945772Spatrick 	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
43321a945772Spatrick 	    MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
43331a945772Spatrick 	mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
43341a945772Spatrick 	mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV6_MC,
43351a945772Spatrick 	    MVPP2_PRS_IPV6_MC_MASK);
43361a945772Spatrick 	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
43371a945772Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
43381a945772Spatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_IP6);
43391a945772Spatrick 	mvpp2_prs_hw_write(sc, &pe);
43401a945772Spatrick 
43411a945772Spatrick 	return 0;
43421a945772Spatrick }
43431a945772Spatrick 
43441a945772Spatrick int
mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry * pe,const uint8_t * da,uint8_t * mask)43451a945772Spatrick mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry *pe, const uint8_t *da,
43461a945772Spatrick     uint8_t *mask)
43471a945772Spatrick {
43481a945772Spatrick 	uint8_t tcam_byte, tcam_mask;
43491a945772Spatrick 	int index;
43501a945772Spatrick 
43511a945772Spatrick 	for (index = 0; index < ETHER_ADDR_LEN; index++) {
43521a945772Spatrick 		mvpp2_prs_tcam_data_byte_get(pe, index, &tcam_byte,
43531a945772Spatrick 		    &tcam_mask);
43541a945772Spatrick 		if (tcam_mask != mask[index])
43551a945772Spatrick 			return 0;
43561a945772Spatrick 		if ((tcam_mask & tcam_byte) != (da[index] & mask[index]))
43571a945772Spatrick 			return 0;
43581a945772Spatrick 	}
43591a945772Spatrick 
43601a945772Spatrick 	return 1;
43611a945772Spatrick }
43621a945772Spatrick 
436341cd246cSpatrick int
mvpp2_prs_mac_da_range_find(struct mvpp2_softc * sc,int pmap,const uint8_t * da,uint8_t * mask,int udf_type)43641a945772Spatrick mvpp2_prs_mac_da_range_find(struct mvpp2_softc *sc, int pmap, const uint8_t *da,
43651a945772Spatrick     uint8_t *mask, int udf_type)
43661a945772Spatrick {
436741cd246cSpatrick 	struct mvpp2_prs_entry pe;
43681a945772Spatrick 	int tid;
43691a945772Spatrick 
4370ce595ab8Spatrick 	for (tid = MVPP2_PE_MAC_RANGE_START; tid <= MVPP2_PE_MAC_RANGE_END;
43711a945772Spatrick 	    tid++) {
43721a945772Spatrick 		uint32_t entry_pmap;
43731a945772Spatrick 
43741a945772Spatrick 		if (!sc->sc_prs_shadow[tid].valid ||
43751a945772Spatrick 		    (sc->sc_prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
43761a945772Spatrick 		    (sc->sc_prs_shadow[tid].udf != udf_type))
43771a945772Spatrick 			continue;
43781a945772Spatrick 
437941cd246cSpatrick 		mvpp2_prs_hw_read(sc, &pe, tid);
438041cd246cSpatrick 		entry_pmap = mvpp2_prs_tcam_port_map_get(&pe);
438141cd246cSpatrick 		if (mvpp2_prs_mac_range_equals(&pe, da, mask) &&
43821a945772Spatrick 		    entry_pmap == pmap)
438341cd246cSpatrick 			return tid;
43841a945772Spatrick 	}
43851a945772Spatrick 
438641cd246cSpatrick 	return -1;
43871a945772Spatrick }
43881a945772Spatrick 
43891a945772Spatrick int
mvpp2_prs_mac_da_accept(struct mvpp2_port * port,const uint8_t * da,int add)439041cd246cSpatrick mvpp2_prs_mac_da_accept(struct mvpp2_port *port, const uint8_t *da, int add)
43911a945772Spatrick {
439241cd246cSpatrick 	struct mvpp2_softc *sc = port->sc;
439341cd246cSpatrick 	struct mvpp2_prs_entry pe;
43941a945772Spatrick 	uint32_t pmap, len, ri;
43951a945772Spatrick 	uint8_t mask[ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
43961a945772Spatrick 	int tid;
43971a945772Spatrick 
439841cd246cSpatrick 	memset(&pe, 0, sizeof(pe));
439941cd246cSpatrick 
440041cd246cSpatrick 	tid = mvpp2_prs_mac_da_range_find(sc, BIT(port->sc_id), da, mask,
44011a945772Spatrick 	    MVPP2_PRS_UDF_MAC_DEF);
440241cd246cSpatrick 	if (tid < 0) {
44031a945772Spatrick 		if (!add)
44041a945772Spatrick 			return 0;
44051a945772Spatrick 
4406ce595ab8Spatrick 		tid = mvpp2_prs_tcam_first_free(sc, MVPP2_PE_MAC_RANGE_START,
4407ce595ab8Spatrick 		    MVPP2_PE_MAC_RANGE_END);
44081a945772Spatrick 		if (tid < 0)
44091a945772Spatrick 			return tid;
44101a945772Spatrick 
441141cd246cSpatrick 		pe.index = tid;
441241cd246cSpatrick 		mvpp2_prs_tcam_port_map_set(&pe, 0);
441341cd246cSpatrick 	} else {
441441cd246cSpatrick 		mvpp2_prs_hw_read(sc, &pe, tid);
44151a945772Spatrick 	}
44161a945772Spatrick 
441741cd246cSpatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
441841cd246cSpatrick 
441941cd246cSpatrick 	mvpp2_prs_tcam_port_set(&pe, port->sc_id, add);
44201a945772Spatrick 
44211a945772Spatrick 	/* invalidate the entry if no ports are left enabled */
442241cd246cSpatrick 	pmap = mvpp2_prs_tcam_port_map_get(&pe);
44231a945772Spatrick 	if (pmap == 0) {
442441cd246cSpatrick 		if (add)
44251a945772Spatrick 			return -1;
442641cd246cSpatrick 		mvpp2_prs_hw_inv(sc, pe.index);
442741cd246cSpatrick 		sc->sc_prs_shadow[pe.index].valid = 0;
44281a945772Spatrick 		return 0;
44291a945772Spatrick 	}
44301a945772Spatrick 
443141cd246cSpatrick 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
44321a945772Spatrick 
44331a945772Spatrick 	len = ETHER_ADDR_LEN;
44341a945772Spatrick 	while (len--)
443541cd246cSpatrick 		mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
44361a945772Spatrick 
44371a945772Spatrick 	if (ETHER_IS_BROADCAST(da))
44381a945772Spatrick 		ri = MVPP2_PRS_RI_L2_BCAST;
44391a945772Spatrick 	else if (ETHER_IS_MULTICAST(da))
44401a945772Spatrick 		ri = MVPP2_PRS_RI_L2_MCAST;
44411a945772Spatrick 	else
44421a945772Spatrick 		ri = MVPP2_PRS_RI_L2_UCAST | MVPP2_PRS_RI_MAC_ME_MASK;
44431a945772Spatrick 
444441cd246cSpatrick 	mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK |
44451a945772Spatrick 	    MVPP2_PRS_RI_MAC_ME_MASK);
444641cd246cSpatrick 	mvpp2_prs_shadow_ri_set(sc, pe.index, ri, MVPP2_PRS_RI_L2_CAST_MASK |
44471a945772Spatrick 	    MVPP2_PRS_RI_MAC_ME_MASK);
444841cd246cSpatrick 	mvpp2_prs_sram_shift_set(&pe, 2 * ETHER_ADDR_LEN,
44491a945772Spatrick 	    MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
445041cd246cSpatrick 	sc->sc_prs_shadow[pe.index].udf = MVPP2_PRS_UDF_MAC_DEF;
445141cd246cSpatrick 	mvpp2_prs_shadow_set(sc, pe.index, MVPP2_PRS_LU_MAC);
445241cd246cSpatrick 	mvpp2_prs_hw_write(sc, &pe);
44531a945772Spatrick 
44541a945772Spatrick 	return 0;
44551a945772Spatrick }
44561a945772Spatrick 
4457ce595ab8Spatrick void
mvpp2_prs_mac_del_all(struct mvpp2_port * port)4458ce595ab8Spatrick mvpp2_prs_mac_del_all(struct mvpp2_port *port)
4459ce595ab8Spatrick {
4460ce595ab8Spatrick 	struct mvpp2_softc *sc = port->sc;
4461ce595ab8Spatrick 	struct mvpp2_prs_entry pe;
4462ce595ab8Spatrick 	uint32_t pmap;
4463ce595ab8Spatrick 	int index, tid;
4464ce595ab8Spatrick 
4465ce595ab8Spatrick 	for (tid = MVPP2_PE_MAC_RANGE_START; tid <= MVPP2_PE_MAC_RANGE_END;
4466ce595ab8Spatrick 	    tid++) {
4467ce595ab8Spatrick 		uint8_t da[ETHER_ADDR_LEN], da_mask[ETHER_ADDR_LEN];
4468ce595ab8Spatrick 
4469ce595ab8Spatrick 		if (!sc->sc_prs_shadow[tid].valid ||
4470ce595ab8Spatrick 		    (sc->sc_prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
4471ce595ab8Spatrick 		    (sc->sc_prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF))
4472ce595ab8Spatrick 			continue;
4473ce595ab8Spatrick 
4474ce595ab8Spatrick 		mvpp2_prs_hw_read(sc, &pe, tid);
4475ce595ab8Spatrick 		pmap = mvpp2_prs_tcam_port_map_get(&pe);
4476ce595ab8Spatrick 
4477ce595ab8Spatrick 		if (!(pmap & (1 << port->sc_id)))
4478ce595ab8Spatrick 			continue;
4479ce595ab8Spatrick 
4480ce595ab8Spatrick 		for (index = 0; index < ETHER_ADDR_LEN; index++)
4481ce595ab8Spatrick 			mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
4482ce595ab8Spatrick 			    &da_mask[index]);
4483ce595ab8Spatrick 
4484ce595ab8Spatrick 		if (ETHER_IS_BROADCAST(da) || ETHER_IS_EQ(da, port->sc_lladdr))
4485ce595ab8Spatrick 			continue;
4486ce595ab8Spatrick 
4487ce595ab8Spatrick 		mvpp2_prs_mac_da_accept(port, da, 0);
4488ce595ab8Spatrick 	}
4489ce595ab8Spatrick }
4490ce595ab8Spatrick 
44911a945772Spatrick int
mvpp2_prs_tag_mode_set(struct mvpp2_softc * sc,int port_id,int type)44921a945772Spatrick mvpp2_prs_tag_mode_set(struct mvpp2_softc *sc, int port_id, int type)
44931a945772Spatrick {
44941a945772Spatrick 	switch (type) {
44951a945772Spatrick 	case MVPP2_TAG_TYPE_EDSA:
44961a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 1, MVPP2_PRS_TAGGED,
44971a945772Spatrick 		    MVPP2_PRS_EDSA);
44981a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 1, MVPP2_PRS_UNTAGGED,
44991a945772Spatrick 		    MVPP2_PRS_EDSA);
45001a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 0, MVPP2_PRS_TAGGED,
45011a945772Spatrick 		    MVPP2_PRS_DSA);
45021a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 0, MVPP2_PRS_UNTAGGED,
45031a945772Spatrick 		    MVPP2_PRS_DSA);
45041a945772Spatrick 		break;
45051a945772Spatrick 	case MVPP2_TAG_TYPE_DSA:
45061a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 1, MVPP2_PRS_TAGGED,
45071a945772Spatrick 		    MVPP2_PRS_DSA);
45081a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 1, MVPP2_PRS_UNTAGGED,
45091a945772Spatrick 		    MVPP2_PRS_DSA);
45101a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 0, MVPP2_PRS_TAGGED,
45111a945772Spatrick 		    MVPP2_PRS_EDSA);
45121a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 0, MVPP2_PRS_UNTAGGED,
45131a945772Spatrick 		    MVPP2_PRS_EDSA);
45141a945772Spatrick 		break;
45151a945772Spatrick 	case MVPP2_TAG_TYPE_MH:
45161a945772Spatrick 	case MVPP2_TAG_TYPE_NONE:
45171a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 0, MVPP2_PRS_TAGGED,
45181a945772Spatrick 		    MVPP2_PRS_DSA);
45191a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 0, MVPP2_PRS_UNTAGGED,
45201a945772Spatrick 		    MVPP2_PRS_DSA);
45211a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 0, MVPP2_PRS_TAGGED,
45221a945772Spatrick 		    MVPP2_PRS_EDSA);
45231a945772Spatrick 		mvpp2_prs_dsa_tag_set(sc, port_id, 0, MVPP2_PRS_UNTAGGED,
45241a945772Spatrick 		    MVPP2_PRS_EDSA);
45251a945772Spatrick 		break;
45261a945772Spatrick 	default:
45271a945772Spatrick 		if ((type < 0) || (type > MVPP2_TAG_TYPE_EDSA))
45281a945772Spatrick 			return EINVAL;
45291a945772Spatrick 		break;
45301a945772Spatrick 	}
45311a945772Spatrick 
45321a945772Spatrick 	return 0;
45331a945772Spatrick }
45341a945772Spatrick 
45351a945772Spatrick int
mvpp2_prs_def_flow(struct mvpp2_port * port)45361a945772Spatrick mvpp2_prs_def_flow(struct mvpp2_port *port)
45371a945772Spatrick {
4538fef01367Spatrick 	struct mvpp2_prs_entry pe;
45391a945772Spatrick 	int tid;
45401a945772Spatrick 
4541fef01367Spatrick 	memset(&pe, 0, sizeof(pe));
4542fef01367Spatrick 
4543fef01367Spatrick 	tid = mvpp2_prs_flow_find(port->sc, port->sc_id);
4544fef01367Spatrick 	if (tid < 0) {
45451a945772Spatrick 		tid = mvpp2_prs_tcam_first_free(port->sc,
45461a945772Spatrick 		    MVPP2_PE_LAST_FREE_TID, MVPP2_PE_FIRST_FREE_TID);
45471a945772Spatrick 		if (tid < 0)
45481a945772Spatrick 			return tid;
45491a945772Spatrick 
4550fef01367Spatrick 		pe.index = tid;
4551fef01367Spatrick 		mvpp2_prs_sram_ai_update(&pe, port->sc_id,
45521a945772Spatrick 		    MVPP2_PRS_FLOW_ID_MASK);
4553fef01367Spatrick 		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
4554fef01367Spatrick 		mvpp2_prs_shadow_set(port->sc, pe.index, MVPP2_PRS_LU_FLOWS);
4555fef01367Spatrick 	} else {
4556fad015d2Spatrick 		mvpp2_prs_hw_read(port->sc, &pe, tid);
45571a945772Spatrick 	}
45581a945772Spatrick 
4559fef01367Spatrick 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
4560fef01367Spatrick 	mvpp2_prs_tcam_port_map_set(&pe, (1 << port->sc_id));
4561fef01367Spatrick 	mvpp2_prs_hw_write(port->sc, &pe);
45621a945772Spatrick 	return 0;
45631a945772Spatrick }
45641a945772Spatrick 
45651a945772Spatrick void
mvpp2_cls_flow_write(struct mvpp2_softc * sc,struct mvpp2_cls_flow_entry * fe)45661a945772Spatrick mvpp2_cls_flow_write(struct mvpp2_softc *sc, struct mvpp2_cls_flow_entry *fe)
45671a945772Spatrick {
45681a945772Spatrick 	mvpp2_write(sc, MVPP2_CLS_FLOW_INDEX_REG, fe->index);
45691a945772Spatrick 	mvpp2_write(sc, MVPP2_CLS_FLOW_TBL0_REG, fe->data[0]);
45701a945772Spatrick 	mvpp2_write(sc, MVPP2_CLS_FLOW_TBL1_REG, fe->data[1]);
45711a945772Spatrick 	mvpp2_write(sc, MVPP2_CLS_FLOW_TBL2_REG, fe->data[2]);
45721a945772Spatrick }
45731a945772Spatrick 
45741a945772Spatrick void
mvpp2_cls_lookup_write(struct mvpp2_softc * sc,struct mvpp2_cls_lookup_entry * le)45751a945772Spatrick mvpp2_cls_lookup_write(struct mvpp2_softc *sc, struct mvpp2_cls_lookup_entry *le)
45761a945772Spatrick {
45771a945772Spatrick 	uint32_t val;
45781a945772Spatrick 
45791a945772Spatrick 	val = (le->way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | le->lkpid;
45801a945772Spatrick 	mvpp2_write(sc, MVPP2_CLS_LKP_INDEX_REG, val);
45811a945772Spatrick 	mvpp2_write(sc, MVPP2_CLS_LKP_TBL_REG, le->data);
45821a945772Spatrick }
45831a945772Spatrick 
45841a945772Spatrick void
mvpp2_cls_init(struct mvpp2_softc * sc)45851a945772Spatrick mvpp2_cls_init(struct mvpp2_softc *sc)
45861a945772Spatrick {
45871a945772Spatrick 	struct mvpp2_cls_lookup_entry le;
45881a945772Spatrick 	struct mvpp2_cls_flow_entry fe;
45891a945772Spatrick 	int index;
45901a945772Spatrick 
45911a945772Spatrick 	mvpp2_write(sc, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK);
4592fbeb3de2Spatrick 	memset(&fe.data, 0, sizeof(fe.data));
45931a945772Spatrick 	for (index = 0; index < MVPP2_CLS_FLOWS_TBL_SIZE; index++) {
45941a945772Spatrick 		fe.index = index;
45951a945772Spatrick 		mvpp2_cls_flow_write(sc, &fe);
45961a945772Spatrick 	}
45971a945772Spatrick 	le.data = 0;
45981a945772Spatrick 	for (index = 0; index < MVPP2_CLS_LKP_TBL_SIZE; index++) {
45991a945772Spatrick 		le.lkpid = index;
46001a945772Spatrick 		le.way = 0;
46011a945772Spatrick 		mvpp2_cls_lookup_write(sc, &le);
46021a945772Spatrick 		le.way = 1;
46031a945772Spatrick 		mvpp2_cls_lookup_write(sc, &le);
46041a945772Spatrick 	}
46051a945772Spatrick }
46061a945772Spatrick 
46071a945772Spatrick void
mvpp2_cls_port_config(struct mvpp2_port * port)46081a945772Spatrick mvpp2_cls_port_config(struct mvpp2_port *port)
46091a945772Spatrick {
46101a945772Spatrick 	struct mvpp2_cls_lookup_entry le;
46111a945772Spatrick 	uint32_t val;
46121a945772Spatrick 
46131a945772Spatrick 	/* set way for the port */
46141a945772Spatrick 	val = mvpp2_read(port->sc, MVPP2_CLS_PORT_WAY_REG);
46151a945772Spatrick 	val &= ~MVPP2_CLS_PORT_WAY_MASK(port->sc_id);
46161a945772Spatrick 	mvpp2_write(port->sc, MVPP2_CLS_PORT_WAY_REG, val);
46171a945772Spatrick 
46181a945772Spatrick 	/*
46191a945772Spatrick 	 * pick the entry to be accessed in lookup ID decoding table
46201a945772Spatrick 	 * according to the way and lkpid.
46211a945772Spatrick 	 */
46221a945772Spatrick 	le.lkpid = port->sc_id;
46231a945772Spatrick 	le.way = 0;
46241a945772Spatrick 	le.data = 0;
46251a945772Spatrick 
46261a945772Spatrick 	/* set initial CPU queue for receiving packets */
46271a945772Spatrick 	le.data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK;
46281a945772Spatrick 	le.data |= (port->sc_id * 32);
46291a945772Spatrick 
46301a945772Spatrick 	/* disable classification engines */
46311a945772Spatrick 	le.data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
46321a945772Spatrick 
46331a945772Spatrick 	/* update lookup ID table entry */
46341a945772Spatrick 	mvpp2_cls_lookup_write(port->sc, &le);
46351a945772Spatrick }
46361a945772Spatrick 
46371a945772Spatrick void
mvpp2_cls_oversize_rxq_set(struct mvpp2_port * port)46381a945772Spatrick mvpp2_cls_oversize_rxq_set(struct mvpp2_port *port)
46391a945772Spatrick {
4640a6029e6cSpatrick 	uint32_t val;
4641a6029e6cSpatrick 
46421a945772Spatrick 	mvpp2_write(port->sc, MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(port->sc_id),
46431a945772Spatrick 	    (port->sc_id * 32) & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK);
4644a6029e6cSpatrick 	mvpp2_write(port->sc, MVPP2_CLS_SWFWD_P2HQ_REG(port->sc_id),
4645a6029e6cSpatrick 	    (port->sc_id * 32) >> MVPP2_CLS_OVERSIZE_RXQ_LOW_BITS);
4646a6029e6cSpatrick 	val = mvpp2_read(port->sc, MVPP2_CLS_SWFWD_PCTRL_REG);
4647a6029e6cSpatrick 	val &= ~MVPP2_CLS_SWFWD_PCTRL_MASK(port->sc_id);
4648a6029e6cSpatrick 	mvpp2_write(port->sc, MVPP2_CLS_SWFWD_PCTRL_REG, val);
46491a945772Spatrick }
4650