if_cnmac.c revision 1.22
1/*	$NetBSD: if_cnmac.c,v 1.22 2020/06/18 13:52:08 simonb Exp $	*/
2
3#include <sys/cdefs.h>
4#if 0
5__KERNEL_RCSID(0, "$NetBSD: if_cnmac.c,v 1.22 2020/06/18 13:52:08 simonb Exp $");
6#endif
7
8#include "opt_octeon.h"
9
10#ifdef	CNMAC_DEBUG
11
12#ifndef DIAGNOSTIC
13#define	DIAGNOSTIC
14#endif
15
16#ifndef DEBUG
17#define	DEBUG
18#endif
19
20#endif
21
22/*
23 * If no free send buffer is available, free all the sent buffers and bail out.
24 */
25#define CNMAC_SEND_QUEUE_CHECK
26
27/* XXX XXX XXX XXX XXX XXX */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/pool.h>
32#include <sys/mbuf.h>
33#include <sys/malloc.h>
34#include <sys/kernel.h>
35#include <sys/socket.h>
36#include <sys/ioctl.h>
37#include <sys/errno.h>
38#include <sys/device.h>
39#include <sys/queue.h>
40#include <sys/conf.h>
41#include <sys/sysctl.h>
42#include <sys/syslog.h>
43
44#include <net/if.h>
45#include <net/if_dl.h>
46#include <net/if_media.h>
47#include <net/if_ether.h>
48#include <net/route.h>
49#include <net/bpf.h>
50
51#include <netinet/in.h>
52#include <netinet/in_systm.h>
53#include <netinet/in_var.h>
54#include <netinet/ip.h>
55
56#include <sys/bus.h>
57#include <machine/intr.h>
58#include <machine/endian.h>
59#include <machine/locore.h>
60
61#include <dev/mii/mii.h>
62#include <dev/mii/miivar.h>
63
64#include <mips/cpuregs.h>
65
66#include <mips/cavium/octeonreg.h>
67#include <mips/cavium/include/iobusvar.h>
68
69#include <mips/cavium/dev/octeon_ciureg.h>
70#include <mips/cavium/dev/octeon_gmxreg.h>
71#include <mips/cavium/dev/octeon_pipreg.h>
72#include <mips/cavium/dev/octeon_powreg.h>
73#include <mips/cavium/dev/octeon_faureg.h>
74#include <mips/cavium/dev/octeon_fpareg.h>
75#include <mips/cavium/dev/octeon_fpavar.h>
76#include <mips/cavium/dev/octeon_gmxvar.h>
77#include <mips/cavium/dev/octeon_fauvar.h>
78#include <mips/cavium/dev/octeon_powvar.h>
79#include <mips/cavium/dev/octeon_ipdvar.h>
80#include <mips/cavium/dev/octeon_pipvar.h>
81#include <mips/cavium/dev/octeon_pkovar.h>
82#include <mips/cavium/dev/octeon_asxvar.h>
83#include <mips/cavium/dev/octeon_smivar.h>
84#include <mips/cavium/dev/if_cnmacvar.h>
85
86#ifdef CNMAC_DEBUG
87#define	CNMAC_KASSERT(x)	KASSERT(x)
88#define	CNMAC_KDASSERT(x)	KDASSERT(x)
89#else
90#define	CNMAC_KASSERT(x)
91#define	CNMAC_KDASSERT(x)
92#endif
93
94/*
95 * Set the PKO to think command buffers are an odd length.  This makes it so we
96 * never have to divide a comamnd across two buffers.
97 */
98#define OCTEON_POOL_NWORDS_CMD	\
99	    (((uint32_t)OCTEON_POOL_SIZE_CMD / sizeof(uint64_t)) - 1)
100#define FPA_COMMAND_BUFFER_POOL_NWORDS	OCTEON_POOL_NWORDS_CMD	/* XXX */
101
102static void	cnmac_buf_init(struct cnmac_softc *);
103
104static int	cnmac_match(device_t, struct cfdata *, void *);
105static void	cnmac_attach(device_t, device_t, void *);
106static void	cnmac_pip_init(struct cnmac_softc *);
107static void	cnmac_ipd_init(struct cnmac_softc *);
108static void	cnmac_pko_init(struct cnmac_softc *);
109static void	cnmac_asx_init(struct cnmac_softc *);
110static void	cnmac_smi_init(struct cnmac_softc *);
111
112static void	cnmac_board_mac_addr(uint8_t *, size_t, struct cnmac_softc *);
113
114static int	cnmac_mii_readreg(device_t, int, int, uint16_t *);
115static int	cnmac_mii_writereg(device_t, int, int, uint16_t);
116static void	cnmac_mii_statchg(struct ifnet *);
117
118static int	cnmac_mediainit(struct cnmac_softc *);
119static void	cnmac_mediastatus(struct ifnet *, struct ifmediareq *);
120
121static inline void cnmac_send_queue_flush_prefetch(struct cnmac_softc *);
122static inline void cnmac_send_queue_flush_fetch(struct cnmac_softc *);
123static inline void cnmac_send_queue_flush(struct cnmac_softc *);
124static inline void cnmac_send_queue_flush_sync(struct cnmac_softc *);
125static inline int cnmac_send_queue_is_full(struct cnmac_softc *);
126static inline void cnmac_send_queue_add(struct cnmac_softc *, struct mbuf *,
127    uint64_t *);
128static inline void cnmac_send_queue_del(struct cnmac_softc *, struct mbuf **,
129    uint64_t **);
130static inline int cnmac_buf_free_work(struct cnmac_softc *, uint64_t *,
131    uint64_t);
132static inline void cnmac_buf_ext_free_m(struct mbuf *, void *, size_t, void *);
133static inline void cnmac_buf_ext_free_ext(struct mbuf *, void *, size_t,
134    void *);
135
136static int	cnmac_ioctl(struct ifnet *, u_long, void *);
137static void	cnmac_watchdog(struct ifnet *);
138static int	cnmac_init(struct ifnet *);
139static void	cnmac_stop(struct ifnet *, int);
140static void	cnmac_start(struct ifnet *);
141
142static inline int cnmac_send_cmd(struct cnmac_softc *, uint64_t, uint64_t,
143    int *);
144static inline uint64_t	cnmac_send_makecmd_w1(int, paddr_t);
145static inline uint64_t	cnmac_send_makecmd_w0(uint64_t, uint64_t, size_t, int);
146static inline int cnmac_send_makecmd_gbuf(struct cnmac_softc *, struct mbuf *,
147    uint64_t *, int *);
148static inline int cnmac_send_makecmd(struct cnmac_softc *, struct mbuf *,
149    uint64_t *, uint64_t *, uint64_t *);
150static inline int cnmac_send_buf(struct cnmac_softc *, struct mbuf *,
151    uint64_t *, int *);
152static inline int cnmac_send(struct cnmac_softc *, struct mbuf *, int *);
153
154static int	cnmac_reset(struct cnmac_softc *);
155static int	cnmac_configure(struct cnmac_softc *);
156static int	cnmac_configure_common(struct cnmac_softc *);
157
158static void	cnmac_tick_free(void *);
159static void	cnmac_tick_misc(void *);
160
161static inline int cnmac_recv_mbuf(struct cnmac_softc *, uint64_t *,
162    struct mbuf **);
163static inline int cnmac_recv_check_code(struct cnmac_softc *, uint64_t);
164static inline int cnmac_recv_check_jumbo(struct cnmac_softc *, uint64_t);
165static inline int cnmac_recv_check_link(struct cnmac_softc *, uint64_t);
166static inline int cnmac_recv_check(struct cnmac_softc *, uint64_t);
167static inline int cnmac_recv(struct cnmac_softc *, uint64_t *);
168static void	cnmac_recv_redir(struct ifnet *, struct mbuf *);
169static inline void cnmac_recv_intr(void *, uint64_t *);
170
171/* Device driver context */
172static struct	cnmac_softc *cnmac_gsc[GMX_PORT_NUNITS];
173static void	*cnmac_pow_recv_ih;
174
175/* sysctl'able parameters */
176int		cnmac_param_pko_cmd_w0_n2 = 1;
177int		cnmac_param_pip_dyn_rs = 1;
178int		cnmac_param_redir = 0;
179int		cnmac_param_pktbuf = 0;
180int		cnmac_param_rate = 0;
181int		cnmac_param_intr = 0;
182
183CFATTACH_DECL_NEW(cnmac, sizeof(struct cnmac_softc),
184    cnmac_match, cnmac_attach, NULL, NULL);
185
186#ifdef CNMAC_DEBUG
187
188static const struct octeon_evcnt_entry octeon_evcnt_entries[] = {
189#define	_ENTRY(name, type, parent, descr) \
190	OCTEON_EVCNT_ENTRY(struct cnmac_softc, name, type, parent, descr)
191	_ENTRY(rx,			MISC, NULL, "rx"),
192	_ENTRY(rxint,			INTR, NULL, "rx intr"),
193	_ENTRY(rxrs,			MISC, NULL, "rx dynamic short"),
194	_ENTRY(rxbufpkalloc,		MISC, NULL, "rx buf pkt alloc"),
195	_ENTRY(rxbufpkput,		MISC, NULL, "rx buf pkt put"),
196	_ENTRY(rxbufwqalloc,		MISC, NULL, "rx buf wqe alloc"),
197	_ENTRY(rxbufwqput,		MISC, NULL, "rx buf wqe put"),
198	_ENTRY(rxerrcode,		MISC, NULL, "rx code error"),
199	_ENTRY(rxerrfix,		MISC, NULL, "rx fixup error"),
200	_ENTRY(rxerrjmb,		MISC, NULL, "rx jmb error"),
201	_ENTRY(rxerrlink,		MISC, NULL, "rx link error"),
202	_ENTRY(rxerroff,		MISC, NULL, "rx offload error"),
203	_ENTRY(rxonperrshort,		MISC, NULL, "rx onp fixup short error"),
204	_ENTRY(rxonperrpreamble,	MISC, NULL, "rx onp fixup preamble error"),
205	_ENTRY(rxonperrcrc,		MISC, NULL, "rx onp fixup crc error"),
206	_ENTRY(rxonperraddress,		MISC, NULL, "rx onp fixup address error"),
207	_ENTRY(rxonponp,		MISC, NULL, "rx onp fixup onp packets"),
208	_ENTRY(rxonpok,			MISC, NULL, "rx onp fixup success packets"),
209	_ENTRY(tx,			MISC, NULL, "tx"),
210	_ENTRY(txadd,			MISC, NULL, "tx add"),
211	_ENTRY(txbufcballoc,		MISC, NULL, "tx buf cb alloc"),
212	_ENTRY(txbufcbget,		MISC, NULL, "tx buf cb get"),
213	_ENTRY(txbufgballoc,		MISC, NULL, "tx buf gb alloc"),
214	_ENTRY(txbufgbget,		MISC, NULL, "tx buf gb get"),
215	_ENTRY(txbufgbput,		MISC, NULL, "tx buf gb put"),
216	_ENTRY(txdel,			MISC, NULL, "tx del"),
217	_ENTRY(txerr,			MISC, NULL, "tx error"),
218	_ENTRY(txerrcmd,		MISC, NULL, "tx cmd error"),
219	_ENTRY(txerrgbuf,		MISC, NULL, "tx gbuf error"),
220	_ENTRY(txerrlink,		MISC, NULL, "tx link error"),
221	_ENTRY(txerrmkcmd,		MISC, NULL, "tx makecmd error"),
222#undef	_ENTRY
223};
224#endif
225
226/* ---- buffer management */
227
228static const struct cnmac_pool_param {
229	int			poolno;
230	size_t			size;
231	size_t			nelems;
232} cnmac_pool_params[] = {
233#define	_ENTRY(x)	{ OCTEON_POOL_NO_##x, OCTEON_POOL_SIZE_##x, OCTEON_POOL_NELEMS_##x }
234	_ENTRY(PKT),
235	_ENTRY(WQE),
236	_ENTRY(CMD),
237	_ENTRY(SG)
238#undef	_ENTRY
239};
240struct octfpa_buf	*cnmac_pools[8/* XXX */];
241#define	cnmac_fb_pkt	cnmac_pools[OCTEON_POOL_NO_PKT]
242#define	cnmac_fb_wqe	cnmac_pools[OCTEON_POOL_NO_WQE]
243#define	cnmac_fb_cmd	cnmac_pools[OCTEON_POOL_NO_CMD]
244#define	cnmac_fb_sg	cnmac_pools[OCTEON_POOL_NO_SG]
245
246static void
247cnmac_buf_init(struct cnmac_softc *sc)
248{
249	static int once;
250	int i;
251	const struct cnmac_pool_param *pp;
252	struct octfpa_buf *fb;
253
254	if (once == 1)
255		return;
256	once = 1;
257
258	for (i = 0; i < (int)__arraycount(cnmac_pool_params); i++) {
259		pp = &cnmac_pool_params[i];
260		octfpa_buf_init(pp->poolno, pp->size, pp->nelems, &fb);
261		cnmac_pools[i] = fb;
262	}
263}
264
265/* ---- autoconf */
266
267static int
268cnmac_match(device_t parent, struct cfdata *match, void *aux)
269{
270	struct octgmx_attach_args *ga = aux;
271
272	if (strcmp(match->cf_name, ga->ga_name) != 0) {
273		return 0;
274	}
275	return 1;
276}
277
278static void
279cnmac_attach(device_t parent, device_t self, void *aux)
280{
281	struct cnmac_softc *sc = device_private(self);
282	struct octgmx_attach_args *ga = aux;
283	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
284	prop_dictionary_t dict;
285	prop_object_t clk;
286	uint8_t enaddr[ETHER_ADDR_LEN];
287
288	sc->sc_dev = self;
289	sc->sc_regt = ga->ga_regt;
290	sc->sc_port = ga->ga_portno;
291	sc->sc_port_type = ga->ga_port_type;
292	sc->sc_gmx = ga->ga_gmx;
293	sc->sc_gmx_port = ga->ga_gmx_port;
294
295	if (sc->sc_port >= CVMSEG_LM_ETHER_COUNT) {
296		/*
297		 * If we got here, increase CVMSEG_LM_ETHER_COUNT
298		 * in octeonvar.h .
299		 */
300		printf("%s: ERROR out of CVMSEG LM buffers\n",
301		    device_xname(self));
302		return;
303	}
304
305	sc->sc_init_flag = 0;
306	/*
307	 * XXXUEBAYASI
308	 * Setting PIP_IP_OFFSET[OFFSET] to 8 causes panic ... why???
309	 */
310	sc->sc_ip_offset = 0/* XXX */;
311
312	if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) <= MIPS_CN30XX) {
313		SET(sc->sc_quirks, CNMAC_QUIRKS_NO_PRE_ALIGN);
314		SET(sc->sc_quirks, CNMAC_QUIRKS_NO_RX_INBND);
315	}
316
317	cnmac_board_mac_addr(enaddr, sizeof(enaddr), sc);
318	printf("%s: Ethernet address %s\n", device_xname(sc->sc_dev),
319	    ether_sprintf(enaddr));
320
321	cnmac_gsc[sc->sc_port] = sc;
322
323	SIMPLEQ_INIT(&sc->sc_sendq);
324	sc->sc_soft_req_thresh = 15/* XXX */;
325	sc->sc_ext_callback_cnt = 0;
326
327	octgmx_stats_init(sc->sc_gmx_port);
328
329	callout_init(&sc->sc_tick_misc_ch, 0);
330	callout_init(&sc->sc_tick_free_ch, 0);
331
332	octfau_op_init(&sc->sc_fau_done,
333	    OCTEON_CVMSEG_ETHER_OFFSET(sc->sc_port, csm_ether_fau_done),
334	    OCT_FAU_REG_ADDR_END - (8 * (sc->sc_port + 1))/* XXX */);
335	octfau_op_set_8(&sc->sc_fau_done, 0);
336
337	cnmac_pip_init(sc);
338	cnmac_ipd_init(sc);
339	cnmac_pko_init(sc);
340	cnmac_asx_init(sc);
341	cnmac_smi_init(sc);
342
343	sc->sc_gmx_port->sc_ipd = sc->sc_ipd;
344	sc->sc_gmx_port->sc_port_asx = sc->sc_asx;
345	sc->sc_gmx_port->sc_port_mii = &sc->sc_mii;
346	sc->sc_gmx_port->sc_port_ec = &sc->sc_ethercom;
347	/* XXX */
348	sc->sc_gmx_port->sc_quirks = sc->sc_quirks;
349
350	/* XXX */
351	sc->sc_pow = &octpow_softc;
352
353	cnmac_mediainit(sc);
354
355	strncpy(ifp->if_xname, device_xname(sc->sc_dev), sizeof(ifp->if_xname));
356	ifp->if_softc = sc;
357	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
358	ifp->if_ioctl = cnmac_ioctl;
359	ifp->if_start = cnmac_start;
360	ifp->if_watchdog = cnmac_watchdog;
361	ifp->if_init = cnmac_init;
362	ifp->if_stop = cnmac_stop;
363	IFQ_SET_MAXLEN(&ifp->if_snd, uimax(GATHER_QUEUE_SIZE, IFQ_MAXLEN));
364	IFQ_SET_READY(&ifp->if_snd);
365
366	/* XXX: not yet tx checksum */
367	ifp->if_capabilities =
368	    IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx |
369	    IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx;
370
371	/* 802.1Q VLAN-sized frames are supported */
372	sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
373
374	octgmx_set_mac_addr(sc->sc_gmx_port, enaddr);
375
376	if_attach(ifp);
377	ether_ifattach(ifp, enaddr);
378	octgmx_set_filter(sc->sc_gmx_port);
379
380	/* XXX */
381	sc->sc_rate_recv_check_link_cap.tv_sec = 1;
382	sc->sc_rate_recv_check_jumbo_cap.tv_sec = 1;
383	sc->sc_rate_recv_check_code_cap.tv_sec = 1;
384	sc->sc_rate_recv_fixup_odd_nibble_short_cap.tv_sec = 1;
385	sc->sc_rate_recv_fixup_odd_nibble_preamble_cap.tv_sec = 1;
386	sc->sc_rate_recv_fixup_odd_nibble_crc_cap.tv_sec = 1;
387#ifdef CNMAC_DEBUG
388	sc->sc_rate_recv_fixup_odd_nibble_addr_cap.tv_sec = 1;
389#endif
390	/* XXX */
391
392#if 1
393	cnmac_buf_init(sc);
394#endif
395
396	if (cnmac_pow_recv_ih == NULL)
397		cnmac_pow_recv_ih
398		    = octpow_intr_establish(OCTEON_POW_GROUP_PIP,
399			IPL_NET, cnmac_recv_intr, NULL, NULL);
400
401	OCTEON_EVCNT_ATTACH_EVCNTS(sc, octeon_evcnt_entries,
402	    device_xname(sc->sc_dev));
403
404	dict = device_properties(sc->sc_gmx->sc_dev);
405
406	clk = prop_dictionary_get(dict, "rgmii-tx");
407	KASSERT(clk != NULL);
408	sc->sc_gmx_port->sc_clk_tx_setting = prop_number_signed_value(clk);
409	clk = prop_dictionary_get(dict, "rgmii-rx");
410	KASSERT(clk != NULL);
411	sc->sc_gmx_port->sc_clk_rx_setting = prop_number_signed_value(clk);
412}
413
414/* ---- submodules */
415
416/* XXX */
417static void
418cnmac_pip_init(struct cnmac_softc *sc)
419{
420	struct octpip_attach_args pip_aa;
421
422	pip_aa.aa_port = sc->sc_port;
423	pip_aa.aa_regt = sc->sc_regt;
424	pip_aa.aa_tag_type = POW_TAG_TYPE_ORDERED/* XXX */;
425	pip_aa.aa_receive_group = OCTEON_POW_GROUP_PIP;
426	pip_aa.aa_ip_offset = sc->sc_ip_offset;
427	octpip_init(&pip_aa, &sc->sc_pip);
428}
429
430/* XXX */
431static void
432cnmac_ipd_init(struct cnmac_softc *sc)
433{
434	struct octipd_attach_args ipd_aa;
435
436	ipd_aa.aa_port = sc->sc_port;
437	ipd_aa.aa_regt = sc->sc_regt;
438	ipd_aa.aa_first_mbuff_skip = 184/* XXX */;
439	ipd_aa.aa_not_first_mbuff_skip = 0/* XXX */;
440	octipd_init(&ipd_aa, &sc->sc_ipd);
441}
442
443/* XXX */
444static void
445cnmac_pko_init(struct cnmac_softc *sc)
446{
447	struct octpko_attach_args pko_aa;
448
449	pko_aa.aa_port = sc->sc_port;
450	pko_aa.aa_regt = sc->sc_regt;
451	pko_aa.aa_cmdptr = &sc->sc_cmdptr;
452	pko_aa.aa_cmd_buf_pool = OCTEON_POOL_NO_CMD;
453	pko_aa.aa_cmd_buf_size = OCTEON_POOL_NWORDS_CMD;
454	octpko_init(&pko_aa, &sc->sc_pko);
455}
456
457/* XXX */
458static void
459cnmac_asx_init(struct cnmac_softc *sc)
460{
461	struct octasx_attach_args asx_aa;
462
463	asx_aa.aa_port = sc->sc_port;
464	asx_aa.aa_regt = sc->sc_regt;
465	octasx_init(&asx_aa, &sc->sc_asx);
466}
467
468static void
469cnmac_smi_init(struct cnmac_softc *sc)
470{
471	struct octsmi_attach_args smi_aa;
472
473	smi_aa.aa_port = sc->sc_port;
474	smi_aa.aa_regt = sc->sc_regt;
475	octsmi_init(&smi_aa, &sc->sc_smi);
476	octsmi_set_clock(sc->sc_smi, 0x1464ULL); /* XXX */
477}
478
479/* ---- XXX */
480
481#define	ADDR2UINT64(u, a) \
482	do { \
483		u = \
484		    (((uint64_t)a[0] << 40) | ((uint64_t)a[1] << 32) | \
485		     ((uint64_t)a[2] << 24) | ((uint64_t)a[3] << 16) | \
486		     ((uint64_t)a[4] <<	 8) | ((uint64_t)a[5] <<  0)); \
487	} while (0)
488#define	UINT642ADDR(a, u) \
489	do { \
490		a[0] = (uint8_t)((u) >> 40); a[1] = (uint8_t)((u) >> 32); \
491		a[2] = (uint8_t)((u) >> 24); a[3] = (uint8_t)((u) >> 16); \
492		a[4] = (uint8_t)((u) >>	 8); a[5] = (uint8_t)((u) >>  0); \
493	} while (0)
494
495static void
496cnmac_board_mac_addr(uint8_t *enaddr, size_t size, struct cnmac_softc *sc)
497{
498	prop_dictionary_t dict;
499	prop_data_t ea;
500
501	dict = device_properties(sc->sc_dev);
502	KASSERT(dict != NULL);
503	ea = prop_dictionary_get(dict, "mac-address");
504	KASSERT(ea != NULL);
505	memcpy(enaddr, prop_data_value(ea), size);
506}
507
508/* ---- media */
509
510static int
511cnmac_mii_readreg(device_t self, int phy_addr, int reg, uint16_t *val)
512{
513	struct cnmac_softc *sc = device_private(self);
514
515	return octsmi_read(sc->sc_smi, phy_addr, reg, val);
516}
517
518static int
519cnmac_mii_writereg(device_t self, int phy_addr, int reg, uint16_t val)
520{
521	struct cnmac_softc *sc = device_private(self);
522
523	return octsmi_write(sc->sc_smi, phy_addr, reg, val);
524}
525
526static void
527cnmac_mii_statchg(struct ifnet *ifp)
528{
529	struct cnmac_softc *sc = ifp->if_softc;
530
531	octpko_port_enable(sc->sc_pko, 0);
532	octgmx_port_enable(sc->sc_gmx_port, 0);
533
534	cnmac_reset(sc);
535
536	if (ISSET(ifp->if_flags, IFF_RUNNING))
537		octgmx_set_filter(sc->sc_gmx_port);
538
539	octpko_port_enable(sc->sc_pko, 1);
540	octgmx_port_enable(sc->sc_gmx_port, 1);
541}
542
543static int
544cnmac_mediainit(struct cnmac_softc *sc)
545{
546	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
547	struct mii_data *mii = &sc->sc_mii;
548	prop_object_t phy;
549
550	mii->mii_ifp = ifp;
551	mii->mii_readreg = cnmac_mii_readreg;
552	mii->mii_writereg = cnmac_mii_writereg;
553	mii->mii_statchg = cnmac_mii_statchg;
554	sc->sc_ethercom.ec_mii = mii;
555
556	/* Initialize ifmedia structures. */
557	ifmedia_init(&mii->mii_media, 0, ether_mediachange, cnmac_mediastatus);
558
559	phy = prop_dictionary_get(device_properties(sc->sc_dev), "phy-addr");
560	KASSERT(phy != NULL);
561
562	mii_attach(sc->sc_dev, mii, 0xffffffff, prop_number_signed_value(phy),
563	    MII_OFFSET_ANY, MIIF_DOPAUSE);
564
565	/* XXX XXX XXX */
566	if (LIST_FIRST(&mii->mii_phys) != NULL) {
567		/* XXX XXX XXX */
568		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
569		/* XXX XXX XXX */
570	} else {
571		/* XXX XXX XXX */
572		ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE,
573		    MII_MEDIA_NONE, NULL);
574		/* XXX XXX XXX */
575		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
576		/* XXX XXX XXX */
577	}
578	/* XXX XXX XXX */
579
580	return 0;
581}
582
583static void
584cnmac_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
585{
586	struct cnmac_softc *sc = ifp->if_softc;
587
588	mii_pollstat(&sc->sc_mii);
589
590	ifmr->ifm_status = sc->sc_mii.mii_media_status;
591	ifmr->ifm_active = sc->sc_mii.mii_media_active;
592	ifmr->ifm_active = (sc->sc_mii.mii_media_active & ~IFM_ETH_FMASK) |
593	    sc->sc_gmx_port->sc_port_flowflags;
594}
595
596/* ---- send buffer garbage collection */
597
598static inline void
599cnmac_send_queue_flush_prefetch(struct cnmac_softc *sc)
600{
601	CNMAC_KASSERT(sc->sc_prefetch == 0);
602	octfau_op_inc_fetch_8(&sc->sc_fau_done, 0);
603	sc->sc_prefetch = 1;
604}
605
606static inline void
607cnmac_send_queue_flush_fetch(struct cnmac_softc *sc)
608{
609#ifndef	 CNMAC_DEBUG
610	if (!sc->sc_prefetch)
611		return;
612#endif
613	CNMAC_KASSERT(sc->sc_prefetch == 1);
614	sc->sc_hard_done_cnt = octfau_op_inc_read_8(&sc->sc_fau_done);
615	CNMAC_KASSERT(sc->sc_hard_done_cnt <= 0);
616	sc->sc_prefetch = 0;
617}
618
619static inline void
620cnmac_send_queue_flush(struct cnmac_softc *sc)
621{
622	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
623	const int64_t sent_count = sc->sc_hard_done_cnt;
624	int i;
625
626	CNMAC_KASSERT(sc->sc_flush == 0);
627	CNMAC_KASSERT(sent_count <= 0);
628
629	for (i = 0; i < 0 - sent_count; i++) {
630		struct mbuf *m;
631		uint64_t *gbuf;
632
633		cnmac_send_queue_del(sc, &m, &gbuf);
634
635		octfpa_buf_put(cnmac_fb_sg, gbuf);
636		OCTEON_EVCNT_INC(sc, txbufgbput);
637
638		m_freem(m);
639
640		CLR(ifp->if_flags, IFF_OACTIVE);
641	}
642
643	octfau_op_inc_fetch_8(&sc->sc_fau_done, i);
644	sc->sc_flush = i;
645}
646
647static inline void
648cnmac_send_queue_flush_sync(struct cnmac_softc *sc)
649{
650	if (sc->sc_flush == 0)
651		return;
652
653	CNMAC_KASSERT(sc->sc_flush > 0);
654
655	/* XXX XXX XXX */
656	octfau_op_inc_read_8(&sc->sc_fau_done);
657	sc->sc_soft_req_cnt -= sc->sc_flush;
658	CNMAC_KASSERT(sc->sc_soft_req_cnt >= 0);
659	/* XXX XXX XXX */
660
661	sc->sc_flush = 0;
662}
663
664static inline int
665cnmac_send_queue_is_full(struct cnmac_softc *sc)
666{
667#ifdef CNMAC_SEND_QUEUE_CHECK
668	int64_t nofree_cnt;
669
670	nofree_cnt = sc->sc_soft_req_cnt + sc->sc_hard_done_cnt;
671
672	if (__predict_false(nofree_cnt == GATHER_QUEUE_SIZE - 1)) {
673		cnmac_send_queue_flush(sc);
674		OCTEON_EVCNT_INC(sc, txerrgbuf);
675		cnmac_send_queue_flush_sync(sc);
676		return 1;
677	}
678
679#endif
680	return 0;
681}
682
683/*
684 * (Ab)use m_nextpkt and m_paddr to maintain mbuf chain and pointer to gather
685 * buffer.  Other mbuf members may be used by m_freem(), so don't touch them!
686 */
687
688struct _send_queue_entry {
689	union {
690		struct mbuf _sqe_s_mbuf;
691		struct {
692			char _sqe_s_entry_pad[offsetof(struct mbuf, m_nextpkt)];
693			SIMPLEQ_ENTRY(_send_queue_entry) _sqe_s_entry_entry;
694		} _sqe_s_entry;
695		struct {
696			char _sqe_s_gbuf_pad[offsetof(struct mbuf, m_paddr)];
697			uint64_t *_sqe_s_gbuf_gbuf;
698		} _sqe_s_gbuf;
699	} _sqe_u;
700#define	_sqe_entry	_sqe_u._sqe_s_entry._sqe_s_entry_entry
701#define	_sqe_gbuf	_sqe_u._sqe_s_gbuf._sqe_s_gbuf_gbuf
702};
703
704static inline void
705cnmac_send_queue_add(struct cnmac_softc *sc, struct mbuf *m,
706    uint64_t *gbuf)
707{
708	struct _send_queue_entry *sqe = (struct _send_queue_entry *)m;
709
710	sqe->_sqe_gbuf = gbuf;
711	SIMPLEQ_INSERT_TAIL(&sc->sc_sendq, sqe, _sqe_entry);
712
713	if ((m->m_flags & M_EXT) && m->m_ext.ext_free != NULL)
714		sc->sc_ext_callback_cnt++;
715
716	OCTEON_EVCNT_INC(sc, txadd);
717}
718
719static inline void
720cnmac_send_queue_del(struct cnmac_softc *sc, struct mbuf **rm, uint64_t **rgbuf)
721{
722	struct _send_queue_entry *sqe;
723
724	sqe = SIMPLEQ_FIRST(&sc->sc_sendq);
725	CNMAC_KASSERT(sqe != NULL);
726	SIMPLEQ_REMOVE_HEAD(&sc->sc_sendq, _sqe_entry);
727
728	*rm = (void *)sqe;
729	*rgbuf = sqe->_sqe_gbuf;
730
731	if (((*rm)->m_flags & M_EXT) && (*rm)->m_ext.ext_free != NULL) {
732		sc->sc_ext_callback_cnt--;
733		CNMAC_KASSERT(sc->sc_ext_callback_cnt >= 0);
734	}
735
736	OCTEON_EVCNT_INC(sc, txdel);
737}
738
739static inline int
740cnmac_buf_free_work(struct cnmac_softc *sc, uint64_t *work, uint64_t word2)
741{
742	/* XXX when jumbo frame */
743	if (ISSET(word2, PIP_WQE_WORD2_IP_BUFS)) {
744		paddr_t addr;
745		paddr_t start_buffer;
746
747		addr = work[3] & PIP_WQE_WORD3_ADDR;
748		start_buffer = addr & ~(2048 - 1);
749
750		octfpa_buf_put_paddr(cnmac_fb_pkt, start_buffer);
751		OCTEON_EVCNT_INC(sc, rxbufpkput);
752	}
753
754	octfpa_buf_put(cnmac_fb_wqe, work);
755	OCTEON_EVCNT_INC(sc, rxbufwqput);
756
757	return 0;
758}
759
760static inline void
761cnmac_buf_ext_free_m(struct mbuf *m, void *buf, size_t size, void *arg)
762{
763	uint64_t *work = (void *)arg;
764#ifdef CNMAC_DEBUG
765	struct cnmac_softc *sc = (void *)(uintptr_t)work[0];
766#endif
767	int s = splnet();
768
769	OCTEON_EVCNT_INC(sc, rxrs);
770
771	octfpa_buf_put(cnmac_fb_wqe, work);
772	OCTEON_EVCNT_INC(sc, rxbufwqput);
773
774	CNMAC_KASSERT(m != NULL);
775
776	pool_cache_put(mb_cache, m);
777
778	splx(s);
779}
780
781static inline void
782cnmac_buf_ext_free_ext(struct mbuf *m, void *buf, size_t size, void *arg)
783{
784	uint64_t *work = (void *)arg;
785#ifdef CNMAC_DEBUG
786	struct cnmac_softc *sc = (void *)(uintptr_t)work[0];
787#endif
788	int s = splnet();
789
790	octfpa_buf_put(cnmac_fb_wqe, work);
791	OCTEON_EVCNT_INC(sc, rxbufwqput);
792
793	octfpa_buf_put(cnmac_fb_pkt, buf);
794	OCTEON_EVCNT_INC(sc, rxbufpkput);
795
796	CNMAC_KASSERT(m != NULL);
797
798	pool_cache_put(mb_cache, m);
799
800	splx(s);
801}
802
803/* ---- ifnet interfaces */
804
805static int
806cnmac_ioctl(struct ifnet *ifp, u_long cmd, void *data)
807{
808	struct cnmac_softc *sc = ifp->if_softc;
809	struct ifreq *ifr = (struct ifreq *)data;
810	int s, error;
811
812	s = splnet();
813	switch (cmd) {
814	case SIOCSIFMEDIA:
815		/* Flow control requires full-duplex mode. */
816		if (IFM_SUBTYPE(ifr->ifr_media) == IFM_AUTO ||
817		    (ifr->ifr_media & IFM_FDX) == 0) {
818			ifr->ifr_media &= ~IFM_ETH_FMASK;
819		}
820		if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO) {
821			if ((ifr->ifr_media & IFM_ETH_FMASK) == IFM_FLOW) {
822				ifr->ifr_media |=
823				    IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE;
824			}
825			sc->sc_gmx_port->sc_port_flowflags =
826				ifr->ifr_media & IFM_ETH_FMASK;
827		}
828		error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
829		break;
830	default:
831		error = ether_ioctl(ifp, cmd, data);
832		if (error == ENETRESET) {
833			/*
834			 * Multicast list has changed; set the hardware filter
835			 * accordingly.
836			 */
837			if (ISSET(ifp->if_flags, IFF_RUNNING))
838				octgmx_set_filter(sc->sc_gmx_port);
839			error = 0;
840		}
841		break;
842	}
843	cnmac_start(ifp);
844	splx(s);
845
846	return error;
847}
848
849/* ---- send (output) */
850
851static inline uint64_t
852cnmac_send_makecmd_w0(uint64_t fau0, uint64_t fau1, size_t len, int segs)
853{
854	return octpko_cmd_word0(
855		OCT_FAU_OP_SIZE_64,		/* sz1 */
856		OCT_FAU_OP_SIZE_64,		/* sz0 */
857		1, fau1, 1, fau0,		/* s1, reg1, s0, reg0 */
858		0,				/* le */
859		cnmac_param_pko_cmd_w0_n2,	/* n2 */
860		1, 0,				/* q, r */
861		(segs == 1) ? 0 : 1,		/* g */
862		0, 0, 1,			/* ipoffp1, ii, df */
863		segs, (int)len);		/* segs, totalbytes */
864}
865
866static inline uint64_t
867cnmac_send_makecmd_w1(int size, paddr_t addr)
868{
869	return octpko_cmd_word1(
870		0, 0,				/* i, back */
871		FPA_GATHER_BUFFER_POOL,		/* pool */
872		size, addr);			/* size, addr */
873}
874
875static inline int
876cnmac_send_makecmd_gbuf(struct cnmac_softc *sc, struct mbuf *m0, uint64_t *gbuf,
877    int *rsegs)
878{
879	struct mbuf *m;
880	int segs = 0;
881	uintptr_t laddr, rlen, nlen;
882
883	for (m = m0; m != NULL; m = m->m_next) {
884
885		if (__predict_false(m->m_len == 0))
886			continue;
887
888#if 0
889		CNMAC_KASSERT(((uint32_t)m->m_data & (PAGE_SIZE - 1))
890		   == (kvtophys((vaddr_t)m->m_data) & (PAGE_SIZE - 1)));
891#endif
892
893		/* Aligned 4k */
894		laddr = (uintptr_t)m->m_data & (PAGE_SIZE - 1);
895
896		if (laddr + m->m_len > PAGE_SIZE) {
897			/* XXX XXX XXX */
898			rlen = PAGE_SIZE - laddr;
899			nlen = m->m_len - rlen;
900			*(gbuf + segs) = cnmac_send_makecmd_w1(rlen,
901			    kvtophys((vaddr_t)m->m_data));
902			segs++;
903			if (segs > 63) {
904				return 1;
905			}
906			/* XXX XXX XXX */
907		} else {
908			rlen = 0;
909			nlen = m->m_len;
910		}
911
912		*(gbuf + segs) = cnmac_send_makecmd_w1(nlen,
913		    kvtophys((vaddr_t)(m->m_data + rlen)));
914		segs++;
915		if (segs > 63) {
916			return 1;
917		}
918	}
919
920	CNMAC_KASSERT(m == NULL);
921
922	*rsegs = segs;
923
924	return 0;
925}
926
927static inline int
928cnmac_send_makecmd(struct cnmac_softc *sc, struct mbuf *m,
929    uint64_t *gbuf, uint64_t *rpko_cmd_w0, uint64_t *rpko_cmd_w1)
930{
931	uint64_t pko_cmd_w0, pko_cmd_w1;
932	int segs;
933	int result = 0;
934
935	if (cnmac_send_makecmd_gbuf(sc, m, gbuf, &segs)) {
936		log(LOG_WARNING, "%s: there are a lot of number of segments"
937		    " of transmission data", device_xname(sc->sc_dev));
938		result = 1;
939		goto done;
940	}
941
942	/*
943	 * segs == 1	-> link mode (single continuous buffer)
944	 *		   WORD1[size] is number of bytes pointed by segment
945	 *
946	 * segs > 1	-> gather mode (scatter-gather buffer)
947	 *		   WORD1[size] is number of segments
948	 */
949	pko_cmd_w0 = cnmac_send_makecmd_w0(sc->sc_fau_done.fd_regno,
950	    0, m->m_pkthdr.len, segs);
951	if (segs == 1) {
952		pko_cmd_w1 = cnmac_send_makecmd_w1(
953		    m->m_pkthdr.len, kvtophys((vaddr_t)m->m_data));
954	} else {
955#ifdef __mips_n32
956		KASSERT(MIPS_KSEG0_P(gbuf));
957		pko_cmd_w1 = cnmac_send_makecmd_w1(segs,
958		    MIPS_KSEG0_TO_PHYS(gbuf));
959#else
960		pko_cmd_w1 = cnmac_send_makecmd_w1(segs,
961		    MIPS_XKPHYS_TO_PHYS(gbuf));
962#endif
963	}
964
965	*rpko_cmd_w0 = pko_cmd_w0;
966	*rpko_cmd_w1 = pko_cmd_w1;
967
968done:
969	return result;
970}
971
972static inline int
973cnmac_send_cmd(struct cnmac_softc *sc, uint64_t pko_cmd_w0,
974    uint64_t pko_cmd_w1, int *pwdc)
975{
976	uint64_t *cmdptr;
977	int result = 0;
978
979#ifdef __mips_n32
980	KASSERT((sc->sc_cmdptr.cmdptr & ~MIPS_PHYS_MASK) == 0);
981	cmdptr = (uint64_t *)MIPS_PHYS_TO_KSEG0(sc->sc_cmdptr.cmdptr);
982#else
983	cmdptr = (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(sc->sc_cmdptr.cmdptr);
984#endif
985	cmdptr += sc->sc_cmdptr.cmdptr_idx;
986
987	CNMAC_KASSERT(cmdptr != NULL);
988
989	*cmdptr++ = pko_cmd_w0;
990	*cmdptr++ = pko_cmd_w1;
991
992	CNMAC_KASSERT(sc->sc_cmdptr.cmdptr_idx + 2 <= FPA_COMMAND_BUFFER_POOL_NWORDS - 1);
993
994	if (sc->sc_cmdptr.cmdptr_idx + 2 == FPA_COMMAND_BUFFER_POOL_NWORDS - 1) {
995		paddr_t buf;
996
997		buf = octfpa_buf_get_paddr(cnmac_fb_cmd);
998		if (buf == 0) {
999			log(LOG_WARNING,
1000			    "%s: can not allocate command buffer from free pool allocator\n",
1001			    device_xname(sc->sc_dev));
1002			result = 1;
1003			goto done;
1004		}
1005		OCTEON_EVCNT_INC(sc, txbufcbget);
1006		*cmdptr++ = buf;
1007		sc->sc_cmdptr.cmdptr = (uint64_t)buf;
1008		sc->sc_cmdptr.cmdptr_idx = 0;
1009	} else {
1010		sc->sc_cmdptr.cmdptr_idx += 2;
1011	}
1012
1013	*pwdc += 2;
1014
1015done:
1016	return result;
1017}
1018
1019static inline int
1020cnmac_send_buf(struct cnmac_softc *sc, struct mbuf *m, uint64_t *gbuf,
1021    int *pwdc)
1022{
1023	int result = 0, error;
1024	uint64_t pko_cmd_w0, pko_cmd_w1;
1025
1026	error = cnmac_send_makecmd(sc, m, gbuf, &pko_cmd_w0, &pko_cmd_w1);
1027	if (error != 0) {
1028		/* Already logging */
1029		OCTEON_EVCNT_INC(sc, txerrmkcmd);
1030		result = error;
1031		goto done;
1032	}
1033
1034	error = cnmac_send_cmd(sc, pko_cmd_w0, pko_cmd_w1, pwdc);
1035	if (error != 0) {
1036		/* Already logging */
1037		OCTEON_EVCNT_INC(sc, txerrcmd);
1038		result = error;
1039	}
1040
1041done:
1042	return result;
1043}
1044
1045static inline int
1046cnmac_send(struct cnmac_softc *sc, struct mbuf *m, int *pwdc)
1047{
1048	paddr_t gaddr = 0;
1049	uint64_t *gbuf = NULL;
1050	int result = 0, error;
1051
1052	OCTEON_EVCNT_INC(sc, tx);
1053
1054	gaddr = octfpa_buf_get_paddr(cnmac_fb_sg);
1055	if (gaddr == 0) {
1056		log(LOG_WARNING, "%s: can not allocate gather buffer from "
1057		    "free pool allocator\n", device_xname(sc->sc_dev));
1058		OCTEON_EVCNT_INC(sc, txerrgbuf);
1059		result = 1;
1060		goto done;
1061	}
1062	OCTEON_EVCNT_INC(sc, txbufgbget);
1063
1064#ifdef __mips_n32
1065	KASSERT((gaddr & ~MIPS_PHYS_MASK) == 0);
1066	gbuf = (uint64_t *)(uintptr_t)MIPS_PHYS_TO_KSEG0(gaddr);
1067#else
1068	gbuf = (uint64_t *)(uintptr_t)MIPS_PHYS_TO_XKPHYS_CACHED(gaddr);
1069#endif
1070
1071	CNMAC_KASSERT(gbuf != NULL);
1072
1073	error = cnmac_send_buf(sc, m, gbuf, pwdc);
1074	if (error != 0) {
1075		/* Already logging */
1076		octfpa_buf_put_paddr(cnmac_fb_sg, gaddr);
1077		OCTEON_EVCNT_INC(sc, txbufgbput);
1078		result = error;
1079		goto done;
1080	}
1081
1082	cnmac_send_queue_add(sc, m, gbuf);
1083
1084done:
1085	return result;
1086}
1087
1088static void
1089cnmac_start(struct ifnet *ifp)
1090{
1091	struct cnmac_softc *sc = ifp->if_softc;
1092	struct mbuf *m;
1093	int wdc = 0;
1094
1095	/*
1096	 * Performance tuning
1097	 * pre-send iobdma request
1098	 */
1099	cnmac_send_queue_flush_prefetch(sc);
1100
1101	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
1102		goto last;
1103
1104	/* XXX assume that OCTEON doesn't buffer packets */
1105	if (__predict_false(!octgmx_link_status(sc->sc_gmx_port))) {
1106		/* Dequeue and drop them */
1107		while (1) {
1108			IFQ_DEQUEUE(&ifp->if_snd, m);
1109			if (m == NULL)
1110				break;
1111
1112			m_freem(m);
1113			IF_DROP(&ifp->if_snd);
1114			OCTEON_EVCNT_INC(sc, txerrlink);
1115		}
1116		goto last;
1117	}
1118
1119	for (;;) {
1120		IFQ_POLL(&ifp->if_snd, m);
1121		if (__predict_false(m == NULL))
1122			break;
1123
1124		/* XXX XXX XXX */
1125		cnmac_send_queue_flush_fetch(sc);
1126
1127		/*
1128		 * If no free send buffer is available, free all the sent
1129		 * buffers and bail out.
1130		 */
1131		if (cnmac_send_queue_is_full(sc)) {
1132			SET(ifp->if_flags, IFF_OACTIVE);
1133			if (wdc > 0)
1134				octpko_op_doorbell_write(sc->sc_port,
1135				    sc->sc_port, wdc);
1136			return;
1137		}
1138		/* XXX XXX XXX */
1139
1140		IFQ_DEQUEUE(&ifp->if_snd, m);
1141
1142		bpf_mtap(ifp, m, BPF_D_OUT);
1143
1144		/* XXX XXX XXX */
1145		if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh)
1146			cnmac_send_queue_flush(sc);
1147		if (cnmac_send(sc, m, &wdc)) {
1148			IF_DROP(&ifp->if_snd);
1149			m_freem(m);
1150			log(LOG_WARNING,
1151			  "%s: failed in the transmission of the packet\n",
1152			  device_xname(sc->sc_dev));
1153			OCTEON_EVCNT_INC(sc, txerr);
1154		} else
1155			sc->sc_soft_req_cnt++;
1156
1157		if (sc->sc_flush)
1158			cnmac_send_queue_flush_sync(sc);
1159		/* XXX XXX XXX */
1160
1161		/* Send next iobdma request */
1162		cnmac_send_queue_flush_prefetch(sc);
1163	}
1164
1165	if (wdc > 0)
1166		octpko_op_doorbell_write(sc->sc_port, sc->sc_port, wdc);
1167
1168/*
1169 * Don't schedule send-buffer-free callout every time - those buffers are freed
1170 * by "free tick".  This makes some packets like NFS slower.
1171 */
1172#ifdef CNMAC_USENFS
1173	if (__predict_false(sc->sc_ext_callback_cnt > 0)) {
1174		int timo;
1175
1176		/* ??? */
1177		timo = hz - (100 * sc->sc_ext_callback_cnt);
1178		if (timo < 10)
1179			timo = 10;
1180		callout_schedule(&sc->sc_tick_free_ch, timo);
1181	}
1182#endif
1183
1184last:
1185	cnmac_send_queue_flush_fetch(sc);
1186}
1187
1188static void
1189cnmac_watchdog(struct ifnet *ifp)
1190{
1191	struct cnmac_softc *sc = ifp->if_softc;
1192
1193	printf("%s: device timeout\n", device_xname(sc->sc_dev));
1194
1195	cnmac_configure(sc);
1196
1197	SET(ifp->if_flags, IFF_RUNNING);
1198	CLR(ifp->if_flags, IFF_OACTIVE);
1199	ifp->if_timer = 0;
1200
1201	cnmac_start(ifp);
1202}
1203
1204static int
1205cnmac_init(struct ifnet *ifp)
1206{
1207	struct cnmac_softc *sc = ifp->if_softc;
1208
1209	/* XXX don't disable commonly used parts!!! XXX */
1210	if (sc->sc_init_flag == 0) {
1211		/* Cancel any pending I/O. */
1212		cnmac_stop(ifp, 0);
1213
1214		/* Initialize the device */
1215		cnmac_configure(sc);
1216
1217		octpko_enable(sc->sc_pko);
1218		octipd_enable(sc->sc_ipd);
1219
1220		sc->sc_init_flag = 1;
1221	} else {
1222		octgmx_port_enable(sc->sc_gmx_port, 1);
1223	}
1224	mii_ifmedia_change(&sc->sc_mii);
1225
1226	octgmx_set_filter(sc->sc_gmx_port);
1227
1228	callout_reset(&sc->sc_tick_misc_ch, hz, cnmac_tick_misc, sc);
1229	callout_reset(&sc->sc_tick_free_ch, hz, cnmac_tick_free, sc);
1230
1231	SET(ifp->if_flags, IFF_RUNNING);
1232	CLR(ifp->if_flags, IFF_OACTIVE);
1233
1234	return 0;
1235}
1236
1237static void
1238cnmac_stop(struct ifnet *ifp, int disable)
1239{
1240	struct cnmac_softc *sc = ifp->if_softc;
1241
1242	callout_stop(&sc->sc_tick_misc_ch);
1243	callout_stop(&sc->sc_tick_free_ch);
1244
1245	mii_down(&sc->sc_mii);
1246
1247	octgmx_port_enable(sc->sc_gmx_port, 0);
1248
1249	/* Mark the interface as down and cancel the watchdog timer. */
1250	CLR(ifp->if_flags, IFF_RUNNING | IFF_OACTIVE);
1251	ifp->if_timer = 0;
1252}
1253
1254/* ---- misc */
1255
1256#define PKO_INDEX_MASK	((1ULL << 12/* XXX */) - 1)
1257
1258static int
1259cnmac_reset(struct cnmac_softc *sc)
1260{
1261	octgmx_reset_speed(sc->sc_gmx_port);
1262	octgmx_reset_flowctl(sc->sc_gmx_port);
1263	octgmx_reset_timing(sc->sc_gmx_port);
1264
1265	return 0;
1266}
1267
1268static int
1269cnmac_configure(struct cnmac_softc *sc)
1270{
1271	octgmx_port_enable(sc->sc_gmx_port, 0);
1272
1273	cnmac_reset(sc);
1274
1275	cnmac_configure_common(sc);
1276
1277	octpko_port_config(sc->sc_pko);
1278	octpko_port_enable(sc->sc_pko, 1);
1279	octpip_port_config(sc->sc_pip);
1280
1281	octgmx_tx_stats_rd_clr(sc->sc_gmx_port, 1);
1282	octgmx_rx_stats_rd_clr(sc->sc_gmx_port, 1);
1283
1284	octgmx_port_enable(sc->sc_gmx_port, 1);
1285
1286	return 0;
1287}
1288
1289static int
1290cnmac_configure_common(struct cnmac_softc *sc)
1291{
1292	static int once;
1293
1294	if (once == 1)
1295		return 0;
1296	once = 1;
1297
1298	octipd_config(sc->sc_ipd);
1299#ifdef CNMAC_IPD_RED
1300	octipd_red(sc->sc_ipd, RECV_QUEUE_SIZE >> 2, RECV_QUEUE_SIZE >> 3);
1301#endif
1302	octpko_config(sc->sc_pko);
1303
1304	octpow_config(sc->sc_pow, OCTEON_POW_GROUP_PIP);
1305
1306	return 0;
1307}
1308
1309/* ---- receive (input) */
1310
1311static inline int
1312cnmac_recv_mbuf(struct cnmac_softc *sc, uint64_t *work, struct mbuf **rm)
1313{
1314	struct mbuf *m;
1315	void (*ext_free)(struct mbuf *, void *, size_t, void *);
1316	void *ext_buf;
1317	size_t ext_size;
1318	void *data;
1319	uint64_t word1 = work[1];
1320	uint64_t word2 = work[2];
1321	uint64_t word3 = work[3];
1322
1323	MGETHDR(m, M_NOWAIT, MT_DATA);
1324	if (m == NULL)
1325		return 1;
1326	CNMAC_KASSERT(m != NULL);
1327
1328	if ((word2 & PIP_WQE_WORD2_IP_BUFS) == 0) {
1329		/* Dynamic short */
1330		ext_free = cnmac_buf_ext_free_m;
1331		ext_buf = &work[4];
1332		ext_size = 96;
1333
1334		data = &work[4 + sc->sc_ip_offset / sizeof(uint64_t)];
1335	} else {
1336		vaddr_t addr;
1337		vaddr_t start_buffer;
1338
1339#ifdef __mips_n32
1340		KASSERT((word3 & ~MIPS_PHYS_MASK) == 0);
1341		addr = MIPS_PHYS_TO_KSEG0(word3 & PIP_WQE_WORD3_ADDR);
1342#else
1343		addr = MIPS_PHYS_TO_XKPHYS_CACHED(word3 & PIP_WQE_WORD3_ADDR);
1344#endif
1345		start_buffer = addr & ~(2048 - 1);
1346
1347		ext_free = cnmac_buf_ext_free_ext;
1348		ext_buf = (void *)start_buffer;
1349		ext_size = 2048;
1350
1351		data = (void *)addr;
1352	}
1353
1354	/* Embed sc pointer into work[0] for _ext_free evcnt */
1355	work[0] = (uintptr_t)sc;
1356
1357	MEXTADD(m, ext_buf, ext_size, 0, ext_free, work);
1358	CNMAC_KASSERT(ISSET(m->m_flags, M_EXT));
1359
1360	m->m_data = data;
1361	m->m_len = m->m_pkthdr.len = (word1 & PIP_WQE_WORD1_LEN) >> 48;
1362	m_set_rcvif(m, &sc->sc_ethercom.ec_if);
1363
1364	/* Not readonly buffer */
1365	m->m_flags |= M_EXT_RW;
1366
1367	*rm = m;
1368
1369	CNMAC_KASSERT(*rm != NULL);
1370
1371	return 0;
1372}
1373
1374static inline int
1375cnmac_recv_check_code(struct cnmac_softc *sc, uint64_t word2)
1376{
1377	uint64_t opecode = word2 & PIP_WQE_WORD2_NOIP_OPECODE;
1378
1379	if (__predict_true(!ISSET(word2, PIP_WQE_WORD2_NOIP_RE)))
1380		return 0;
1381
1382	/* This error is harmless */
1383	if (opecode == PIP_OVER_ERR)
1384		return 0;
1385
1386	return 1;
1387}
1388
1389static inline int
1390cnmac_recv_check_jumbo(struct cnmac_softc *sc, uint64_t word2)
1391{
1392	if (__predict_false((word2 & PIP_WQE_WORD2_IP_BUFS) > (1ULL << 56)))
1393		return 1;
1394	return 0;
1395}
1396
1397static inline int
1398cnmac_recv_check_link(struct cnmac_softc *sc, uint64_t word2)
1399{
1400	if (__predict_false(!octgmx_link_status(sc->sc_gmx_port)))
1401		return 1;
1402	return 0;
1403}
1404
1405static inline int
1406cnmac_recv_check(struct cnmac_softc *sc, uint64_t word2)
1407{
1408	if (__predict_false(cnmac_recv_check_link(sc, word2)) != 0) {
1409		if (ratecheck(&sc->sc_rate_recv_check_link_last,
1410		    &sc->sc_rate_recv_check_link_cap))
1411			log(LOG_DEBUG,
1412			    "%s: link is not up, the packet was dropped\n",
1413			    device_xname(sc->sc_dev));
1414		OCTEON_EVCNT_INC(sc, rxerrlink);
1415		return 1;
1416	}
1417
1418#if 0 /* XXX Performance tuning (Jumbo-frame is not supported yet!) */
1419	if (__predict_false(cnmac_recv_check_jumbo(sc, word2)) != 0) {
1420		/* XXX jumbo frame */
1421		if (ratecheck(&sc->sc_rate_recv_check_jumbo_last,
1422		    &sc->sc_rate_recv_check_jumbo_cap))
1423			log(LOG_DEBUG,
1424			    "jumbo frame was received\n");
1425		OCTEON_EVCNT_INC(sc, rxerrjmb);
1426		return 1;
1427	}
1428#endif
1429
1430	if (__predict_false(cnmac_recv_check_code(sc, word2)) != 0) {
1431
1432		if ((word2 & PIP_WQE_WORD2_NOIP_OPECODE) ==
1433				PIP_WQE_WORD2_RE_OPCODE_LENGTH) {
1434			/* No logging */
1435			/* XXX increment special error count */
1436		} else if ((word2 & PIP_WQE_WORD2_NOIP_OPECODE) ==
1437				PIP_WQE_WORD2_RE_OPCODE_PARTIAL) {
1438			/* Not an error, it's because of overload */
1439		} else {
1440
1441			if (ratecheck(&sc->sc_rate_recv_check_code_last,
1442			    &sc->sc_rate_recv_check_code_cap))
1443				log(LOG_WARNING,
1444				    "%s: reception error, packet dropped "
1445				    "(error code = %" PRId64 ")\n",
1446				    device_xname(sc->sc_dev), word2 & PIP_WQE_WORD2_NOIP_OPECODE);
1447		}
1448		OCTEON_EVCNT_INC(sc, rxerrcode);
1449		return 1;
1450	}
1451
1452	return 0;
1453}
1454
1455static inline int
1456cnmac_recv(struct cnmac_softc *sc, uint64_t *work)
1457{
1458	int result = 0;
1459	struct ifnet *ifp;
1460	struct mbuf *m;
1461	uint64_t word2;
1462
1463	/* XXX XXX XXX */
1464	/*
1465	 * Performance tuning
1466	 * pre-send iobdma request
1467	 */
1468	if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) {
1469		cnmac_send_queue_flush_prefetch(sc);
1470	}
1471	/* XXX XXX XXX */
1472
1473	CNMAC_KASSERT(sc != NULL);
1474	CNMAC_KASSERT(work != NULL);
1475
1476	OCTEON_EVCNT_INC(sc, rx);
1477
1478	word2 = work[2];
1479	ifp = &sc->sc_ethercom.ec_if;
1480
1481	CNMAC_KASSERT(ifp != NULL);
1482
1483	if (__predict_false(cnmac_recv_check(sc, word2) != 0)) {
1484		if_statinc(ifp, if_ierrors);
1485		result = 1;
1486		cnmac_buf_free_work(sc, work, word2);
1487		goto drop;
1488	}
1489
1490	if (__predict_false(cnmac_recv_mbuf(sc, work, &m) != 0)) {
1491		if_statinc(ifp, if_ierrors);
1492		result = 1;
1493		cnmac_buf_free_work(sc, work, word2);
1494		goto drop;
1495	}
1496
1497	/* work[0] .. work[3] may not be valid any more */
1498
1499	CNMAC_KASSERT(m != NULL);
1500
1501	octipd_offload(word2, m->m_data, &m->m_pkthdr.csum_flags);
1502
1503	/* XXX XXX XXX */
1504	if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) {
1505		cnmac_send_queue_flush_fetch(sc);
1506		cnmac_send_queue_flush(sc);
1507	}
1508
1509	/* XXX XXX XXX */
1510	if (sc->sc_flush)
1511		cnmac_send_queue_flush_sync(sc);
1512	/* XXX XXX XXX */
1513
1514	if_percpuq_enqueue(ifp->if_percpuq, m);
1515
1516	return 0;
1517
1518drop:
1519	/* XXX XXX XXX */
1520	if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) {
1521		cnmac_send_queue_flush_fetch(sc);
1522	}
1523	/* XXX XXX XXX */
1524
1525	return result;
1526}
1527
1528static void
1529cnmac_recv_redir(struct ifnet *ifp, struct mbuf *m)
1530{
1531	struct cnmac_softc *rsc = ifp->if_softc;
1532	struct cnmac_softc *sc = NULL;
1533	int i, wdc = 0;
1534
1535	for (i = 0; i < 3 /* XXX */; i++) {
1536		if (rsc->sc_redir & (1 << i))
1537			sc = cnmac_gsc[i];
1538	}
1539
1540	if (sc == NULL) {
1541		m_freem(m);
1542		return;
1543	}
1544	cnmac_send_queue_flush_prefetch(sc);
1545
1546	cnmac_send_queue_flush_fetch(sc);
1547
1548	if (cnmac_send_queue_is_full(sc)) {
1549		m_freem(m);
1550		return;
1551	}
1552	if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh)
1553		cnmac_send_queue_flush(sc);
1554
1555	if (cnmac_send(sc, m, &wdc)) {
1556		IF_DROP(&ifp->if_snd);
1557		m_freem(m);
1558	} else {
1559		octpko_op_doorbell_write(sc->sc_port, sc->sc_port, wdc);
1560		sc->sc_soft_req_cnt++;
1561	}
1562
1563	if (sc->sc_flush)
1564		cnmac_send_queue_flush_sync(sc);
1565}
1566
1567static inline void
1568cnmac_recv_intr(void *data, uint64_t *work)
1569{
1570	struct cnmac_softc *sc;
1571	int port;
1572
1573	CNMAC_KASSERT(work != NULL);
1574
1575	port = (work[1] & PIP_WQE_WORD1_IPRT) >> 42;
1576
1577	CNMAC_KASSERT(port < GMX_PORT_NUNITS);
1578
1579	sc = cnmac_gsc[port];
1580
1581	CNMAC_KASSERT(sc != NULL);
1582	CNMAC_KASSERT(port == sc->sc_port);
1583
1584	/* XXX process all work queue entries anyway */
1585
1586	(void)cnmac_recv(sc, work);
1587}
1588
1589/* ---- tick */
1590
1591/*
1592 * cnmac_tick_free
1593 *
1594 * => garbage collect send gather buffer / mbuf
1595 * => called at softclock
1596 */
1597static void
1598cnmac_tick_free(void *arg)
1599{
1600	struct cnmac_softc *sc = arg;
1601	int timo;
1602	int s;
1603
1604	s = splnet();
1605	/* XXX XXX XXX */
1606	if (sc->sc_soft_req_cnt > 0) {
1607		cnmac_send_queue_flush_prefetch(sc);
1608		cnmac_send_queue_flush_fetch(sc);
1609		cnmac_send_queue_flush(sc);
1610		cnmac_send_queue_flush_sync(sc);
1611	}
1612	/* XXX XXX XXX */
1613
1614	/* XXX XXX XXX */
1615	/* ??? */
1616	timo = hz - (100 * sc->sc_ext_callback_cnt);
1617	if (timo < 10)
1618		 timo = 10;
1619	callout_schedule(&sc->sc_tick_free_ch, timo);
1620	/* XXX XXX XXX */
1621	splx(s);
1622}
1623
1624/*
1625 * cnmac_tick_misc
1626 *
1627 * => collect statistics
1628 * => check link status
1629 * => called at softclock
1630 */
1631static void
1632cnmac_tick_misc(void *arg)
1633{
1634	struct cnmac_softc *sc = arg;
1635	struct ifnet *ifp;
1636	int s;
1637
1638	s = splnet();
1639
1640	ifp = &sc->sc_ethercom.ec_if;
1641
1642	octgmx_stats(sc->sc_gmx_port);
1643	octpip_stats(sc->sc_pip, ifp, sc->sc_port);
1644	mii_tick(&sc->sc_mii);
1645
1646	splx(s);
1647
1648	callout_schedule(&sc->sc_tick_misc_ch, hz);
1649}
1650
1651/* ---- Odd nibble preamble workaround (software CRC processing) */
1652
1653/* ---- sysctl */
1654
1655static int	cnmac_sysctl_verify(SYSCTLFN_ARGS);
1656static int	cnmac_sysctl_pool(SYSCTLFN_ARGS);
1657static int	cnmac_sysctl_rd(SYSCTLFN_ARGS);
1658
1659static int	cnmac_sysctl_pkocmdw0n2_num;
1660static int	cnmac_sysctl_pipdynrs_num;
1661static int	cnmac_sysctl_redir_num;
1662static int	cnmac_sysctl_pkt_pool_num;
1663static int	cnmac_sysctl_wqe_pool_num;
1664static int	cnmac_sysctl_cmd_pool_num;
1665static int	cnmac_sysctl_sg_pool_num;
1666static int	cnmac_sysctl_pktbuf_num;
1667
1668/*
1669 * Set up sysctl(3) MIB, hw.cnmac.*.
1670 */
1671SYSCTL_SETUP(sysctl_octeon_eth, "sysctl cnmac subtree setup")
1672{
1673	int rc;
1674	int cnmac_sysctl_root_num;
1675	const struct sysctlnode *node;
1676
1677	if ((rc = sysctl_createv(clog, 0, NULL, NULL,
1678		    0, CTLTYPE_NODE, "hw", NULL,
1679		    NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) {
1680		goto err;
1681	}
1682
1683	if ((rc = sysctl_createv(clog, 0, NULL, &node,
1684		    0, CTLTYPE_NODE, "cnmac",
1685		    SYSCTL_DESCR("cnmac interface controls"),
1686		    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
1687		goto err;
1688	}
1689
1690	cnmac_sysctl_root_num = node->sysctl_num;
1691
1692	if ((rc = sysctl_createv(clog, 0, NULL, &node,
1693		    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1694		    CTLTYPE_INT, "pko_cmd_w0_n2",
1695		    SYSCTL_DESCR("PKO command WORD0 N2 bit"),
1696		    cnmac_sysctl_verify, 0,
1697		    &cnmac_param_pko_cmd_w0_n2,
1698		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
1699		    CTL_EOL)) != 0) {
1700		goto err;
1701	}
1702
1703	cnmac_sysctl_pkocmdw0n2_num = node->sysctl_num;
1704
1705	if ((rc = sysctl_createv(clog, 0, NULL, &node,
1706		    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1707		    CTLTYPE_INT, "pip_dyn_rs",
1708		    SYSCTL_DESCR("PIP dynamic short in WQE"),
1709		    cnmac_sysctl_verify, 0,
1710		    &cnmac_param_pip_dyn_rs,
1711		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
1712		    CTL_EOL)) != 0) {
1713		goto err;
1714	}
1715
1716	cnmac_sysctl_pipdynrs_num = node->sysctl_num;
1717
1718	if ((rc = sysctl_createv(clog, 0, NULL, &node,
1719		    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1720		    CTLTYPE_INT, "redir",
1721		    SYSCTL_DESCR("input port redirection"),
1722		    cnmac_sysctl_verify, 0,
1723		    &cnmac_param_redir,
1724		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
1725		    CTL_EOL)) != 0) {
1726		goto err;
1727	}
1728
1729	cnmac_sysctl_redir_num = node->sysctl_num;
1730
1731	if ((rc = sysctl_createv(clog, 0, NULL, &node,
1732		    CTLFLAG_PERMANENT,
1733		    CTLTYPE_INT, "pkt_pool",
1734		    SYSCTL_DESCR("packet pool available"),
1735		    cnmac_sysctl_pool, 0, NULL,
1736		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
1737		    CTL_EOL)) != 0) {
1738		goto err;
1739	}
1740
1741	cnmac_sysctl_pkt_pool_num = node->sysctl_num;
1742
1743	if ((rc = sysctl_createv(clog, 0, NULL, &node,
1744		    CTLFLAG_PERMANENT,
1745		    CTLTYPE_INT, "wqe_pool",
1746		    SYSCTL_DESCR("wqe pool available"),
1747		    cnmac_sysctl_pool, 0, NULL,
1748		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
1749		    CTL_EOL)) != 0) {
1750		goto err;
1751	}
1752
1753	cnmac_sysctl_wqe_pool_num = node->sysctl_num;
1754
1755	if ((rc = sysctl_createv(clog, 0, NULL, &node,
1756		    CTLFLAG_PERMANENT,
1757		    CTLTYPE_INT, "cmd_pool",
1758		    SYSCTL_DESCR("cmd pool available"),
1759		    cnmac_sysctl_pool, 0, NULL,
1760		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
1761		    CTL_EOL)) != 0) {
1762		goto err;
1763	}
1764
1765	cnmac_sysctl_cmd_pool_num = node->sysctl_num;
1766
1767	if ((rc = sysctl_createv(clog, 0, NULL, &node,
1768		    CTLFLAG_PERMANENT,
1769		    CTLTYPE_INT, "sg_pool",
1770		    SYSCTL_DESCR("sg pool available"),
1771		    cnmac_sysctl_pool, 0, NULL,
1772		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
1773		    CTL_EOL)) != 0) {
1774		goto err;
1775	}
1776
1777	cnmac_sysctl_sg_pool_num = node->sysctl_num;
1778
1779	if ((rc = sysctl_createv(clog, 0, NULL, &node,
1780		    CTLFLAG_PERMANENT | CTLFLAG_READONLY,
1781		    CTLTYPE_INT, "pktbuf",
1782		    SYSCTL_DESCR("input packet buffer size on POW"),
1783		    cnmac_sysctl_rd, 0,
1784		    &cnmac_param_pktbuf,
1785		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
1786		    CTL_EOL)) != 0) {
1787		goto err;
1788	}
1789
1790	cnmac_sysctl_pktbuf_num = node->sysctl_num;
1791
1792	return;
1793
1794err:
1795	aprint_error("%s: syctl_createv failed (rc = %d)\n", __func__, rc);
1796}
1797
1798static int
1799cnmac_sysctl_verify(SYSCTLFN_ARGS)
1800{
1801	int error, v;
1802	struct sysctlnode node;
1803	struct cnmac_softc *sc;
1804	int i;
1805	int s;
1806
1807	node = *rnode;
1808	v = *(int *)rnode->sysctl_data;
1809	node.sysctl_data = &v;
1810	error = sysctl_lookup(SYSCTLFN_CALL(&node));
1811	if (error || newp == NULL)
1812		return error;
1813
1814	if (node.sysctl_num == cnmac_sysctl_pkocmdw0n2_num) {
1815		if (v < 0 || v > 1)
1816			return EINVAL;
1817		*(int *)rnode->sysctl_data = v;
1818		return 0;
1819	}
1820
1821	if (node.sysctl_num == cnmac_sysctl_pipdynrs_num) {
1822		if (v < 0 || v > 1)
1823			return EINVAL;
1824		*(int *)rnode->sysctl_data = v;
1825		s = splnet();
1826		for (i = 0; i < 3/* XXX */; i++) {
1827			sc = cnmac_gsc[i];	/* XXX */
1828			octpip_prt_cfg_enable(sc->sc_pip,
1829			    PIP_PRT_CFGN_DYN_RS, v);
1830		}
1831		splx(s);
1832		return 0;
1833	}
1834
1835	if (node.sysctl_num == cnmac_sysctl_redir_num) {
1836		if (v & ~((0x7 << (4 * 0)) | (0x7 << (4 * 1)) | (0x7 << (4 * 2))))
1837			return EINVAL;
1838		*(int *)rnode->sysctl_data = v;
1839		s = splnet();
1840		for (i = 0; i < 3/* XXX */; i++) {
1841			struct ifnet *ifp;
1842
1843			sc = cnmac_gsc[i];	/* XXX */
1844			ifp = &sc->sc_ethercom.ec_if;
1845
1846			sc->sc_redir
1847			    = (cnmac_param_redir >> (4 * i)) & 0x7;
1848			if (sc->sc_redir == 0) {
1849				if (ISSET(ifp->if_flags, IFF_PROMISC)) {
1850					CLR(ifp->if_flags, IFF_PROMISC);
1851					cnmac_mii_statchg(ifp);
1852					/* octgmx_set_filter(sc->sc_gmx_port); */
1853				}
1854				ifp->_if_input = ether_input;
1855			}
1856			else {
1857				if (!ISSET(ifp->if_flags, IFF_PROMISC)) {
1858					SET(ifp->if_flags, IFF_PROMISC);
1859					cnmac_mii_statchg(ifp);
1860					/* octgmx_set_filter(sc->sc_gmx_port); */
1861				}
1862				ifp->_if_input = cnmac_recv_redir;
1863			}
1864		}
1865		splx(s);
1866		return 0;
1867	}
1868
1869	return EINVAL;
1870}
1871
1872static int
1873cnmac_sysctl_pool(SYSCTLFN_ARGS)
1874{
1875	int error, newval = 0;
1876	struct sysctlnode node;
1877	int s;
1878
1879	node = *rnode;
1880	node.sysctl_data = &newval;
1881	s = splnet();
1882	if (node.sysctl_num == cnmac_sysctl_pkt_pool_num) {
1883		error = octfpa_available_fpa_pool(&newval,
1884		    OCTEON_POOL_NO_PKT);
1885	} else if (node.sysctl_num == cnmac_sysctl_wqe_pool_num) {
1886		error = octfpa_available_fpa_pool(&newval,
1887		    OCTEON_POOL_NO_WQE);
1888	} else if (node.sysctl_num == cnmac_sysctl_cmd_pool_num) {
1889		error = octfpa_available_fpa_pool(&newval,
1890		    OCTEON_POOL_NO_CMD);
1891	} else if (node.sysctl_num == cnmac_sysctl_sg_pool_num) {
1892		error = octfpa_available_fpa_pool(&newval,
1893		    OCTEON_POOL_NO_SG);
1894	} else {
1895		splx(s);
1896		return EINVAL;
1897	}
1898	splx(s);
1899	if (error)
1900		return error;
1901	error = sysctl_lookup(SYSCTLFN_CALL(&node));
1902	if (error || newp == NULL)
1903		return error;
1904
1905	return 0;
1906}
1907
1908static int
1909cnmac_sysctl_rd(SYSCTLFN_ARGS)
1910{
1911	int error, v;
1912	struct sysctlnode node;
1913	int s;
1914
1915	node = *rnode;
1916	v = *(int *)rnode->sysctl_data;
1917	node.sysctl_data = &v;
1918	error = sysctl_lookup(SYSCTLFN_CALL(&node));
1919	if (error || newp != NULL)
1920		return error;
1921
1922	if (node.sysctl_num == cnmac_sysctl_pktbuf_num) {
1923		uint64_t tmp;
1924		int n;
1925
1926		s = splnet();
1927		tmp = octfpa_query(0);
1928		n = (int)tmp;
1929		splx(s);
1930		*(int *)rnode->sysctl_data = n;
1931		cnmac_param_pktbuf = n;
1932		*(int *)oldp = n;
1933		return 0;
1934	}
1935
1936	return EINVAL;
1937}
1938