1f9f848faSopenharmony_ci/*-
2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
3f9f848faSopenharmony_ci *
4f9f848faSopenharmony_ci * Copyright (c) 2013-2014 Kevin Lo
5f9f848faSopenharmony_ci * All rights reserved.
6f9f848faSopenharmony_ci *
7f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without
8f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions
9f9f848faSopenharmony_ci * are met:
10f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright
11f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer.
12f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
13f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
14f9f848faSopenharmony_ci *    documentation and/or other materials provided with the distribution.
15f9f848faSopenharmony_ci *
16f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f9f848faSopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f9f848faSopenharmony_ci * SUCH DAMAGE.
27f9f848faSopenharmony_ci */
28f9f848faSopenharmony_ci
29f9f848faSopenharmony_ci#include <sys/cdefs.h>
30f9f848faSopenharmony_ci/*
31f9f848faSopenharmony_ci * ASIX Electronics AX88178A/AX88179/AX88179A USB 2.0/3.0 gigabit ethernet
32f9f848faSopenharmony_ci * driver.
33f9f848faSopenharmony_ci */
34f9f848faSopenharmony_ci
35f9f848faSopenharmony_ci#include <lwip/netif.h>
36f9f848faSopenharmony_ci#include <lwip/dhcp.h>
37f9f848faSopenharmony_ci#include <lwip/netifapi.h>
38f9f848faSopenharmony_ci#include <lwip/inet.h>
39f9f848faSopenharmony_ci
40f9f848faSopenharmony_ci#include "implementation/global_implementation.h"
41f9f848faSopenharmony_ci#include "usb_ethernet.h"
42f9f848faSopenharmony_ci#include "if_axgereg.h"
43f9f848faSopenharmony_ci
44f9f848faSopenharmony_cistatic void axge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen);
45f9f848faSopenharmony_cistatic void axge_miibus_statchg(struct axge_softc *sc, uint8_t link_status);
46f9f848faSopenharmony_ci
47f9f848faSopenharmony_ci#define	IFF_DRV_OACTIVE  IFF_MASTER
48f9f848faSopenharmony_ci#define	IFF_SIMPLEX	  IFF_SLAVE
49f9f848faSopenharmony_ci
50f9f848faSopenharmony_ci#undef USB_DEBUG_VAR
51f9f848faSopenharmony_ci#define	USB_DEBUG_VAR   axge_debug
52f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG
53f9f848faSopenharmony_cistatic int axge_debug = 0;
54f9f848faSopenharmony_civoid
55f9f848faSopenharmony_ciusb_axge_debug_func(int level)
56f9f848faSopenharmony_ci{
57f9f848faSopenharmony_ci	axge_debug = level;
58f9f848faSopenharmony_ci	PRINTK("The level of usb axge debug is %d\n", level);
59f9f848faSopenharmony_ci}
60f9f848faSopenharmony_ciDEBUG_MODULE(axge, usb_axge_debug_func);
61f9f848faSopenharmony_ci#endif
62f9f848faSopenharmony_ci
63f9f848faSopenharmony_ci/*
64f9f848faSopenharmony_ci * Various supported device vendors/products.
65f9f848faSopenharmony_ci */
66f9f848faSopenharmony_cistatic const STRUCT_USB_HOST_ID axge_devs[] = {
67f9f848faSopenharmony_ci	{ USB_VPI(0x0B95, 0x178A, AXE_FLAG_178A) },
68f9f848faSopenharmony_ci};
69f9f848faSopenharmony_ci
70f9f848faSopenharmony_cistatic device_probe_t axge_probe;
71f9f848faSopenharmony_cistatic device_attach_t axge_attach;
72f9f848faSopenharmony_cistatic device_detach_t axge_detach;
73f9f848faSopenharmony_ci
74f9f848faSopenharmony_cistatic usb_callback_t axge_bulk_read_callback;
75f9f848faSopenharmony_cistatic usb_callback_t axge_bulk_write_callback;
76f9f848faSopenharmony_ci
77f9f848faSopenharmony_cistatic uether_fn_t axge_attach_post;
78f9f848faSopenharmony_cistatic uether_fn_t axge_init;
79f9f848faSopenharmony_cistatic uether_fn_t axge_stop;
80f9f848faSopenharmony_cistatic uether_fn_t axge_start;
81f9f848faSopenharmony_cistatic uether_fn_t axge_setmulti;
82f9f848faSopenharmony_cistatic uether_fn_t axge_setpromisc;
83f9f848faSopenharmony_cistatic uether_fn_t axge_tick;
84f9f848faSopenharmony_ci
85f9f848faSopenharmony_cistatic const struct usb_config axge_config[AXGE_N_TRANSFER] = {
86f9f848faSopenharmony_ci	{ /* [AXGE_BULK_DT_WR] = */
87f9f848faSopenharmony_ci		.type = UE_BULK,
88f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
89f9f848faSopenharmony_ci		.direction = UE_DIR_OUT,
90f9f848faSopenharmony_ci		.frames = 16,
91f9f848faSopenharmony_ci		.bufsize = 16 * MCLBYTES,
92f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
93f9f848faSopenharmony_ci		.callback = axge_bulk_write_callback,
94f9f848faSopenharmony_ci		.timeout = 10000,	/* 10 seconds */
95f9f848faSopenharmony_ci	},
96f9f848faSopenharmony_ci	{ /* [AXGE_BULK_DT_RD] = */
97f9f848faSopenharmony_ci		.type = UE_BULK,
98f9f848faSopenharmony_ci		.endpoint = UE_ADDR_ANY,
99f9f848faSopenharmony_ci		.direction = UE_DIR_IN,
100f9f848faSopenharmony_ci		.bufsize = 16 * MCLBYTES,	/* bytes */
101f9f848faSopenharmony_ci		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
102f9f848faSopenharmony_ci		.callback = axge_bulk_read_callback,
103f9f848faSopenharmony_ci		.timeout = 0,	/* no timeout */
104f9f848faSopenharmony_ci	},
105f9f848faSopenharmony_ci};
106f9f848faSopenharmony_ci
107f9f848faSopenharmony_cistatic const struct {
108f9f848faSopenharmony_ci	uint8_t ctrl;
109f9f848faSopenharmony_ci	uint8_t timer_l;
110f9f848faSopenharmony_ci	uint8_t timer_h;
111f9f848faSopenharmony_ci	uint8_t size;
112f9f848faSopenharmony_ci	uint8_t ifg;
113f9f848faSopenharmony_ci}__packed axge_bulk_size[] = {
114f9f848faSopenharmony_ci	{ 7, 0x4f, 0x00, 0x12, 0xff },
115f9f848faSopenharmony_ci	{ 7, 0x20, 0x03, 0x16, 0xff },
116f9f848faSopenharmony_ci	{ 7, 0xae, 0x07, 0x18, 0xff },
117f9f848faSopenharmony_ci	{ 7, 0xcc, 0x4c, 0x18, 0x08 }
118f9f848faSopenharmony_ci};
119f9f848faSopenharmony_ci
120f9f848faSopenharmony_cistatic device_method_t axge_methods[] = {
121f9f848faSopenharmony_ci	/* Device interface */
122f9f848faSopenharmony_ci	DEVMETHOD(device_probe, axge_probe),
123f9f848faSopenharmony_ci	DEVMETHOD(device_attach, axge_attach),
124f9f848faSopenharmony_ci	DEVMETHOD(device_detach, axge_detach),
125f9f848faSopenharmony_ci	DEVMETHOD_END
126f9f848faSopenharmony_ci};
127f9f848faSopenharmony_ci
128f9f848faSopenharmony_cistatic driver_t axge_driver = {
129f9f848faSopenharmony_ci	.name = "USB_AXGE",
130f9f848faSopenharmony_ci	.methods = axge_methods,
131f9f848faSopenharmony_ci	.size = sizeof(struct axge_softc),
132f9f848faSopenharmony_ci};
133f9f848faSopenharmony_ci
134f9f848faSopenharmony_cistatic devclass_t axge_devclass;
135f9f848faSopenharmony_ciDRIVER_MODULE(axge, uhub, axge_driver, axge_devclass, 0, 0);
136f9f848faSopenharmony_ci
137f9f848faSopenharmony_cistatic const struct usb_ether_methods axge_ue_methods = {
138f9f848faSopenharmony_ci	.ue_attach_post = axge_attach_post,
139f9f848faSopenharmony_ci	.ue_start = axge_start,
140f9f848faSopenharmony_ci	.ue_init = axge_init,
141f9f848faSopenharmony_ci	.ue_stop = axge_stop,
142f9f848faSopenharmony_ci	.ue_setmulti = axge_setmulti,
143f9f848faSopenharmony_ci	.ue_setpromisc = axge_setpromisc,
144f9f848faSopenharmony_ci	.ue_tick = axge_tick,
145f9f848faSopenharmony_ci};
146f9f848faSopenharmony_ci
147f9f848faSopenharmony_cistatic void
148f9f848faSopenharmony_ciaxge_write_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index,
149f9f848faSopenharmony_ci			    uint16_t val, void *buf, unsigned int len)
150f9f848faSopenharmony_ci{
151f9f848faSopenharmony_ci	struct usb_device_request req;
152f9f848faSopenharmony_ci
153f9f848faSopenharmony_ci	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
154f9f848faSopenharmony_ci	req.bRequest = cmd;
155f9f848faSopenharmony_ci	USETW(req.wValue, val);
156f9f848faSopenharmony_ci	USETW(req.wIndex, index);
157f9f848faSopenharmony_ci	USETW(req.wLength, len);
158f9f848faSopenharmony_ci
159f9f848faSopenharmony_ci	if (uether_do_request(&sc->sc_ue, &req, buf, 1000)) {
160f9f848faSopenharmony_ci		/* Error ignored. */
161f9f848faSopenharmony_ci	}
162f9f848faSopenharmony_ci}
163f9f848faSopenharmony_ci
164f9f848faSopenharmony_cistatic void
165f9f848faSopenharmony_ciaxge_write_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg, uint8_t val)
166f9f848faSopenharmony_ci{
167f9f848faSopenharmony_ci	axge_write_mem(sc, cmd, 1, reg, &val, 1);
168f9f848faSopenharmony_ci}
169f9f848faSopenharmony_ci
170f9f848faSopenharmony_cistatic void
171f9f848faSopenharmony_ciaxge_write_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index,
172f9f848faSopenharmony_ci			    uint16_t reg, uint16_t val)
173f9f848faSopenharmony_ci{
174f9f848faSopenharmony_ci	uint8_t temp[2];
175f9f848faSopenharmony_ci
176f9f848faSopenharmony_ci	USETW(temp, val);
177f9f848faSopenharmony_ci	axge_write_mem(sc, cmd, index, reg, &temp, 2);
178f9f848faSopenharmony_ci}
179f9f848faSopenharmony_ci
180f9f848faSopenharmony_ci
181f9f848faSopenharmony_cistatic int
182f9f848faSopenharmony_ciaxge_read_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index,
183f9f848faSopenharmony_ci			    uint16_t val, void *buf, int len)
184f9f848faSopenharmony_ci{
185f9f848faSopenharmony_ci	struct usb_device_request req;
186f9f848faSopenharmony_ci
187f9f848faSopenharmony_ci	AXGE_LOCK_ASSERT(sc, MA_OWNED);
188f9f848faSopenharmony_ci
189f9f848faSopenharmony_ci	req.bmRequestType = UT_READ_VENDOR_DEVICE;
190f9f848faSopenharmony_ci	req.bRequest = cmd;
191f9f848faSopenharmony_ci	USETW(req.wValue, val);
192f9f848faSopenharmony_ci	USETW(req.wIndex, index);
193f9f848faSopenharmony_ci	USETW(req.wLength, len);
194f9f848faSopenharmony_ci
195f9f848faSopenharmony_ci	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
196f9f848faSopenharmony_ci}
197f9f848faSopenharmony_ci
198f9f848faSopenharmony_cistatic uint8_t
199f9f848faSopenharmony_ciaxge_read_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg)
200f9f848faSopenharmony_ci{
201f9f848faSopenharmony_ci	uint8_t val;
202f9f848faSopenharmony_ci
203f9f848faSopenharmony_ci	(void)axge_read_mem(sc, cmd, 1, reg, &val, 1);
204f9f848faSopenharmony_ci	return (val);
205f9f848faSopenharmony_ci}
206f9f848faSopenharmony_ci
207f9f848faSopenharmony_cistatic uint16_t
208f9f848faSopenharmony_ciaxge_read_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index, uint16_t reg)
209f9f848faSopenharmony_ci{
210f9f848faSopenharmony_ci	uint8_t val[2];
211f9f848faSopenharmony_ci
212f9f848faSopenharmony_ci	(void)axge_read_mem(sc, cmd, index, reg, &val, 2);
213f9f848faSopenharmony_ci	return (UGETW(val));
214f9f848faSopenharmony_ci}
215f9f848faSopenharmony_ci
216f9f848faSopenharmony_cistatic void
217f9f848faSopenharmony_ciaxge_chip_init(struct axge_softc *sc)
218f9f848faSopenharmony_ci{
219f9f848faSopenharmony_ci	/* Power up ethernet PHY. */
220f9f848faSopenharmony_ci	axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, 0);
221f9f848faSopenharmony_ci	axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, EPPRCR_IPRL);
222f9f848faSopenharmony_ci	(void)uether_pause(&sc->sc_ue, hz / 4);
223f9f848faSopenharmony_ci	axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CLK_SELECT,
224f9f848faSopenharmony_ci				    AXGE_CLK_SELECT_ACS | AXGE_CLK_SELECT_BCS);
225f9f848faSopenharmony_ci	(void)uether_pause(&sc->sc_ue, hz / 10);
226f9f848faSopenharmony_ci}
227f9f848faSopenharmony_ci
228f9f848faSopenharmony_cistatic void
229f9f848faSopenharmony_ciaxge_csum_cfg(struct usb_ether *ue)
230f9f848faSopenharmony_ci{
231f9f848faSopenharmony_ci	struct axge_softc *sc = ue->ue_sc;
232f9f848faSopenharmony_ci	uint8_t csum;
233f9f848faSopenharmony_ci
234f9f848faSopenharmony_ci	csum = 0;
235f9f848faSopenharmony_ci	csum |= CTCR_IP | CTCR_TCP | CTCR_UDP;
236f9f848faSopenharmony_ci	axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CTCR, csum);
237f9f848faSopenharmony_ci
238f9f848faSopenharmony_ci	csum = 0;
239f9f848faSopenharmony_ci	csum |= CRCR_IP | CRCR_TCP | CRCR_UDP;
240f9f848faSopenharmony_ci	axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CRCR, csum);
241f9f848faSopenharmony_ci}
242f9f848faSopenharmony_ci
243f9f848faSopenharmony_cistatic void
244f9f848faSopenharmony_ciaxge_setmulti(struct usb_ether *ue)
245f9f848faSopenharmony_ci{
246f9f848faSopenharmony_ci	struct axge_softc *sc = ue->ue_sc;
247f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
248f9f848faSopenharmony_ci	uint16_t rxmode;
249f9f848faSopenharmony_ci
250f9f848faSopenharmony_ci	rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR);
251f9f848faSopenharmony_ci	if (ifp->ac_if.flags & (IFF_ALLMULTI | IFF_PROMISC)) {
252f9f848faSopenharmony_ci		rxmode |= RCR_AMALL;
253f9f848faSopenharmony_ci		axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
254f9f848faSopenharmony_ci		return;
255f9f848faSopenharmony_ci	}
256f9f848faSopenharmony_ci
257f9f848faSopenharmony_ci	rxmode &= ~RCR_AMALL;
258f9f848faSopenharmony_ci	axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
259f9f848faSopenharmony_ci}
260f9f848faSopenharmony_ci
261f9f848faSopenharmony_cistatic void
262f9f848faSopenharmony_ciaxge_setpromisc(struct usb_ether *ue)
263f9f848faSopenharmony_ci{
264f9f848faSopenharmony_ci	struct axge_softc *sc = uether_getsc(ue);
265f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
266f9f848faSopenharmony_ci	uint16_t rxmode;
267f9f848faSopenharmony_ci
268f9f848faSopenharmony_ci	rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR);
269f9f848faSopenharmony_ci
270f9f848faSopenharmony_ci	if (ifp->ac_if.flags & IFF_PROMISC)
271f9f848faSopenharmony_ci		rxmode |= RCR_PRO;
272f9f848faSopenharmony_ci	else
273f9f848faSopenharmony_ci		rxmode &= ~RCR_PRO;
274f9f848faSopenharmony_ci
275f9f848faSopenharmony_ci	axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
276f9f848faSopenharmony_ci	axge_setmulti(ue);
277f9f848faSopenharmony_ci}
278f9f848faSopenharmony_ci
279f9f848faSopenharmony_cistatic void
280f9f848faSopenharmony_ciaxge_tick(struct usb_ether *ue)
281f9f848faSopenharmony_ci{
282f9f848faSopenharmony_ci	struct axge_softc *sc = uether_getsc(ue);
283f9f848faSopenharmony_ci	uint8_t link_status;
284f9f848faSopenharmony_ci
285f9f848faSopenharmony_ci	AXGE_LOCK_ASSERT(sc, MA_OWNED);
286f9f848faSopenharmony_ci
287f9f848faSopenharmony_ci	link_status = axge_read_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PLSR);
288f9f848faSopenharmony_ci
289f9f848faSopenharmony_ci	if (sc->sc_link_status != (link_status & AXGE_LINK_MASK)) {
290f9f848faSopenharmony_ci		axge_miibus_statchg(sc, link_status);
291f9f848faSopenharmony_ci		sc->sc_link_status = link_status & AXGE_LINK_MASK;
292f9f848faSopenharmony_ci	}
293f9f848faSopenharmony_ci}
294f9f848faSopenharmony_ci
295f9f848faSopenharmony_cistatic void
296f9f848faSopenharmony_ciaxge_reset(struct axge_softc *sc)
297f9f848faSopenharmony_ci{
298f9f848faSopenharmony_ci	struct usb_config_descriptor *cd;
299f9f848faSopenharmony_ci	usb_error_t err;
300f9f848faSopenharmony_ci
301f9f848faSopenharmony_ci	cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev);
302f9f848faSopenharmony_ci
303f9f848faSopenharmony_ci	err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx,
304f9f848faSopenharmony_ci							    cd->bConfigurationValue);
305f9f848faSopenharmony_ci	if (err)
306f9f848faSopenharmony_ci		DPRINTF("reset failed (ignored)\n");
307f9f848faSopenharmony_ci
308f9f848faSopenharmony_ci	/* Wait a little while for the chip to get its brains in order. */
309f9f848faSopenharmony_ci	(void)uether_pause(&sc->sc_ue, hz / 100);
310f9f848faSopenharmony_ci
311f9f848faSopenharmony_ci	axge_chip_init(sc);
312f9f848faSopenharmony_ci}
313f9f848faSopenharmony_ci
314f9f848faSopenharmony_cistatic void
315f9f848faSopenharmony_ciaxge_attach_post(struct usb_ether *ue)
316f9f848faSopenharmony_ci{
317f9f848faSopenharmony_ci	struct axge_softc *sc = uether_getsc(ue);
318f9f848faSopenharmony_ci
319f9f848faSopenharmony_ci	/* Initialize controller and get station address. */
320f9f848faSopenharmony_ci	axge_chip_init(sc);
321f9f848faSopenharmony_ci	(void)axge_read_mem(sc, AXGE_ACCESS_MAC, NETIF_MAX_HWADDR_LEN, AXGE_NIDR,
322f9f848faSopenharmony_ci					    ue->ue_eaddr, NETIF_MAX_HWADDR_LEN);
323f9f848faSopenharmony_ci}
324f9f848faSopenharmony_ci/*
325f9f848faSopenharmony_ci * Probe for a AX88172 chip.
326f9f848faSopenharmony_ci */
327f9f848faSopenharmony_cistatic int
328f9f848faSopenharmony_ciaxge_probe(device_t dev)
329f9f848faSopenharmony_ci{
330f9f848faSopenharmony_ci	struct usb_attach_arg *uaa = device_get_ivars(dev);
331f9f848faSopenharmony_ci
332f9f848faSopenharmony_ci	if (uaa->usb_mode != USB_MODE_HOST)
333f9f848faSopenharmony_ci		return (ENXIO);
334f9f848faSopenharmony_ci	if (uaa->info.bConfigIndex != AXGE_CONFIG_IDX)
335f9f848faSopenharmony_ci		return (ENXIO);
336f9f848faSopenharmony_ci	if (uaa->info.bIfaceIndex != AXGE_IFACE_IDX)
337f9f848faSopenharmony_ci		return (ENXIO);
338f9f848faSopenharmony_ci
339f9f848faSopenharmony_ci	return (usbd_lookup_id_by_uaa(axge_devs, sizeof(axge_devs), uaa));
340f9f848faSopenharmony_ci}
341f9f848faSopenharmony_ci
342f9f848faSopenharmony_ci/*
343f9f848faSopenharmony_ci * Attach the interface. Allocate softc structures, do ifmedia
344f9f848faSopenharmony_ci * setup and ethernet/BPF attach.
345f9f848faSopenharmony_ci */
346f9f848faSopenharmony_cistatic int
347f9f848faSopenharmony_ciaxge_attach(device_t dev)
348f9f848faSopenharmony_ci{
349f9f848faSopenharmony_ci	struct usb_attach_arg *uaa = device_get_ivars(dev);
350f9f848faSopenharmony_ci	struct axge_softc *sc = device_get_softc(dev);
351f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
352f9f848faSopenharmony_ci	uint8_t iface_index;
353f9f848faSopenharmony_ci	int error;
354f9f848faSopenharmony_ci	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
355f9f848faSopenharmony_ci	sc->sc_link_status = AXGE_LINK_MASK;
356f9f848faSopenharmony_ci
357f9f848faSopenharmony_ci	device_set_usb_desc(dev);
358f9f848faSopenharmony_ci	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_RECURSE);
359f9f848faSopenharmony_ci
360f9f848faSopenharmony_ci	iface_index = AXGE_IFACE_IDX;
361f9f848faSopenharmony_ci	error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
362f9f848faSopenharmony_ci							    axge_config, AXGE_N_TRANSFER, sc, &sc->sc_mtx);
363f9f848faSopenharmony_ci	if (error) {
364f9f848faSopenharmony_ci		device_printf(dev, "allocating USB transfers failed\n");
365f9f848faSopenharmony_ci		goto detach;
366f9f848faSopenharmony_ci	}
367f9f848faSopenharmony_ci	ue->ue_sc = sc;
368f9f848faSopenharmony_ci	ue->ue_dev = dev;
369f9f848faSopenharmony_ci	ue->ue_udev = uaa->device;
370f9f848faSopenharmony_ci	ue->ue_mtx = &sc->sc_mtx;
371f9f848faSopenharmony_ci	ue->ue_methods = &axge_ue_methods;
372f9f848faSopenharmony_ci	error = uether_ifattach(ue);
373f9f848faSopenharmony_ci	if (error) {
374f9f848faSopenharmony_ci		device_printf(dev, "could not attach interface\n");
375f9f848faSopenharmony_ci		goto detach;
376f9f848faSopenharmony_ci	}
377f9f848faSopenharmony_ci	return (0);			/* success */
378f9f848faSopenharmony_ci
379f9f848faSopenharmony_cidetach:
380f9f848faSopenharmony_ci	(void) axge_detach(dev);
381f9f848faSopenharmony_ci	return (ENXIO);			/* failure */
382f9f848faSopenharmony_ci}
383f9f848faSopenharmony_ci
384f9f848faSopenharmony_cistatic int
385f9f848faSopenharmony_ciaxge_detach(device_t dev)
386f9f848faSopenharmony_ci{
387f9f848faSopenharmony_ci	struct axge_softc *sc = device_get_softc(dev);
388f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
389f9f848faSopenharmony_ci
390f9f848faSopenharmony_ci	usbd_transfer_unsetup(sc->sc_xfer, AXGE_N_TRANSFER);
391f9f848faSopenharmony_ci	uether_ifdetach(ue);
392f9f848faSopenharmony_ci	mtx_destroy(&sc->sc_mtx);
393f9f848faSopenharmony_ci
394f9f848faSopenharmony_ci	return (0);
395f9f848faSopenharmony_ci}
396f9f848faSopenharmony_ci
397f9f848faSopenharmony_cistatic void
398f9f848faSopenharmony_ciaxge_miibus_statchg(struct axge_softc *sc, uint8_t link_status)
399f9f848faSopenharmony_ci{
400f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
401f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
402f9f848faSopenharmony_ci	uint8_t tmp[5];
403f9f848faSopenharmony_ci	uint16_t val = 0;
404f9f848faSopenharmony_ci
405f9f848faSopenharmony_ci	if (link_status & AXGE_LINK_MASK) {
406f9f848faSopenharmony_ci		val = MSR_RE;
407f9f848faSopenharmony_ci		if (link_status & IFM_1000_T) {
408f9f848faSopenharmony_ci			val |= MSR_GM | MSR_EN_125MHZ;
409f9f848faSopenharmony_ci			if (link_status & PLSR_USB_SS)
410f9f848faSopenharmony_ci				(void)memcpy_s(tmp, sizeof(tmp), &axge_bulk_size[0], sizeof(axge_bulk_size[0]));
411f9f848faSopenharmony_ci			else if (link_status & PLSR_USB_HS)
412f9f848faSopenharmony_ci				(void)memcpy_s(tmp, sizeof(tmp), &axge_bulk_size[1], sizeof(axge_bulk_size[1]));
413f9f848faSopenharmony_ci			else
414f9f848faSopenharmony_ci				(void)memcpy_s(tmp, sizeof(tmp), &axge_bulk_size[3], sizeof(axge_bulk_size[3]));
415f9f848faSopenharmony_ci		}
416f9f848faSopenharmony_ci		else if (link_status & IFM_100_TX) {
417f9f848faSopenharmony_ci			val |= MSR_PS;
418f9f848faSopenharmony_ci			if (link_status & (PLSR_USB_SS | PLSR_USB_HS))
419f9f848faSopenharmony_ci				(void)memcpy_s(tmp, sizeof(tmp), &axge_bulk_size[2], sizeof(axge_bulk_size[2]));
420f9f848faSopenharmony_ci			else
421f9f848faSopenharmony_ci				(void)memcpy_s(tmp, sizeof(tmp), &axge_bulk_size[3], sizeof(axge_bulk_size[3]));
422f9f848faSopenharmony_ci		}
423f9f848faSopenharmony_ci		else if (link_status & IFM_10_T) {
424f9f848faSopenharmony_ci			(void)memcpy_s(tmp, sizeof(tmp), &axge_bulk_size[3], sizeof(axge_bulk_size[3]));
425f9f848faSopenharmony_ci		}
426f9f848faSopenharmony_ci		else {
427f9f848faSopenharmony_ci			PRINT_WARN("%s, link_status:%x\n", __FUNCTION__, link_status);
428f9f848faSopenharmony_ci			return;
429f9f848faSopenharmony_ci		}
430f9f848faSopenharmony_ci
431f9f848faSopenharmony_ci		/* Rx bulk configuration. */
432f9f848faSopenharmony_ci		axge_write_mem(sc, AXGE_ACCESS_MAC, 5, AXGE_RX_BULKIN_QCTRL, tmp, 5);
433f9f848faSopenharmony_ci		axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MSR, val);
434f9f848faSopenharmony_ci
435f9f848faSopenharmony_ci		ifp->ac_if.flags |= NETIF_FLAG_LINK_UP;
436f9f848faSopenharmony_ci
437f9f848faSopenharmony_ci		(void)netifapi_netif_set_up(&ifp->ac_if);
438f9f848faSopenharmony_ci		PRINTK("AX88178A Link Up\n");
439f9f848faSopenharmony_ci	}
440f9f848faSopenharmony_ci	else {
441f9f848faSopenharmony_ci		ifp->ac_if.flags &= ~NETIF_FLAG_LINK_UP;
442f9f848faSopenharmony_ci		PRINTK("AX88178A Link Down\n");
443f9f848faSopenharmony_ci	}
444f9f848faSopenharmony_ci}
445f9f848faSopenharmony_ci
446f9f848faSopenharmony_cistatic void
447f9f848faSopenharmony_ciaxge_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
448f9f848faSopenharmony_ci{
449f9f848faSopenharmony_ci	struct axge_softc *sc = usbd_xfer_softc(xfer);
450f9f848faSopenharmony_ci	struct usb_ether *ue = &sc->sc_ue;
451f9f848faSopenharmony_ci	struct usb_page_cache *pc;
452f9f848faSopenharmony_ci	int actlen;
453f9f848faSopenharmony_ci
454f9f848faSopenharmony_ci	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
455f9f848faSopenharmony_ci	switch (USB_GET_STATE(xfer)) {
456f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
457f9f848faSopenharmony_ci		pc = usbd_xfer_get_frame(xfer, 0);
458f9f848faSopenharmony_ci		axge_rx_frame(ue, pc, actlen);
459f9f848faSopenharmony_ci		/* FALLTHROUGH */
460f9f848faSopenharmony_ci	case USB_ST_SETUP:
461f9f848faSopenharmony_citr_setup:
462f9f848faSopenharmony_ci		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
463f9f848faSopenharmony_ci		usbd_transfer_submit(xfer);
464f9f848faSopenharmony_ci		uether_rxflush(ue);
465f9f848faSopenharmony_ci		return;
466f9f848faSopenharmony_ci
467f9f848faSopenharmony_ci	default:			/* Error */
468f9f848faSopenharmony_ci		DPRINTF("bulk read error, %s\n", usbd_errstr(error));
469f9f848faSopenharmony_ci
470f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
471f9f848faSopenharmony_ci			/* try to clear stall first */
472f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
473f9f848faSopenharmony_ci			goto tr_setup;
474f9f848faSopenharmony_ci		}
475f9f848faSopenharmony_ci		return;
476f9f848faSopenharmony_ci	}
477f9f848faSopenharmony_ci}
478f9f848faSopenharmony_ci
479f9f848faSopenharmony_cistatic int
480f9f848faSopenharmony_ciaxge_rxeof(struct usb_ether *ue, struct usb_page_cache *pc, unsigned int offset,
481f9f848faSopenharmony_ci	unsigned int len, uint32_t pkt_hdr)
482f9f848faSopenharmony_ci{
483f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
484f9f848faSopenharmony_ci	struct pbuf *m = pbuf_alloc(PBUF_RAW, len+ETH_PAD_SIZE, PBUF_RAM);
485f9f848faSopenharmony_ci	struct pbuf *p;
486f9f848faSopenharmony_ci
487f9f848faSopenharmony_ci	if (len < ETHER_HDR_LEN) {
488f9f848faSopenharmony_ci		(void)pbuf_free(m);
489f9f848faSopenharmony_ci		return (EINVAL);
490f9f848faSopenharmony_ci	}
491f9f848faSopenharmony_ci
492f9f848faSopenharmony_ci#if ETH_PAD_SIZE
493f9f848faSopenharmony_ci	/* drop the padding word */
494f9f848faSopenharmony_ci	if (pbuf_header(m, -ETH_PAD_SIZE)) {
495f9f848faSopenharmony_ci		PRINTK("[AXE_ERROR]axe_rxeof : pbuf_header drop failed\n");
496f9f848faSopenharmony_ci		(void)pbuf_free(m);
497f9f848faSopenharmony_ci		return (EINVAL);
498f9f848faSopenharmony_ci	}
499f9f848faSopenharmony_ci#endif
500f9f848faSopenharmony_ci
501f9f848faSopenharmony_ci	for (p = m; p != NULL; p = p->next)
502f9f848faSopenharmony_ci		usbd_copy_out(pc, offset, p->payload, p->len);
503f9f848faSopenharmony_ci
504f9f848faSopenharmony_ci#if ETH_PAD_SIZE
505f9f848faSopenharmony_ci	/* reclaim the padding word */
506f9f848faSopenharmony_ci	if (pbuf_header(m, ETH_PAD_SIZE)) {
507f9f848faSopenharmony_ci		PRINTK("[AXE_ERROR]axe_rxeof : pbuf_header drop failed\n");
508f9f848faSopenharmony_ci		(void)pbuf_free(m);
509f9f848faSopenharmony_ci		return (EINVAL);
510f9f848faSopenharmony_ci	}
511f9f848faSopenharmony_ci#endif
512f9f848faSopenharmony_ci
513f9f848faSopenharmony_ci	driverif_input(&ifp->ac_if, m);
514f9f848faSopenharmony_ci	return (0);
515f9f848faSopenharmony_ci}
516f9f848faSopenharmony_ci
517f9f848faSopenharmony_cistatic void
518f9f848faSopenharmony_ciaxge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen)
519f9f848faSopenharmony_ci{
520f9f848faSopenharmony_ci	uint32_t pos;
521f9f848faSopenharmony_ci	uint32_t pkt_cnt;
522f9f848faSopenharmony_ci	uint32_t rxhdr;
523f9f848faSopenharmony_ci	uint32_t pkt_hdr;
524f9f848faSopenharmony_ci	uint32_t hdr_off;
525f9f848faSopenharmony_ci	uint32_t pktlen;
526f9f848faSopenharmony_ci
527f9f848faSopenharmony_ci	/* verify we have enough data */
528f9f848faSopenharmony_ci	if (actlen < (int)sizeof(rxhdr))
529f9f848faSopenharmony_ci		return;
530f9f848faSopenharmony_ci
531f9f848faSopenharmony_ci	pos = 0;
532f9f848faSopenharmony_ci
533f9f848faSopenharmony_ci	usbd_copy_out(pc, actlen - sizeof(rxhdr), &rxhdr, sizeof(rxhdr));
534f9f848faSopenharmony_ci	rxhdr = le32toh(rxhdr);
535f9f848faSopenharmony_ci
536f9f848faSopenharmony_ci	pkt_cnt = (uint16_t)rxhdr;
537f9f848faSopenharmony_ci	hdr_off = (uint16_t)(rxhdr >> 16);
538f9f848faSopenharmony_ci
539f9f848faSopenharmony_ci	while (pkt_cnt--) {
540f9f848faSopenharmony_ci		/* verify the header offset */
541f9f848faSopenharmony_ci		if ((int)(hdr_off + sizeof(pkt_hdr)) > actlen) {
542f9f848faSopenharmony_ci			DPRINTF("End of packet headers\n");
543f9f848faSopenharmony_ci			break;
544f9f848faSopenharmony_ci		}
545f9f848faSopenharmony_ci		if ((int)pos >= actlen) {
546f9f848faSopenharmony_ci			DPRINTF("Data position reached end\n");
547f9f848faSopenharmony_ci			break;
548f9f848faSopenharmony_ci		}
549f9f848faSopenharmony_ci		usbd_copy_out(pc, hdr_off, &pkt_hdr, sizeof(pkt_hdr));
550f9f848faSopenharmony_ci
551f9f848faSopenharmony_ci		pkt_hdr = le32toh(pkt_hdr);
552f9f848faSopenharmony_ci		pktlen = (pkt_hdr >> 16) & 0x1fff;
553f9f848faSopenharmony_ci		if (pkt_hdr & (AXGE_RXHDR_CRC_ERR | AXGE_RXHDR_DROP_ERR)) {
554f9f848faSopenharmony_ci			DPRINTF("Dropped a packet\n");
555f9f848faSopenharmony_ci		}
556f9f848faSopenharmony_ci		if (pktlen >= 6 && (int)(pos + pktlen) <= actlen) {
557f9f848faSopenharmony_ci			(void)axge_rxeof(ue, pc, pos, pktlen, pkt_hdr);
558f9f848faSopenharmony_ci		} else {
559f9f848faSopenharmony_ci			DPRINTF("Invalid packet pos=%d len=%d\n",
560f9f848faSopenharmony_ci				    (int)pos, (int)pktlen);
561f9f848faSopenharmony_ci		}
562f9f848faSopenharmony_ci		pos += (pktlen + 7) & ~7;
563f9f848faSopenharmony_ci		hdr_off += sizeof(pkt_hdr);
564f9f848faSopenharmony_ci	}
565f9f848faSopenharmony_ci}
566f9f848faSopenharmony_ci
567f9f848faSopenharmony_cistatic void
568f9f848faSopenharmony_ciaxge_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
569f9f848faSopenharmony_ci{
570f9f848faSopenharmony_ci	struct axge_softc *sc = usbd_xfer_softc(xfer);
571f9f848faSopenharmony_ci	struct usb_ether *ue = &(sc->sc_ue);
572f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
573f9f848faSopenharmony_ci	struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)ifp->driver_context;
574f9f848faSopenharmony_ci	struct usb_page_cache *pc;
575f9f848faSopenharmony_ci	uint16_t txlen;
576f9f848faSopenharmony_ci	uint32_t nframes, pos;
577f9f848faSopenharmony_ci	struct pbuf *p;
578f9f848faSopenharmony_ci	uint8_t ustat;
579f9f848faSopenharmony_ci	uint32_t txhdr;
580f9f848faSopenharmony_ci
581f9f848faSopenharmony_ci	ustat = USB_GET_STATE(xfer);
582f9f848faSopenharmony_citr_setup:
583f9f848faSopenharmony_ci	switch (ustat) {
584f9f848faSopenharmony_ci	case USB_ST_TRANSFERRED:
585f9f848faSopenharmony_ci		drv_sc->state &= ~IFF_DRV_OACTIVE;
586f9f848faSopenharmony_ci		/* FALLTHROUGH */
587f9f848faSopenharmony_ci
588f9f848faSopenharmony_ci	case USB_ST_SETUP:
589f9f848faSopenharmony_ci		if (drv_sc->state & IFF_DRV_OACTIVE)
590f9f848faSopenharmony_ci			return;
591f9f848faSopenharmony_ci
592f9f848faSopenharmony_ci		UE_LOCK(ue);
593f9f848faSopenharmony_ci		IF_DEQUEUE(&(ue->ue_txq), p);
594f9f848faSopenharmony_ci		UE_UNLOCK(ue);
595f9f848faSopenharmony_ci
596f9f848faSopenharmony_ci		nframes = 0;
597f9f848faSopenharmony_ci		while (p) {
598f9f848faSopenharmony_ci			txlen = p->len;
599f9f848faSopenharmony_ci			if (txlen <= 0)
600f9f848faSopenharmony_ci				break;
601f9f848faSopenharmony_ci
602f9f848faSopenharmony_ci			usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES, nframes);
603f9f848faSopenharmony_ci			pos = 0;
604f9f848faSopenharmony_ci			pc = usbd_xfer_get_frame(xfer, nframes);
605f9f848faSopenharmony_ci
606f9f848faSopenharmony_ci			txhdr = htole32(txlen);
607f9f848faSopenharmony_ci			usbd_copy_in(pc, 0, &txhdr, sizeof(txhdr));
608f9f848faSopenharmony_ci			txhdr = 0;
609f9f848faSopenharmony_ci			txhdr = htole32(txhdr);
610f9f848faSopenharmony_ci			usbd_copy_in(pc, 4, &txhdr, sizeof(txhdr));
611f9f848faSopenharmony_ci			pos += 8;
612f9f848faSopenharmony_ci			usbd_copy_in(pc, pos, p->payload, txlen);
613f9f848faSopenharmony_ci			pos += txlen;
614f9f848faSopenharmony_ci			if ((pos % usbd_xfer_max_framelen(xfer)) == 0)
615f9f848faSopenharmony_ci				txhdr |= 0x80008000;
616f9f848faSopenharmony_ci
617f9f848faSopenharmony_ci			/* Set frame length. */
618f9f848faSopenharmony_ci			usbd_xfer_set_frame_len(xfer, nframes, pos);
619f9f848faSopenharmony_ci
620f9f848faSopenharmony_ci			uether_freebuf(p);
621f9f848faSopenharmony_ci			nframes++;
622f9f848faSopenharmony_ci			if (nframes >= 16)
623f9f848faSopenharmony_ci				break;
624f9f848faSopenharmony_ci
625f9f848faSopenharmony_ci			UE_LOCK(ue);
626f9f848faSopenharmony_ci			IF_DEQUEUE(&(ue->ue_txq), p);
627f9f848faSopenharmony_ci			UE_UNLOCK(ue);
628f9f848faSopenharmony_ci		}
629f9f848faSopenharmony_ci		if (nframes != 0) {
630f9f848faSopenharmony_ci			usbd_xfer_set_frames(xfer, nframes);
631f9f848faSopenharmony_ci			usbd_transfer_submit(xfer);
632f9f848faSopenharmony_ci			drv_sc->state |= IFF_DRV_OACTIVE;
633f9f848faSopenharmony_ci		}
634f9f848faSopenharmony_ci		break;
635f9f848faSopenharmony_ci
636f9f848faSopenharmony_ci	default:			/* Error */
637f9f848faSopenharmony_ci		drv_sc->state &= ~IFF_DRV_OACTIVE;
638f9f848faSopenharmony_ci		if (error != USB_ERR_CANCELLED) {
639f9f848faSopenharmony_ci			/* try to clear stall first */
640f9f848faSopenharmony_ci			usbd_xfer_set_stall(xfer);
641f9f848faSopenharmony_ci			ustat = USB_ST_SETUP;
642f9f848faSopenharmony_ci			goto tr_setup;
643f9f848faSopenharmony_ci		}
644f9f848faSopenharmony_ci		break;
645f9f848faSopenharmony_ci	}
646f9f848faSopenharmony_ci}
647f9f848faSopenharmony_ci
648f9f848faSopenharmony_cistatic void
649f9f848faSopenharmony_ciaxge_start(struct usb_ether *ue)
650f9f848faSopenharmony_ci{
651f9f848faSopenharmony_ci	struct axge_softc *sc = ue->ue_sc;
652f9f848faSopenharmony_ci
653f9f848faSopenharmony_ci	/*
654f9f848faSopenharmony_ci	 * start the USB transfers, if not already started:
655f9f848faSopenharmony_ci	 */
656f9f848faSopenharmony_ci	usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_WR]);
657f9f848faSopenharmony_ci	usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_RD]);
658f9f848faSopenharmony_ci}
659f9f848faSopenharmony_ci
660f9f848faSopenharmony_cistatic void
661f9f848faSopenharmony_ciaxge_init(struct usb_ether *ue)
662f9f848faSopenharmony_ci{
663f9f848faSopenharmony_ci	struct axge_softc *sc = uether_getsc(ue);
664f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
665f9f848faSopenharmony_ci	struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)ifp->driver_context;
666f9f848faSopenharmony_ci	uint16_t rxmode;
667f9f848faSopenharmony_ci
668f9f848faSopenharmony_ci	drv_sc->state = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
669f9f848faSopenharmony_ci
670f9f848faSopenharmony_ci	AXGE_LOCK_ASSERT(sc, MA_OWNED);
671f9f848faSopenharmony_ci	if ((drv_sc->state & IFF_DRV_RUNNING) != 0)
672f9f848faSopenharmony_ci		return;
673f9f848faSopenharmony_ci
674f9f848faSopenharmony_ci	/* Cancel pending I/O */
675f9f848faSopenharmony_ci	axge_stop(ue);
676f9f848faSopenharmony_ci	axge_reset(sc);
677f9f848faSopenharmony_ci
678f9f848faSopenharmony_ci	/* Set MAC address. */
679f9f848faSopenharmony_ci	ifp->ac_if.hwaddr_len = NETIF_MAX_HWADDR_LEN;
680f9f848faSopenharmony_ci	(void)axge_read_mem(sc, AXGE_ACCESS_MAC, 6, AXGE_NIDR, ifp ->ac_if.hwaddr, 6);
681f9f848faSopenharmony_ci
682f9f848faSopenharmony_ci	axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLLR, 0x34);
683f9f848faSopenharmony_ci	axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLHR, 0x52);
684f9f848faSopenharmony_ci
685f9f848faSopenharmony_ci	ifp->ac_if.flags |= NETIF_FLAG_UP | NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
686f9f848faSopenharmony_ci
687f9f848faSopenharmony_ci	/* Configure TX/RX checksum offloading. */
688f9f848faSopenharmony_ci	axge_csum_cfg(ue);
689f9f848faSopenharmony_ci
690f9f848faSopenharmony_ci	/* Configure RX settings. */
691f9f848faSopenharmony_ci	rxmode = (RCR_AM | RCR_SO | RCR_DROP_CRCE);
692f9f848faSopenharmony_ci
693f9f848faSopenharmony_ci	/* If we want promiscuous mode, set the allframes bit. */
694f9f848faSopenharmony_ci	if (ifp->ac_if.flags & IFF_PROMISC)
695f9f848faSopenharmony_ci		rxmode |= RCR_PRO;
696f9f848faSopenharmony_ci
697f9f848faSopenharmony_ci	if (ifp->ac_if.flags & IFF_BROADCAST)
698f9f848faSopenharmony_ci		rxmode |= RCR_AB;
699f9f848faSopenharmony_ci
700f9f848faSopenharmony_ci	axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
701f9f848faSopenharmony_ci
702f9f848faSopenharmony_ci	axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_MMSR,
703f9f848faSopenharmony_ci				    MMSR_PME_TYPE | MMSR_PME_POL | MMSR_RWMP);
704f9f848faSopenharmony_ci
705f9f848faSopenharmony_ci	/* Load the multicast filter. */
706f9f848faSopenharmony_ci	axge_setmulti(ue);
707f9f848faSopenharmony_ci
708f9f848faSopenharmony_ci	drv_sc->state |= IFF_DRV_RUNNING;
709f9f848faSopenharmony_ci}
710f9f848faSopenharmony_ci
711f9f848faSopenharmony_cistatic void
712f9f848faSopenharmony_ciaxge_stop(struct usb_ether *ue)
713f9f848faSopenharmony_ci{
714f9f848faSopenharmony_ci	struct axge_softc *sc = uether_getsc(ue);
715f9f848faSopenharmony_ci	struct los_eth_driver *ifp = ue->ue_drv_sc;
716f9f848faSopenharmony_ci	struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)ifp->driver_context;
717f9f848faSopenharmony_ci
718f9f848faSopenharmony_ci	AXGE_LOCK_ASSERT(sc, MA_OWNED);
719f9f848faSopenharmony_ci	drv_sc->state &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
720f9f848faSopenharmony_ci	sc->sc_flags &= ~AXE_FLAG_LINK;
721f9f848faSopenharmony_ci	/*
722f9f848faSopenharmony_ci	 * stop all the transfers, if not already stopped:
723f9f848faSopenharmony_ci	 */
724f9f848faSopenharmony_ci	usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_WR]);
725f9f848faSopenharmony_ci	usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_RD]);
726f9f848faSopenharmony_ci}
727f9f848faSopenharmony_ci
728f9f848faSopenharmony_ci#undef USB_DEBUG_VAR
729