nic_main.c revision 289551
1230557Sjimharris/*
2230557Sjimharris * Copyright (C) 2015 Cavium Inc.
3230557Sjimharris * All rights reserved.
4230557Sjimharris *
5230557Sjimharris * Redistribution and use in source and binary forms, with or without
6230557Sjimharris * modification, are permitted provided that the following conditions
7230557Sjimharris * are met:
8230557Sjimharris * 1. Redistributions of source code must retain the above copyright
9230557Sjimharris *    notice, this list of conditions and the following disclaimer.
10230557Sjimharris * 2. Redistributions in binary form must reproduce the above copyright
11230557Sjimharris *    notice, this list of conditions and the following disclaimer in the
12230557Sjimharris *    documentation and/or other materials provided with the distribution.
13230557Sjimharris *
14230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15230557Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16230557Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17230557Sjimharris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18230557Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19230557Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20230557Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21230557Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22230557Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23230557Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24230557Sjimharris * SUCH DAMAGE.
25230557Sjimharris *
26230557Sjimharris * $FreeBSD: head/sys/dev/vnic/nic_main.c 289551 2015-10-18 22:02:58Z zbb $
27230557Sjimharris *
28230557Sjimharris */
29230557Sjimharris
30230557Sjimharris#include <sys/cdefs.h>
31230557Sjimharris__FBSDID("$FreeBSD: head/sys/dev/vnic/nic_main.c 289551 2015-10-18 22:02:58Z zbb $");
32230557Sjimharris
33230557Sjimharris#include <sys/param.h>
34230557Sjimharris#include <sys/systm.h>
35230557Sjimharris#include <sys/bitset.h>
36230557Sjimharris#include <sys/bitstring.h>
37230557Sjimharris#include <sys/bus.h>
38230557Sjimharris#include <sys/endian.h>
39230557Sjimharris#include <sys/kernel.h>
40230557Sjimharris#include <sys/malloc.h>
41230557Sjimharris#include <sys/module.h>
42230557Sjimharris#include <sys/rman.h>
43230557Sjimharris#include <sys/pciio.h>
44230557Sjimharris#include <sys/pcpu.h>
45230557Sjimharris#include <sys/proc.h>
46230557Sjimharris#include <sys/socket.h>
47230557Sjimharris#include <sys/sockio.h>
48230557Sjimharris#include <sys/cpuset.h>
49230557Sjimharris#include <sys/lock.h>
50230557Sjimharris#include <sys/mutex.h>
51230557Sjimharris
52230557Sjimharris#include <net/ethernet.h>
53230557Sjimharris#include <net/if.h>
54230557Sjimharris#include <net/if_media.h>
55230557Sjimharris
56230557Sjimharris#include <machine/bus.h>
57230557Sjimharris#include <machine/_inttypes.h>
58230557Sjimharris
59230557Sjimharris#include <dev/pci/pcireg.h>
60230557Sjimharris#include <dev/pci/pcivar.h>
61230557Sjimharris
62230557Sjimharris#include <sys/dnv.h>
63230557Sjimharris#include <sys/nv.h>
64230557Sjimharris#ifdef PCI_IOV
65230557Sjimharris#include <sys/iov_schema.h>
66230557Sjimharris#include <dev/pci/pci_iov.h>
67230557Sjimharris#endif
68230557Sjimharris
69230557Sjimharris#include "thunder_bgx.h"
70230557Sjimharris#include "nic_reg.h"
71230557Sjimharris#include "nic.h"
72230557Sjimharris#include "q_struct.h"
73230557Sjimharris
74230557Sjimharris#define	VNIC_PF_DEVSTR		"Cavium Thunder NIC Physical Function Driver"
75230557Sjimharris
76230557Sjimharris#define	VNIC_PF_REG_RID		PCIR_BAR(PCI_CFG_REG_BAR_NUM)
77230557Sjimharris
78230557Sjimharris#define	NIC_SET_VF_LMAC_MAP(bgx, lmac)		((((bgx) & 0xF) << 4) | ((lmac) & 0xF))
79230557Sjimharris#define	NIC_GET_BGX_FROM_VF_LMAC_MAP(map)	(((map) >> 4) & 0xF)
80230557Sjimharris#define	NIC_GET_LMAC_FROM_VF_LMAC_MAP(map)	((map) & 0xF)
81230557Sjimharris
82230557Sjimharris/* Structure to be used by the SR-IOV for VF configuration schemas */
83230557Sjimharrisstruct nicvf_info {
84230557Sjimharris	boolean_t		vf_enabled;
85230557Sjimharris	int			vf_flags;
86230557Sjimharris};
87230557Sjimharris
88230557Sjimharrisstruct nicpf {
89230557Sjimharris	device_t		dev;
90230557Sjimharris	uint8_t			rev_id;
91230557Sjimharris	uint8_t			node;
92230557Sjimharris	u_int			flags;
93230557Sjimharris	uint8_t			num_vf_en;      /* No of VF enabled */
94230557Sjimharris	struct nicvf_info	vf_info[MAX_NUM_VFS_SUPPORTED];
95230557Sjimharris	struct resource *	reg_base;       /* Register start address */
96230557Sjimharris	struct pkind_cfg	pkind;
97230557Sjimharris	uint8_t			vf_lmac_map[MAX_LMAC];
98230557Sjimharris	boolean_t		mbx_lock[MAX_NUM_VFS_SUPPORTED];
99230557Sjimharris
100230557Sjimharris	struct callout		check_link;
101230557Sjimharris	struct mtx		check_link_mtx;
102230557Sjimharris
103230557Sjimharris	uint8_t			link[MAX_LMAC];
104230557Sjimharris	uint8_t			duplex[MAX_LMAC];
105230557Sjimharris	uint32_t		speed[MAX_LMAC];
106230557Sjimharris	uint16_t		cpi_base[MAX_NUM_VFS_SUPPORTED];
107230557Sjimharris	uint16_t		rss_ind_tbl_size;
108230557Sjimharris
109230557Sjimharris	/* MSI-X */
110230557Sjimharris	boolean_t		msix_enabled;
111230557Sjimharris	uint8_t			num_vec;
112230557Sjimharris	struct msix_entry	msix_entries[NIC_PF_MSIX_VECTORS];
113230557Sjimharris	struct resource *	msix_table_res;
114230557Sjimharris};
115230557Sjimharris
116230557Sjimharrisstatic int nicpf_probe(device_t);
117230557Sjimharrisstatic int nicpf_attach(device_t);
118230557Sjimharrisstatic int nicpf_detach(device_t);
119230557Sjimharris
120230557Sjimharris#ifdef PCI_IOV
121230557Sjimharrisstatic int nicpf_iov_init(device_t, uint16_t, const nvlist_t *);
122230557Sjimharrisstatic void nicpf_iov_uninit(device_t);
123230557Sjimharrisstatic int nicpf_iov_addr_vf(device_t, uint16_t, const nvlist_t *);
124230557Sjimharris#endif
125230557Sjimharris
126230557Sjimharrisstatic device_method_t nicpf_methods[] = {
127230557Sjimharris	/* Device interface */
128230557Sjimharris	DEVMETHOD(device_probe,		nicpf_probe),
129230557Sjimharris	DEVMETHOD(device_attach,	nicpf_attach),
130230557Sjimharris	DEVMETHOD(device_detach,	nicpf_detach),
131230557Sjimharris	/* PCI SR-IOV interface */
132230557Sjimharris#ifdef PCI_IOV
133230557Sjimharris	DEVMETHOD(pci_iov_init,		nicpf_iov_init),
134230557Sjimharris	DEVMETHOD(pci_iov_uninit,	nicpf_iov_uninit),
135230557Sjimharris	DEVMETHOD(pci_iov_add_vf,	nicpf_iov_addr_vf),
136230557Sjimharris#endif
137230557Sjimharris	DEVMETHOD_END,
138230557Sjimharris};
139230557Sjimharris
140230557Sjimharrisstatic driver_t nicpf_driver = {
141230557Sjimharris	"vnicpf",
142230557Sjimharris	nicpf_methods,
143230557Sjimharris	sizeof(struct nicpf),
144230557Sjimharris};
145230557Sjimharris
146230557Sjimharrisstatic devclass_t nicpf_devclass;
147230557Sjimharris
148230557SjimharrisDRIVER_MODULE(nicpf, pci, nicpf_driver, nicpf_devclass, 0, 0);
149230557SjimharrisMODULE_DEPEND(nicpf, pci, 1, 1, 1);
150230557SjimharrisMODULE_DEPEND(nicpf, ether, 1, 1, 1);
151230557SjimharrisMODULE_DEPEND(nicpf, thunder_bgx, 1, 1, 1);
152230557Sjimharris
153230557Sjimharrisstatic int nicpf_alloc_res(struct nicpf *);
154230557Sjimharrisstatic void nicpf_free_res(struct nicpf *);
155230557Sjimharrisstatic void nic_set_lmac_vf_mapping(struct nicpf *);
156230557Sjimharrisstatic void nic_init_hw(struct nicpf *);
157230557Sjimharrisstatic int nic_sriov_init(device_t, struct nicpf *);
158230557Sjimharrisstatic void nic_poll_for_link(void *);
159230557Sjimharrisstatic int nic_register_interrupts(struct nicpf *);
160230557Sjimharrisstatic void nic_unregister_interrupts(struct nicpf *);
161230557Sjimharris
162230557Sjimharris/*
163230557Sjimharris * Device interface
164230557Sjimharris */
165230557Sjimharrisstatic int
166230557Sjimharrisnicpf_probe(device_t dev)
167230557Sjimharris{
168230557Sjimharris	uint16_t vendor_id;
169230557Sjimharris	uint16_t device_id;
170230557Sjimharris
171230557Sjimharris	vendor_id = pci_get_vendor(dev);
172230557Sjimharris	device_id = pci_get_device(dev);
173230557Sjimharris
174230557Sjimharris	if (vendor_id == PCI_VENDOR_ID_CAVIUM &&
175230557Sjimharris	    device_id == PCI_DEVICE_ID_THUNDER_NIC_PF) {
176230557Sjimharris		device_set_desc(dev, VNIC_PF_DEVSTR);
177230557Sjimharris		return (BUS_PROBE_DEFAULT);
178230557Sjimharris	}
179230557Sjimharris
180230557Sjimharris	return (ENXIO);
181230557Sjimharris}
182230557Sjimharris
183230557Sjimharrisstatic int
184230557Sjimharrisnicpf_attach(device_t dev)
185230557Sjimharris{
186230557Sjimharris	struct nicpf *nic;
187230557Sjimharris	int err;
188230557Sjimharris
189230557Sjimharris	nic = device_get_softc(dev);
190230557Sjimharris	nic->dev = dev;
191230557Sjimharris
192230557Sjimharris	/* Enable bus mastering */
193230557Sjimharris	pci_enable_busmaster(dev);
194230557Sjimharris
195230557Sjimharris	/* Allocate PCI resources */
196230557Sjimharris	err = nicpf_alloc_res(nic);
197230557Sjimharris	if (err != 0) {
198230557Sjimharris		device_printf(dev, "Could not allocate PCI resources\n");
199230557Sjimharris		return (err);
200230557Sjimharris	}
201230557Sjimharris
202230557Sjimharris	nic->node = nic_get_node_id(nic->reg_base);
203230557Sjimharris	nic->rev_id = pci_read_config(dev, PCIR_REVID, 1);
204230557Sjimharris
205230557Sjimharris	/* Enable Traffic Network Switch (TNS) bypass mode by default */
206230557Sjimharris	nic->flags &= ~NIC_TNS_ENABLED;
207230557Sjimharris	nic_set_lmac_vf_mapping(nic);
208230557Sjimharris
209230557Sjimharris	/* Initialize hardware */
210230557Sjimharris	nic_init_hw(nic);
211230557Sjimharris
212230557Sjimharris	/* Set RSS TBL size for each VF */
213230557Sjimharris	nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
214230557Sjimharris
215230557Sjimharris	/* Setup interrupts */
216230557Sjimharris	err = nic_register_interrupts(nic);
217230557Sjimharris	if (err != 0)
218230557Sjimharris		goto err_free_res;
219230557Sjimharris
220230557Sjimharris	/* Configure SRIOV */
221230557Sjimharris	err = nic_sriov_init(dev, nic);
222230557Sjimharris	if (err != 0)
223230557Sjimharris		goto err_free_intr;
224230557Sjimharris
225230557Sjimharris	if (nic->flags & NIC_TNS_ENABLED)
226230557Sjimharris		return (0);
227230557Sjimharris
228230557Sjimharris	mtx_init(&nic->check_link_mtx, "VNIC PF link poll", NULL, MTX_DEF);
229230557Sjimharris	/* Register physical link status poll callout */
230230557Sjimharris	callout_init_mtx(&nic->check_link, &nic->check_link_mtx, 0);
231230557Sjimharris	mtx_lock(&nic->check_link_mtx);
232230557Sjimharris	nic_poll_for_link(nic);
233230557Sjimharris	mtx_unlock(&nic->check_link_mtx);
234230557Sjimharris
235230557Sjimharris	return (0);
236230557Sjimharris
237230557Sjimharriserr_free_intr:
238230557Sjimharris	nic_unregister_interrupts(nic);
239230557Sjimharriserr_free_res:
240230557Sjimharris	nicpf_free_res(nic);
241230557Sjimharris	pci_disable_busmaster(dev);
242230557Sjimharris
243230557Sjimharris	return (err);
244230557Sjimharris}
245230557Sjimharris
246230557Sjimharrisstatic int
247230557Sjimharrisnicpf_detach(device_t dev)
248230557Sjimharris{
249230557Sjimharris	struct nicpf *nic;
250230557Sjimharris
251230557Sjimharris	nic = device_get_softc(dev);
252230557Sjimharris
253230557Sjimharris	callout_drain(&nic->check_link);
254230557Sjimharris	mtx_destroy(&nic->check_link_mtx);
255230557Sjimharris
256230557Sjimharris	nic_unregister_interrupts(nic);
257230557Sjimharris	nicpf_free_res(nic);
258230557Sjimharris	pci_disable_busmaster(dev);
259230557Sjimharris
260230557Sjimharris	return (0);
261230557Sjimharris}
262230557Sjimharris
263230557Sjimharris/*
264230557Sjimharris * SR-IOV interface
265230557Sjimharris */
266230557Sjimharris#ifdef PCI_IOV
267230557Sjimharrisstatic int
268230557Sjimharrisnicpf_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
269230557Sjimharris{
270230557Sjimharris	struct nicpf *nic;
271230557Sjimharris
272230557Sjimharris	nic = device_get_softc(dev);
273230557Sjimharris
274230557Sjimharris	nic->num_vf_en = 0;
275230557Sjimharris	if (num_vfs == 0)
276230557Sjimharris		return (ENXIO);
277230557Sjimharris	if (num_vfs > MAX_NUM_VFS_SUPPORTED)
278230557Sjimharris		return (EINVAL);
279230557Sjimharris
280230557Sjimharris	/*
281230557Sjimharris	 * Just set variables here.
282230557Sjimharris	 * The number of VFs will be written to configuration
283230557Sjimharris	 * space later in PCI_ADD_VF().
284230557Sjimharris	 */
285230557Sjimharris	nic->num_vf_en = num_vfs;
286230557Sjimharris	nic->flags |= NIC_SRIOV_ENABLED;
287230557Sjimharris
288230557Sjimharris	return (0);
289230557Sjimharris}
290230557Sjimharris
291230557Sjimharrisstatic void
292230557Sjimharrisnicpf_iov_uninit(device_t dev)
293230557Sjimharris{
294230557Sjimharris
295230557Sjimharris	/* ARM64TODO: Implement this function */
296230557Sjimharris}
297230557Sjimharris
298230557Sjimharrisstatic int
299230557Sjimharrisnicpf_iov_addr_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
300230557Sjimharris{
301230557Sjimharris	const void *mac;
302230557Sjimharris	struct nicpf *nic;
303230557Sjimharris	size_t size;
304230557Sjimharris	int bgx, lmac;
305230557Sjimharris
306230557Sjimharris	nic = device_get_softc(dev);
307230557Sjimharris
308230557Sjimharris	if ((nic->flags & NIC_SRIOV_ENABLED) == 0)
309230557Sjimharris		return (ENXIO);
310230557Sjimharris
311230557Sjimharris	if (nvlist_exists_binary(params, "mac-addr") != 0) {
312230557Sjimharris		mac = nvlist_get_binary(params, "mac-addr", &size);
313230557Sjimharris		bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]);
314230557Sjimharris		lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]);
315230557Sjimharris		bgx_set_lmac_mac(nic->node, bgx, lmac, mac);
316230557Sjimharris	}
317230557Sjimharris
318230557Sjimharris	return (0);
319230557Sjimharris}
320230557Sjimharris#endif
321230557Sjimharris
322230557Sjimharris/*
323230557Sjimharris * Helper routines
324230557Sjimharris */
325230557Sjimharrisstatic int
326230557Sjimharrisnicpf_alloc_res(struct nicpf *nic)
327230557Sjimharris{
328230557Sjimharris	device_t dev;
329230557Sjimharris	int rid;
330230557Sjimharris
331230557Sjimharris	dev = nic->dev;
332230557Sjimharris
333230557Sjimharris	rid = VNIC_PF_REG_RID;
334230557Sjimharris	nic->reg_base = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
335230557Sjimharris	    RF_ACTIVE);
336230557Sjimharris	if (nic->reg_base == NULL) {
337230557Sjimharris		/* For verbose output print some more details */
338230557Sjimharris		if (bootverbose) {
339230557Sjimharris			device_printf(dev,
340230557Sjimharris			    "Could not allocate registers memory\n");
341230557Sjimharris		}
342230557Sjimharris		return (ENXIO);
343230557Sjimharris	}
344230557Sjimharris
345230557Sjimharris	return (0);
346230557Sjimharris}
347230557Sjimharris
348230557Sjimharrisstatic void
349230557Sjimharrisnicpf_free_res(struct nicpf *nic)
350230557Sjimharris{
351230557Sjimharris	device_t dev;
352230557Sjimharris
353230557Sjimharris	dev = nic->dev;
354230557Sjimharris
355230557Sjimharris	if (nic->reg_base != NULL) {
356230557Sjimharris		bus_release_resource(dev, SYS_RES_MEMORY,
357230557Sjimharris		    rman_get_rid(nic->reg_base), nic->reg_base);
358230557Sjimharris	}
359230557Sjimharris}
360230557Sjimharris
361230557Sjimharris/* Register read/write APIs */
362235043Sjimharrisstatic __inline void
363230557Sjimharrisnic_reg_write(struct nicpf *nic, bus_space_handle_t offset,
364230557Sjimharris    uint64_t val)
365230557Sjimharris{
366230557Sjimharris
367230557Sjimharris	bus_write_8(nic->reg_base, offset, val);
368230557Sjimharris}
369230557Sjimharris
370230557Sjimharrisstatic __inline uint64_t
371230557Sjimharrisnic_reg_read(struct nicpf *nic, uint64_t offset)
372230557Sjimharris{
373230557Sjimharris	uint64_t val;
374230557Sjimharris
375230557Sjimharris	val = bus_read_8(nic->reg_base, offset);
376230557Sjimharris	return (val);
377230557Sjimharris}
378230557Sjimharris
379230557Sjimharris/* PF -> VF mailbox communication APIs */
380230557Sjimharrisstatic void
381230557Sjimharrisnic_enable_mbx_intr(struct nicpf *nic)
382230557Sjimharris{
383230557Sjimharris
384230557Sjimharris	/* Enable mailbox interrupt for all 128 VFs */
385230557Sjimharris	nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, ~0UL);
386230557Sjimharris	nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(uint64_t), ~0UL);
387230557Sjimharris}
388230557Sjimharris
389230557Sjimharrisstatic void
390230557Sjimharrisnic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg)
391230557Sjimharris{
392230557Sjimharris
393230557Sjimharris	nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), (1UL << vf));
394230557Sjimharris}
395230557Sjimharris
396230557Sjimharrisstatic uint64_t
397230557Sjimharrisnic_get_mbx_addr(int vf)
398230557Sjimharris{
399230557Sjimharris
400230557Sjimharris	return (NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT));
401230557Sjimharris}
402230557Sjimharris
403230557Sjimharris/*
404230557Sjimharris * Send a mailbox message to VF
405230557Sjimharris * @vf: vf to which this message to be sent
406230557Sjimharris * @mbx: Message to be sent
407230557Sjimharris */
408230557Sjimharrisstatic void
409230557Sjimharrisnic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx)
410230557Sjimharris{
411230557Sjimharris	bus_space_handle_t mbx_addr = nic_get_mbx_addr(vf);
412230557Sjimharris	uint64_t *msg = (uint64_t *)mbx;
413230557Sjimharris
414230557Sjimharris	/*
415230557Sjimharris	 * In first revision HW, mbox interrupt is triggerred
416230557Sjimharris	 * when PF writes to MBOX(1), in next revisions when
417230557Sjimharris	 * PF writes to MBOX(0)
418230557Sjimharris	 */
419230557Sjimharris	if (nic->rev_id == 0) {
420230557Sjimharris		nic_reg_write(nic, mbx_addr + 0, msg[0]);
421230557Sjimharris		nic_reg_write(nic, mbx_addr + 8, msg[1]);
422230557Sjimharris	} else {
423230557Sjimharris		nic_reg_write(nic, mbx_addr + 8, msg[1]);
424230557Sjimharris		nic_reg_write(nic, mbx_addr + 0, msg[0]);
425230557Sjimharris	}
426230557Sjimharris}
427230557Sjimharris
428230557Sjimharris/*
429230557Sjimharris * Responds to VF's READY message with VF's
430230557Sjimharris * ID, node, MAC address e.t.c
431230557Sjimharris * @vf: VF which sent READY message
432230557Sjimharris */
433230557Sjimharrisstatic void
434230557Sjimharrisnic_mbx_send_ready(struct nicpf *nic, int vf)
435230557Sjimharris{
436230557Sjimharris	union nic_mbx mbx = {};
437230557Sjimharris	int bgx_idx, lmac;
438230557Sjimharris	const char *mac;
439230557Sjimharris
440230557Sjimharris	mbx.nic_cfg.msg = NIC_MBOX_MSG_READY;
441230557Sjimharris	mbx.nic_cfg.vf_id = vf;
442230557Sjimharris
443230557Sjimharris	if (nic->flags & NIC_TNS_ENABLED)
444230557Sjimharris		mbx.nic_cfg.tns_mode = NIC_TNS_MODE;
445230557Sjimharris	else
446230557Sjimharris		mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE;
447230557Sjimharris
448230557Sjimharris	if (vf < MAX_LMAC) {
449230557Sjimharris		bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
450230557Sjimharris		lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
451230557Sjimharris
452230557Sjimharris		mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac);
453230557Sjimharris		if (mac) {
454230557Sjimharris			memcpy((uint8_t *)&mbx.nic_cfg.mac_addr, mac,
455230557Sjimharris			    ETHER_ADDR_LEN);
456230557Sjimharris		}
457230557Sjimharris	}
458230557Sjimharris	mbx.nic_cfg.node_id = nic->node;
459230557Sjimharris
460230557Sjimharris	mbx.nic_cfg.loopback_supported = vf < MAX_LMAC;
461230557Sjimharris
462230557Sjimharris	nic_send_msg_to_vf(nic, vf, &mbx);
463230557Sjimharris}
464230557Sjimharris
465230557Sjimharris/*
466230557Sjimharris * ACKs VF's mailbox message
467230557Sjimharris * @vf: VF to which ACK to be sent
468230557Sjimharris */
469230557Sjimharrisstatic void
470230557Sjimharrisnic_mbx_send_ack(struct nicpf *nic, int vf)
471230557Sjimharris{
472230557Sjimharris	union nic_mbx mbx = {};
473230557Sjimharris
474230557Sjimharris	mbx.msg.msg = NIC_MBOX_MSG_ACK;
475230557Sjimharris	nic_send_msg_to_vf(nic, vf, &mbx);
476230557Sjimharris}
477230557Sjimharris
478230557Sjimharris/*
479230557Sjimharris * NACKs VF's mailbox message that PF is not able to
480230557Sjimharris * complete the action
481230557Sjimharris * @vf: VF to which ACK to be sent
482230557Sjimharris */
483230557Sjimharrisstatic void
484230557Sjimharrisnic_mbx_send_nack(struct nicpf *nic, int vf)
485230557Sjimharris{
486230557Sjimharris	union nic_mbx mbx = {};
487230557Sjimharris
488230557Sjimharris	mbx.msg.msg = NIC_MBOX_MSG_NACK;
489230557Sjimharris	nic_send_msg_to_vf(nic, vf, &mbx);
490230557Sjimharris}
491230557Sjimharris
492230557Sjimharris/*
493230557Sjimharris * Flush all in flight receive packets to memory and
494230557Sjimharris * bring down an active RQ
495230557Sjimharris */
496230557Sjimharrisstatic int
497230557Sjimharrisnic_rcv_queue_sw_sync(struct nicpf *nic)
498230557Sjimharris{
499230557Sjimharris	uint16_t timeout = ~0x00;
500230557Sjimharris
501230557Sjimharris	nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01);
502230557Sjimharris	/* Wait till sync cycle is finished */
503230557Sjimharris	while (timeout) {
504230557Sjimharris		if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1)
505230557Sjimharris			break;
506230557Sjimharris		timeout--;
507230557Sjimharris	}
508230557Sjimharris	nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00);
509230557Sjimharris	if (!timeout) {
510230557Sjimharris		device_printf(nic->dev, "Receive queue software sync failed\n");
511230557Sjimharris		return (ETIMEDOUT);
512230557Sjimharris	}
513230557Sjimharris	return (0);
514230557Sjimharris}
515230557Sjimharris
516230557Sjimharris/* Get BGX Rx/Tx stats and respond to VF's request */
517230557Sjimharrisstatic void
518230557Sjimharrisnic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx)
519230557Sjimharris{
520230557Sjimharris	int bgx_idx, lmac;
521230557Sjimharris	union nic_mbx mbx = {};
522230557Sjimharris
523230557Sjimharris	bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]);
524230557Sjimharris	lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]);
525230557Sjimharris
526230557Sjimharris	mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS;
527230557Sjimharris	mbx.bgx_stats.vf_id = bgx->vf_id;
528230557Sjimharris	mbx.bgx_stats.rx = bgx->rx;
529230557Sjimharris	mbx.bgx_stats.idx = bgx->idx;
530230557Sjimharris	if (bgx->rx != 0) {
531230557Sjimharris		mbx.bgx_stats.stats =
532230557Sjimharris		    bgx_get_rx_stats(nic->node, bgx_idx, lmac, bgx->idx);
533230557Sjimharris	} else {
534230557Sjimharris		mbx.bgx_stats.stats =
535230557Sjimharris		    bgx_get_tx_stats(nic->node, bgx_idx, lmac, bgx->idx);
536230557Sjimharris	}
537230557Sjimharris	nic_send_msg_to_vf(nic, bgx->vf_id, &mbx);
538230557Sjimharris}
539230557Sjimharris
540230557Sjimharris/* Update hardware min/max frame size */
541230557Sjimharrisstatic int
542230557Sjimharrisnic_update_hw_frs(struct nicpf *nic, int new_frs, int vf)
543230557Sjimharris{
544230557Sjimharris
545230557Sjimharris	if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) {
546230557Sjimharris		device_printf(nic->dev,
547230557Sjimharris		    "Invalid MTU setting from VF%d rejected, "
548230557Sjimharris		    "should be between %d and %d\n",
549230557Sjimharris		    vf, NIC_HW_MIN_FRS, NIC_HW_MAX_FRS);
550230557Sjimharris		return (EINVAL);
551230557Sjimharris	}
552230557Sjimharris	new_frs += ETHER_HDR_LEN;
553230557Sjimharris	if (new_frs <= nic->pkind.maxlen)
554230557Sjimharris		return (0);
555230557Sjimharris
556230557Sjimharris	nic->pkind.maxlen = new_frs;
557230557Sjimharris	nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *(uint64_t *)&nic->pkind);
558230557Sjimharris	return (0);
559230557Sjimharris}
560230557Sjimharris
561230557Sjimharris/* Set minimum transmit packet size */
562230557Sjimharrisstatic void
563230557Sjimharrisnic_set_tx_pkt_pad(struct nicpf *nic, int size)
564230557Sjimharris{
565230557Sjimharris	int lmac;
566230557Sjimharris	uint64_t lmac_cfg;
567230557Sjimharris
568230557Sjimharris	/* Max value that can be set is 60 */
569230557Sjimharris	if (size > 60)
570230557Sjimharris		size = 60;
571230557Sjimharris
572230557Sjimharris	for (lmac = 0; lmac < (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX); lmac++) {
573230557Sjimharris		lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3));
574230557Sjimharris		lmac_cfg &= ~(0xF << 2);
575230557Sjimharris		lmac_cfg |= ((size / 4) << 2);
576230557Sjimharris		nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg);
577230557Sjimharris	}
578230557Sjimharris}
579230557Sjimharris
580230557Sjimharris/*
581230557Sjimharris * Function to check number of LMACs present and set VF::LMAC mapping.
582230557Sjimharris * Mapping will be used while initializing channels.
583230557Sjimharris */
584230557Sjimharrisstatic void
585230557Sjimharrisnic_set_lmac_vf_mapping(struct nicpf *nic)
586230557Sjimharris{
587230557Sjimharris	unsigned bgx_map = bgx_get_map(nic->node);
588230557Sjimharris	int bgx, next_bgx_lmac = 0;
589230557Sjimharris	int lmac, lmac_cnt = 0;
590230557Sjimharris	uint64_t lmac_credit;
591230557Sjimharris
592230557Sjimharris	nic->num_vf_en = 0;
593230557Sjimharris	if (nic->flags & NIC_TNS_ENABLED) {
594230557Sjimharris		nic->num_vf_en = DEFAULT_NUM_VF_ENABLED;
595230557Sjimharris		return;
596230557Sjimharris	}
597230557Sjimharris
598230557Sjimharris	for (bgx = 0; bgx < NIC_MAX_BGX; bgx++) {
599230557Sjimharris		if ((bgx_map & (1 << bgx)) == 0)
600230557Sjimharris			continue;
601230557Sjimharris		lmac_cnt = bgx_get_lmac_count(nic->node, bgx);
602230557Sjimharris		for (lmac = 0; lmac < lmac_cnt; lmac++)
603230557Sjimharris			nic->vf_lmac_map[next_bgx_lmac++] =
604230557Sjimharris						NIC_SET_VF_LMAC_MAP(bgx, lmac);
605230557Sjimharris		nic->num_vf_en += lmac_cnt;
606230557Sjimharris
607230557Sjimharris		/* Program LMAC credits */
608230557Sjimharris		lmac_credit = (1UL << 1); /* channel credit enable */
609230557Sjimharris		lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */
610230557Sjimharris		/* 48KB BGX Tx buffer size, each unit is of size 16bytes */
611230557Sjimharris		lmac_credit |= (((((48 * 1024) / lmac_cnt) -
612230557Sjimharris		    NIC_HW_MAX_FRS) / 16) << 12);
613230557Sjimharris		lmac = bgx * MAX_LMAC_PER_BGX;
614230557Sjimharris		for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) {
615230557Sjimharris			nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8),
616230557Sjimharris			    lmac_credit);
617230557Sjimharris		}
618230557Sjimharris	}
619230557Sjimharris}
620230557Sjimharris
621230557Sjimharris#define TNS_PORT0_BLOCK 6
622230557Sjimharris#define TNS_PORT1_BLOCK 7
623230557Sjimharris#define BGX0_BLOCK 8
624230557Sjimharris#define BGX1_BLOCK 9
625230557Sjimharris
626230557Sjimharrisstatic void
627230557Sjimharrisnic_init_hw(struct nicpf *nic)
628230557Sjimharris{
629230557Sjimharris	int i;
630230557Sjimharris
631230557Sjimharris	/* Reset NIC, in case the driver is repeatedly inserted and removed */
632230557Sjimharris	nic_reg_write(nic, NIC_PF_SOFT_RESET, 1);
633230557Sjimharris
634230557Sjimharris	/* Enable NIC HW block */
635230557Sjimharris	nic_reg_write(nic, NIC_PF_CFG, 0x3);
636230557Sjimharris
637230557Sjimharris	/* Enable backpressure */
638230557Sjimharris	nic_reg_write(nic, NIC_PF_BP_CFG, (1UL << 6) | 0x03);
639230557Sjimharris
640230557Sjimharris	if (nic->flags & NIC_TNS_ENABLED) {
641230557Sjimharris		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG,
642230557Sjimharris		    (NIC_TNS_MODE << 7) | TNS_PORT0_BLOCK);
643230557Sjimharris		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8),
644230557Sjimharris		    (NIC_TNS_MODE << 7) | TNS_PORT1_BLOCK);
645230557Sjimharris		nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG,
646230557Sjimharris		    (1UL << 63) | TNS_PORT0_BLOCK);
647230557Sjimharris		nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8),
648230557Sjimharris		    (1UL << 63) | TNS_PORT1_BLOCK);
649230557Sjimharris
650230557Sjimharris	} else {
651230557Sjimharris		/* Disable TNS mode on both interfaces */
652230557Sjimharris		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG,
653230557Sjimharris		    (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK);
654230557Sjimharris		nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8),
655230557Sjimharris		    (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK);
656230557Sjimharris		nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG,
657230557Sjimharris		    (1UL << 63) | BGX0_BLOCK);
658230557Sjimharris		nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8),
659230557Sjimharris		    (1UL << 63) | BGX1_BLOCK);
660230557Sjimharris	}
661230557Sjimharris
662230557Sjimharris	/* PKIND configuration */
663230557Sjimharris	nic->pkind.minlen = 0;
664230557Sjimharris	nic->pkind.maxlen = NIC_HW_MAX_FRS + ETHER_HDR_LEN;
665230557Sjimharris	nic->pkind.lenerr_en = 1;
666230557Sjimharris	nic->pkind.rx_hdr = 0;
667230557Sjimharris	nic->pkind.hdr_sl = 0;
668230557Sjimharris
669230557Sjimharris	for (i = 0; i < NIC_MAX_PKIND; i++) {
670230557Sjimharris		nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3),
671230557Sjimharris		    *(uint64_t *)&nic->pkind);
672230557Sjimharris	}
673230557Sjimharris
674230557Sjimharris	nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS);
675230557Sjimharris
676230557Sjimharris	/* Timer config */
677230557Sjimharris	nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK);
678230557Sjimharris
679230557Sjimharris	/* Enable VLAN ethertype matching and stripping */
680230557Sjimharris	nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7,
681230557Sjimharris	    (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETHERTYPE_VLAN);
682230557Sjimharris}
683230557Sjimharris
684230557Sjimharris/* Channel parse index configuration */
685230557Sjimharrisstatic void
686230557Sjimharrisnic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg)
687230557Sjimharris{
688230557Sjimharris	uint32_t vnic, bgx, lmac, chan;
689230557Sjimharris	uint32_t padd, cpi_count = 0;
690230557Sjimharris	uint64_t cpi_base, cpi, rssi_base, rssi;
691230557Sjimharris	uint8_t qset, rq_idx = 0;
692230557Sjimharris
693230557Sjimharris	vnic = cfg->vf_id;
694230557Sjimharris	bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
695230557Sjimharris	lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]);
696230557Sjimharris
697230557Sjimharris	chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF);
698230557Sjimharris	cpi_base = (lmac * NIC_MAX_CPI_PER_LMAC) + (bgx * NIC_CPI_PER_BGX);
699230557Sjimharris	rssi_base = (lmac * nic->rss_ind_tbl_size) + (bgx * NIC_RSSI_PER_BGX);
700230557Sjimharris
701230557Sjimharris	/* Rx channel configuration */
702230557Sjimharris	nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3),
703230557Sjimharris	    (1UL << 63) | (vnic << 0));
704230557Sjimharris	nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3),
705230557Sjimharris	    ((uint64_t)cfg->cpi_alg << 62) | (cpi_base << 48));
706230557Sjimharris
707230557Sjimharris	if (cfg->cpi_alg == CPI_ALG_NONE)
708230557Sjimharris		cpi_count = 1;
709230557Sjimharris	else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */
710230557Sjimharris		cpi_count = 8;
711230557Sjimharris	else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */
712230557Sjimharris		cpi_count = 16;
713230557Sjimharris	else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */
714230557Sjimharris		cpi_count = NIC_MAX_CPI_PER_LMAC;
715230557Sjimharris
716230557Sjimharris	/* RSS Qset, Qidx mapping */
717230557Sjimharris	qset = cfg->vf_id;
718230557Sjimharris	rssi = rssi_base;
719230557Sjimharris	for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) {
720230557Sjimharris		nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3),
721230557Sjimharris		    (qset << 3) | rq_idx);
722230557Sjimharris		rq_idx++;
723230557Sjimharris	}
724230557Sjimharris
725230557Sjimharris	rssi = 0;
726230557Sjimharris	cpi = cpi_base;
727230557Sjimharris	for (; cpi < (cpi_base + cpi_count); cpi++) {
728230557Sjimharris		/* Determine port to channel adder */
729230557Sjimharris		if (cfg->cpi_alg != CPI_ALG_DIFF)
730230557Sjimharris			padd = cpi % cpi_count;
731230557Sjimharris		else
732230557Sjimharris			padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */
733230557Sjimharris
734230557Sjimharris		/* Leave RSS_SIZE as '0' to disable RSS */
735230557Sjimharris		nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3),
736230557Sjimharris		    (vnic << 24) | (padd << 16) | (rssi_base + rssi));
737230557Sjimharris
738230557Sjimharris		if ((rssi + 1) >= cfg->rq_cnt)
739230557Sjimharris			continue;
740230557Sjimharris
741230557Sjimharris		if (cfg->cpi_alg == CPI_ALG_VLAN)
742230557Sjimharris			rssi++;
743230557Sjimharris		else if (cfg->cpi_alg == CPI_ALG_VLAN16)
744230557Sjimharris			rssi = ((cpi - cpi_base) & 0xe) >> 1;
745230557Sjimharris		else if (cfg->cpi_alg == CPI_ALG_DIFF)
746230557Sjimharris			rssi = ((cpi - cpi_base) & 0x38) >> 3;
747230557Sjimharris	}
748230557Sjimharris	nic->cpi_base[cfg->vf_id] = cpi_base;
749230557Sjimharris}
750230557Sjimharris
751230557Sjimharris/*
752230557Sjimharris * 4 level transmit side scheduler configutation
753230557Sjimharris * for TNS bypass mode
754230557Sjimharris *
755230557Sjimharris * Sample configuration for SQ0
756230557Sjimharris * VNIC0-SQ0 -> TL4(0)   -> TL3[0]   -> TL2[0]  -> TL1[0] -> BGX0
757230557Sjimharris * VNIC1-SQ0 -> TL4(8)   -> TL3[2]   -> TL2[0]  -> TL1[0] -> BGX0
758230557Sjimharris * VNIC2-SQ0 -> TL4(16)  -> TL3[4]   -> TL2[1]  -> TL1[0] -> BGX0
759230557Sjimharris * VNIC3-SQ0 -> TL4(24)  -> TL3[6]   -> TL2[1]  -> TL1[0] -> BGX0
760230557Sjimharris * VNIC4-SQ0 -> TL4(512) -> TL3[128] -> TL2[32] -> TL1[1] -> BGX1
761230557Sjimharris * VNIC5-SQ0 -> TL4(520) -> TL3[130] -> TL2[32] -> TL1[1] -> BGX1
762230557Sjimharris * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1
763230557Sjimharris * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1
764230557Sjimharris */
765230557Sjimharrisstatic void
766230557Sjimharrisnic_tx_channel_cfg(struct nicpf *nic, uint8_t vnic, struct sq_cfg_msg *sq)
767230557Sjimharris{
768230557Sjimharris	uint32_t bgx, lmac, chan;
769230557Sjimharris	uint32_t tl2, tl3, tl4;
770230557Sjimharris	uint32_t rr_quantum;
771230557Sjimharris	uint8_t sq_idx = sq->sq_num;
772230557Sjimharris	uint8_t pqs_vnic;
773230557Sjimharris
774230557Sjimharris	pqs_vnic = vnic;
775230557Sjimharris
776230557Sjimharris	bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]);
777230557Sjimharris	lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]);
778230557Sjimharris
779230557Sjimharris	/* 24 bytes for FCS, IPG and preamble */
780230557Sjimharris	rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4);
781230557Sjimharris
782230557Sjimharris	tl4 = (lmac * NIC_TL4_PER_LMAC) + (bgx * NIC_TL4_PER_BGX);
783230557Sjimharris	tl4 += sq_idx;
784230557Sjimharris
785230557Sjimharris	tl3 = tl4 / (NIC_MAX_TL4 / NIC_MAX_TL3);
786230557Sjimharris	nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 |
787230557Sjimharris	    ((uint64_t)vnic << NIC_QS_ID_SHIFT) |
788230557Sjimharris	    ((uint32_t)sq_idx << NIC_Q_NUM_SHIFT), tl4);
789230557Sjimharris	nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3),
790230557Sjimharris	    ((uint64_t)vnic << 27) | ((uint32_t)sq_idx << 24) | rr_quantum);
791230557Sjimharris
792230557Sjimharris	nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum);
793230557Sjimharris	chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF);
794230557Sjimharris	nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan);
795230557Sjimharris	/* Enable backpressure on the channel */
796230557Sjimharris	nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1);
797230557Sjimharris
798230557Sjimharris	tl2 = tl3 >> 2;
799230557Sjimharris	nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2);
800	nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum);
801	/* No priorities as of now */
802	nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00);
803}
804
805static int
806nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
807{
808	int bgx_idx, lmac_idx;
809
810	if (lbk->vf_id > MAX_LMAC)
811		return (ENXIO);
812
813	bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
814	lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
815
816	bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable);
817
818	return (0);
819}
820
821/* Interrupt handler to handle mailbox messages from VFs */
822static void
823nic_handle_mbx_intr(struct nicpf *nic, int vf)
824{
825	union nic_mbx mbx = {};
826	uint64_t *mbx_data;
827	uint64_t mbx_addr;
828	uint64_t reg_addr;
829	uint64_t cfg;
830	int bgx, lmac;
831	int i;
832	int ret = 0;
833
834	nic->mbx_lock[vf] = TRUE;
835
836	mbx_addr = nic_get_mbx_addr(vf);
837	mbx_data = (uint64_t *)&mbx;
838
839	for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
840		*mbx_data = nic_reg_read(nic, mbx_addr);
841		mbx_data++;
842		mbx_addr += sizeof(uint64_t);
843	}
844
845	switch (mbx.msg.msg) {
846	case NIC_MBOX_MSG_READY:
847		nic_mbx_send_ready(nic, vf);
848		if (vf < MAX_LMAC) {
849			nic->link[vf] = 0;
850			nic->duplex[vf] = 0;
851			nic->speed[vf] = 0;
852		}
853		ret = 1;
854		break;
855	case NIC_MBOX_MSG_QS_CFG:
856		reg_addr = NIC_PF_QSET_0_127_CFG |
857		    (mbx.qs.num << NIC_QS_ID_SHIFT);
858		cfg = mbx.qs.cfg;
859		nic_reg_write(nic, reg_addr, cfg);
860		break;
861	case NIC_MBOX_MSG_RQ_CFG:
862		reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG |
863		    (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
864		    (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
865		nic_reg_write(nic, reg_addr, mbx.rq.cfg);
866		break;
867	case NIC_MBOX_MSG_RQ_BP_CFG:
868		reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG |
869		    (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
870		    (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
871		nic_reg_write(nic, reg_addr, mbx.rq.cfg);
872		break;
873	case NIC_MBOX_MSG_RQ_SW_SYNC:
874		ret = nic_rcv_queue_sw_sync(nic);
875		break;
876	case NIC_MBOX_MSG_RQ_DROP_CFG:
877		reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG |
878		    (mbx.rq.qs_num << NIC_QS_ID_SHIFT) |
879		    (mbx.rq.rq_num << NIC_Q_NUM_SHIFT);
880		nic_reg_write(nic, reg_addr, mbx.rq.cfg);
881		break;
882	case NIC_MBOX_MSG_SQ_CFG:
883		reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG |
884		    (mbx.sq.qs_num << NIC_QS_ID_SHIFT) |
885		    (mbx.sq.sq_num << NIC_Q_NUM_SHIFT);
886		nic_reg_write(nic, reg_addr, mbx.sq.cfg);
887		nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq);
888		break;
889	case NIC_MBOX_MSG_SET_MAC:
890		lmac = mbx.mac.vf_id;
891		bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
892		lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
893		bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr);
894		break;
895	case NIC_MBOX_MSG_SET_MAX_FRS:
896		ret = nic_update_hw_frs(nic, mbx.frs.max_frs, mbx.frs.vf_id);
897		break;
898	case NIC_MBOX_MSG_CPI_CFG:
899		nic_config_cpi(nic, &mbx.cpi_cfg);
900		break;
901	case NIC_MBOX_MSG_CFG_DONE:
902		/* Last message of VF config msg sequence */
903		nic->vf_info[vf].vf_enabled = TRUE;
904		goto unlock;
905	case NIC_MBOX_MSG_SHUTDOWN:
906		/* First msg in VF teardown sequence */
907		nic->vf_info[vf].vf_enabled = FALSE;
908		break;
909	case NIC_MBOX_MSG_BGX_STATS:
910		nic_get_bgx_stats(nic, &mbx.bgx_stats);
911		goto unlock;
912	case NIC_MBOX_MSG_LOOPBACK:
913		ret = nic_config_loopback(nic, &mbx.lbk);
914		break;
915	default:
916		device_printf(nic->dev,
917		    "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
918		break;
919	}
920
921	if (ret == 0)
922		nic_mbx_send_ack(nic, vf);
923	else if (mbx.msg.msg != NIC_MBOX_MSG_READY)
924		nic_mbx_send_nack(nic, vf);
925unlock:
926	nic->mbx_lock[vf] = FALSE;
927}
928
929static void
930nic_mbx_intr_handler(struct nicpf *nic, int mbx)
931{
932	uint64_t intr;
933	uint8_t  vf, vf_per_mbx_reg = 64;
934
935	intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3));
936	for (vf = 0; vf < vf_per_mbx_reg; vf++) {
937		if (intr & (1UL << vf)) {
938			nic_handle_mbx_intr(nic, vf + (mbx * vf_per_mbx_reg));
939			nic_clear_mbx_intr(nic, vf, mbx);
940		}
941	}
942}
943
944static void
945nic_mbx0_intr_handler (void *arg)
946{
947	struct nicpf *nic = (struct nicpf *)arg;
948
949	nic_mbx_intr_handler(nic, 0);
950}
951
952static void
953nic_mbx1_intr_handler (void *arg)
954{
955	struct nicpf *nic = (struct nicpf *)arg;
956
957	nic_mbx_intr_handler(nic, 1);
958}
959
960static int
961nic_enable_msix(struct nicpf *nic)
962{
963	struct pci_devinfo *dinfo;
964	int rid, count;
965	int ret;
966
967	dinfo = device_get_ivars(nic->dev);
968	rid = dinfo->cfg.msix.msix_table_bar;
969	nic->msix_table_res =
970	    bus_alloc_resource_any(nic->dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
971	if (nic->msix_table_res == NULL) {
972		device_printf(nic->dev,
973		    "Could not allocate memory for MSI-X table\n");
974		return (ENXIO);
975	}
976
977	count = nic->num_vec = NIC_PF_MSIX_VECTORS;
978
979	ret = pci_alloc_msix(nic->dev, &count);
980	if ((ret != 0) || (count != nic->num_vec)) {
981		device_printf(nic->dev,
982		    "Request for #%d msix vectors failed, error: %d\n",
983		    nic->num_vec, ret);
984		return (ret);
985	}
986
987	nic->msix_enabled = 1;
988	return (0);
989}
990
991static void
992nic_disable_msix(struct nicpf *nic)
993{
994	if (nic->msix_enabled) {
995		pci_release_msi(nic->dev);
996		nic->msix_enabled = 0;
997		nic->num_vec = 0;
998	}
999}
1000
1001static void
1002nic_free_all_interrupts(struct nicpf *nic)
1003{
1004	int irq;
1005
1006	for (irq = 0; irq < nic->num_vec; irq++) {
1007		if (nic->msix_entries[irq].irq_res == NULL)
1008			continue;
1009		if (nic->msix_entries[irq].handle != NULL) {
1010			bus_teardown_intr(nic->dev,
1011			    nic->msix_entries[irq].irq_res,
1012			    nic->msix_entries[irq].handle);
1013		}
1014
1015		bus_release_resource(nic->dev, SYS_RES_IRQ, irq,
1016		    nic->msix_entries[irq].irq_res);
1017	}
1018}
1019
1020static int
1021nic_register_interrupts(struct nicpf *nic)
1022{
1023	int irq, rid;
1024	int ret;
1025
1026	/* Enable MSI-X */
1027	ret = nic_enable_msix(nic);
1028	if (ret != 0)
1029		return (ret);
1030
1031	/* Register mailbox interrupt handlers */
1032	irq = NIC_PF_INTR_ID_MBOX0;
1033	rid = irq + 1;
1034	nic->msix_entries[irq].irq_res = bus_alloc_resource_any(nic->dev,
1035	    SYS_RES_IRQ, &rid, (RF_SHAREABLE | RF_ACTIVE));
1036	if (nic->msix_entries[irq].irq_res == NULL) {
1037		ret = ENXIO;
1038		goto fail;
1039	}
1040	ret = bus_setup_intr(nic->dev, nic->msix_entries[irq].irq_res,
1041	    (INTR_MPSAFE | INTR_TYPE_MISC), NULL, nic_mbx0_intr_handler, nic,
1042	    &nic->msix_entries[irq].handle);
1043	if (ret != 0)
1044		goto fail;
1045
1046	irq = NIC_PF_INTR_ID_MBOX1;
1047	rid = irq + 1;
1048	nic->msix_entries[irq].irq_res = bus_alloc_resource_any(nic->dev,
1049	    SYS_RES_IRQ, &rid, (RF_SHAREABLE | RF_ACTIVE));
1050	if (nic->msix_entries[irq].irq_res == NULL) {
1051		ret = ENXIO;
1052		goto fail;
1053	}
1054	ret = bus_setup_intr(nic->dev, nic->msix_entries[irq].irq_res,
1055	    (INTR_MPSAFE | INTR_TYPE_MISC), NULL, nic_mbx1_intr_handler, nic,
1056	    &nic->msix_entries[irq].handle);
1057	if (ret != 0)
1058		goto fail;
1059
1060	/* Enable mailbox interrupt */
1061	nic_enable_mbx_intr(nic);
1062	return (0);
1063
1064fail:
1065	nic_free_all_interrupts(nic);
1066	return (ret);
1067}
1068
1069static void
1070nic_unregister_interrupts(struct nicpf *nic)
1071{
1072
1073	nic_free_all_interrupts(nic);
1074	nic_disable_msix(nic);
1075}
1076
1077static int nic_sriov_init(device_t dev, struct nicpf *nic)
1078{
1079#ifdef PCI_IOV
1080	nvlist_t *pf_schema, *vf_schema;
1081	int iov_pos;
1082	int err;
1083	uint16_t total_vf_cnt;
1084
1085	err = pci_find_extcap(dev, PCIZ_SRIOV, &iov_pos);
1086	if (err != 0) {
1087		device_printf(dev,
1088		    "SR-IOV capability is not found in PCIe config space\n");
1089		return (err);
1090	}
1091	/* Fix-up the number of enabled VFs */
1092	total_vf_cnt = pci_read_config(dev, iov_pos + PCIR_SRIOV_TOTAL_VFS, 2);
1093	if (total_vf_cnt < nic->num_vf_en)
1094		nic->num_vf_en = total_vf_cnt;
1095
1096	if (total_vf_cnt == 0)
1097		return (0);
1098
1099	/* Attach SR-IOV */
1100	pf_schema = pci_iov_schema_alloc_node();
1101	vf_schema = pci_iov_schema_alloc_node();
1102	pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
1103	/*
1104	 * All VFs can change their MACs.
1105	 * This flag will be ignored but we set it just for the record.
1106	 */
1107	pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
1108	    IOV_SCHEMA_HASDEFAULT, TRUE);
1109
1110	err = pci_iov_attach(dev, pf_schema, vf_schema);
1111	if (err != 0) {
1112		device_printf(dev,
1113		    "Failed to initialize SR-IOV (error=%d)\n",
1114		    err);
1115		nic->num_vf_en = 0;
1116		return (err);
1117	}
1118#endif
1119	return (0);
1120}
1121
1122/*
1123 * Poll for BGX LMAC link status and update corresponding VF
1124 * if there is a change, valid only if internal L2 switch
1125 * is not present otherwise VF link is always treated as up
1126 */
1127static void
1128nic_poll_for_link(void *arg)
1129{
1130	union nic_mbx mbx = {};
1131	struct nicpf *nic;
1132	struct bgx_link_status link;
1133	uint8_t vf, bgx, lmac;
1134
1135	nic = (struct nicpf *)arg;
1136
1137	mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE;
1138
1139	for (vf = 0; vf < nic->num_vf_en; vf++) {
1140		/* Poll only if VF is UP */
1141		if (!nic->vf_info[vf].vf_enabled)
1142			continue;
1143
1144		/* Get BGX, LMAC indices for the VF */
1145		bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
1146		lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
1147		/* Get interface link status */
1148		bgx_get_lmac_link_state(nic->node, bgx, lmac, &link);
1149
1150		/* Inform VF only if link status changed */
1151		if (nic->link[vf] == link.link_up)
1152			continue;
1153
1154		if (!nic->mbx_lock[vf]) {
1155			nic->link[vf] = link.link_up;
1156			nic->duplex[vf] = link.duplex;
1157			nic->speed[vf] = link.speed;
1158
1159			/* Send a mbox message to VF with current link status */
1160			mbx.link_status.link_up = link.link_up;
1161			mbx.link_status.duplex = link.duplex;
1162			mbx.link_status.speed = link.speed;
1163			nic_send_msg_to_vf(nic, vf, &mbx);
1164		}
1165	}
1166	callout_reset(&nic->check_link, hz * 2, nic_poll_for_link, nic);
1167}
1168