1233545Sjchandra/*-
2233545Sjchandra * Copyright (c) 2003-2012 Broadcom Corporation
3233545Sjchandra * All Rights Reserved
4233545Sjchandra *
5233545Sjchandra * Redistribution and use in source and binary forms, with or without
6233545Sjchandra * modification, are permitted provided that the following conditions
7233545Sjchandra * are met:
8233545Sjchandra *
9233545Sjchandra * 1. Redistributions of source code must retain the above copyright
10233545Sjchandra *    notice, this list of conditions and the following disclaimer.
11233545Sjchandra * 2. Redistributions in binary form must reproduce the above copyright
12233545Sjchandra *    notice, this list of conditions and the following disclaimer in
13233545Sjchandra *    the documentation and/or other materials provided with the
14233545Sjchandra *    distribution.
15233545Sjchandra *
16233545Sjchandra * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
17233545Sjchandra * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18233545Sjchandra * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19233545Sjchandra * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
20233545Sjchandra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21233545Sjchandra * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22233545Sjchandra * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23233545Sjchandra * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24233545Sjchandra * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25233545Sjchandra * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26233545Sjchandra * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27233545Sjchandra */
28233545Sjchandra
29233545Sjchandra#include <sys/cdefs.h>
30233545Sjchandra__FBSDID("$FreeBSD: stable/10/sys/mips/nlm/dev/net/xlpge.c 314667 2017-03-04 13:03:31Z avg $");
31233545Sjchandra#include <sys/endian.h>
32233545Sjchandra#include <sys/systm.h>
33233545Sjchandra#include <sys/sockio.h>
34233545Sjchandra#include <sys/param.h>
35233545Sjchandra#include <sys/lock.h>
36233545Sjchandra#include <sys/mutex.h>
37233545Sjchandra#include <sys/proc.h>
38233545Sjchandra#include <sys/limits.h>
39233545Sjchandra#include <sys/bus.h>
40233545Sjchandra#include <sys/mbuf.h>
41233545Sjchandra#include <sys/malloc.h>
42233545Sjchandra#include <sys/kernel.h>
43233545Sjchandra#include <sys/module.h>
44233545Sjchandra#include <sys/socket.h>
45233545Sjchandra#define __RMAN_RESOURCE_VISIBLE
46233545Sjchandra#include <sys/rman.h>
47233545Sjchandra#include <sys/taskqueue.h>
48233545Sjchandra
49233545Sjchandra#include <net/if.h>
50233545Sjchandra#include <net/if_arp.h>
51233545Sjchandra#include <net/ethernet.h>
52233545Sjchandra#include <net/if_dl.h>
53233545Sjchandra#include <net/if_media.h>
54233545Sjchandra#include <net/bpf.h>
55233545Sjchandra#include <net/if_types.h>
56233545Sjchandra#include <net/if_vlan_var.h>
57233545Sjchandra
58233545Sjchandra#include <dev/pci/pcivar.h>
59233545Sjchandra
60233545Sjchandra#include <netinet/in_systm.h>
61233545Sjchandra#include <netinet/in.h>
62233545Sjchandra#include <netinet/ip.h>
63233545Sjchandra
64233545Sjchandra#include <vm/vm.h>
65233545Sjchandra#include <vm/pmap.h>
66233545Sjchandra#include <vm/uma.h>
67233545Sjchandra
68233545Sjchandra#include <machine/reg.h>
69233545Sjchandra#include <machine/cpu.h>
70233545Sjchandra#include <machine/mips_opcode.h>
71233545Sjchandra#include <machine/asm.h>
72233545Sjchandra#include <machine/cpuregs.h>
73233545Sjchandra
74233545Sjchandra#include <machine/param.h>
75233545Sjchandra#include <machine/intr_machdep.h>
76233545Sjchandra#include <machine/clock.h>	/* for DELAY */
77233545Sjchandra#include <machine/bus.h>
78233545Sjchandra#include <machine/resource.h>
79233545Sjchandra#include <mips/nlm/hal/haldefs.h>
80233545Sjchandra#include <mips/nlm/hal/iomap.h>
81233545Sjchandra#include <mips/nlm/hal/mips-extns.h>
82233545Sjchandra#include <mips/nlm/hal/cop2.h>
83233545Sjchandra#include <mips/nlm/hal/fmn.h>
84233545Sjchandra#include <mips/nlm/hal/sys.h>
85233545Sjchandra#include <mips/nlm/hal/nae.h>
86233545Sjchandra#include <mips/nlm/hal/mdio.h>
87233545Sjchandra#include <mips/nlm/hal/sgmii.h>
88233545Sjchandra#include <mips/nlm/hal/xaui.h>
89233545Sjchandra#include <mips/nlm/hal/poe.h>
90233545Sjchandra#include <ucore_app_bin.h>
91233545Sjchandra#include <mips/nlm/hal/ucore_loader.h>
92233545Sjchandra#include <mips/nlm/xlp.h>
93233545Sjchandra#include <mips/nlm/board.h>
94233545Sjchandra#include <mips/nlm/msgring.h>
95233545Sjchandra
96233545Sjchandra#include <dev/mii/mii.h>
97233545Sjchandra#include <dev/mii/miivar.h>
98233545Sjchandra#include "miidevs.h"
99233545Sjchandra#include <dev/mii/brgphyreg.h>
100233545Sjchandra#include "miibus_if.h"
101233545Sjchandra#include <sys/sysctl.h>
102233545Sjchandra
103233545Sjchandra#include <mips/nlm/dev/net/xlpge.h>
104233545Sjchandra
105233545Sjchandra/*#define XLP_DRIVER_LOOPBACK*/
106233545Sjchandra
107233545Sjchandrastatic struct nae_port_config nae_port_config[64];
108233545Sjchandra
109233545Sjchandraint poe_cl_tbl[MAX_POE_CLASSES] = {
110233545Sjchandra	0x0, 0x249249,
111233545Sjchandra	0x492492, 0x6db6db,
112233545Sjchandra	0x924924, 0xb6db6d,
113233545Sjchandra	0xdb6db6, 0xffffff
114233545Sjchandra};
115233545Sjchandra
116233545Sjchandra/* #define DUMP_PACKET */
117233545Sjchandra
118233545Sjchandrastatic uint64_t
119233545Sjchandranlm_paddr_ld(uint64_t paddr)
120233545Sjchandra{
121233545Sjchandra	uint64_t xkaddr = 0x9800000000000000 | paddr;
122233545Sjchandra
123233545Sjchandra	return (nlm_load_dword_daddr(xkaddr));
124233545Sjchandra}
125233545Sjchandra
126233545Sjchandrastruct nlm_xlp_portdata ifp_ports[64];
127233545Sjchandrastatic uma_zone_t nl_tx_desc_zone;
128233545Sjchandra
129233545Sjchandra/* This implementation will register the following tree of device
130233545Sjchandra * registration:
131233545Sjchandra *                      pcibus
132233545Sjchandra *                       |
133233545Sjchandra *                      xlpnae (1 instance - virtual entity)
134233545Sjchandra *                       |
135233545Sjchandra *                     xlpge
136233545Sjchandra *      (18 sgmii / 4 xaui / 2 interlaken instances)
137233545Sjchandra *                       |
138233545Sjchandra *                    miibus
139233545Sjchandra */
140233545Sjchandra
141233545Sjchandrastatic int nlm_xlpnae_probe(device_t);
142233545Sjchandrastatic int nlm_xlpnae_attach(device_t);
143233545Sjchandrastatic int nlm_xlpnae_detach(device_t);
144233545Sjchandrastatic int nlm_xlpnae_suspend(device_t);
145233545Sjchandrastatic int nlm_xlpnae_resume(device_t);
146233545Sjchandrastatic int nlm_xlpnae_shutdown(device_t);
147233545Sjchandra
148233545Sjchandrastatic device_method_t nlm_xlpnae_methods[] = {
149233545Sjchandra	/* Methods from the device interface */
150233545Sjchandra	DEVMETHOD(device_probe,		nlm_xlpnae_probe),
151233545Sjchandra	DEVMETHOD(device_attach,	nlm_xlpnae_attach),
152233545Sjchandra	DEVMETHOD(device_detach,	nlm_xlpnae_detach),
153233545Sjchandra	DEVMETHOD(device_suspend,	nlm_xlpnae_suspend),
154233545Sjchandra	DEVMETHOD(device_resume,	nlm_xlpnae_resume),
155233545Sjchandra	DEVMETHOD(device_shutdown,	nlm_xlpnae_shutdown),
156233545Sjchandra
157233545Sjchandra	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
158233545Sjchandra
159233545Sjchandra	DEVMETHOD_END
160233545Sjchandra};
161233545Sjchandra
162233545Sjchandrastatic driver_t nlm_xlpnae_driver = {
163233545Sjchandra	"xlpnae",
164233545Sjchandra	nlm_xlpnae_methods,
165233545Sjchandra	sizeof(struct nlm_xlpnae_softc)
166233545Sjchandra};
167233545Sjchandra
168233545Sjchandrastatic devclass_t nlm_xlpnae_devclass;
169233545Sjchandra
170233545Sjchandrastatic int nlm_xlpge_probe(device_t);
171233545Sjchandrastatic int nlm_xlpge_attach(device_t);
172233545Sjchandrastatic int nlm_xlpge_detach(device_t);
173233545Sjchandrastatic int nlm_xlpge_suspend(device_t);
174233545Sjchandrastatic int nlm_xlpge_resume(device_t);
175233545Sjchandrastatic int nlm_xlpge_shutdown(device_t);
176233545Sjchandra
177233545Sjchandra/* mii override functions */
178233545Sjchandrastatic int nlm_xlpge_mii_read(struct device *, int, int);
179233545Sjchandrastatic int nlm_xlpge_mii_write(struct device *, int, int, int);
180233545Sjchandrastatic void nlm_xlpge_mii_statchg(device_t);
181233545Sjchandra
182233545Sjchandrastatic device_method_t nlm_xlpge_methods[] = {
183233545Sjchandra	/* Methods from the device interface */
184233545Sjchandra	DEVMETHOD(device_probe,		nlm_xlpge_probe),
185233545Sjchandra	DEVMETHOD(device_attach,	nlm_xlpge_attach),
186233545Sjchandra	DEVMETHOD(device_detach,	nlm_xlpge_detach),
187233545Sjchandra	DEVMETHOD(device_suspend,	nlm_xlpge_suspend),
188233545Sjchandra	DEVMETHOD(device_resume,	nlm_xlpge_resume),
189233545Sjchandra	DEVMETHOD(device_shutdown,	nlm_xlpge_shutdown),
190233545Sjchandra
191233545Sjchandra	/* Methods from the nexus bus needed for explicitly
192233545Sjchandra	 * probing children when driver is loaded as a kernel module
193233545Sjchandra	 */
194233545Sjchandra	DEVMETHOD(miibus_readreg,	nlm_xlpge_mii_read),
195233545Sjchandra	DEVMETHOD(miibus_writereg,	nlm_xlpge_mii_write),
196233545Sjchandra	DEVMETHOD(miibus_statchg,	nlm_xlpge_mii_statchg),
197233545Sjchandra
198233545Sjchandra	/* Terminate method list */
199233545Sjchandra	DEVMETHOD_END
200233545Sjchandra};
201233545Sjchandra
202233545Sjchandrastatic driver_t nlm_xlpge_driver = {
203233545Sjchandra	"xlpge",
204233545Sjchandra	nlm_xlpge_methods,
205233545Sjchandra	sizeof(struct nlm_xlpge_softc)
206233545Sjchandra};
207233545Sjchandra
208233545Sjchandrastatic devclass_t nlm_xlpge_devclass;
209233545Sjchandra
210233545SjchandraDRIVER_MODULE(xlpnae, pci, nlm_xlpnae_driver, nlm_xlpnae_devclass, 0, 0);
211233545SjchandraDRIVER_MODULE(xlpge, xlpnae, nlm_xlpge_driver, nlm_xlpge_devclass, 0, 0);
212233545SjchandraDRIVER_MODULE(miibus, xlpge, miibus_driver, miibus_devclass, 0, 0);
213233545Sjchandra
214233545SjchandraMODULE_DEPEND(pci, xlpnae, 1, 1, 1);
215233545SjchandraMODULE_DEPEND(xlpnae, xlpge, 1, 1, 1);
216233545SjchandraMODULE_DEPEND(xlpge, ether, 1, 1, 1);
217233545SjchandraMODULE_DEPEND(xlpge, miibus, 1, 1, 1);
218233545Sjchandra
219233545Sjchandra#define SGMII_RCV_CONTEXT_WIDTH 8
220233545Sjchandra
221233545Sjchandra/* prototypes */
222233545Sjchandrastatic void nlm_xlpge_msgring_handler(int vc, int size,
223233545Sjchandra    int code, int srcid, struct nlm_fmn_msg *msg, void *data);
224233545Sjchandrastatic void nlm_xlpge_submit_rx_free_desc(struct nlm_xlpge_softc *sc, int num);
225233545Sjchandrastatic void nlm_xlpge_init(void *addr);
226233545Sjchandrastatic void nlm_xlpge_port_disable(struct nlm_xlpge_softc *sc);
227233545Sjchandrastatic void nlm_xlpge_port_enable(struct nlm_xlpge_softc *sc);
228233545Sjchandra
229233545Sjchandra/* globals */
230233545Sjchandraint dbg_on = 1;
231233545Sjchandraint cntx2port[524];
232233545Sjchandra
233233545Sjchandrastatic __inline void
234233545Sjchandraatomic_incr_long(unsigned long *addr)
235233545Sjchandra{
236233545Sjchandra	atomic_add_long(addr, 1);
237233545Sjchandra}
238233545Sjchandra
239233545Sjchandra/*
240233545Sjchandra * xlpnae driver implementation
241233545Sjchandra */
242233545Sjchandrastatic int
243233545Sjchandranlm_xlpnae_probe(device_t dev)
244233545Sjchandra{
245233545Sjchandra	if (pci_get_vendor(dev) != PCI_VENDOR_NETLOGIC ||
246233545Sjchandra	    pci_get_device(dev) != PCI_DEVICE_ID_NLM_NAE)
247233545Sjchandra		return (ENXIO);
248233545Sjchandra
249233545Sjchandra	return (BUS_PROBE_DEFAULT);
250233545Sjchandra}
251233545Sjchandra
252233545Sjchandrastatic void
253233545Sjchandranlm_xlpnae_print_frin_desc_carving(struct nlm_xlpnae_softc *sc)
254233545Sjchandra{
255233545Sjchandra	int intf;
256233545Sjchandra	uint32_t value;
257233545Sjchandra	int start, size;
258233545Sjchandra
259233545Sjchandra	/* XXXJC: use max_ports instead of 20 ? */
260233545Sjchandra	for (intf = 0; intf < 20; intf++) {
261233545Sjchandra		nlm_write_nae_reg(sc->base, NAE_FREE_IN_FIFO_CFG,
262233545Sjchandra		    (0x80000000 | intf));
263233545Sjchandra		value = nlm_read_nae_reg(sc->base, NAE_FREE_IN_FIFO_CFG);
264233545Sjchandra		size = 2 * ((value >> 20) & 0x3ff);
265233545Sjchandra		start = 2 * ((value >> 8) & 0x1ff);
266233545Sjchandra	}
267233545Sjchandra}
268233545Sjchandra
269233545Sjchandrastatic void
270233545Sjchandranlm_config_egress(struct nlm_xlpnae_softc *sc, int nblock,
271233545Sjchandra    int context_base, int hwport, int max_channels)
272233545Sjchandra{
273233545Sjchandra	int offset, num_channels;
274233545Sjchandra	uint32_t data;
275233545Sjchandra
276233545Sjchandra	num_channels = sc->portcfg[hwport].num_channels;
277233545Sjchandra
278233545Sjchandra	data = (2048 << 12) | (hwport << 4) | 1;
279233545Sjchandra	nlm_write_nae_reg(sc->base, NAE_TX_IF_BURSTMAX_CMD, data);
280233545Sjchandra
281233545Sjchandra	data = ((context_base + num_channels - 1) << 22) |
282233545Sjchandra	    (context_base << 12) | (hwport << 4) | 1;
283233545Sjchandra	nlm_write_nae_reg(sc->base, NAE_TX_DDR_ACTVLIST_CMD, data);
284233545Sjchandra
285233545Sjchandra	config_egress_fifo_carvings(sc->base, hwport,
286233545Sjchandra	    context_base, num_channels, max_channels, sc->portcfg);
287233545Sjchandra	config_egress_fifo_credits(sc->base, hwport,
288233545Sjchandra	    context_base, num_channels, max_channels, sc->portcfg);
289233545Sjchandra
290233545Sjchandra	data = nlm_read_nae_reg(sc->base, NAE_DMA_TX_CREDIT_TH);
291233545Sjchandra	data |= (1 << 25) | (1 << 24);
292233545Sjchandra	nlm_write_nae_reg(sc->base, NAE_DMA_TX_CREDIT_TH, data);
293233545Sjchandra
294233545Sjchandra	for (offset = 0; offset < num_channels; offset++) {
295233545Sjchandra		nlm_write_nae_reg(sc->base, NAE_TX_SCHED_MAP_CMD1,
296233545Sjchandra		    NAE_DRR_QUANTA);
297233545Sjchandra		data = (hwport << 15) | ((context_base + offset) << 5);
298233545Sjchandra		if (sc->cmplx_type[nblock] == ILC)
299233545Sjchandra			data |= (offset << 20);
300233545Sjchandra		nlm_write_nae_reg(sc->base, NAE_TX_SCHED_MAP_CMD0, data | 1);
301233545Sjchandra		nlm_write_nae_reg(sc->base, NAE_TX_SCHED_MAP_CMD0, data);
302233545Sjchandra	}
303233545Sjchandra}
304233545Sjchandra
305233545Sjchandrastatic int
306233545Sjchandraxlpnae_get_maxchannels(struct nlm_xlpnae_softc *sc)
307233545Sjchandra{
308233545Sjchandra	int maxchans = 0;
309255368Sjchandra	int i;
310233545Sjchandra
311255368Sjchandra	for (i = 0; i < sc->max_ports; i++) {
312255368Sjchandra		if (sc->portcfg[i].type == UNKNOWN)
313255368Sjchandra			continue;
314255368Sjchandra		maxchans += sc->portcfg[i].num_channels;
315233545Sjchandra	}
316233545Sjchandra
317233545Sjchandra	return (maxchans);
318233545Sjchandra}
319233545Sjchandra
320233545Sjchandrastatic void
321233545Sjchandranlm_setup_interface(struct nlm_xlpnae_softc *sc, int nblock,
322233545Sjchandra    int port, uint32_t cur_flow_base, uint32_t flow_mask,
323233545Sjchandra    int max_channels, int context)
324233545Sjchandra{
325233545Sjchandra	uint64_t nae_base = sc->base;
326233545Sjchandra	int mtu = 1536;			/* XXXJC: don't hard code */
327233545Sjchandra	uint32_t ucore_mask;
328233545Sjchandra
329233545Sjchandra	if (sc->cmplx_type[nblock] == XAUIC)
330233545Sjchandra		nlm_config_xaui(nae_base, nblock, mtu,
331233545Sjchandra		    mtu, sc->portcfg[port].vlan_pri_en);
332233545Sjchandra	nlm_config_freein_fifo_uniq_cfg(nae_base,
333233545Sjchandra	    port, sc->portcfg[port].free_desc_sizes);
334233545Sjchandra	nlm_config_ucore_iface_mask_cfg(nae_base,
335233545Sjchandra	    port, sc->portcfg[port].ucore_mask);
336233545Sjchandra
337233545Sjchandra	nlm_program_flow_cfg(nae_base, port, cur_flow_base, flow_mask);
338233545Sjchandra
339233545Sjchandra	if (sc->cmplx_type[nblock] == SGMIIC)
340233545Sjchandra		nlm_configure_sgmii_interface(nae_base, nblock, port, mtu, 0);
341233545Sjchandra
342233545Sjchandra	nlm_config_egress(sc, nblock, context, port, max_channels);
343233545Sjchandra
344233545Sjchandra	nlm_nae_init_netior(nae_base, sc->nblocks);
345233545Sjchandra	nlm_nae_open_if(nae_base, nblock, sc->cmplx_type[nblock], port,
346233545Sjchandra	    sc->portcfg[port].free_desc_sizes);
347233545Sjchandra
348233545Sjchandra	/*  XXXJC: check mask calculation */
349233545Sjchandra	ucore_mask = (1 << sc->nucores) - 1;
350233545Sjchandra	nlm_nae_init_ucore(nae_base, port, ucore_mask);
351233545Sjchandra}
352233545Sjchandra
353233545Sjchandrastatic void
354233545Sjchandranlm_setup_interfaces(struct nlm_xlpnae_softc *sc)
355233545Sjchandra{
356233545Sjchandra	uint64_t nae_base;
357233545Sjchandra	uint32_t cur_slot, cur_slot_base;
358233545Sjchandra	uint32_t cur_flow_base, port, flow_mask;
359233545Sjchandra	int max_channels;
360255368Sjchandra	int i, context;
361233545Sjchandra
362233545Sjchandra	cur_slot = 0;
363233545Sjchandra	cur_slot_base = 0;
364233545Sjchandra	cur_flow_base = 0;
365233545Sjchandra	nae_base = sc->base;
366233545Sjchandra	flow_mask = nlm_get_flow_mask(sc->total_num_ports);
367233545Sjchandra	/* calculate max_channels */
368233545Sjchandra	max_channels = xlpnae_get_maxchannels(sc);
369233545Sjchandra
370233545Sjchandra	port = 0;
371233545Sjchandra	context = 0;
372255368Sjchandra	for (i = 0; i < sc->max_ports; i++) {
373255368Sjchandra		if (sc->portcfg[i].type == UNKNOWN)
374255368Sjchandra			continue;
375255368Sjchandra		nlm_setup_interface(sc, sc->portcfg[i].block, i, cur_flow_base,
376255368Sjchandra		    flow_mask, max_channels, context);
377255368Sjchandra		cur_flow_base += sc->per_port_num_flows;
378255368Sjchandra		context += sc->portcfg[i].num_channels;
379233545Sjchandra	}
380233545Sjchandra}
381233545Sjchandra
382233545Sjchandrastatic void
383233545Sjchandranlm_xlpnae_init(int node, struct nlm_xlpnae_softc *sc)
384233545Sjchandra{
385233545Sjchandra	uint64_t nae_base;
386233545Sjchandra	uint32_t ucoremask = 0;
387233545Sjchandra	uint32_t val;
388233545Sjchandra	int i;
389233545Sjchandra
390233545Sjchandra	nae_base = sc->base;
391233545Sjchandra
392233545Sjchandra	nlm_nae_flush_free_fifo(nae_base, sc->nblocks);
393233545Sjchandra	nlm_deflate_frin_fifo_carving(nae_base, sc->max_ports);
394233545Sjchandra	nlm_reset_nae(node);
395233545Sjchandra
396233545Sjchandra	for (i = 0; i < sc->nucores; i++)	/* XXXJC: code repeated below */
397233545Sjchandra		ucoremask |= (0x1 << i);
398233545Sjchandra	printf("Loading 0x%x ucores with microcode\n", ucoremask);
399233545Sjchandra	nlm_ucore_load_all(nae_base, ucoremask, 1);
400233545Sjchandra
401233545Sjchandra	val = nlm_set_device_frequency(node, DFS_DEVICE_NAE, sc->freq);
402233545Sjchandra	printf("Setup NAE frequency to %dMHz\n", val);
403233545Sjchandra
404245881Sjchandra	nlm_mdio_reset_all(nae_base);
405245881Sjchandra
406233545Sjchandra	printf("Initialze SGMII PCS for blocks 0x%x\n", sc->sgmiimask);
407233545Sjchandra	nlm_sgmii_pcs_init(nae_base, sc->sgmiimask);
408233545Sjchandra
409233545Sjchandra	printf("Initialze XAUI PCS for blocks 0x%x\n", sc->xauimask);
410233545Sjchandra	nlm_xaui_pcs_init(nae_base, sc->xauimask);
411233545Sjchandra
412233545Sjchandra	/* clear NETIOR soft reset */
413233545Sjchandra	nlm_write_nae_reg(nae_base, NAE_LANE_CFG_SOFTRESET, 0x0);
414233545Sjchandra
415233545Sjchandra	/* Disable RX enable bit in RX_CONFIG */
416233545Sjchandra	val = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG);
417233545Sjchandra	val &= 0xfffffffe;
418233545Sjchandra	nlm_write_nae_reg(nae_base, NAE_RX_CONFIG, val);
419233545Sjchandra
420233545Sjchandra	if (nlm_is_xlp8xx_ax() == 0) {
421233545Sjchandra		val = nlm_read_nae_reg(nae_base, NAE_TX_CONFIG);
422233545Sjchandra		val &= ~(1 << 3);
423233545Sjchandra		nlm_write_nae_reg(nae_base, NAE_TX_CONFIG, val);
424233545Sjchandra	}
425233545Sjchandra
426233545Sjchandra	nlm_setup_poe_class_config(nae_base, MAX_POE_CLASSES,
427233545Sjchandra	    sc->ncontexts, poe_cl_tbl);
428233545Sjchandra
429233545Sjchandra	nlm_setup_vfbid_mapping(nae_base);
430233545Sjchandra
431233545Sjchandra	nlm_setup_flow_crc_poly(nae_base, sc->flow_crc_poly);
432233545Sjchandra
433233545Sjchandra	nlm_setup_rx_cal_cfg(nae_base, sc->max_ports, sc->portcfg);
434233545Sjchandra	/* note: xlp8xx Ax does not have Tx Calendering */
435233545Sjchandra	if (!nlm_is_xlp8xx_ax())
436233545Sjchandra		nlm_setup_tx_cal_cfg(nae_base, sc->max_ports, sc->portcfg);
437233545Sjchandra
438233545Sjchandra	nlm_setup_interfaces(sc);
439233545Sjchandra	nlm_config_poe(sc->poe_base, sc->poedv_base);
440233545Sjchandra
441233545Sjchandra	if (sc->hw_parser_en)
442233545Sjchandra		nlm_enable_hardware_parser(nae_base);
443233545Sjchandra
444233545Sjchandra	if (sc->prepad_en)
445233545Sjchandra		nlm_prepad_enable(nae_base, sc->prepad_size);
446233545Sjchandra
447233545Sjchandra	if (sc->ieee_1588_en)
448233545Sjchandra		nlm_setup_1588_timer(sc->base, sc->portcfg);
449233545Sjchandra}
450233545Sjchandra
451233545Sjchandrastatic void
452233545Sjchandranlm_xlpnae_update_pde(void *dummy __unused)
453233545Sjchandra{
454233545Sjchandra	struct nlm_xlpnae_softc *sc;
455233545Sjchandra	uint32_t dv[NUM_WORDS_PER_DV];
456233545Sjchandra	device_t dev;
457233545Sjchandra	int vec;
458233545Sjchandra
459233545Sjchandra	dev = devclass_get_device(devclass_find("xlpnae"), 0);
460233545Sjchandra	sc = device_get_softc(dev);
461233545Sjchandra
462233545Sjchandra	nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 0);
463233545Sjchandra	for (vec = 0; vec < NUM_DIST_VEC; vec++) {
464233545Sjchandra		if (nlm_get_poe_distvec(vec, dv) != 0)
465233545Sjchandra			continue;
466233545Sjchandra
467233545Sjchandra		nlm_write_poe_distvec(sc->poedv_base, vec, dv);
468233545Sjchandra	}
469233545Sjchandra	nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 1);
470233545Sjchandra}
471233545Sjchandra
472233545SjchandraSYSINIT(nlm_xlpnae_update_pde, SI_SUB_SMP, SI_ORDER_ANY,
473233545Sjchandra    nlm_xlpnae_update_pde, NULL);
474233545Sjchandra
475233545Sjchandra/* configuration common for sgmii, xaui, ilaken goes here */
476233545Sjchandrastatic void
477233545Sjchandranlm_setup_portcfg(struct nlm_xlpnae_softc *sc, struct xlp_nae_ivars *naep,
478233545Sjchandra    int block, int port)
479233545Sjchandra{
480233545Sjchandra	int i;
481233545Sjchandra	uint32_t ucore_mask = 0;
482233545Sjchandra	struct xlp_block_ivars *bp;
483233545Sjchandra	struct xlp_port_ivars *p;
484233545Sjchandra
485233545Sjchandra	bp = &(naep->block_ivars[block]);
486233545Sjchandra	p  = &(bp->port_ivars[port & 0x3]);
487233545Sjchandra
488255368Sjchandra	sc->portcfg[port].node = p->node;
489255368Sjchandra	sc->portcfg[port].block = p->block;
490255368Sjchandra	sc->portcfg[port].port = p->port;
491255368Sjchandra	sc->portcfg[port].type = p->type;
492255368Sjchandra	sc->portcfg[port].mdio_bus = p->mdio_bus;
493255368Sjchandra	sc->portcfg[port].phy_addr = p->phy_addr;
494233545Sjchandra	sc->portcfg[port].loopback_mode = p->loopback_mode;
495233545Sjchandra	sc->portcfg[port].num_channels = p->num_channels;
496233545Sjchandra	if (p->free_desc_sizes != MCLBYTES) {
497233545Sjchandra		printf("[%d, %d] Error: free_desc_sizes %d != %d\n",
498233545Sjchandra		    block, port, p->free_desc_sizes, MCLBYTES);
499233545Sjchandra		return;
500233545Sjchandra	}
501233545Sjchandra	sc->portcfg[port].free_desc_sizes = p->free_desc_sizes;
502233545Sjchandra	for (i = 0; i < sc->nucores; i++)	/* XXXJC: configure this */
503233545Sjchandra		ucore_mask |= (0x1 << i);
504233545Sjchandra	sc->portcfg[port].ucore_mask = ucore_mask;
505233545Sjchandra	sc->portcfg[port].vlan_pri_en = p->vlan_pri_en;
506233545Sjchandra	sc->portcfg[port].num_free_descs = p->num_free_descs;
507233545Sjchandra	sc->portcfg[port].iface_fifo_size = p->iface_fifo_size;
508233545Sjchandra	sc->portcfg[port].rxbuf_size = p->rxbuf_size;
509233545Sjchandra	sc->portcfg[port].rx_slots_reqd = p->rx_slots_reqd;
510233545Sjchandra	sc->portcfg[port].tx_slots_reqd = p->tx_slots_reqd;
511233545Sjchandra	sc->portcfg[port].pseq_fifo_size = p->pseq_fifo_size;
512233545Sjchandra
513233545Sjchandra	sc->portcfg[port].stg2_fifo_size = p->stg2_fifo_size;
514233545Sjchandra	sc->portcfg[port].eh_fifo_size = p->eh_fifo_size;
515233545Sjchandra	sc->portcfg[port].frout_fifo_size = p->frout_fifo_size;
516233545Sjchandra	sc->portcfg[port].ms_fifo_size = p->ms_fifo_size;
517233545Sjchandra	sc->portcfg[port].pkt_fifo_size = p->pkt_fifo_size;
518233545Sjchandra	sc->portcfg[port].pktlen_fifo_size = p->pktlen_fifo_size;
519233545Sjchandra	sc->portcfg[port].max_stg2_offset = p->max_stg2_offset;
520233545Sjchandra	sc->portcfg[port].max_eh_offset = p->max_eh_offset;
521233545Sjchandra	sc->portcfg[port].max_frout_offset = p->max_frout_offset;
522233545Sjchandra	sc->portcfg[port].max_ms_offset = p->max_ms_offset;
523233545Sjchandra	sc->portcfg[port].max_pmem_offset = p->max_pmem_offset;
524233545Sjchandra	sc->portcfg[port].stg1_2_credit = p->stg1_2_credit;
525233545Sjchandra	sc->portcfg[port].stg2_eh_credit = p->stg2_eh_credit;
526233545Sjchandra	sc->portcfg[port].stg2_frout_credit = p->stg2_frout_credit;
527233545Sjchandra	sc->portcfg[port].stg2_ms_credit = p->stg2_ms_credit;
528233545Sjchandra	sc->portcfg[port].ieee1588_inc_intg = p->ieee1588_inc_intg;
529233545Sjchandra	sc->portcfg[port].ieee1588_inc_den = p->ieee1588_inc_den;
530233545Sjchandra	sc->portcfg[port].ieee1588_inc_num = p->ieee1588_inc_num;
531233545Sjchandra	sc->portcfg[port].ieee1588_userval = p->ieee1588_userval;
532233545Sjchandra	sc->portcfg[port].ieee1588_ptpoff = p->ieee1588_ptpoff;
533233545Sjchandra	sc->portcfg[port].ieee1588_tmr1 = p->ieee1588_tmr1;
534233545Sjchandra	sc->portcfg[port].ieee1588_tmr2 = p->ieee1588_tmr2;
535233545Sjchandra	sc->portcfg[port].ieee1588_tmr3 = p->ieee1588_tmr3;
536233545Sjchandra
537233545Sjchandra	sc->total_free_desc += sc->portcfg[port].free_desc_sizes;
538233545Sjchandra	sc->total_num_ports++;
539233545Sjchandra}
540233545Sjchandra
541233545Sjchandrastatic int
542233545Sjchandranlm_xlpnae_attach(device_t dev)
543233545Sjchandra{
544233545Sjchandra	struct xlp_nae_ivars	*nae_ivars;
545233545Sjchandra	struct nlm_xlpnae_softc *sc;
546233545Sjchandra	device_t tmpd;
547233545Sjchandra	uint32_t dv[NUM_WORDS_PER_DV];
548255368Sjchandra	int port, i, j, nchan, nblock, node, qstart, qnum;
549233545Sjchandra	int offset, context, txq_base, rxvcbase;
550233545Sjchandra	uint64_t poe_pcibase, nae_pcibase;
551233545Sjchandra
552233545Sjchandra	node = pci_get_slot(dev) / 8;
553233545Sjchandra	nae_ivars = &xlp_board_info.nodes[node].nae_ivars;
554233545Sjchandra
555233545Sjchandra	sc = device_get_softc(dev);
556233545Sjchandra	sc->xlpnae_dev = dev;
557233545Sjchandra	sc->node = nae_ivars->node;
558233545Sjchandra	sc->base = nlm_get_nae_regbase(sc->node);
559233545Sjchandra	sc->poe_base = nlm_get_poe_regbase(sc->node);
560233545Sjchandra	sc->poedv_base = nlm_get_poedv_regbase(sc->node);
561233545Sjchandra	sc->portcfg = nae_port_config;
562255368Sjchandra	sc->blockmask = nae_ivars->blockmask;
563255368Sjchandra	sc->ilmask = nae_ivars->ilmask;
564233545Sjchandra	sc->xauimask = nae_ivars->xauimask;
565233545Sjchandra	sc->sgmiimask = nae_ivars->sgmiimask;
566233545Sjchandra	sc->nblocks = nae_ivars->nblocks;
567233545Sjchandra	sc->freq = nae_ivars->freq;
568233545Sjchandra
569233545Sjchandra	/* flow table generation is done by CRC16 polynomial */
570233545Sjchandra	sc->flow_crc_poly = nae_ivars->flow_crc_poly;
571233545Sjchandra
572233545Sjchandra	sc->hw_parser_en = nae_ivars->hw_parser_en;
573233545Sjchandra	sc->prepad_en = nae_ivars->prepad_en;
574233545Sjchandra	sc->prepad_size = nae_ivars->prepad_size;
575233545Sjchandra	sc->ieee_1588_en = nae_ivars->ieee_1588_en;
576233545Sjchandra
577233545Sjchandra	nae_pcibase = nlm_get_nae_pcibase(sc->node);
578233545Sjchandra	sc->ncontexts = nlm_read_reg(nae_pcibase, XLP_PCI_DEVINFO_REG5);
579233545Sjchandra	sc->nucores = nlm_num_uengines(nae_pcibase);
580233545Sjchandra
581255368Sjchandra	for (nblock = 0; nblock < sc->nblocks; nblock++) {
582233545Sjchandra		sc->cmplx_type[nblock] = nae_ivars->block_ivars[nblock].type;
583255368Sjchandra		sc->portmask[nblock] = nae_ivars->block_ivars[nblock].portmask;
584255368Sjchandra	}
585233545Sjchandra
586233545Sjchandra	for (i = 0; i < sc->ncontexts; i++)
587233545Sjchandra		cntx2port[i] = 18;	/* 18 is an invalid port */
588233545Sjchandra
589233545Sjchandra	if (sc->nblocks == 5)
590233545Sjchandra		sc->max_ports = 18;	/* 8xx has a block 4 with 2 ports */
591233545Sjchandra	else
592233545Sjchandra		sc->max_ports = sc->nblocks * PORTS_PER_CMPLX;
593233545Sjchandra
594255368Sjchandra	for (i = 0; i < sc->max_ports; i++)
595255368Sjchandra		sc->portcfg[i].type = UNKNOWN; /* Port Not Present */
596233545Sjchandra	/*
597233545Sjchandra	 * Now setup all internal fifo carvings based on
598233545Sjchandra	 * total number of ports in the system
599233545Sjchandra	 */
600233545Sjchandra	sc->total_free_desc = 0;
601233545Sjchandra	sc->total_num_ports = 0;
602233545Sjchandra	port = 0;
603233545Sjchandra	context = 0;
604233545Sjchandra	txq_base = nlm_qidstart(nae_pcibase);
605233545Sjchandra	rxvcbase = txq_base + sc->ncontexts;
606233545Sjchandra	for (i = 0; i < sc->nblocks; i++) {
607255368Sjchandra		uint32_t portmask;
608255368Sjchandra
609255368Sjchandra		if ((nae_ivars->blockmask & (1 << i)) == 0) {
610255368Sjchandra			port += 4;
611255368Sjchandra			continue;
612255368Sjchandra		}
613255368Sjchandra		portmask = nae_ivars->block_ivars[i].portmask;
614255368Sjchandra		for (j = 0; j < PORTS_PER_CMPLX; j++, port++) {
615255368Sjchandra			if ((portmask & (1 << j)) == 0)
616233545Sjchandra				continue;
617233545Sjchandra			nlm_setup_portcfg(sc, nae_ivars, i, port);
618233545Sjchandra			nchan = sc->portcfg[port].num_channels;
619233545Sjchandra			for (offset = 0; offset < nchan; offset++)
620233545Sjchandra				cntx2port[context + offset] = port;
621233545Sjchandra			sc->portcfg[port].txq = txq_base + context;
622233545Sjchandra			sc->portcfg[port].rxfreeq = rxvcbase + port;
623233545Sjchandra			context += nchan;
624233545Sjchandra		}
625233545Sjchandra	}
626233545Sjchandra
627233545Sjchandra	poe_pcibase = nlm_get_poe_pcibase(sc->node);
628233545Sjchandra	sc->per_port_num_flows =
629233545Sjchandra	    nlm_poe_max_flows(poe_pcibase) / sc->total_num_ports;
630233545Sjchandra
631233545Sjchandra	/* zone for P2P descriptors */
632233545Sjchandra	nl_tx_desc_zone = uma_zcreate("NL Tx Desc",
633233545Sjchandra	    sizeof(struct xlpge_tx_desc), NULL, NULL, NULL, NULL,
634233545Sjchandra	    NAE_CACHELINE_SIZE, 0);
635233545Sjchandra
636233545Sjchandra	/* NAE FMN messages have CMS src station id's in the
637233545Sjchandra	 * range of qstart to qnum.
638233545Sjchandra	 */
639233545Sjchandra	qstart = nlm_qidstart(nae_pcibase);
640233545Sjchandra	qnum = nlm_qnum(nae_pcibase);
641233545Sjchandra	if (register_msgring_handler(qstart, qstart + qnum - 1,
642233545Sjchandra	    nlm_xlpge_msgring_handler, sc)) {
643233545Sjchandra		panic("Couldn't register NAE msgring handler\n");
644233545Sjchandra	}
645233545Sjchandra
646233545Sjchandra	/* POE FMN messages have CMS src station id's in the
647233545Sjchandra	 * range of qstart to qnum.
648233545Sjchandra	 */
649233545Sjchandra	qstart = nlm_qidstart(poe_pcibase);
650233545Sjchandra	qnum = nlm_qnum(poe_pcibase);
651233545Sjchandra	if (register_msgring_handler(qstart, qstart + qnum - 1,
652233545Sjchandra	    nlm_xlpge_msgring_handler, sc)) {
653233545Sjchandra		panic("Couldn't register POE msgring handler\n");
654233545Sjchandra	}
655233545Sjchandra
656233545Sjchandra	nlm_xlpnae_init(node, sc);
657233545Sjchandra
658255368Sjchandra	for (i = 0; i < sc->max_ports; i++) {
659233545Sjchandra		char desc[32];
660255368Sjchandra		int block, port;
661233545Sjchandra
662255368Sjchandra		if (sc->portcfg[i].type == UNKNOWN)
663233545Sjchandra			continue;
664255368Sjchandra		block = sc->portcfg[i].block;
665255368Sjchandra		port = sc->portcfg[i].port;
666255368Sjchandra		tmpd = device_add_child(dev, "xlpge", i);
667255368Sjchandra		device_set_ivars(tmpd,
668255368Sjchandra		    &(nae_ivars->block_ivars[block].port_ivars[port]));
669255368Sjchandra		sprintf(desc, "XLP NAE Port %d,%d", block, port);
670255368Sjchandra		device_set_desc_copy(tmpd, desc);
671233545Sjchandra	}
672255368Sjchandra	nlm_setup_iface_fifo_cfg(sc->base, sc->max_ports, sc->portcfg);
673255368Sjchandra	nlm_setup_rx_base_config(sc->base, sc->max_ports, sc->portcfg);
674255368Sjchandra	nlm_setup_rx_buf_config(sc->base, sc->max_ports, sc->portcfg);
675255368Sjchandra	nlm_setup_freein_fifo_cfg(sc->base, sc->portcfg);
676255368Sjchandra	nlm_program_nae_parser_seq_fifo(sc->base, sc->max_ports, sc->portcfg);
677233545Sjchandra
678255368Sjchandra	nlm_xlpnae_print_frin_desc_carving(sc);
679233545Sjchandra	bus_generic_probe(dev);
680233545Sjchandra	bus_generic_attach(dev);
681233545Sjchandra
682233545Sjchandra	/*
683233545Sjchandra	 * Enable only boot cpu at this point, full distribution comes
684233545Sjchandra	 * only after SMP is started
685233545Sjchandra	 */
686233545Sjchandra	nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 0);
687233545Sjchandra	nlm_calc_poe_distvec(0x1, 0, 0, 0, 0x1 << XLPGE_RX_VC, dv);
688233545Sjchandra	nlm_write_poe_distvec(sc->poedv_base, 0, dv);
689233545Sjchandra	nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 1);
690233545Sjchandra
691233545Sjchandra	return (0);
692233545Sjchandra}
693233545Sjchandra
694233545Sjchandrastatic int
695233545Sjchandranlm_xlpnae_detach(device_t dev)
696233545Sjchandra{
697233545Sjchandra	/*  TODO - free zone here */
698233545Sjchandra	return (0);
699233545Sjchandra}
700233545Sjchandra
701233545Sjchandrastatic int
702233545Sjchandranlm_xlpnae_suspend(device_t dev)
703233545Sjchandra{
704233545Sjchandra	return (0);
705233545Sjchandra}
706233545Sjchandra
707233545Sjchandrastatic int
708233545Sjchandranlm_xlpnae_resume(device_t dev)
709233545Sjchandra{
710233545Sjchandra	return (0);
711233545Sjchandra}
712233545Sjchandra
713233545Sjchandrastatic int
714233545Sjchandranlm_xlpnae_shutdown(device_t dev)
715233545Sjchandra{
716233545Sjchandra	return (0);
717233545Sjchandra}
718233545Sjchandra
719233545Sjchandra/*
720233545Sjchandra * xlpge driver implementation
721233545Sjchandra */
722233545Sjchandra
723233545Sjchandrastatic void
724233545Sjchandranlm_xlpge_mac_set_rx_mode(struct nlm_xlpge_softc *sc)
725233545Sjchandra{
726233545Sjchandra	if (sc->if_flags & IFF_PROMISC) {
727233545Sjchandra		if (sc->type == SGMIIC)
728233545Sjchandra			nlm_nae_setup_rx_mode_sgmii(sc->base_addr,
729233545Sjchandra			    sc->block, sc->port, sc->type, 1 /* broadcast */,
730233545Sjchandra			    1/* multicast */, 0 /* pause */, 1 /* promisc */);
731233545Sjchandra		else
732233545Sjchandra			nlm_nae_setup_rx_mode_xaui(sc->base_addr,
733233545Sjchandra			    sc->block, sc->port, sc->type, 1 /* broadcast */,
734233545Sjchandra			    1/* multicast */, 0 /* pause */, 1 /* promisc */);
735233545Sjchandra	} else {
736233545Sjchandra		if (sc->type == SGMIIC)
737233545Sjchandra			nlm_nae_setup_rx_mode_sgmii(sc->base_addr,
738233545Sjchandra			    sc->block, sc->port, sc->type, 1 /* broadcast */,
739233545Sjchandra			    1/* multicast */, 0 /* pause */, 0 /* promisc */);
740233545Sjchandra		else
741233545Sjchandra			nlm_nae_setup_rx_mode_xaui(sc->base_addr,
742233545Sjchandra			    sc->block, sc->port, sc->type, 1 /* broadcast */,
743233545Sjchandra			    1/* multicast */, 0 /* pause */, 0 /* promisc */);
744233545Sjchandra	}
745233545Sjchandra}
746233545Sjchandra
747233545Sjchandrastatic int
748233545Sjchandranlm_xlpge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
749233545Sjchandra{
750233545Sjchandra	struct mii_data		*mii;
751233545Sjchandra	struct nlm_xlpge_softc	*sc;
752233545Sjchandra	struct ifreq		*ifr;
753233545Sjchandra	int 			error;
754233545Sjchandra
755233545Sjchandra	sc = ifp->if_softc;
756233545Sjchandra	error = 0;
757233545Sjchandra	ifr = (struct ifreq *)data;
758233545Sjchandra
759233545Sjchandra	switch (command) {
760233545Sjchandra	case SIOCSIFFLAGS:
761233545Sjchandra		XLPGE_LOCK(sc);
762233545Sjchandra		sc->if_flags = ifp->if_flags;
763233545Sjchandra		if (ifp->if_flags & IFF_UP) {
764233545Sjchandra			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
765233545Sjchandra				nlm_xlpge_init(sc);
766245881Sjchandra			else
767245881Sjchandra				nlm_xlpge_port_enable(sc);
768245881Sjchandra			nlm_xlpge_mac_set_rx_mode(sc);
769233545Sjchandra			sc->link = NLM_LINK_UP;
770233545Sjchandra		} else {
771233545Sjchandra			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
772233545Sjchandra				nlm_xlpge_port_disable(sc);
773233545Sjchandra			sc->link = NLM_LINK_DOWN;
774233545Sjchandra		}
775233545Sjchandra		XLPGE_UNLOCK(sc);
776233545Sjchandra		error = 0;
777233545Sjchandra		break;
778233545Sjchandra	case SIOCGIFMEDIA:
779233545Sjchandra	case SIOCSIFMEDIA:
780233545Sjchandra		if (sc->mii_bus != NULL) {
781233545Sjchandra			mii = device_get_softc(sc->mii_bus);
782233545Sjchandra			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media,
783233545Sjchandra			    command);
784233545Sjchandra		}
785233545Sjchandra		break;
786233545Sjchandra	default:
787233545Sjchandra		error = ether_ioctl(ifp, command, data);
788233545Sjchandra		break;
789233545Sjchandra	}
790233545Sjchandra
791233545Sjchandra	return (error);
792233545Sjchandra}
793233545Sjchandra
794233545Sjchandrastatic int
795233545Sjchandraxlpge_tx(struct ifnet *ifp, struct mbuf *mbuf_chain)
796233545Sjchandra{
797233545Sjchandra	struct nlm_fmn_msg	msg;
798233545Sjchandra	struct xlpge_tx_desc	*p2p;
799233545Sjchandra	struct nlm_xlpge_softc	*sc;
800233545Sjchandra	struct mbuf	*m;
801233545Sjchandra	vm_paddr_t      paddr;
802233545Sjchandra	int		fbid, dst, pos, err;
803233545Sjchandra	int		ret = 0, tx_msgstatus, retries;
804233545Sjchandra
805233545Sjchandra	err = 0;
806233545Sjchandra	if (mbuf_chain == NULL)
807233545Sjchandra		return (0);
808233545Sjchandra
809233545Sjchandra	sc = ifp->if_softc;
810233545Sjchandra	p2p = NULL;
811233545Sjchandra	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING) ||
812233545Sjchandra	    ifp->if_drv_flags & IFF_DRV_OACTIVE) {
813233545Sjchandra		err = ENXIO;
814233545Sjchandra		goto fail;
815233545Sjchandra	}
816233545Sjchandra
817233545Sjchandra	/* free a few in coming messages on the fb vc */
818233545Sjchandra	xlp_handle_msg_vc(1 << XLPGE_FB_VC, 2);
819233545Sjchandra
820233545Sjchandra	/* vfb id table is setup to map cpu to vc 3 of the cpu */
821233545Sjchandra	fbid = nlm_cpuid();
822233545Sjchandra	dst = sc->txq;
823233545Sjchandra
824233545Sjchandra	pos = 0;
825233545Sjchandra	p2p = uma_zalloc(nl_tx_desc_zone, M_NOWAIT);
826233545Sjchandra	if (p2p == NULL) {
827233545Sjchandra		printf("alloc fail\n");
828233545Sjchandra		err = ENOBUFS;
829233545Sjchandra		goto fail;
830233545Sjchandra	}
831233545Sjchandra
832233545Sjchandra	for (m = mbuf_chain; m != NULL; m = m->m_next) {
833233545Sjchandra		vm_offset_t buf = (vm_offset_t) m->m_data;
834233545Sjchandra		int	len = m->m_len;
835233545Sjchandra		int	frag_sz;
836245884Sjchandra		uint64_t desc;
837233545Sjchandra
838233545Sjchandra		/*printf("m_data = %p len %d\n", m->m_data, len); */
839233545Sjchandra		while (len) {
840233545Sjchandra			if (pos == XLP_NTXFRAGS - 3) {
841233545Sjchandra				device_printf(sc->xlpge_dev,
842233545Sjchandra				    "packet defrag %d\n",
843233545Sjchandra				    m_length(mbuf_chain, NULL));
844233545Sjchandra				err = ENOBUFS; /* TODO fix error */
845233545Sjchandra				goto fail;
846233545Sjchandra			}
847233545Sjchandra			paddr = vtophys(buf);
848233545Sjchandra			frag_sz = PAGE_SIZE - (buf & PAGE_MASK);
849233545Sjchandra			if (len < frag_sz)
850233545Sjchandra				frag_sz = len;
851245884Sjchandra			desc = nae_tx_desc(P2D_NEOP, 0, 127,
852233545Sjchandra			    frag_sz, paddr);
853245884Sjchandra			p2p->frag[pos] = htobe64(desc);
854233545Sjchandra			pos++;
855233545Sjchandra			len -= frag_sz;
856233545Sjchandra			buf += frag_sz;
857233545Sjchandra		}
858233545Sjchandra	}
859233545Sjchandra
860233545Sjchandra	KASSERT(pos != 0, ("Zero-length mbuf chain?\n"));
861233545Sjchandra
862233545Sjchandra	/* Make the last one P2D EOP */
863245884Sjchandra	p2p->frag[pos-1] |= htobe64((uint64_t)P2D_EOP << 62);
864233545Sjchandra
865233545Sjchandra	/* stash useful pointers in the desc */
866233545Sjchandra	p2p->frag[XLP_NTXFRAGS-3] = 0xf00bad;
867233545Sjchandra	p2p->frag[XLP_NTXFRAGS-2] = (uintptr_t)p2p;
868233545Sjchandra	p2p->frag[XLP_NTXFRAGS-1] = (uintptr_t)mbuf_chain;
869233545Sjchandra
870233545Sjchandra	paddr = vtophys(p2p);
871233545Sjchandra	msg.msg[0] = nae_tx_desc(P2P, 0, fbid, pos, paddr);
872233545Sjchandra
873233545Sjchandra	for (retries = 16;  retries > 0; retries--) {
874233545Sjchandra		ret = nlm_fmn_msgsend(dst, 1, FMN_SWCODE_NAE, &msg);
875233545Sjchandra		if (ret == 0)
876233545Sjchandra			return (0);
877233545Sjchandra	}
878233545Sjchandra
879233545Sjchandrafail:
880233545Sjchandra	if (ret != 0) {
881233545Sjchandra		tx_msgstatus = nlm_read_c2_txmsgstatus();
882233545Sjchandra		if ((tx_msgstatus >> 24) & 0x1)
883233545Sjchandra			device_printf(sc->xlpge_dev, "Transmit queue full - ");
884233545Sjchandra		if ((tx_msgstatus >> 3) & 0x1)
885233545Sjchandra			device_printf(sc->xlpge_dev, "ECC error - ");
886233545Sjchandra		if ((tx_msgstatus >> 2) & 0x1)
887233545Sjchandra			device_printf(sc->xlpge_dev, "Pending Sync - ");
888233545Sjchandra		if ((tx_msgstatus >> 1) & 0x1)
889233545Sjchandra			device_printf(sc->xlpge_dev,
890233545Sjchandra			    "Insufficient input queue credits - ");
891233545Sjchandra		if (tx_msgstatus & 0x1)
892233545Sjchandra			device_printf(sc->xlpge_dev,
893233545Sjchandra			    "Insufficient output queue credits - ");
894233545Sjchandra	}
895233545Sjchandra	device_printf(sc->xlpge_dev, "Send failed! err = %d\n", err);
896233545Sjchandra	if (p2p)
897233545Sjchandra		uma_zfree(nl_tx_desc_zone, p2p);
898233545Sjchandra	m_freem(mbuf_chain);
899233545Sjchandra	/*atomic_incr_long(&ifp->if_iqdrops); */
900233545Sjchandra	ifp->if_iqdrops++;
901233545Sjchandra	return (err);
902233545Sjchandra}
903233545Sjchandra
904233545Sjchandra
905233545Sjchandrastatic int
906233545Sjchandranlm_xlpge_gmac_config_speed(struct nlm_xlpge_softc *sc)
907233545Sjchandra{
908233545Sjchandra	struct mii_data *mii;
909233545Sjchandra
910233545Sjchandra	if (sc->type == XAUIC || sc->type == ILC)
911233545Sjchandra		return (0);
912233545Sjchandra
913233545Sjchandra	if (sc->mii_bus) {
914233545Sjchandra		mii = device_get_softc(sc->mii_bus);
915233545Sjchandra		mii_pollstat(mii);
916233545Sjchandra	}
917233545Sjchandra
918233545Sjchandra	return (0);
919233545Sjchandra}
920233545Sjchandra
921233545Sjchandrastatic void
922233545Sjchandranlm_xlpge_port_disable(struct nlm_xlpge_softc *sc)
923233545Sjchandra{
924233545Sjchandra	struct ifnet   *ifp;
925233545Sjchandra
926233545Sjchandra	ifp = sc->xlpge_if;
927233545Sjchandra	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
928233545Sjchandra
929233545Sjchandra	callout_stop(&sc->xlpge_callout);
930233545Sjchandra	nlm_mac_disable(sc->base_addr, sc->block, sc->type, sc->port);
931233545Sjchandra}
932233545Sjchandra
933233545Sjchandrastatic void
934233545Sjchandranlm_mii_pollstat(void *arg)
935233545Sjchandra{
936233545Sjchandra	struct nlm_xlpge_softc *sc = (struct nlm_xlpge_softc *)arg;
937233545Sjchandra	struct mii_data *mii = NULL;
938233545Sjchandra
939233545Sjchandra	if (sc->mii_bus) {
940233545Sjchandra		mii = device_get_softc(sc->mii_bus);
941233545Sjchandra
942249409Sjchandra		KASSERT(mii != NULL, ("mii ptr is NULL"));
943233545Sjchandra
944233545Sjchandra		mii_pollstat(mii);
945233545Sjchandra
946233545Sjchandra		callout_reset(&sc->xlpge_callout, hz,
947233545Sjchandra		    nlm_mii_pollstat, sc);
948233545Sjchandra	}
949233545Sjchandra}
950233545Sjchandra
951233545Sjchandrastatic void
952233545Sjchandranlm_xlpge_port_enable(struct nlm_xlpge_softc *sc)
953233545Sjchandra{
954233545Sjchandra	if ((sc->type != SGMIIC) && (sc->type != XAUIC))
955233545Sjchandra		return;
956233545Sjchandra	nlm_mac_enable(sc->base_addr, sc->block, sc->type, sc->port);
957233545Sjchandra	nlm_mii_pollstat((void *)sc);
958233545Sjchandra}
959233545Sjchandra
960233545Sjchandrastatic void
961233545Sjchandranlm_xlpge_init(void *addr)
962233545Sjchandra{
963233545Sjchandra	struct nlm_xlpge_softc *sc;
964233545Sjchandra	struct ifnet   *ifp;
965233545Sjchandra	struct mii_data *mii = NULL;
966233545Sjchandra
967233545Sjchandra	sc = (struct nlm_xlpge_softc *)addr;
968233545Sjchandra	ifp = sc->xlpge_if;
969233545Sjchandra
970233545Sjchandra	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
971233545Sjchandra		return;
972233545Sjchandra
973233545Sjchandra	if (sc->mii_bus) {
974233545Sjchandra		mii = device_get_softc(sc->mii_bus);
975233545Sjchandra		mii_mediachg(mii);
976233545Sjchandra	}
977233545Sjchandra
978233545Sjchandra	nlm_xlpge_gmac_config_speed(sc);
979233545Sjchandra	ifp->if_drv_flags |= IFF_DRV_RUNNING;
980233545Sjchandra	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
981233545Sjchandra	nlm_xlpge_port_enable(sc);
982233545Sjchandra
983233545Sjchandra	/* start the callout */
984233545Sjchandra	callout_reset(&sc->xlpge_callout, hz, nlm_mii_pollstat, sc);
985233545Sjchandra}
986233545Sjchandra
987233545Sjchandra/*
988233545Sjchandra * Read the MAC address from FDT or board eeprom.
989233545Sjchandra */
990233545Sjchandrastatic void
991233545Sjchandraxlpge_read_mac_addr(struct nlm_xlpge_softc *sc)
992233545Sjchandra{
993233545Sjchandra
994233545Sjchandra	xlpge_get_macaddr(sc->dev_addr);
995233545Sjchandra	/* last octet is port specific */
996233545Sjchandra	sc->dev_addr[5] += (sc->block * 4) + sc->port;
997233545Sjchandra
998233545Sjchandra	if (sc->type == SGMIIC)
999233545Sjchandra		nlm_nae_setup_mac_addr_sgmii(sc->base_addr, sc->block,
1000233545Sjchandra		    sc->port, sc->type, sc->dev_addr);
1001233545Sjchandra	else if (sc->type == XAUIC)
1002233545Sjchandra		nlm_nae_setup_mac_addr_xaui(sc->base_addr, sc->block,
1003233545Sjchandra		    sc->port, sc->type, sc->dev_addr);
1004233545Sjchandra}
1005233545Sjchandra
1006233545Sjchandra
1007233545Sjchandrastatic int
1008233545Sjchandraxlpge_mediachange(struct ifnet *ifp)
1009233545Sjchandra{
1010233545Sjchandra	return (0);
1011233545Sjchandra}
1012233545Sjchandra
1013233545Sjchandrastatic void
1014233545Sjchandraxlpge_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1015233545Sjchandra{
1016233545Sjchandra	struct nlm_xlpge_softc *sc;
1017233545Sjchandra	struct mii_data *md;
1018233545Sjchandra
1019233545Sjchandra	md = NULL;
1020233545Sjchandra	sc = ifp->if_softc;
1021233545Sjchandra
1022233545Sjchandra	if (sc->mii_bus)
1023233545Sjchandra		md = device_get_softc(sc->mii_bus);
1024233545Sjchandra
1025233545Sjchandra	ifmr->ifm_status = IFM_AVALID;
1026233545Sjchandra	ifmr->ifm_active = IFM_ETHER;
1027233545Sjchandra
1028233545Sjchandra	if (sc->link == NLM_LINK_DOWN)
1029233545Sjchandra		return;
1030233545Sjchandra
1031233545Sjchandra	if (md != NULL)
1032233545Sjchandra		ifmr->ifm_active = md->mii_media.ifm_cur->ifm_media;
1033233545Sjchandra	ifmr->ifm_status |= IFM_ACTIVE;
1034233545Sjchandra}
1035233545Sjchandra
1036233545Sjchandrastatic int
1037233545Sjchandranlm_xlpge_ifinit(struct nlm_xlpge_softc *sc)
1038233545Sjchandra{
1039233545Sjchandra	struct ifnet *ifp;
1040233545Sjchandra	device_t dev;
1041233545Sjchandra	int port = sc->block * 4 + sc->port;
1042233545Sjchandra
1043233545Sjchandra	dev = sc->xlpge_dev;
1044233545Sjchandra	ifp = sc->xlpge_if = if_alloc(IFT_ETHER);
1045233545Sjchandra	/*(sc->network_sc)->ifp_ports[port].xlpge_if = ifp;*/
1046233545Sjchandra	ifp_ports[port].xlpge_if = ifp;
1047233545Sjchandra
1048233545Sjchandra	if (ifp == NULL) {
1049233545Sjchandra		device_printf(dev, "cannot if_alloc()\n");
1050233545Sjchandra		return (ENOSPC);
1051233545Sjchandra	}
1052233545Sjchandra	ifp->if_softc = sc;
1053233545Sjchandra	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1054233545Sjchandra	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1055233545Sjchandra	sc->if_flags = ifp->if_flags;
1056233545Sjchandra	/*ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_VLAN_HWTAGGING;*/
1057233545Sjchandra	ifp->if_capabilities = 0;
1058233545Sjchandra	ifp->if_capenable = ifp->if_capabilities;
1059233545Sjchandra	ifp->if_ioctl = nlm_xlpge_ioctl;
1060233545Sjchandra	ifp->if_init  = nlm_xlpge_init ;
1061233545Sjchandra	ifp->if_hwassist = 0;
1062233545Sjchandra	ifp->if_snd.ifq_drv_maxlen = NLM_XLPGE_TXQ_SIZE; /* TODO: make this a sysint */
1063233545Sjchandra	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
1064233545Sjchandra	IFQ_SET_READY(&ifp->if_snd);
1065233545Sjchandra
1066233545Sjchandra	ifmedia_init(&sc->xlpge_mii.mii_media, 0, xlpge_mediachange,
1067233545Sjchandra	    xlpge_mediastatus);
1068233545Sjchandra	ifmedia_add(&sc->xlpge_mii.mii_media, IFM_ETHER | IFM_AUTO, 0, NULL);
1069233545Sjchandra	ifmedia_set(&sc->xlpge_mii.mii_media, IFM_ETHER | IFM_AUTO);
1070233545Sjchandra	sc->xlpge_mii.mii_media.ifm_media =
1071233545Sjchandra	    sc->xlpge_mii.mii_media.ifm_cur->ifm_media;
1072233545Sjchandra	xlpge_read_mac_addr(sc);
1073233545Sjchandra
1074233545Sjchandra	ether_ifattach(ifp, sc->dev_addr);
1075233545Sjchandra
1076233545Sjchandra	/* override if_transmit : per ifnet(9), do it after if_attach */
1077233545Sjchandra	ifp->if_transmit = xlpge_tx;
1078233545Sjchandra
1079233545Sjchandra	return (0);
1080233545Sjchandra}
1081233545Sjchandra
1082233545Sjchandrastatic int
1083233545Sjchandranlm_xlpge_probe(device_t dev)
1084233545Sjchandra{
1085233545Sjchandra	return (BUS_PROBE_DEFAULT);
1086233545Sjchandra}
1087233545Sjchandra
1088233545Sjchandrastatic void *
1089233545Sjchandraget_buf(void)
1090233545Sjchandra{
1091233545Sjchandra	struct mbuf     *m_new;
1092233545Sjchandra	uint64_t        *md;
1093233545Sjchandra#ifdef INVARIANTS
1094233545Sjchandra	vm_paddr_t      temp1, temp2;
1095233545Sjchandra#endif
1096233545Sjchandra
1097243882Sglebius	if ((m_new = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL)
1098233545Sjchandra		return (NULL);
1099233545Sjchandra	m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
1100245884Sjchandra	KASSERT(((uintptr_t)m_new->m_data & (NAE_CACHELINE_SIZE - 1)) == 0,
1101245884Sjchandra	    ("m_new->m_data is not cacheline aligned"));
1102233545Sjchandra	md = (uint64_t *)m_new->m_data;
1103233545Sjchandra	md[0] = (intptr_t)m_new;        /* Back Ptr */
1104233545Sjchandra	md[1] = 0xf00bad;
1105233545Sjchandra	m_adj(m_new, NAE_CACHELINE_SIZE);
1106233545Sjchandra
1107233545Sjchandra#ifdef INVARIANTS
1108233545Sjchandra	temp1 = vtophys((vm_offset_t) m_new->m_data);
1109233545Sjchandra	temp2 = vtophys((vm_offset_t) m_new->m_data + 1536);
1110249409Sjchandra	KASSERT((temp1 + 1536) == temp2,
1111233545Sjchandra	    ("Alloced buffer is not contiguous"));
1112233545Sjchandra#endif
1113233545Sjchandra	return ((void *)m_new->m_data);
1114233545Sjchandra}
1115233545Sjchandra
1116233545Sjchandrastatic void
1117233545Sjchandranlm_xlpge_mii_init(device_t dev, struct nlm_xlpge_softc *sc)
1118233545Sjchandra{
1119233545Sjchandra	int error;
1120233545Sjchandra
1121233545Sjchandra	error = mii_attach(dev, &sc->mii_bus, sc->xlpge_if,
1122233545Sjchandra			xlpge_mediachange, xlpge_mediastatus,
1123233545Sjchandra			BMSR_DEFCAPMASK, sc->phy_addr, MII_OFFSET_ANY, 0);
1124233545Sjchandra
1125233545Sjchandra	if (error) {
1126233545Sjchandra		device_printf(dev, "attaching PHYs failed\n");
1127233545Sjchandra		sc->mii_bus = NULL;
1128233545Sjchandra	}
1129233545Sjchandra
1130233545Sjchandra	if (sc->mii_bus != NULL) {
1131233545Sjchandra		/* enable MDIO interrupts in the PHY */
1132233545Sjchandra		/* XXXJC: TODO */
1133233545Sjchandra	}
1134233545Sjchandra}
1135233545Sjchandra
1136233545Sjchandrastatic int
1137233545Sjchandraxlpge_stats_sysctl(SYSCTL_HANDLER_ARGS)
1138233545Sjchandra{
1139233545Sjchandra	struct nlm_xlpge_softc *sc;
1140233545Sjchandra	uint32_t val;
1141233545Sjchandra	int reg, field;
1142233545Sjchandra
1143233545Sjchandra	sc = arg1;
1144233545Sjchandra	field = arg2;
1145233545Sjchandra	reg = SGMII_STATS_MLR(sc->block, sc->port) + field;
1146233545Sjchandra	val = nlm_read_nae_reg(sc->base_addr, reg);
1147233545Sjchandra	return (sysctl_handle_int(oidp, &val, 0, req));
1148233545Sjchandra}
1149233545Sjchandra
1150233545Sjchandrastatic void
1151233545Sjchandranlm_xlpge_setup_stats_sysctl(device_t dev, struct nlm_xlpge_softc *sc)
1152233545Sjchandra{
1153233545Sjchandra	struct sysctl_ctx_list *ctx;
1154233545Sjchandra	struct sysctl_oid_list *child;
1155233545Sjchandra	struct sysctl_oid *tree;
1156233545Sjchandra
1157233545Sjchandra	ctx = device_get_sysctl_ctx(dev);
1158233545Sjchandra	tree = device_get_sysctl_tree(dev);
1159233545Sjchandra	child = SYSCTL_CHILDREN(tree);
1160233545Sjchandra
1161233545Sjchandra#define XLPGE_STAT(name, offset, desc) \
1162233545Sjchandra	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, name, 	\
1163233545Sjchandra	    CTLTYPE_UINT | CTLFLAG_RD, sc, offset,	\
1164233545Sjchandra	    xlpge_stats_sysctl, "IU", desc)
1165233545Sjchandra
1166233545Sjchandra	XLPGE_STAT("tr127", nlm_sgmii_stats_tr127, "TxRx 64 - 127 Bytes");
1167233545Sjchandra	XLPGE_STAT("tr255", nlm_sgmii_stats_tr255, "TxRx 128 - 255 Bytes");
1168233545Sjchandra	XLPGE_STAT("tr511", nlm_sgmii_stats_tr511, "TxRx 256 - 511 Bytes");
1169233545Sjchandra	XLPGE_STAT("tr1k",  nlm_sgmii_stats_tr1k,  "TxRx 512 - 1023 Bytes");
1170233545Sjchandra	XLPGE_STAT("trmax", nlm_sgmii_stats_trmax, "TxRx 1024 - 1518 Bytes");
1171233545Sjchandra	XLPGE_STAT("trmgv", nlm_sgmii_stats_trmgv, "TxRx 1519 - 1522 Bytes");
1172233545Sjchandra
1173233545Sjchandra	XLPGE_STAT("rbyt", nlm_sgmii_stats_rbyt, "Rx Bytes");
1174233545Sjchandra	XLPGE_STAT("rpkt", nlm_sgmii_stats_rpkt, "Rx Packets");
1175233545Sjchandra	XLPGE_STAT("rfcs", nlm_sgmii_stats_rfcs, "Rx FCS Error");
1176233545Sjchandra	XLPGE_STAT("rmca", nlm_sgmii_stats_rmca, "Rx Multicast Packets");
1177233545Sjchandra	XLPGE_STAT("rbca", nlm_sgmii_stats_rbca, "Rx Broadcast Packets");
1178233545Sjchandra	XLPGE_STAT("rxcf", nlm_sgmii_stats_rxcf, "Rx Control Frames");
1179233545Sjchandra	XLPGE_STAT("rxpf", nlm_sgmii_stats_rxpf, "Rx Pause Frames");
1180233545Sjchandra	XLPGE_STAT("rxuo", nlm_sgmii_stats_rxuo, "Rx Unknown Opcode");
1181233545Sjchandra	XLPGE_STAT("raln", nlm_sgmii_stats_raln, "Rx Alignment Errors");
1182233545Sjchandra	XLPGE_STAT("rflr", nlm_sgmii_stats_rflr, "Rx Framelength Errors");
1183233545Sjchandra	XLPGE_STAT("rcde", nlm_sgmii_stats_rcde, "Rx Code Errors");
1184233545Sjchandra	XLPGE_STAT("rcse", nlm_sgmii_stats_rcse, "Rx Carrier Sense Errors");
1185233545Sjchandra	XLPGE_STAT("rund", nlm_sgmii_stats_rund, "Rx Undersize Packet Errors");
1186233545Sjchandra	XLPGE_STAT("rovr", nlm_sgmii_stats_rovr, "Rx Oversize Packet Errors");
1187233545Sjchandra	XLPGE_STAT("rfrg", nlm_sgmii_stats_rfrg, "Rx Fragments");
1188233545Sjchandra	XLPGE_STAT("rjbr", nlm_sgmii_stats_rjbr, "Rx Jabber");
1189233545Sjchandra
1190233545Sjchandra	XLPGE_STAT("tbyt", nlm_sgmii_stats_tbyt, "Tx Bytes");
1191233545Sjchandra	XLPGE_STAT("tpkt", nlm_sgmii_stats_tpkt, "Tx Packets");
1192233545Sjchandra	XLPGE_STAT("tmca", nlm_sgmii_stats_tmca, "Tx Multicast Packets");
1193233545Sjchandra	XLPGE_STAT("tbca", nlm_sgmii_stats_tbca, "Tx Broadcast Packets");
1194233545Sjchandra	XLPGE_STAT("txpf", nlm_sgmii_stats_txpf, "Tx Pause Frame");
1195233545Sjchandra	XLPGE_STAT("tdfr", nlm_sgmii_stats_tdfr, "Tx Deferral Packets");
1196233545Sjchandra	XLPGE_STAT("tedf", nlm_sgmii_stats_tedf, "Tx Excessive Deferral Pkts");
1197233545Sjchandra	XLPGE_STAT("tscl", nlm_sgmii_stats_tscl, "Tx Single Collisions");
1198233545Sjchandra	XLPGE_STAT("tmcl", nlm_sgmii_stats_tmcl, "Tx Multiple Collisions");
1199233545Sjchandra	XLPGE_STAT("tlcl", nlm_sgmii_stats_tlcl, "Tx Late Collision Pkts");
1200233545Sjchandra	XLPGE_STAT("txcl", nlm_sgmii_stats_txcl, "Tx Excessive Collisions");
1201233545Sjchandra	XLPGE_STAT("tncl", nlm_sgmii_stats_tncl, "Tx Total Collisions");
1202233545Sjchandra	XLPGE_STAT("tjbr", nlm_sgmii_stats_tjbr, "Tx Jabber Frames");
1203233545Sjchandra	XLPGE_STAT("tfcs", nlm_sgmii_stats_tfcs, "Tx FCS Errors");
1204233545Sjchandra	XLPGE_STAT("txcf", nlm_sgmii_stats_txcf, "Tx Control Frames");
1205233545Sjchandra	XLPGE_STAT("tovr", nlm_sgmii_stats_tovr, "Tx Oversize Frames");
1206233545Sjchandra	XLPGE_STAT("tund", nlm_sgmii_stats_tund, "Tx Undersize Frames");
1207233545Sjchandra	XLPGE_STAT("tfrg", nlm_sgmii_stats_tfrg, "Tx Fragments");
1208233545Sjchandra#undef XLPGE_STAT
1209233545Sjchandra}
1210233545Sjchandra
1211233545Sjchandrastatic int
1212233545Sjchandranlm_xlpge_attach(device_t dev)
1213233545Sjchandra{
1214233545Sjchandra	struct xlp_port_ivars *pv;
1215233545Sjchandra	struct nlm_xlpge_softc *sc;
1216233545Sjchandra	int port;
1217233545Sjchandra
1218233545Sjchandra	pv = device_get_ivars(dev);
1219233545Sjchandra	sc = device_get_softc(dev);
1220233545Sjchandra	sc->xlpge_dev = dev;
1221233545Sjchandra	sc->mii_bus = NULL;
1222233545Sjchandra	sc->block = pv->block;
1223233545Sjchandra	sc->node = pv->node;
1224233545Sjchandra	sc->port = pv->port;
1225233545Sjchandra	sc->type = pv->type;
1226233545Sjchandra	sc->xlpge_if = NULL;
1227233545Sjchandra	sc->phy_addr = pv->phy_addr;
1228233545Sjchandra	sc->mdio_bus = pv->mdio_bus;
1229233545Sjchandra	sc->portcfg = nae_port_config;
1230233545Sjchandra	sc->hw_parser_en = pv->hw_parser_en;
1231233545Sjchandra
1232233545Sjchandra	/* default settings */
1233233545Sjchandra	sc->speed = NLM_SGMII_SPEED_10;
1234233545Sjchandra	sc->duplexity = NLM_SGMII_DUPLEX_FULL;
1235233545Sjchandra	sc->link = NLM_LINK_DOWN;
1236233545Sjchandra	sc->flowctrl = NLM_FLOWCTRL_DISABLED;
1237233545Sjchandra
1238233545Sjchandra	sc->network_sc = device_get_softc(device_get_parent(dev));
1239233545Sjchandra	sc->base_addr = sc->network_sc->base;
1240233545Sjchandra	sc->prepad_en = sc->network_sc->prepad_en;
1241233545Sjchandra	sc->prepad_size = sc->network_sc->prepad_size;
1242233545Sjchandra
1243314667Savg	callout_init(&sc->xlpge_callout, 1);
1244233545Sjchandra
1245233545Sjchandra	XLPGE_LOCK_INIT(sc, device_get_nameunit(dev));
1246233545Sjchandra
1247233545Sjchandra	port = (sc->block*4)+sc->port;
1248233545Sjchandra	sc->nfree_desc = nae_port_config[port].num_free_descs;
1249233545Sjchandra	sc->txq = nae_port_config[port].txq;
1250233545Sjchandra	sc->rxfreeq = nae_port_config[port].rxfreeq;
1251233545Sjchandra
1252233545Sjchandra	nlm_xlpge_submit_rx_free_desc(sc, sc->nfree_desc);
1253233545Sjchandra	if (sc->hw_parser_en)
1254233545Sjchandra		nlm_enable_hardware_parser_per_port(sc->base_addr,
1255233545Sjchandra		    sc->block, sc->port);
1256233545Sjchandra
1257233545Sjchandra	nlm_xlpge_ifinit(sc);
1258233545Sjchandra	ifp_ports[port].xlpge_sc = sc;
1259233545Sjchandra	nlm_xlpge_mii_init(dev, sc);
1260245881Sjchandra
1261233545Sjchandra	nlm_xlpge_setup_stats_sysctl(dev, sc);
1262233545Sjchandra
1263233545Sjchandra	return (0);
1264233545Sjchandra}
1265233545Sjchandra
1266233545Sjchandrastatic int
1267233545Sjchandranlm_xlpge_detach(device_t dev)
1268233545Sjchandra{
1269233545Sjchandra	return (0);
1270233545Sjchandra}
1271233545Sjchandra
1272233545Sjchandrastatic int
1273233545Sjchandranlm_xlpge_suspend(device_t dev)
1274233545Sjchandra{
1275233545Sjchandra	return (0);
1276233545Sjchandra}
1277233545Sjchandra
1278233545Sjchandrastatic int
1279233545Sjchandranlm_xlpge_resume(device_t dev)
1280233545Sjchandra{
1281233545Sjchandra	return (0);
1282233545Sjchandra}
1283233545Sjchandra
1284233545Sjchandrastatic int
1285233545Sjchandranlm_xlpge_shutdown(device_t dev)
1286233545Sjchandra{
1287233545Sjchandra	return (0);
1288233545Sjchandra}
1289233545Sjchandra
1290233545Sjchandra/*
1291233545Sjchandra * miibus function with custom implementation
1292233545Sjchandra */
1293233545Sjchandrastatic int
1294233545Sjchandranlm_xlpge_mii_read(struct device *dev, int phyaddr, int regidx)
1295233545Sjchandra{
1296233545Sjchandra	struct nlm_xlpge_softc *sc;
1297233545Sjchandra	int val;
1298233545Sjchandra
1299233545Sjchandra	sc = device_get_softc(dev);
1300233545Sjchandra	if (sc->type == SGMIIC)
1301233545Sjchandra		val = nlm_gmac_mdio_read(sc->base_addr, sc->mdio_bus,
1302233545Sjchandra		    BLOCK_7, LANE_CFG, phyaddr, regidx);
1303233545Sjchandra	else
1304233545Sjchandra		val = 0xffff;
1305233545Sjchandra
1306233545Sjchandra	return (val);
1307233545Sjchandra}
1308233545Sjchandra
1309233545Sjchandrastatic int
1310233545Sjchandranlm_xlpge_mii_write(struct device *dev, int phyaddr, int regidx, int val)
1311233545Sjchandra{
1312233545Sjchandra	struct nlm_xlpge_softc *sc;
1313233545Sjchandra
1314233545Sjchandra	sc = device_get_softc(dev);
1315233545Sjchandra	if (sc->type == SGMIIC)
1316233545Sjchandra		nlm_gmac_mdio_write(sc->base_addr, sc->mdio_bus, BLOCK_7,
1317233545Sjchandra		    LANE_CFG, phyaddr, regidx, val);
1318233545Sjchandra
1319233545Sjchandra	return (0);
1320233545Sjchandra}
1321233545Sjchandra
1322233545Sjchandrastatic void
1323233545Sjchandranlm_xlpge_mii_statchg(device_t dev)
1324233545Sjchandra{
1325233545Sjchandra	struct nlm_xlpge_softc *sc;
1326233545Sjchandra	struct mii_data *mii;
1327233545Sjchandra	char *speed, *duplexity;
1328233545Sjchandra
1329233545Sjchandra	sc = device_get_softc(dev);
1330233545Sjchandra	if (sc->mii_bus == NULL)
1331233545Sjchandra		return;
1332233545Sjchandra
1333233545Sjchandra	mii = device_get_softc(sc->mii_bus);
1334233545Sjchandra	if (mii->mii_media_status & IFM_ACTIVE) {
1335233545Sjchandra		if (IFM_SUBTYPE(mii->mii_media_active) ==  IFM_10_T) {
1336233545Sjchandra			sc->speed = NLM_SGMII_SPEED_10;
1337245880Sjchandra			speed =  "10Mbps";
1338233545Sjchandra		} else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) {
1339233545Sjchandra			sc->speed = NLM_SGMII_SPEED_100;
1340245880Sjchandra			speed = "100Mbps";
1341233545Sjchandra		} else { /* default to 1G */
1342233545Sjchandra			sc->speed = NLM_SGMII_SPEED_1000;
1343245880Sjchandra			speed =  "1Gbps";
1344233545Sjchandra		}
1345233545Sjchandra
1346233545Sjchandra		if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
1347233545Sjchandra			sc->duplexity = NLM_SGMII_DUPLEX_FULL;
1348233545Sjchandra			duplexity =  "full";
1349233545Sjchandra		} else {
1350233545Sjchandra			sc->duplexity = NLM_SGMII_DUPLEX_HALF;
1351233545Sjchandra			duplexity = "half";
1352233545Sjchandra		}
1353233545Sjchandra
1354245880Sjchandra		printf("Port [%d, %d] setup with speed=%s duplex=%s\n",
1355233545Sjchandra		    sc->block, sc->port, speed, duplexity);
1356233545Sjchandra
1357233545Sjchandra		nlm_nae_setup_mac(sc->base_addr, sc->block, sc->port, 0, 1, 1,
1358245881Sjchandra		    sc->speed, sc->duplexity);
1359233545Sjchandra	}
1360233545Sjchandra}
1361233545Sjchandra
1362233545Sjchandra/*
1363233545Sjchandra * xlpge support function implementations
1364233545Sjchandra */
1365233545Sjchandrastatic void
1366233545Sjchandranlm_xlpge_release_mbuf(uint64_t paddr)
1367233545Sjchandra{
1368233545Sjchandra	uint64_t	mag, desc, mbuf;
1369233545Sjchandra
1370233545Sjchandra	paddr += (XLP_NTXFRAGS - 3) * sizeof(uint64_t);
1371233545Sjchandra	mag = nlm_paddr_ld(paddr);
1372233545Sjchandra	desc = nlm_paddr_ld(paddr + sizeof(uint64_t));
1373233545Sjchandra	mbuf = nlm_paddr_ld(paddr + 2 * sizeof(uint64_t));
1374233545Sjchandra
1375233545Sjchandra	if (mag != 0xf00bad) {
1376233545Sjchandra		/* somebody else packet Error - FIXME in intialization */
1377233545Sjchandra		printf("cpu %d: ERR Tx packet paddr %jx, mag %jx, desc %jx mbuf %jx\n",
1378233545Sjchandra		    nlm_cpuid(), (uintmax_t)paddr, (uintmax_t)mag,
1379233545Sjchandra		    (intmax_t)desc, (uintmax_t)mbuf);
1380233545Sjchandra		return;
1381233545Sjchandra	}
1382233545Sjchandra	m_freem((struct mbuf *)(uintptr_t)mbuf);
1383233545Sjchandra	uma_zfree(nl_tx_desc_zone, (void *)(uintptr_t)desc);
1384233545Sjchandra}
1385233545Sjchandra
1386233545Sjchandrastatic void
1387233545Sjchandranlm_xlpge_rx(struct nlm_xlpge_softc *sc, int port, vm_paddr_t paddr, int len)
1388233545Sjchandra{
1389233545Sjchandra	struct ifnet	*ifp;
1390233545Sjchandra	struct mbuf	*m;
1391233545Sjchandra	vm_offset_t	temp;
1392233545Sjchandra	unsigned long	mag;
1393233545Sjchandra	int		prepad_size;
1394233545Sjchandra
1395233545Sjchandra	ifp = sc->xlpge_if;
1396233545Sjchandra	temp = nlm_paddr_ld(paddr - NAE_CACHELINE_SIZE);
1397233545Sjchandra	mag = nlm_paddr_ld(paddr - NAE_CACHELINE_SIZE + sizeof(uint64_t));
1398233545Sjchandra
1399233545Sjchandra	m = (struct mbuf *)(intptr_t)temp;
1400233545Sjchandra	if (mag != 0xf00bad) {
1401233545Sjchandra		/* somebody else packet Error - FIXME in intialization */
1402233545Sjchandra		printf("cpu %d: ERR Rx packet paddr %jx, temp %p, mag %lx\n",
1403233545Sjchandra		    nlm_cpuid(), (uintmax_t)paddr, (void *)temp, mag);
1404233545Sjchandra		return;
1405233545Sjchandra	}
1406233545Sjchandra
1407233545Sjchandra	m->m_pkthdr.rcvif = ifp;
1408233545Sjchandra
1409233545Sjchandra#ifdef DUMP_PACKET
1410233545Sjchandra	{
1411233545Sjchandra		int     i = 0, j = 64;
1412233545Sjchandra		unsigned char *buf = (char *)m->m_data;
1413233545Sjchandra		printf("(cpu_%d: nlge_rx, !RX_COPY) Rx Packet: length=%d\n",
1414233545Sjchandra				nlm_cpuid(), len);
1415233545Sjchandra		if (len < j)
1416233545Sjchandra			j = len;
1417233545Sjchandra		if (sc->prepad_en)
1418233545Sjchandra			j += ((sc->prepad_size + 1) * 16);
1419233545Sjchandra		for (i = 0; i < j; i++) {
1420233545Sjchandra			if (i && (i % 16) == 0)
1421233545Sjchandra				printf("\n");
1422233545Sjchandra			printf("%02x ", buf[i]);
1423233545Sjchandra		}
1424233545Sjchandra		printf("\n");
1425233545Sjchandra	}
1426233545Sjchandra#endif
1427233545Sjchandra
1428233545Sjchandra	if (sc->prepad_en) {
1429233545Sjchandra		prepad_size = ((sc->prepad_size + 1) * 16);
1430233545Sjchandra		m->m_data += prepad_size;
1431233545Sjchandra		m->m_pkthdr.len = m->m_len = (len - prepad_size);
1432233545Sjchandra	} else
1433233545Sjchandra		m->m_pkthdr.len = m->m_len = len;
1434233545Sjchandra
1435233545Sjchandra	/*atomic_incr_long(&ifp->if_ipackets);*/
1436233545Sjchandra	ifp->if_ipackets++;
1437233545Sjchandra#ifdef XLP_DRIVER_LOOPBACK
1438233545Sjchandra	if (port == 16 || port == 17)
1439233545Sjchandra		(*ifp->if_input)(ifp, m);
1440233545Sjchandra	else
1441233545Sjchandra		xlpge_tx(ifp, m);
1442233545Sjchandra#else
1443233545Sjchandra	(*ifp->if_input)(ifp, m);
1444233545Sjchandra#endif
1445233545Sjchandra}
1446233545Sjchandra
1447233545Sjchandravoid
1448233545Sjchandranlm_xlpge_submit_rx_free_desc(struct nlm_xlpge_softc *sc, int num)
1449233545Sjchandra{
1450233545Sjchandra	int i, size, ret, n;
1451233545Sjchandra	struct nlm_fmn_msg msg;
1452233545Sjchandra	void *ptr;
1453233545Sjchandra
1454233545Sjchandra	for(i = 0; i < num; i++) {
1455233545Sjchandra		memset(&msg, 0, sizeof(msg));
1456233545Sjchandra		ptr = get_buf();
1457233545Sjchandra		if (!ptr) {
1458233545Sjchandra			device_printf(sc->xlpge_dev, "Cannot allocate mbuf\n");
1459233545Sjchandra			break;
1460233545Sjchandra		}
1461233545Sjchandra
1462233545Sjchandra		msg.msg[0] = vtophys(ptr);
1463233545Sjchandra		if (msg.msg[0] == 0) {
1464233545Sjchandra			printf("Bad ptr for %p\n", ptr);
1465233545Sjchandra			break;
1466233545Sjchandra		}
1467233545Sjchandra		size = 1;
1468233545Sjchandra
1469233545Sjchandra		n = 0;
1470233545Sjchandra		while (1) {
1471233545Sjchandra			/* on success returns 1, else 0 */
1472233545Sjchandra			ret = nlm_fmn_msgsend(sc->rxfreeq, size, 0, &msg);
1473233545Sjchandra			if (ret == 0)
1474233545Sjchandra				break;
1475233545Sjchandra			if (n++ > 10000) {
1476233545Sjchandra				printf("Too many credit fails for send free desc\n");
1477233545Sjchandra				break;
1478233545Sjchandra			}
1479233545Sjchandra		}
1480233545Sjchandra	}
1481233545Sjchandra}
1482233545Sjchandra
1483233545Sjchandravoid
1484233545Sjchandranlm_xlpge_msgring_handler(int vc, int size, int code, int src_id,
1485233545Sjchandra    struct nlm_fmn_msg *msg, void *data)
1486233545Sjchandra{
1487233545Sjchandra	uint64_t phys_addr;
1488233545Sjchandra	struct nlm_xlpnae_softc *sc;
1489233545Sjchandra	struct nlm_xlpge_softc *xlpge_sc;
1490233545Sjchandra	struct ifnet *ifp;
1491233545Sjchandra	uint32_t context;
1492233545Sjchandra	uint32_t port = 0;
1493233545Sjchandra	uint32_t length;
1494233545Sjchandra
1495233545Sjchandra	sc = (struct nlm_xlpnae_softc *)data;
1496233545Sjchandra	KASSERT(sc != NULL, ("Null sc in msgring handler"));
1497233545Sjchandra
1498233545Sjchandra	if (size == 1) { /* process transmit complete */
1499233545Sjchandra		phys_addr = msg->msg[0] & 0xffffffffffULL;
1500233545Sjchandra
1501233545Sjchandra		/* context is SGMII_RCV_CONTEXT_NUM + three bit vlan type
1502233545Sjchandra		 * or vlan priority
1503233545Sjchandra		 */
1504233545Sjchandra		context = (msg->msg[0] >> 40) & 0x3fff;
1505233545Sjchandra		port = cntx2port[context];
1506233545Sjchandra
1507233545Sjchandra		if (port >= XLP_MAX_PORTS) {
1508233545Sjchandra			printf("%s:%d Bad port %d (context=%d)\n",
1509233545Sjchandra				__func__, __LINE__, port, context);
1510233545Sjchandra			return;
1511233545Sjchandra		}
1512233545Sjchandra		ifp = ifp_ports[port].xlpge_if;
1513233545Sjchandra		xlpge_sc = ifp_ports[port].xlpge_sc;
1514233545Sjchandra
1515233545Sjchandra		nlm_xlpge_release_mbuf(phys_addr);
1516233545Sjchandra
1517233545Sjchandra		/*atomic_incr_long(&ifp->if_opackets);*/
1518233545Sjchandra		ifp->if_opackets++;
1519233545Sjchandra
1520233545Sjchandra	} else if (size > 1) { /* Recieve packet */
1521245884Sjchandra		phys_addr = msg->msg[1] & 0xffffffffc0ULL;
1522233545Sjchandra		length = (msg->msg[1] >> 40) & 0x3fff;
1523233545Sjchandra		length -= MAC_CRC_LEN;
1524233545Sjchandra
1525233545Sjchandra		/* context is SGMII_RCV_CONTEXT_NUM + three bit vlan type
1526233545Sjchandra		 * or vlan priority
1527233545Sjchandra		 */
1528233545Sjchandra		context = (msg->msg[1] >> 54) & 0x3ff;
1529233545Sjchandra		port = cntx2port[context];
1530233545Sjchandra
1531233545Sjchandra		if (port >= XLP_MAX_PORTS) {
1532233545Sjchandra			printf("%s:%d Bad port %d (context=%d)\n",
1533233545Sjchandra				__func__, __LINE__, port, context);
1534233545Sjchandra			return;
1535233545Sjchandra		}
1536233545Sjchandra
1537233545Sjchandra		ifp = ifp_ports[port].xlpge_if;
1538233545Sjchandra		xlpge_sc = ifp_ports[port].xlpge_sc;
1539233545Sjchandra
1540233545Sjchandra		nlm_xlpge_rx(xlpge_sc, port, phys_addr, length);
1541233545Sjchandra		/* return back a free descriptor to NA */
1542233545Sjchandra		nlm_xlpge_submit_rx_free_desc(xlpge_sc, 1);
1543233545Sjchandra	}
1544233545Sjchandra}
1545