xref: /freebsd/sys/dev/dpaa/if_memac.c (revision 7a40b8a89e7da2a7e8d8e132bc37885b22e9bfb1)
1*7a40b8a8SJustin Hibbits /*
2fd8d34ceSJustin Hibbits  * Copyright (c) 2026 Justin Hibbits
3*7a40b8a8SJustin Hibbits  *
4*7a40b8a8SJustin Hibbits  * SPDX-License-Identifier: BSD-2-Clause
5fd8d34ceSJustin Hibbits  */
6fd8d34ceSJustin Hibbits 
7fd8d34ceSJustin Hibbits #include <sys/param.h>
8fd8d34ceSJustin Hibbits #include <sys/systm.h>
9fd8d34ceSJustin Hibbits #include <sys/bus.h>
10fd8d34ceSJustin Hibbits #include <sys/kernel.h>
11fd8d34ceSJustin Hibbits #include <sys/malloc.h>
12fd8d34ceSJustin Hibbits #include <sys/mbuf.h>
13fd8d34ceSJustin Hibbits #include <sys/module.h>
14fd8d34ceSJustin Hibbits #include <sys/rman.h>
15fd8d34ceSJustin Hibbits #include <sys/socket.h>
16fd8d34ceSJustin Hibbits #include <sys/sysctl.h>
17fd8d34ceSJustin Hibbits #include <sys/sockio.h>
18fd8d34ceSJustin Hibbits 
19fd8d34ceSJustin Hibbits #include <machine/bus.h>
20fd8d34ceSJustin Hibbits #include <machine/resource.h>
21fd8d34ceSJustin Hibbits 
22fd8d34ceSJustin Hibbits #include <net/ethernet.h>
23fd8d34ceSJustin Hibbits #include <net/if.h>
24fd8d34ceSJustin Hibbits #include <net/if_dl.h>
25fd8d34ceSJustin Hibbits #include <net/if_media.h>
26fd8d34ceSJustin Hibbits #include <net/if_types.h>
27fd8d34ceSJustin Hibbits #include <net/if_arp.h>
28fd8d34ceSJustin Hibbits 
29fd8d34ceSJustin Hibbits #include <dev/mii/mii.h>
30fd8d34ceSJustin Hibbits #include <dev/mii/miivar.h>
31fd8d34ceSJustin Hibbits #include <dev/ofw/ofw_bus.h>
32fd8d34ceSJustin Hibbits #include <dev/ofw/ofw_bus_subr.h>
33fd8d34ceSJustin Hibbits #include <dev/ofw/openfirm.h>
34fd8d34ceSJustin Hibbits 
35fd8d34ceSJustin Hibbits #include "miibus_if.h"
36fd8d34ceSJustin Hibbits 
37fd8d34ceSJustin Hibbits #include "dpaa_eth.h"
38fd8d34ceSJustin Hibbits #include "fman.h"
39fd8d34ceSJustin Hibbits #include "fman_port.h"
40fd8d34ceSJustin Hibbits #include "if_memac.h"
41fd8d34ceSJustin Hibbits 
42fd8d34ceSJustin Hibbits #include "fman_if.h"
43fd8d34ceSJustin Hibbits #include "fman_port_if.h"
44fd8d34ceSJustin Hibbits 
45fd8d34ceSJustin Hibbits #define	MEMAC_MIN_FRAME_SIZE	64
46fd8d34ceSJustin Hibbits #define	MEMAC_MAX_FRAME_SIZE	32736
47fd8d34ceSJustin Hibbits 
48fd8d34ceSJustin Hibbits #define	MEMAC_COMMAND_CONFIG		0x008
49fd8d34ceSJustin Hibbits #define	  COMMAND_CONFIG_RXSTP		  0x20000000
50fd8d34ceSJustin Hibbits #define	  COMMAND_CONFIG_NO_LEN_CHK	  0x00020000
51fd8d34ceSJustin Hibbits #define	  COMMAND_CONFIG_SWR		  0x00001000
52fd8d34ceSJustin Hibbits #define	  COMMAND_CONFIG_TXP		  0x00000800
53fd8d34ceSJustin Hibbits #define	  COMMAND_CONFIG_CRC		  0x00000040
54fd8d34ceSJustin Hibbits #define	  COMMAND_CONFIG_PROMISC	  0x00000010
55fd8d34ceSJustin Hibbits #define	  COMMAND_CONFIG_RX_EN		  0x00000002
56fd8d34ceSJustin Hibbits #define	  COMMAND_CONFIG_TX_EN		  0x00000001
57fd8d34ceSJustin Hibbits #define	MEMAC_MAC_ADDR_0		0x00c
58fd8d34ceSJustin Hibbits #define	MEMAC_MAC_ADDR_1		0x010
59fd8d34ceSJustin Hibbits #define	MEMAC_REG_MAXFRM		0x14
60fd8d34ceSJustin Hibbits #define	MEMAC_REG_TX_FIFO_SECTIONS	0x020
61fd8d34ceSJustin Hibbits #define	  TX_FIFO_SECTIONS_TX_EMPTY_M	  0xffff0000
62fd8d34ceSJustin Hibbits #define	  TX_FIFO_SECTIONS_TX_EMPTY_S	  16
63fd8d34ceSJustin Hibbits #define	  TX_FIFO_SECTIONS_TX_AVAIL_M	  0x0000ffff
64fd8d34ceSJustin Hibbits 
65fd8d34ceSJustin Hibbits #define	HASHTABLE_CTRL		0x02c
66fd8d34ceSJustin Hibbits #define	  CTRL_MCAST		  0x00000100
67fd8d34ceSJustin Hibbits #define	  CTRL_HASH_ADDR_M	  0x0000003f
68fd8d34ceSJustin Hibbits #define	  HASHTABLE_SIZE	  64
69fd8d34ceSJustin Hibbits #define	MEMAC_IEVENT		0x040
70fd8d34ceSJustin Hibbits #define	  IEVENT_RX_EMPTY	  0x00000040
71fd8d34ceSJustin Hibbits #define	  IEVENT_TX_EMPTY	  0x00000020
72fd8d34ceSJustin Hibbits #define	MEMAC_CL01_PAUSE_QUANTA	0x054
73fd8d34ceSJustin Hibbits #define	MEMAC_IF_MODE		0x300
74fd8d34ceSJustin Hibbits #define	  IF_MODE_ENA		  0x00008000
75fd8d34ceSJustin Hibbits #define	  IF_MODE_SSP_M		  0x00006000
76fd8d34ceSJustin Hibbits #define	  IF_MODE_SSP_100MB	  0x00000000
77fd8d34ceSJustin Hibbits #define	  IF_MODE_SSP_10MB	  0x00002000
78fd8d34ceSJustin Hibbits #define	  IF_MODE_SSP_1GB	  0x00004000
79fd8d34ceSJustin Hibbits #define	  IF_MODE_SFD		  0x00001000
80fd8d34ceSJustin Hibbits #define	  IF_MODE_MSG		  0x00000200
81fd8d34ceSJustin Hibbits #define	  IF_MODE_HG		  0x00000100
82fd8d34ceSJustin Hibbits #define	  IF_MODE_HD		  0x00000040
83fd8d34ceSJustin Hibbits #define	  IF_MODE_RLP		  0x00000020
84fd8d34ceSJustin Hibbits #define	  IF_MODE_RG		  0x00000004
85fd8d34ceSJustin Hibbits #define	  IF_MODE_IFMODE_M	  0x00000003
86fd8d34ceSJustin Hibbits #define	  IF_MODE_IFMODE_XGMII	  0x00000000
87fd8d34ceSJustin Hibbits #define	  IF_MODE_IFMODE_MII	  0x00000001
88fd8d34ceSJustin Hibbits #define	  IF_MODE_IFMODE_GMII	  0x00000002
89fd8d34ceSJustin Hibbits 
90fd8d34ceSJustin Hibbits #define	DEFAULT_PAUSE_QUANTA	0xf000
91fd8d34ceSJustin Hibbits 
926464974cSJustin Hibbits #define	DPAA_CSUM_TX_OFFLOAD	(CSUM_IP | CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6)
93fd8d34ceSJustin Hibbits 
94fd8d34ceSJustin Hibbits 
95fd8d34ceSJustin Hibbits /**
96fd8d34ceSJustin Hibbits  * @group FMan MAC routines.
97fd8d34ceSJustin Hibbits  * @{
98fd8d34ceSJustin Hibbits  */
99fd8d34ceSJustin Hibbits #define	MEMAC_MAC_EXCEPTIONS_END	(-1)
100fd8d34ceSJustin Hibbits 
101fd8d34ceSJustin Hibbits static void memac_if_init_locked(struct memac_softc *sc);
102fd8d34ceSJustin Hibbits 
103fd8d34ceSJustin Hibbits static int
memac_fm_mac_init(struct memac_softc * sc,uint8_t * mac)104fd8d34ceSJustin Hibbits memac_fm_mac_init(struct memac_softc *sc, uint8_t *mac)
105fd8d34ceSJustin Hibbits {
106fd8d34ceSJustin Hibbits 	uint32_t reg;
107fd8d34ceSJustin Hibbits 
108fd8d34ceSJustin Hibbits 	FMAN_GET_REVISION(device_get_parent(sc->sc_base.sc_dev), &sc->sc_base.sc_rev_major,
109fd8d34ceSJustin Hibbits 	    &sc->sc_base.sc_rev_minor);
110fd8d34ceSJustin Hibbits 
111fd8d34ceSJustin Hibbits 	if (FMAN_RESET_MAC(device_get_parent(sc->sc_base.sc_dev), sc->sc_base.sc_eth_id) != 0)
112fd8d34ceSJustin Hibbits 		return (ENXIO);
113fd8d34ceSJustin Hibbits 
114fd8d34ceSJustin Hibbits 	reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG);
115fd8d34ceSJustin Hibbits 	reg |= COMMAND_CONFIG_SWR;
116fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG, reg);
117fd8d34ceSJustin Hibbits 
118fd8d34ceSJustin Hibbits 	while (bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG) & COMMAND_CONFIG_SWR)
119fd8d34ceSJustin Hibbits 		;
120fd8d34ceSJustin Hibbits 
121fd8d34ceSJustin Hibbits 	/* TODO: TX_FIFO_SECTIONS */
122fd8d34ceSJustin Hibbits 	/* TODO: CL01 pause quantum */
123fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG,
124fd8d34ceSJustin Hibbits 	    COMMAND_CONFIG_NO_LEN_CHK | COMMAND_CONFIG_TXP | COMMAND_CONFIG_CRC);
125fd8d34ceSJustin Hibbits 
126fd8d34ceSJustin Hibbits 	reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_IF_MODE);
127fd8d34ceSJustin Hibbits 	reg &= ~(IF_MODE_IFMODE_M | IF_MODE_RG);
128fd8d34ceSJustin Hibbits 	switch (sc->sc_base.sc_mac_enet_mode) {
129fd8d34ceSJustin Hibbits 	case MII_CONTYPE_RGMII:
130fd8d34ceSJustin Hibbits 		reg |= IF_MODE_RG;
131fd8d34ceSJustin Hibbits 		/* FALLTHROUGH */
132fd8d34ceSJustin Hibbits 	case MII_CONTYPE_GMII:
133fd8d34ceSJustin Hibbits 	case MII_CONTYPE_SGMII:
134fd8d34ceSJustin Hibbits 	case MII_CONTYPE_QSGMII:
135fd8d34ceSJustin Hibbits 		reg |= IF_MODE_IFMODE_GMII;
136fd8d34ceSJustin Hibbits 		break;
137fd8d34ceSJustin Hibbits 	case MII_CONTYPE_RMII:
138fd8d34ceSJustin Hibbits 		reg |= IF_MODE_RG;
139fd8d34ceSJustin Hibbits 		/* FALLTHROUGH */
140fd8d34ceSJustin Hibbits 	case MII_CONTYPE_MII:
141fd8d34ceSJustin Hibbits 		reg |= IF_MODE_IFMODE_MII;
142fd8d34ceSJustin Hibbits 		break;
143fd8d34ceSJustin Hibbits 	}
144fd8d34ceSJustin Hibbits 
145fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, MEMAC_IF_MODE, reg);
146fd8d34ceSJustin Hibbits 
147fd8d34ceSJustin Hibbits 	return (0);
148fd8d34ceSJustin Hibbits }
149fd8d34ceSJustin Hibbits /** @} */
150fd8d34ceSJustin Hibbits 
151fd8d34ceSJustin Hibbits 
152fd8d34ceSJustin Hibbits /**
153fd8d34ceSJustin Hibbits  * @group IFnet routines.
154fd8d34ceSJustin Hibbits  * @{
155fd8d34ceSJustin Hibbits  */
156fd8d34ceSJustin Hibbits static int
memac_set_mtu(struct memac_softc * sc,unsigned int mtu)157fd8d34ceSJustin Hibbits memac_set_mtu(struct memac_softc *sc, unsigned int mtu)
158fd8d34ceSJustin Hibbits {
159fd8d34ceSJustin Hibbits 
160fd8d34ceSJustin Hibbits 	mtu += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
161fd8d34ceSJustin Hibbits 
162fd8d34ceSJustin Hibbits 	MEMAC_LOCK_ASSERT(sc);
163fd8d34ceSJustin Hibbits 
164fd8d34ceSJustin Hibbits 	if (mtu >= MEMAC_MIN_FRAME_SIZE && mtu <= MEMAC_MAX_FRAME_SIZE) {
165fd8d34ceSJustin Hibbits 		bus_write_4(sc->sc_base.sc_mem, MEMAC_REG_MAXFRM, mtu);
166fd8d34ceSJustin Hibbits 		return (mtu);
167fd8d34ceSJustin Hibbits 	}
168fd8d34ceSJustin Hibbits 
169fd8d34ceSJustin Hibbits 	return (0);
170fd8d34ceSJustin Hibbits }
171fd8d34ceSJustin Hibbits 
172fd8d34ceSJustin Hibbits static u_int
memac_hash_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)173fd8d34ceSJustin Hibbits memac_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
174fd8d34ceSJustin Hibbits {
175fd8d34ceSJustin Hibbits 	struct memac_softc *sc = arg;
176fd8d34ceSJustin Hibbits 	uint8_t *addr = LLADDR(sdl);
177fd8d34ceSJustin Hibbits 	uint32_t hash = 0;
178fd8d34ceSJustin Hibbits 	uint8_t a, h;
179fd8d34ceSJustin Hibbits 
180fd8d34ceSJustin Hibbits 	/* Hash is 6 bits, composed if [XOR{47:40},XOR{39:32},....] */
181fd8d34ceSJustin Hibbits 	for (int i = 0; i < 6; i++) {
182fd8d34ceSJustin Hibbits 		a = addr[i];
183fd8d34ceSJustin Hibbits 		h = 0;
184fd8d34ceSJustin Hibbits 		for (int j = 0; j < 8; j++, a >>= 1) {
185fd8d34ceSJustin Hibbits 			h ^= (a & 0x1);
186fd8d34ceSJustin Hibbits 		}
187fd8d34ceSJustin Hibbits 		hash |= (h << i);
188fd8d34ceSJustin Hibbits 	}
189fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, HASHTABLE_CTRL, hash | CTRL_MCAST);
190fd8d34ceSJustin Hibbits 
191fd8d34ceSJustin Hibbits 	return (1);
192fd8d34ceSJustin Hibbits }
193fd8d34ceSJustin Hibbits 
194fd8d34ceSJustin Hibbits static void
memac_setup_multicast(struct memac_softc * sc)195fd8d34ceSJustin Hibbits memac_setup_multicast(struct memac_softc *sc)
196fd8d34ceSJustin Hibbits {
197fd8d34ceSJustin Hibbits 
198fd8d34ceSJustin Hibbits 	if (if_getflags(sc->sc_base.sc_ifnet) & IFF_ALLMULTI) {
199fd8d34ceSJustin Hibbits 		for (int i = 0; i < HASHTABLE_SIZE; i++)
200fd8d34ceSJustin Hibbits 			bus_write_4(sc->sc_base.sc_mem,
201fd8d34ceSJustin Hibbits 			    HASHTABLE_CTRL, CTRL_MCAST | i);
202fd8d34ceSJustin Hibbits 	} else {
203fd8d34ceSJustin Hibbits 		/* Clear the hash table */
204fd8d34ceSJustin Hibbits 		for (int i = 0; i < HASHTABLE_SIZE; i++)
205fd8d34ceSJustin Hibbits 			bus_write_4(sc->sc_base.sc_mem,
206fd8d34ceSJustin Hibbits 			    HASHTABLE_CTRL, i);
207fd8d34ceSJustin Hibbits 	}
208fd8d34ceSJustin Hibbits 
209fd8d34ceSJustin Hibbits 	if_foreach_llmaddr(sc->sc_base.sc_ifnet, memac_hash_maddr, sc);
210fd8d34ceSJustin Hibbits }
211fd8d34ceSJustin Hibbits 
212fd8d34ceSJustin Hibbits static void
memac_setup_promisc(struct memac_softc * sc)213fd8d34ceSJustin Hibbits memac_setup_promisc(struct memac_softc *sc)
214fd8d34ceSJustin Hibbits {
215fd8d34ceSJustin Hibbits 	uint32_t reg;
216fd8d34ceSJustin Hibbits 
217fd8d34ceSJustin Hibbits 	reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG);
218fd8d34ceSJustin Hibbits 	reg &= ~COMMAND_CONFIG_PROMISC;
219fd8d34ceSJustin Hibbits 
220fd8d34ceSJustin Hibbits 	if ((if_getflags(sc->sc_base.sc_ifnet) & IFF_PROMISC) != 0)
221fd8d34ceSJustin Hibbits 		bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG,
222fd8d34ceSJustin Hibbits 		    reg | COMMAND_CONFIG_PROMISC);
223fd8d34ceSJustin Hibbits }
224fd8d34ceSJustin Hibbits 
225fd8d34ceSJustin Hibbits static void
memac_if_graceful_stop(struct memac_softc * sc)226fd8d34ceSJustin Hibbits memac_if_graceful_stop(struct memac_softc *sc)
227fd8d34ceSJustin Hibbits {
228fd8d34ceSJustin Hibbits 	struct resource *regs = sc->sc_base.sc_mem;
229fd8d34ceSJustin Hibbits 	uint32_t reg;
230fd8d34ceSJustin Hibbits 
231fd8d34ceSJustin Hibbits 	reg = bus_read_4(regs, MEMAC_COMMAND_CONFIG);
232fd8d34ceSJustin Hibbits 	reg |= COMMAND_CONFIG_RXSTP;
233fd8d34ceSJustin Hibbits 
234fd8d34ceSJustin Hibbits 	bus_write_4(regs, MEMAC_COMMAND_CONFIG, reg);
235fd8d34ceSJustin Hibbits 	while ((bus_read_4(regs, MEMAC_IEVENT) & IEVENT_RX_EMPTY) == 0)
236fd8d34ceSJustin Hibbits 		;
237fd8d34ceSJustin Hibbits 	reg &= COMMAND_CONFIG_RX_EN;
238fd8d34ceSJustin Hibbits 	bus_write_4(regs, MEMAC_COMMAND_CONFIG, reg);
239fd8d34ceSJustin Hibbits 
240fd8d34ceSJustin Hibbits 	while ((bus_read_4(regs, MEMAC_IEVENT) & IEVENT_TX_EMPTY) == 0)
241fd8d34ceSJustin Hibbits 		;
242fd8d34ceSJustin Hibbits 	bus_write_4(regs, MEMAC_COMMAND_CONFIG, reg & ~COMMAND_CONFIG_TX_EN);
243fd8d34ceSJustin Hibbits }
244fd8d34ceSJustin Hibbits 
245fd8d34ceSJustin Hibbits static void
memac_mac_enable(struct memac_softc * sc)246fd8d34ceSJustin Hibbits memac_mac_enable(struct memac_softc *sc)
247fd8d34ceSJustin Hibbits {
248fd8d34ceSJustin Hibbits 	uint32_t reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG);
249fd8d34ceSJustin Hibbits 
250fd8d34ceSJustin Hibbits 	reg |= (COMMAND_CONFIG_RX_EN | COMMAND_CONFIG_TX_EN);
251fd8d34ceSJustin Hibbits 
252fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG, reg);
253fd8d34ceSJustin Hibbits }
254fd8d34ceSJustin Hibbits 
255fd8d34ceSJustin Hibbits static int
memac_if_enable_locked(struct memac_softc * sc)256fd8d34ceSJustin Hibbits memac_if_enable_locked(struct memac_softc *sc)
257fd8d34ceSJustin Hibbits {
258fd8d34ceSJustin Hibbits 	int error;
259fd8d34ceSJustin Hibbits 
260fd8d34ceSJustin Hibbits 	MEMAC_LOCK_ASSERT(sc);
261fd8d34ceSJustin Hibbits 
262fd8d34ceSJustin Hibbits 	memac_set_mtu(sc, if_getmtu(sc->sc_base.sc_ifnet));
263fd8d34ceSJustin Hibbits 	memac_mac_enable(sc);
264fd8d34ceSJustin Hibbits 
265fd8d34ceSJustin Hibbits 	error = FMAN_PORT_ENABLE(sc->sc_base.sc_rx_port);
266fd8d34ceSJustin Hibbits 	if (error != 0)
267fd8d34ceSJustin Hibbits 		return (EIO);
268fd8d34ceSJustin Hibbits 
269fd8d34ceSJustin Hibbits 	error = FMAN_PORT_ENABLE(sc->sc_base.sc_tx_port);
270fd8d34ceSJustin Hibbits 	if (error != 0)
271fd8d34ceSJustin Hibbits 		return (EIO);
272fd8d34ceSJustin Hibbits 
273fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, MEMAC_IEVENT, 0);
274fd8d34ceSJustin Hibbits 	memac_setup_multicast(sc);
275fd8d34ceSJustin Hibbits 	memac_setup_promisc(sc);
276fd8d34ceSJustin Hibbits 
277fd8d34ceSJustin Hibbits 	if_setdrvflagbits(sc->sc_base.sc_ifnet, IFF_DRV_RUNNING, 0);
278fd8d34ceSJustin Hibbits 
279fd8d34ceSJustin Hibbits 	/* Refresh link state */
280fd8d34ceSJustin Hibbits 	memac_miibus_statchg(sc->sc_base.sc_dev);
281fd8d34ceSJustin Hibbits 
282fd8d34ceSJustin Hibbits 	return (0);
283fd8d34ceSJustin Hibbits }
284fd8d34ceSJustin Hibbits 
285fd8d34ceSJustin Hibbits static int
memac_if_disable_locked(struct memac_softc * sc)286fd8d34ceSJustin Hibbits memac_if_disable_locked(struct memac_softc *sc)
287fd8d34ceSJustin Hibbits {
288fd8d34ceSJustin Hibbits 	int error;
289fd8d34ceSJustin Hibbits 
290fd8d34ceSJustin Hibbits 	MEMAC_LOCK_ASSERT(sc);
291fd8d34ceSJustin Hibbits 
292fd8d34ceSJustin Hibbits 	error = FMAN_PORT_DISABLE(sc->sc_base.sc_tx_port);
293fd8d34ceSJustin Hibbits 	if (error != 0)
294fd8d34ceSJustin Hibbits 		return (EIO);
295fd8d34ceSJustin Hibbits 
296fd8d34ceSJustin Hibbits 	memac_if_graceful_stop(sc);
297fd8d34ceSJustin Hibbits 
298fd8d34ceSJustin Hibbits 	error = FMAN_PORT_DISABLE(sc->sc_base.sc_rx_port);
299fd8d34ceSJustin Hibbits 	if (error != 0)
300fd8d34ceSJustin Hibbits 		return (EIO);
301fd8d34ceSJustin Hibbits 
302fd8d34ceSJustin Hibbits 	if_setdrvflagbits(sc->sc_base.sc_ifnet, 0, IFF_DRV_RUNNING);
303fd8d34ceSJustin Hibbits 
304fd8d34ceSJustin Hibbits 	return (0);
305fd8d34ceSJustin Hibbits }
306fd8d34ceSJustin Hibbits 
307fd8d34ceSJustin Hibbits static int
memac_if_ioctl(if_t ifp,u_long command,caddr_t data)308fd8d34ceSJustin Hibbits memac_if_ioctl(if_t ifp, u_long command, caddr_t data)
309fd8d34ceSJustin Hibbits {
310fd8d34ceSJustin Hibbits 	struct memac_softc *sc;
311fd8d34ceSJustin Hibbits 	struct ifreq *ifr;
3126464974cSJustin Hibbits 	uint32_t changed;
313fd8d34ceSJustin Hibbits 	int error;
314fd8d34ceSJustin Hibbits 
315fd8d34ceSJustin Hibbits 	sc = if_getsoftc(ifp);
316fd8d34ceSJustin Hibbits 	ifr = (struct ifreq *)data;
317fd8d34ceSJustin Hibbits 	error = 0;
318fd8d34ceSJustin Hibbits 
319fd8d34ceSJustin Hibbits 	/* Basic functionality to achieve media status reports */
320fd8d34ceSJustin Hibbits 	switch (command) {
321fd8d34ceSJustin Hibbits 	case SIOCSIFMTU:
322fd8d34ceSJustin Hibbits 		MEMAC_LOCK(sc);
323fd8d34ceSJustin Hibbits 		if (memac_set_mtu(sc, ifr->ifr_mtu))
324fd8d34ceSJustin Hibbits 			if_setmtu(ifp, ifr->ifr_mtu);
325fd8d34ceSJustin Hibbits 		else
326fd8d34ceSJustin Hibbits 			error = EINVAL;
327fd8d34ceSJustin Hibbits 		MEMAC_UNLOCK(sc);
328fd8d34ceSJustin Hibbits 		break;
329fd8d34ceSJustin Hibbits 	case SIOCSIFFLAGS:
330fd8d34ceSJustin Hibbits 		MEMAC_LOCK(sc);
331fd8d34ceSJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
332fd8d34ceSJustin Hibbits 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
333fd8d34ceSJustin Hibbits 				memac_if_init_locked(sc);
334fd8d34ceSJustin Hibbits 		} else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
335fd8d34ceSJustin Hibbits 			error = memac_if_disable_locked(sc);
336fd8d34ceSJustin Hibbits 
337fd8d34ceSJustin Hibbits 		MEMAC_UNLOCK(sc);
338fd8d34ceSJustin Hibbits 		break;
339fd8d34ceSJustin Hibbits 
340fd8d34ceSJustin Hibbits 	case SIOCADDMULTI:
341fd8d34ceSJustin Hibbits 	case SIOCDELMULTI:
342fd8d34ceSJustin Hibbits 		if (if_getflags(sc->sc_base.sc_ifnet) & IFF_UP) {
343fd8d34ceSJustin Hibbits 			MEMAC_LOCK(sc);
344fd8d34ceSJustin Hibbits 			memac_setup_multicast(sc);
345fd8d34ceSJustin Hibbits 			MEMAC_UNLOCK(sc);
346fd8d34ceSJustin Hibbits 		}
347fd8d34ceSJustin Hibbits 		break;
348fd8d34ceSJustin Hibbits 
3496464974cSJustin Hibbits 	case SIOCSIFCAP:
3506464974cSJustin Hibbits 		changed = if_getcapenable(ifp) ^ ifr->ifr_reqcap;
3516464974cSJustin Hibbits 		if ((changed & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) != 0)
3526464974cSJustin Hibbits 			if_togglecapenable(ifp,
3536464974cSJustin Hibbits 			    IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6);
3546464974cSJustin Hibbits 		if ((changed & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) != 0) {
3556464974cSJustin Hibbits 			if_togglecapenable(ifp,
3566464974cSJustin Hibbits 			    IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6);
3576464974cSJustin Hibbits 			if_togglehwassist(ifp, DPAA_CSUM_TX_OFFLOAD);
3586464974cSJustin Hibbits 		}
3596464974cSJustin Hibbits 		break;
3606464974cSJustin Hibbits 
361fd8d34ceSJustin Hibbits 	case SIOCGIFMEDIA:
362fd8d34ceSJustin Hibbits 	case SIOCSIFMEDIA:
363fd8d34ceSJustin Hibbits 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_base.sc_mii->mii_media,
364fd8d34ceSJustin Hibbits 		    command);
365fd8d34ceSJustin Hibbits 		break;
366fd8d34ceSJustin Hibbits 
367fd8d34ceSJustin Hibbits 	default:
368fd8d34ceSJustin Hibbits 		error = ether_ioctl(ifp, command, data);
369fd8d34ceSJustin Hibbits 	}
370fd8d34ceSJustin Hibbits 
371fd8d34ceSJustin Hibbits 	return (error);
372fd8d34ceSJustin Hibbits }
373fd8d34ceSJustin Hibbits 
374fd8d34ceSJustin Hibbits static void
memac_if_tick(void * arg)375fd8d34ceSJustin Hibbits memac_if_tick(void *arg)
376fd8d34ceSJustin Hibbits {
377fd8d34ceSJustin Hibbits 	struct memac_softc *sc;
378fd8d34ceSJustin Hibbits 
379fd8d34ceSJustin Hibbits 	sc = arg;
380fd8d34ceSJustin Hibbits 
381fd8d34ceSJustin Hibbits 	/* TODO */
382fd8d34ceSJustin Hibbits 	MEMAC_LOCK(sc);
383fd8d34ceSJustin Hibbits 
384fd8d34ceSJustin Hibbits 	mii_tick(sc->sc_base.sc_mii);
385fd8d34ceSJustin Hibbits 	callout_reset(&sc->sc_base.sc_tick_callout, hz, memac_if_tick, sc);
386fd8d34ceSJustin Hibbits 
387fd8d34ceSJustin Hibbits 	MEMAC_UNLOCK(sc);
388fd8d34ceSJustin Hibbits }
389fd8d34ceSJustin Hibbits 
390fd8d34ceSJustin Hibbits static void
memac_if_deinit_locked(struct memac_softc * sc)391fd8d34ceSJustin Hibbits memac_if_deinit_locked(struct memac_softc *sc)
392fd8d34ceSJustin Hibbits {
393fd8d34ceSJustin Hibbits 
394fd8d34ceSJustin Hibbits 	MEMAC_LOCK_ASSERT(sc);
395fd8d34ceSJustin Hibbits 
396fd8d34ceSJustin Hibbits 	MEMAC_UNLOCK(sc);
397fd8d34ceSJustin Hibbits 	callout_drain(&sc->sc_base.sc_tick_callout);
398fd8d34ceSJustin Hibbits 	MEMAC_LOCK(sc);
399fd8d34ceSJustin Hibbits }
400fd8d34ceSJustin Hibbits 
401fd8d34ceSJustin Hibbits static void
memac_if_set_macaddr(struct memac_softc * sc,const char * addr)402fd8d34ceSJustin Hibbits memac_if_set_macaddr(struct memac_softc *sc, const char *addr)
403fd8d34ceSJustin Hibbits {
404fd8d34ceSJustin Hibbits 	uint32_t reg;
405fd8d34ceSJustin Hibbits 
406fd8d34ceSJustin Hibbits 	reg = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
407fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, MEMAC_MAC_ADDR_0, reg);
408fd8d34ceSJustin Hibbits 	reg = (addr[5] << 8) | (addr[4]);
409fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, MEMAC_MAC_ADDR_1, reg);
410fd8d34ceSJustin Hibbits }
411fd8d34ceSJustin Hibbits 
412fd8d34ceSJustin Hibbits static void
memac_if_init_locked(struct memac_softc * sc)413fd8d34ceSJustin Hibbits memac_if_init_locked(struct memac_softc *sc)
414fd8d34ceSJustin Hibbits {
415fd8d34ceSJustin Hibbits 	int error;
416fd8d34ceSJustin Hibbits 	const char *macaddr;
417fd8d34ceSJustin Hibbits 
418fd8d34ceSJustin Hibbits 	MEMAC_LOCK_ASSERT(sc);
419fd8d34ceSJustin Hibbits 
420fd8d34ceSJustin Hibbits 	macaddr = if_getlladdr(sc->sc_base.sc_ifnet);
421fd8d34ceSJustin Hibbits 	memac_if_set_macaddr(sc, macaddr);
422fd8d34ceSJustin Hibbits 
423fd8d34ceSJustin Hibbits 	/* Start MII polling */
424fd8d34ceSJustin Hibbits 	if (sc->sc_base.sc_mii)
425fd8d34ceSJustin Hibbits 		callout_reset(&sc->sc_base.sc_tick_callout, hz,
426fd8d34ceSJustin Hibbits 		    memac_if_tick, sc);
427fd8d34ceSJustin Hibbits 
428fd8d34ceSJustin Hibbits 	if (if_getflags(sc->sc_base.sc_ifnet) & IFF_UP) {
429fd8d34ceSJustin Hibbits 		error = memac_if_enable_locked(sc);
430fd8d34ceSJustin Hibbits 		if (error != 0)
431fd8d34ceSJustin Hibbits 			goto err;
432fd8d34ceSJustin Hibbits 	} else {
433fd8d34ceSJustin Hibbits 		error = memac_if_disable_locked(sc);
434fd8d34ceSJustin Hibbits 		if (error != 0)
435fd8d34ceSJustin Hibbits 			goto err;
436fd8d34ceSJustin Hibbits 	}
437fd8d34ceSJustin Hibbits 
438fd8d34ceSJustin Hibbits 	if_link_state_change(sc->sc_base.sc_ifnet, LINK_STATE_UP);
439fd8d34ceSJustin Hibbits 
440fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, MEMAC_CL01_PAUSE_QUANTA,
441fd8d34ceSJustin Hibbits 	    DEFAULT_PAUSE_QUANTA);
442fd8d34ceSJustin Hibbits 
443fd8d34ceSJustin Hibbits 	return;
444fd8d34ceSJustin Hibbits 
445fd8d34ceSJustin Hibbits err:
446fd8d34ceSJustin Hibbits 	memac_if_deinit_locked(sc);
447fd8d34ceSJustin Hibbits 	device_printf(sc->sc_base.sc_dev, "initialization error.\n");
448fd8d34ceSJustin Hibbits 	return;
449fd8d34ceSJustin Hibbits }
450fd8d34ceSJustin Hibbits 
451fd8d34ceSJustin Hibbits static void
memac_if_init(void * data)452fd8d34ceSJustin Hibbits memac_if_init(void *data)
453fd8d34ceSJustin Hibbits {
454fd8d34ceSJustin Hibbits 	struct memac_softc *sc;
455fd8d34ceSJustin Hibbits 
456fd8d34ceSJustin Hibbits 	sc = data;
457fd8d34ceSJustin Hibbits 
458fd8d34ceSJustin Hibbits 	MEMAC_LOCK(sc);
459fd8d34ceSJustin Hibbits 	memac_if_init_locked(sc);
460fd8d34ceSJustin Hibbits 	MEMAC_UNLOCK(sc);
461fd8d34ceSJustin Hibbits }
462fd8d34ceSJustin Hibbits 
463fd8d34ceSJustin Hibbits static void
memac_if_start(if_t ifp)464fd8d34ceSJustin Hibbits memac_if_start(if_t ifp)
465fd8d34ceSJustin Hibbits {
466fd8d34ceSJustin Hibbits 	struct memac_softc *sc;
467fd8d34ceSJustin Hibbits 
468fd8d34ceSJustin Hibbits 	sc = if_getsoftc(ifp);
469fd8d34ceSJustin Hibbits 	MEMAC_LOCK(sc);
470fd8d34ceSJustin Hibbits 	dpaa_eth_if_start_locked(&sc->sc_base);
471fd8d34ceSJustin Hibbits 	MEMAC_UNLOCK(sc);
472fd8d34ceSJustin Hibbits }
473fd8d34ceSJustin Hibbits 
474fd8d34ceSJustin Hibbits static void
memac_if_watchdog(if_t ifp)475fd8d34ceSJustin Hibbits memac_if_watchdog(if_t ifp)
476fd8d34ceSJustin Hibbits {
477fd8d34ceSJustin Hibbits 	/* TODO */
478fd8d34ceSJustin Hibbits }
479fd8d34ceSJustin Hibbits /** @} */
480fd8d34ceSJustin Hibbits 
481fd8d34ceSJustin Hibbits 
482fd8d34ceSJustin Hibbits /**
483fd8d34ceSJustin Hibbits  * @group IFmedia routines.
484fd8d34ceSJustin Hibbits  * @{
485fd8d34ceSJustin Hibbits  */
486fd8d34ceSJustin Hibbits static int
memac_ifmedia_upd(if_t ifp)487fd8d34ceSJustin Hibbits memac_ifmedia_upd(if_t ifp)
488fd8d34ceSJustin Hibbits {
489fd8d34ceSJustin Hibbits 	struct memac_softc *sc = if_getsoftc(ifp);
490fd8d34ceSJustin Hibbits 
491fd8d34ceSJustin Hibbits 	return (0);
492fd8d34ceSJustin Hibbits 	MEMAC_LOCK(sc);
493fd8d34ceSJustin Hibbits 	mii_mediachg(sc->sc_base.sc_mii);
494fd8d34ceSJustin Hibbits 	MEMAC_UNLOCK(sc);
495fd8d34ceSJustin Hibbits 
496fd8d34ceSJustin Hibbits 	return (0);
497fd8d34ceSJustin Hibbits }
498fd8d34ceSJustin Hibbits 
499fd8d34ceSJustin Hibbits static void
memac_ifmedia_fixed_sts(if_t ifp,struct ifmediareq * ifmr)500fd8d34ceSJustin Hibbits memac_ifmedia_fixed_sts(if_t ifp, struct ifmediareq *ifmr)
501fd8d34ceSJustin Hibbits {
502fd8d34ceSJustin Hibbits 	struct memac_softc *sc = if_getsoftc(ifp);
503fd8d34ceSJustin Hibbits 
504fd8d34ceSJustin Hibbits 	MEMAC_LOCK(sc);
505fd8d34ceSJustin Hibbits 	ifmr->ifm_count = 1;
506fd8d34ceSJustin Hibbits 	ifmr->ifm_mask = 0;
507fd8d34ceSJustin Hibbits 	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
508fd8d34ceSJustin Hibbits 	ifmr->ifm_current = ifmr->ifm_active =
509fd8d34ceSJustin Hibbits 	    sc->sc_base.sc_mii->mii_media.ifm_cur->ifm_media;
510fd8d34ceSJustin Hibbits 	ifmr->ifm_active = ifmr->ifm_current;
511fd8d34ceSJustin Hibbits 
512fd8d34ceSJustin Hibbits 	/*
513fd8d34ceSJustin Hibbits 	 * In non-PHY usecases, we need to signal link state up, otherwise
514fd8d34ceSJustin Hibbits 	 * certain things requiring a link event (e.g async DHCP client) from
515fd8d34ceSJustin Hibbits 	 * devd do not happen.
516fd8d34ceSJustin Hibbits 	 */
517fd8d34ceSJustin Hibbits 	if (if_getlinkstate(ifp) == LINK_STATE_UNKNOWN) {
518fd8d34ceSJustin Hibbits 		if_link_state_change(ifp, LINK_STATE_UP);
519fd8d34ceSJustin Hibbits 	}
520fd8d34ceSJustin Hibbits 
521fd8d34ceSJustin Hibbits 	/* We assume the link is static, as in a peer switch. */
522fd8d34ceSJustin Hibbits 
523fd8d34ceSJustin Hibbits 	MEMAC_UNLOCK(sc);
524fd8d34ceSJustin Hibbits 
525fd8d34ceSJustin Hibbits 	return;
526fd8d34ceSJustin Hibbits }
527fd8d34ceSJustin Hibbits 
528fd8d34ceSJustin Hibbits static void
memac_ifmedia_sts(if_t ifp,struct ifmediareq * ifmr)529fd8d34ceSJustin Hibbits memac_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
530fd8d34ceSJustin Hibbits {
531fd8d34ceSJustin Hibbits 	struct memac_softc *sc = if_getsoftc(ifp);
532fd8d34ceSJustin Hibbits 
533fd8d34ceSJustin Hibbits 	MEMAC_LOCK(sc);
534fd8d34ceSJustin Hibbits 
535fd8d34ceSJustin Hibbits 	mii_pollstat(sc->sc_base.sc_mii);
536fd8d34ceSJustin Hibbits 
537fd8d34ceSJustin Hibbits 	ifmr->ifm_active = sc->sc_base.sc_mii->mii_media_active;
538fd8d34ceSJustin Hibbits 	ifmr->ifm_status = sc->sc_base.sc_mii->mii_media_status;
539fd8d34ceSJustin Hibbits 
540fd8d34ceSJustin Hibbits 	MEMAC_UNLOCK(sc);
541fd8d34ceSJustin Hibbits }
542fd8d34ceSJustin Hibbits /** @} */
543fd8d34ceSJustin Hibbits 
544fd8d34ceSJustin Hibbits 
545fd8d34ceSJustin Hibbits /**
546fd8d34ceSJustin Hibbits  * @group dTSEC bus interface.
547fd8d34ceSJustin Hibbits  * @{
548fd8d34ceSJustin Hibbits  */
549fd8d34ceSJustin Hibbits 
550fd8d34ceSJustin Hibbits int
memac_attach(device_t dev)551fd8d34ceSJustin Hibbits memac_attach(device_t dev)
552fd8d34ceSJustin Hibbits {
553fd8d34ceSJustin Hibbits 	struct memac_softc *sc;
554fd8d34ceSJustin Hibbits 	int error;
555fd8d34ceSJustin Hibbits 	if_t ifp;
556fd8d34ceSJustin Hibbits 
557fd8d34ceSJustin Hibbits 	sc = device_get_softc(dev);
558fd8d34ceSJustin Hibbits 
559fd8d34ceSJustin Hibbits 	sc->sc_base.sc_dev = dev;
560fd8d34ceSJustin Hibbits 
561fd8d34ceSJustin Hibbits 	/* Init locks */
562fd8d34ceSJustin Hibbits 	mtx_init(&sc->sc_base.sc_lock, device_get_nameunit(dev),
563fd8d34ceSJustin Hibbits 	    "mEMAC Global Lock", MTX_DEF);
564fd8d34ceSJustin Hibbits 
565fd8d34ceSJustin Hibbits 	mtx_init(&sc->sc_base.sc_mii_lock, device_get_nameunit(dev),
566fd8d34ceSJustin Hibbits 	    "mEMAC MII Lock", MTX_DEF);
567fd8d34ceSJustin Hibbits 
568fd8d34ceSJustin Hibbits 	/* Init callouts */
569fd8d34ceSJustin Hibbits 	callout_init(&sc->sc_base.sc_tick_callout, CALLOUT_MPSAFE);
570fd8d34ceSJustin Hibbits 
571fd8d34ceSJustin Hibbits 	/* Create RX buffer pool */
572fd8d34ceSJustin Hibbits 	error = dpaa_eth_pool_rx_init(&sc->sc_base);
573fd8d34ceSJustin Hibbits 	if (error != 0)
574fd8d34ceSJustin Hibbits 		return (EIO);
575fd8d34ceSJustin Hibbits 
576fd8d34ceSJustin Hibbits 	/* Create RX frame queue range */
577fd8d34ceSJustin Hibbits 	error = dpaa_eth_fq_rx_init(&sc->sc_base);
578fd8d34ceSJustin Hibbits 	if (error != 0)
579fd8d34ceSJustin Hibbits 		return (EIO);
580fd8d34ceSJustin Hibbits 
581fd8d34ceSJustin Hibbits 	/* Create frame info pool */
582fd8d34ceSJustin Hibbits 	error = dpaa_eth_fi_pool_init(&sc->sc_base);
583fd8d34ceSJustin Hibbits 	if (error != 0)
584fd8d34ceSJustin Hibbits 		return (EIO);
585fd8d34ceSJustin Hibbits 
586fd8d34ceSJustin Hibbits 	/* Create TX frame queue range */
587fd8d34ceSJustin Hibbits 	error = dpaa_eth_fq_tx_init(&sc->sc_base);
588fd8d34ceSJustin Hibbits 	if (error != 0)
589fd8d34ceSJustin Hibbits 		return (EIO);
590fd8d34ceSJustin Hibbits 
591fd8d34ceSJustin Hibbits 	/* Init FMan MAC module. */
592fd8d34ceSJustin Hibbits 	error = memac_fm_mac_init(sc, sc->sc_base.sc_mac_addr);
593fd8d34ceSJustin Hibbits 	if (error != 0) {
594fd8d34ceSJustin Hibbits 		memac_detach(dev);
595fd8d34ceSJustin Hibbits 		return (ENXIO);
596fd8d34ceSJustin Hibbits 	}
597fd8d34ceSJustin Hibbits 
598fd8d34ceSJustin Hibbits 	dpaa_eth_fm_port_rx_init(&sc->sc_base);
599fd8d34ceSJustin Hibbits 	dpaa_eth_fm_port_tx_init(&sc->sc_base);
600fd8d34ceSJustin Hibbits 
601fd8d34ceSJustin Hibbits 	/* Create network interface for upper layers */
602fd8d34ceSJustin Hibbits 	ifp = sc->sc_base.sc_ifnet = if_alloc(IFT_ETHER);
603fd8d34ceSJustin Hibbits 	if_setsoftc(ifp, sc);
604fd8d34ceSJustin Hibbits 
605fd8d34ceSJustin Hibbits 	if_setflags(ifp, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST);
606fd8d34ceSJustin Hibbits 	if_setinitfn(ifp, memac_if_init);
607fd8d34ceSJustin Hibbits 	if_setstartfn(ifp, memac_if_start);
608fd8d34ceSJustin Hibbits 	if_setioctlfn(ifp, memac_if_ioctl);
609fd8d34ceSJustin Hibbits 	if_setsendqlen(ifp, IFQ_MAXLEN);
610fd8d34ceSJustin Hibbits 	if_setsendqready(ifp);
611fd8d34ceSJustin Hibbits 
612fd8d34ceSJustin Hibbits 	if (sc->sc_base.sc_phy_addr >= 0)
613fd8d34ceSJustin Hibbits 		if_initname(ifp, device_get_name(sc->sc_base.sc_dev),
614fd8d34ceSJustin Hibbits 		    device_get_unit(sc->sc_base.sc_dev));
615fd8d34ceSJustin Hibbits 	else
616fd8d34ceSJustin Hibbits 		if_initname(ifp, "memac_phy",
617fd8d34ceSJustin Hibbits 		    device_get_unit(sc->sc_base.sc_dev));
618fd8d34ceSJustin Hibbits 
619fd8d34ceSJustin Hibbits 
6209d423705SJustin Hibbits 	if_setcapabilities(ifp, IFCAP_JUMBO_MTU |
6219d423705SJustin Hibbits 	    IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM |
6226464974cSJustin Hibbits 	    IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 |
6236464974cSJustin Hibbits 	    IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6);
624fd8d34ceSJustin Hibbits 	if_setcapenable(ifp, if_getcapabilities(ifp));
6256464974cSJustin Hibbits 	if_sethwassist(ifp, DPAA_CSUM_TX_OFFLOAD);
626fd8d34ceSJustin Hibbits 
627fd8d34ceSJustin Hibbits 	/* Attach PHY(s) */
628fd8d34ceSJustin Hibbits 	if (!sc->sc_fixed_link) {
629fd8d34ceSJustin Hibbits 		error = mii_attach(sc->sc_base.sc_dev, &sc->sc_base.sc_mii_dev,
630fd8d34ceSJustin Hibbits 		    ifp, memac_ifmedia_upd, memac_ifmedia_sts, BMSR_DEFCAPMASK,
631fd8d34ceSJustin Hibbits 		    sc->sc_base.sc_phy_addr, MII_OFFSET_ANY, 0);
632fd8d34ceSJustin Hibbits 		if (error) {
633fd8d34ceSJustin Hibbits 			device_printf(sc->sc_base.sc_dev,
634fd8d34ceSJustin Hibbits 			    "attaching PHYs failed: %d\n", error);
635fd8d34ceSJustin Hibbits 			memac_detach(sc->sc_base.sc_dev);
636fd8d34ceSJustin Hibbits 			return (error);
637fd8d34ceSJustin Hibbits 		}
638fd8d34ceSJustin Hibbits 		sc->sc_base.sc_mii = device_get_softc(sc->sc_base.sc_mii_dev);
639fd8d34ceSJustin Hibbits 	} else {
640fd8d34ceSJustin Hibbits 		phandle_t node;
641fd8d34ceSJustin Hibbits 		uint32_t type = IFM_ETHER;
642fd8d34ceSJustin Hibbits 		uint32_t speed;
643fd8d34ceSJustin Hibbits 
644fd8d34ceSJustin Hibbits 		node = ofw_bus_find_child(ofw_bus_get_node(dev), "fixed-link");
645fd8d34ceSJustin Hibbits 		if (OF_getencprop(node, "speed", &speed, sizeof(speed)) <= 0) {
646fd8d34ceSJustin Hibbits 			device_printf(dev,
647fd8d34ceSJustin Hibbits 			    "fixed link has no speed property\n");
648fd8d34ceSJustin Hibbits 			memac_detach(sc->sc_base.sc_dev);
649fd8d34ceSJustin Hibbits 			return (ENXIO);
650fd8d34ceSJustin Hibbits 		}
651fd8d34ceSJustin Hibbits 		switch (speed) {
652fd8d34ceSJustin Hibbits 		case 10:
653fd8d34ceSJustin Hibbits 			type |= IFM_10_T;
654fd8d34ceSJustin Hibbits 			break;
655fd8d34ceSJustin Hibbits 		case 100:
656fd8d34ceSJustin Hibbits 			type |= IFM_100_TX;
657fd8d34ceSJustin Hibbits 			break;
658fd8d34ceSJustin Hibbits 		case 1000:
659fd8d34ceSJustin Hibbits 			type |= IFM_1000_T;
660fd8d34ceSJustin Hibbits 			break;
661fd8d34ceSJustin Hibbits 		case 2500:
662fd8d34ceSJustin Hibbits 			type |= IFM_2500_T;
663fd8d34ceSJustin Hibbits 			break;
664fd8d34ceSJustin Hibbits 		case 5000:
665fd8d34ceSJustin Hibbits 			type |= IFM_5000_T;
666fd8d34ceSJustin Hibbits 			break;
667fd8d34ceSJustin Hibbits 		case 10000:
668fd8d34ceSJustin Hibbits 			type |= IFM_10G_T;
669fd8d34ceSJustin Hibbits 			break;
670fd8d34ceSJustin Hibbits 		}
671fd8d34ceSJustin Hibbits 		if (OF_hasprop(node, "full-duplex"))
672fd8d34ceSJustin Hibbits 			type |= IFM_FDX;
673fd8d34ceSJustin Hibbits 		sc->sc_base.sc_mii = malloc(sizeof(*sc->sc_base.sc_mii),
674fd8d34ceSJustin Hibbits 		    M_DEVBUF, M_WAITOK | M_ZERO);
675fd8d34ceSJustin Hibbits 		ifmedia_init(&sc->sc_base.sc_mii->mii_media, 0,
676fd8d34ceSJustin Hibbits 		    memac_ifmedia_upd, memac_ifmedia_fixed_sts);
677fd8d34ceSJustin Hibbits 		ifmedia_add(&sc->sc_base.sc_mii->mii_media, type, 0, NULL);
678fd8d34ceSJustin Hibbits 		ifmedia_set(&sc->sc_base.sc_mii->mii_media, type);
679fd8d34ceSJustin Hibbits 	}
680fd8d34ceSJustin Hibbits 
681fd8d34ceSJustin Hibbits 	/* Attach to stack */
682fd8d34ceSJustin Hibbits 	ether_ifattach(ifp, sc->sc_base.sc_mac_addr);
683fd8d34ceSJustin Hibbits 
684fd8d34ceSJustin Hibbits 	return (0);
685fd8d34ceSJustin Hibbits }
686fd8d34ceSJustin Hibbits 
687fd8d34ceSJustin Hibbits int
memac_detach(device_t dev)688fd8d34ceSJustin Hibbits memac_detach(device_t dev)
689fd8d34ceSJustin Hibbits {
690fd8d34ceSJustin Hibbits 	struct memac_softc *sc;
691fd8d34ceSJustin Hibbits 	if_t ifp;
692fd8d34ceSJustin Hibbits 
693fd8d34ceSJustin Hibbits 	sc = device_get_softc(dev);
694fd8d34ceSJustin Hibbits 	ifp = sc->sc_base.sc_ifnet;
695fd8d34ceSJustin Hibbits 
696fd8d34ceSJustin Hibbits 	if (device_is_attached(dev)) {
697fd8d34ceSJustin Hibbits 		ether_ifdetach(ifp);
698fd8d34ceSJustin Hibbits 		/* Shutdown interface */
699fd8d34ceSJustin Hibbits 		MEMAC_LOCK(sc);
700fd8d34ceSJustin Hibbits 		memac_if_deinit_locked(sc);
701fd8d34ceSJustin Hibbits 		MEMAC_UNLOCK(sc);
702fd8d34ceSJustin Hibbits 	}
703fd8d34ceSJustin Hibbits 
704fd8d34ceSJustin Hibbits 	if (sc->sc_base.sc_ifnet) {
705fd8d34ceSJustin Hibbits 		if_free(sc->sc_base.sc_ifnet);
706fd8d34ceSJustin Hibbits 		sc->sc_base.sc_ifnet = NULL;
707fd8d34ceSJustin Hibbits 	}
708fd8d34ceSJustin Hibbits 
709fd8d34ceSJustin Hibbits 	/* Free RX/TX FQRs */
710fd8d34ceSJustin Hibbits 	dpaa_eth_fq_rx_free(&sc->sc_base);
711fd8d34ceSJustin Hibbits 	dpaa_eth_fq_tx_free(&sc->sc_base);
712fd8d34ceSJustin Hibbits 
713fd8d34ceSJustin Hibbits 	/* Free frame info pool */
714fd8d34ceSJustin Hibbits 	dpaa_eth_fi_pool_free(&sc->sc_base);
715fd8d34ceSJustin Hibbits 
716fd8d34ceSJustin Hibbits 	/* Free RX buffer pool */
717fd8d34ceSJustin Hibbits 	dpaa_eth_pool_rx_free(&sc->sc_base);
718fd8d34ceSJustin Hibbits 
719fd8d34ceSJustin Hibbits 	/* Destroy lock */
720fd8d34ceSJustin Hibbits 	mtx_destroy(&sc->sc_base.sc_lock);
721fd8d34ceSJustin Hibbits 
722fd8d34ceSJustin Hibbits 	return (0);
723fd8d34ceSJustin Hibbits }
724fd8d34ceSJustin Hibbits 
725fd8d34ceSJustin Hibbits int
memac_suspend(device_t dev)726fd8d34ceSJustin Hibbits memac_suspend(device_t dev)
727fd8d34ceSJustin Hibbits {
728fd8d34ceSJustin Hibbits 
729fd8d34ceSJustin Hibbits 	return (0);
730fd8d34ceSJustin Hibbits }
731fd8d34ceSJustin Hibbits 
732fd8d34ceSJustin Hibbits int
memac_resume(device_t dev)733fd8d34ceSJustin Hibbits memac_resume(device_t dev)
734fd8d34ceSJustin Hibbits {
735fd8d34ceSJustin Hibbits 
736fd8d34ceSJustin Hibbits 	return (0);
737fd8d34ceSJustin Hibbits }
738fd8d34ceSJustin Hibbits 
739fd8d34ceSJustin Hibbits int
memac_shutdown(device_t dev)740fd8d34ceSJustin Hibbits memac_shutdown(device_t dev)
741fd8d34ceSJustin Hibbits {
742fd8d34ceSJustin Hibbits 
743fd8d34ceSJustin Hibbits 	return (0);
744fd8d34ceSJustin Hibbits }
745fd8d34ceSJustin Hibbits /** @} */
746fd8d34ceSJustin Hibbits 
747fd8d34ceSJustin Hibbits 
748fd8d34ceSJustin Hibbits /**
749fd8d34ceSJustin Hibbits  * @group MII bus interface.
750fd8d34ceSJustin Hibbits  * @{
751fd8d34ceSJustin Hibbits  */
752fd8d34ceSJustin Hibbits int
memac_miibus_readreg(device_t dev,int phy,int reg)753fd8d34ceSJustin Hibbits memac_miibus_readreg(device_t dev, int phy, int reg)
754fd8d34ceSJustin Hibbits {
755fd8d34ceSJustin Hibbits 	struct memac_softc *sc;
756fd8d34ceSJustin Hibbits 
757fd8d34ceSJustin Hibbits 	sc = device_get_softc(dev);
758fd8d34ceSJustin Hibbits 
759fd8d34ceSJustin Hibbits 	return (MIIBUS_READREG(sc->sc_base.sc_mdio, phy, reg));
760fd8d34ceSJustin Hibbits }
761fd8d34ceSJustin Hibbits 
762fd8d34ceSJustin Hibbits int
memac_miibus_writereg(device_t dev,int phy,int reg,int value)763fd8d34ceSJustin Hibbits memac_miibus_writereg(device_t dev, int phy, int reg, int value)
764fd8d34ceSJustin Hibbits {
765fd8d34ceSJustin Hibbits 
766fd8d34ceSJustin Hibbits 	struct memac_softc *sc;
767fd8d34ceSJustin Hibbits 
768fd8d34ceSJustin Hibbits 	sc = device_get_softc(dev);
769fd8d34ceSJustin Hibbits 
770fd8d34ceSJustin Hibbits 	return (MIIBUS_WRITEREG(sc->sc_base.sc_mdio, phy, reg, value));
771fd8d34ceSJustin Hibbits }
772fd8d34ceSJustin Hibbits 
773fd8d34ceSJustin Hibbits void
memac_miibus_statchg(device_t dev)774fd8d34ceSJustin Hibbits memac_miibus_statchg(device_t dev)
775fd8d34ceSJustin Hibbits {
776fd8d34ceSJustin Hibbits 	struct memac_softc *sc;
777fd8d34ceSJustin Hibbits 	uint32_t reg;
778fd8d34ceSJustin Hibbits 	bool duplex;
779fd8d34ceSJustin Hibbits 	int speed;
780fd8d34ceSJustin Hibbits 
781fd8d34ceSJustin Hibbits 	sc = device_get_softc(dev);
782fd8d34ceSJustin Hibbits 
783fd8d34ceSJustin Hibbits 	MEMAC_LOCK_ASSERT(sc);
784fd8d34ceSJustin Hibbits 
785fd8d34ceSJustin Hibbits 	duplex = ((sc->sc_base.sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX);
786fd8d34ceSJustin Hibbits 
787fd8d34ceSJustin Hibbits 	switch (IFM_SUBTYPE(sc->sc_base.sc_mii->mii_media_active)) {
788fd8d34ceSJustin Hibbits 	case IFM_AUTO:
789fd8d34ceSJustin Hibbits 		speed = IF_MODE_ENA;
790fd8d34ceSJustin Hibbits 		break;
791fd8d34ceSJustin Hibbits 	case IFM_1000_T:
792fd8d34ceSJustin Hibbits 	case IFM_1000_SX:
793fd8d34ceSJustin Hibbits 		if (!duplex) {
794fd8d34ceSJustin Hibbits 			device_printf(sc->sc_base.sc_dev,
795fd8d34ceSJustin Hibbits 			    "Only full-duplex supported for 1Gbps speeds");
796fd8d34ceSJustin Hibbits 			return;
797fd8d34ceSJustin Hibbits 		}
798fd8d34ceSJustin Hibbits 		speed = IF_MODE_SSP_1GB;
799fd8d34ceSJustin Hibbits 		break;
800fd8d34ceSJustin Hibbits 
801fd8d34ceSJustin Hibbits 	case IFM_100_TX:
802fd8d34ceSJustin Hibbits 		speed = IF_MODE_SSP_100MB;
803fd8d34ceSJustin Hibbits 		break;
804fd8d34ceSJustin Hibbits 	default:
805fd8d34ceSJustin Hibbits 		speed = IF_MODE_SSP_10MB;
806fd8d34ceSJustin Hibbits 		break;
807fd8d34ceSJustin Hibbits 	}
808fd8d34ceSJustin Hibbits 
809fd8d34ceSJustin Hibbits 	reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_IF_MODE);
810fd8d34ceSJustin Hibbits 	reg &= ~(IF_MODE_ENA | IF_MODE_SSP_M | IF_MODE_SFD);
811fd8d34ceSJustin Hibbits 	reg |= 0x2;
812fd8d34ceSJustin Hibbits 
813fd8d34ceSJustin Hibbits 	if (duplex)
814fd8d34ceSJustin Hibbits 		reg |= IF_MODE_SFD;
815fd8d34ceSJustin Hibbits 	else
816fd8d34ceSJustin Hibbits 		reg |= IF_MODE_HD;
817fd8d34ceSJustin Hibbits 	reg |= speed;
818fd8d34ceSJustin Hibbits 	bus_write_4(sc->sc_base.sc_mem, MEMAC_IF_MODE, reg);
819fd8d34ceSJustin Hibbits }
820fd8d34ceSJustin Hibbits /** @} */
821