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