xref: /freebsd-src/sys/dev/liquidio/lio_main.c (revision 57cd8f27b727e7a87312f6f141cfa13807dc81a0)
1f173c2b7SSean Bruno /*
2f173c2b7SSean Bruno  *   BSD LICENSE
3f173c2b7SSean Bruno  *
4f173c2b7SSean Bruno  *   Copyright(c) 2017 Cavium, Inc.. All rights reserved.
5f173c2b7SSean Bruno  *   All rights reserved.
6f173c2b7SSean Bruno  *
7f173c2b7SSean Bruno  *   Redistribution and use in source and binary forms, with or without
8f173c2b7SSean Bruno  *   modification, are permitted provided that the following conditions
9f173c2b7SSean Bruno  *   are met:
10f173c2b7SSean Bruno  *
11f173c2b7SSean Bruno  *     * Redistributions of source code must retain the above copyright
12f173c2b7SSean Bruno  *       notice, this list of conditions and the following disclaimer.
13f173c2b7SSean Bruno  *     * Redistributions in binary form must reproduce the above copyright
14f173c2b7SSean Bruno  *       notice, this list of conditions and the following disclaimer in
15f173c2b7SSean Bruno  *       the documentation and/or other materials provided with the
16f173c2b7SSean Bruno  *       distribution.
17f173c2b7SSean Bruno  *     * Neither the name of Cavium, Inc. nor the names of its
18f173c2b7SSean Bruno  *       contributors may be used to endorse or promote products derived
19f173c2b7SSean Bruno  *       from this software without specific prior written permission.
20f173c2b7SSean Bruno  *
21f173c2b7SSean Bruno  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22f173c2b7SSean Bruno  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23f173c2b7SSean Bruno  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24f173c2b7SSean Bruno  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25f173c2b7SSean Bruno  *   OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26f173c2b7SSean Bruno  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27f173c2b7SSean Bruno  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28f173c2b7SSean Bruno  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29f173c2b7SSean Bruno  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30f173c2b7SSean Bruno  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31f173c2b7SSean Bruno  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32f173c2b7SSean Bruno  */
33f173c2b7SSean Bruno 
34f173c2b7SSean Bruno #include "lio_bsd.h"
35f173c2b7SSean Bruno #include "lio_common.h"
36f173c2b7SSean Bruno 
37f173c2b7SSean Bruno #include "lio_droq.h"
38f173c2b7SSean Bruno #include "lio_iq.h"
39f173c2b7SSean Bruno #include "lio_response_manager.h"
40f173c2b7SSean Bruno #include "lio_device.h"
41f173c2b7SSean Bruno #include "lio_ctrl.h"
42f173c2b7SSean Bruno #include "lio_main.h"
43f173c2b7SSean Bruno #include "lio_network.h"
44f173c2b7SSean Bruno #include "cn23xx_pf_device.h"
45f173c2b7SSean Bruno #include "lio_image.h"
46f173c2b7SSean Bruno #include "lio_ioctl.h"
47f173c2b7SSean Bruno #include "lio_rxtx.h"
48f173c2b7SSean Bruno #include "lio_rss.h"
49f173c2b7SSean Bruno 
50f173c2b7SSean Bruno /* Number of milliseconds to wait for DDR initialization */
51f173c2b7SSean Bruno #define LIO_DDR_TIMEOUT	10000
52f173c2b7SSean Bruno #define LIO_MAX_FW_TYPE_LEN	8
53f173c2b7SSean Bruno 
54f173c2b7SSean Bruno static char fw_type[LIO_MAX_FW_TYPE_LEN];
55f173c2b7SSean Bruno TUNABLE_STR("hw.lio.fw_type", fw_type, sizeof(fw_type));
56f173c2b7SSean Bruno 
57f173c2b7SSean Bruno /*
58f173c2b7SSean Bruno  * Integers that specify number of queues per PF.
59f173c2b7SSean Bruno  * Valid range is 0 to 64.
60f173c2b7SSean Bruno  * Use 0 to derive from CPU count.
61f173c2b7SSean Bruno  */
62f173c2b7SSean Bruno static int	num_queues_per_pf0;
63f173c2b7SSean Bruno static int	num_queues_per_pf1;
64f173c2b7SSean Bruno TUNABLE_INT("hw.lio.num_queues_per_pf0", &num_queues_per_pf0);
65f173c2b7SSean Bruno TUNABLE_INT("hw.lio.num_queues_per_pf1", &num_queues_per_pf1);
66f173c2b7SSean Bruno 
67f173c2b7SSean Bruno #ifdef RSS
68f173c2b7SSean Bruno static int	lio_rss = 1;
69f173c2b7SSean Bruno TUNABLE_INT("hw.lio.rss", &lio_rss);
70f173c2b7SSean Bruno #endif	/* RSS */
71f173c2b7SSean Bruno 
72f173c2b7SSean Bruno /* Hardware LRO */
73f173c2b7SSean Bruno unsigned int	lio_hwlro = 0;
74f173c2b7SSean Bruno TUNABLE_INT("hw.lio.hwlro", &lio_hwlro);
75f173c2b7SSean Bruno 
76f173c2b7SSean Bruno /*
77f173c2b7SSean Bruno  * Bitmask indicating which consoles have debug
78f173c2b7SSean Bruno  * output redirected to syslog.
79f173c2b7SSean Bruno  */
80f173c2b7SSean Bruno static unsigned long	console_bitmask;
81f173c2b7SSean Bruno TUNABLE_ULONG("hw.lio.console_bitmask", &console_bitmask);
82f173c2b7SSean Bruno 
83f173c2b7SSean Bruno /*
84f173c2b7SSean Bruno  * \brief determines if a given console has debug enabled.
85f173c2b7SSean Bruno  * @param console console to check
86f173c2b7SSean Bruno  * @returns  1 = enabled. 0 otherwise
87f173c2b7SSean Bruno  */
88f173c2b7SSean Bruno int
89f173c2b7SSean Bruno lio_console_debug_enabled(uint32_t console)
90f173c2b7SSean Bruno {
91f173c2b7SSean Bruno 
92f173c2b7SSean Bruno 	return (console_bitmask >> (console)) & 0x1;
93f173c2b7SSean Bruno }
94f173c2b7SSean Bruno 
95f173c2b7SSean Bruno static int	lio_detach(device_t dev);
96f173c2b7SSean Bruno 
97f173c2b7SSean Bruno static int	lio_device_init(struct octeon_device *octeon_dev);
98f173c2b7SSean Bruno static int	lio_chip_specific_setup(struct octeon_device *oct);
99f173c2b7SSean Bruno static void	lio_watchdog(void *param);
100f173c2b7SSean Bruno static int	lio_load_firmware(struct octeon_device *oct);
101f173c2b7SSean Bruno static int	lio_nic_starter(struct octeon_device *oct);
102f173c2b7SSean Bruno static int	lio_init_nic_module(struct octeon_device *oct);
103f173c2b7SSean Bruno static int	lio_setup_nic_devices(struct octeon_device *octeon_dev);
104f173c2b7SSean Bruno static int	lio_link_info(struct lio_recv_info *recv_info, void *ptr);
105f173c2b7SSean Bruno static void	lio_if_cfg_callback(struct octeon_device *oct, uint32_t status,
106f173c2b7SSean Bruno 				    void *buf);
1072c50292dSJustin Hibbits static int	lio_set_rxcsum_command(if_t ifp, int command,
108f173c2b7SSean Bruno 				       uint8_t rx_cmd);
109f173c2b7SSean Bruno static int	lio_setup_glists(struct octeon_device *oct, struct lio *lio,
110f173c2b7SSean Bruno 				 int num_iqs);
111f173c2b7SSean Bruno static void	lio_destroy_nic_device(struct octeon_device *oct, int ifidx);
1122c50292dSJustin Hibbits static inline void	lio_update_link_status(if_t ifp,
113f173c2b7SSean Bruno 					       union octeon_link_status *ls);
114f173c2b7SSean Bruno static void	lio_send_rx_ctrl_cmd(struct lio *lio, int start_stop);
115f173c2b7SSean Bruno static int	lio_stop_nic_module(struct octeon_device *oct);
116f173c2b7SSean Bruno static void	lio_destroy_resources(struct octeon_device *oct);
1172c50292dSJustin Hibbits static int	lio_setup_rx_oom_poll_fn(if_t ifp);
118f173c2b7SSean Bruno 
1192c50292dSJustin Hibbits static void	lio_vlan_rx_add_vid(void *arg, if_t ifp, uint16_t vid);
1202c50292dSJustin Hibbits static void	lio_vlan_rx_kill_vid(void *arg, if_t ifp,
121f173c2b7SSean Bruno 				     uint16_t vid);
122f173c2b7SSean Bruno static struct octeon_device *
123f173c2b7SSean Bruno 	lio_get_other_octeon_device(struct octeon_device *oct);
124f173c2b7SSean Bruno 
125f173c2b7SSean Bruno static int	lio_wait_for_oq_pkts(struct octeon_device *oct);
126f173c2b7SSean Bruno 
127f173c2b7SSean Bruno int	lio_send_rss_param(struct lio *lio);
128f173c2b7SSean Bruno static int	lio_dbg_console_print(struct octeon_device *oct,
129f173c2b7SSean Bruno 				      uint32_t console_num, char *prefix,
130f173c2b7SSean Bruno 				      char *suffix);
131f173c2b7SSean Bruno 
132f173c2b7SSean Bruno /* Polling interval for determining when NIC application is alive */
133f173c2b7SSean Bruno #define LIO_STARTER_POLL_INTERVAL_MS	100
134f173c2b7SSean Bruno 
135f173c2b7SSean Bruno /*
136f173c2b7SSean Bruno  * vendor_info_array.
137f173c2b7SSean Bruno  * This array contains the list of IDs on which the driver should load.
138f173c2b7SSean Bruno  */
139f173c2b7SSean Bruno struct lio_vendor_info {
140f173c2b7SSean Bruno 	uint16_t	vendor_id;
141f173c2b7SSean Bruno 	uint16_t	device_id;
142f173c2b7SSean Bruno 	uint16_t	subdevice_id;
143f173c2b7SSean Bruno 	uint8_t		revision_id;
144f173c2b7SSean Bruno 	uint8_t		index;
145f173c2b7SSean Bruno };
146f173c2b7SSean Bruno 
147f173c2b7SSean Bruno static struct lio_vendor_info lio_pci_tbl[] = {
148f173c2b7SSean Bruno 	/* CN2350 10G */
149f173c2b7SSean Bruno 	{PCI_VENDOR_ID_CAVIUM, LIO_CN23XX_PF_VID, LIO_CN2350_10G_SUBDEVICE,
150f173c2b7SSean Bruno 		0x02, 0},
151f173c2b7SSean Bruno 
152f173c2b7SSean Bruno 	/* CN2350 10G */
153f173c2b7SSean Bruno 	{PCI_VENDOR_ID_CAVIUM, LIO_CN23XX_PF_VID, LIO_CN2350_10G_SUBDEVICE1,
154f173c2b7SSean Bruno 		0x02, 0},
155f173c2b7SSean Bruno 
156f173c2b7SSean Bruno 	/* CN2360 10G */
157f173c2b7SSean Bruno 	{PCI_VENDOR_ID_CAVIUM, LIO_CN23XX_PF_VID, LIO_CN2360_10G_SUBDEVICE,
158f173c2b7SSean Bruno 		0x02, 1},
159f173c2b7SSean Bruno 
160f173c2b7SSean Bruno 	/* CN2350 25G */
161f173c2b7SSean Bruno 	{PCI_VENDOR_ID_CAVIUM, LIO_CN23XX_PF_VID, LIO_CN2350_25G_SUBDEVICE,
162f173c2b7SSean Bruno 		0x02, 2},
163f173c2b7SSean Bruno 
164f173c2b7SSean Bruno 	/* CN2360 25G */
165f173c2b7SSean Bruno 	{PCI_VENDOR_ID_CAVIUM, LIO_CN23XX_PF_VID, LIO_CN2360_25G_SUBDEVICE,
166f173c2b7SSean Bruno 		0x02, 3},
167f173c2b7SSean Bruno 
168f173c2b7SSean Bruno 	{0, 0, 0, 0, 0}
169f173c2b7SSean Bruno };
170f173c2b7SSean Bruno 
171f173c2b7SSean Bruno static char *lio_strings[] = {
172f173c2b7SSean Bruno 	"LiquidIO 2350 10GbE Server Adapter",
173f173c2b7SSean Bruno 	"LiquidIO 2360 10GbE Server Adapter",
174f173c2b7SSean Bruno 	"LiquidIO 2350 25GbE Server Adapter",
175f173c2b7SSean Bruno 	"LiquidIO 2360 25GbE Server Adapter",
176f173c2b7SSean Bruno };
177f173c2b7SSean Bruno 
178f173c2b7SSean Bruno struct lio_if_cfg_resp {
179f173c2b7SSean Bruno 	uint64_t	rh;
180f173c2b7SSean Bruno 	struct octeon_if_cfg_info cfg_info;
181f173c2b7SSean Bruno 	uint64_t	status;
182f173c2b7SSean Bruno };
183f173c2b7SSean Bruno 
184f173c2b7SSean Bruno struct lio_if_cfg_context {
185f173c2b7SSean Bruno 	int		octeon_id;
186f173c2b7SSean Bruno 	volatile int	cond;
187f173c2b7SSean Bruno };
188f173c2b7SSean Bruno 
189f173c2b7SSean Bruno struct lio_rx_ctl_context {
190f173c2b7SSean Bruno 	int		octeon_id;
191f173c2b7SSean Bruno 	volatile int	cond;
192f173c2b7SSean Bruno };
193f173c2b7SSean Bruno 
194f173c2b7SSean Bruno static int
195f173c2b7SSean Bruno lio_probe(device_t dev)
196f173c2b7SSean Bruno {
197f173c2b7SSean Bruno 	struct lio_vendor_info	*tbl;
198f173c2b7SSean Bruno 
199f173c2b7SSean Bruno 	uint16_t	vendor_id;
200f173c2b7SSean Bruno 	uint16_t	device_id;
201f173c2b7SSean Bruno 	uint16_t	subdevice_id;
202f173c2b7SSean Bruno 	uint8_t		revision_id;
203f173c2b7SSean Bruno 
204f173c2b7SSean Bruno 	vendor_id = pci_get_vendor(dev);
205f173c2b7SSean Bruno 	if (vendor_id != PCI_VENDOR_ID_CAVIUM)
206f173c2b7SSean Bruno 		return (ENXIO);
207f173c2b7SSean Bruno 
208f173c2b7SSean Bruno 	device_id = pci_get_device(dev);
209f173c2b7SSean Bruno 	subdevice_id = pci_get_subdevice(dev);
210f173c2b7SSean Bruno 	revision_id = pci_get_revid(dev);
211f173c2b7SSean Bruno 
212f173c2b7SSean Bruno 	tbl = lio_pci_tbl;
213f173c2b7SSean Bruno 	while (tbl->vendor_id) {
214f173c2b7SSean Bruno 		if ((vendor_id == tbl->vendor_id) &&
215f173c2b7SSean Bruno 		    (device_id == tbl->device_id) &&
216f173c2b7SSean Bruno 		    (subdevice_id == tbl->subdevice_id) &&
217f173c2b7SSean Bruno 		    (revision_id == tbl->revision_id)) {
218*1794a0a8SMark Johnston 			device_set_descf(dev, "%s, Version - %s",
219f173c2b7SSean Bruno 			    lio_strings[tbl->index], LIO_VERSION);
220f173c2b7SSean Bruno 			return (BUS_PROBE_DEFAULT);
221f173c2b7SSean Bruno 		}
222f173c2b7SSean Bruno 
223f173c2b7SSean Bruno 		tbl++;
224f173c2b7SSean Bruno 	}
225f173c2b7SSean Bruno 
226f173c2b7SSean Bruno 	return (ENXIO);
227f173c2b7SSean Bruno }
228f173c2b7SSean Bruno 
229f173c2b7SSean Bruno static int
230f173c2b7SSean Bruno lio_attach(device_t device)
231f173c2b7SSean Bruno {
232f173c2b7SSean Bruno 	struct octeon_device	*oct_dev = NULL;
233f173c2b7SSean Bruno 	uint64_t	scratch1;
234f173c2b7SSean Bruno 	uint32_t	error;
235f173c2b7SSean Bruno 	int		timeout, ret = 1;
236f173c2b7SSean Bruno 	uint8_t		bus, dev, function;
237f173c2b7SSean Bruno 
238f173c2b7SSean Bruno 	oct_dev = lio_allocate_device(device);
239f173c2b7SSean Bruno 	if (oct_dev == NULL) {
240f173c2b7SSean Bruno 		device_printf(device, "Error: Unable to allocate device\n");
241f173c2b7SSean Bruno 		return (-ENOMEM);
242f173c2b7SSean Bruno 	}
243f173c2b7SSean Bruno 
244f173c2b7SSean Bruno 	oct_dev->tx_budget = LIO_DEFAULT_TX_PKTS_PROCESS_BUDGET;
245f173c2b7SSean Bruno 	oct_dev->rx_budget = LIO_DEFAULT_RX_PKTS_PROCESS_BUDGET;
246f173c2b7SSean Bruno 	oct_dev->msix_on = LIO_FLAG_MSIX_ENABLED;
247f173c2b7SSean Bruno 
248f173c2b7SSean Bruno 	oct_dev->device = device;
249f173c2b7SSean Bruno 	bus = pci_get_bus(device);
250f173c2b7SSean Bruno 	dev = pci_get_slot(device);
251f173c2b7SSean Bruno 	function = pci_get_function(device);
252f173c2b7SSean Bruno 
253f173c2b7SSean Bruno 	lio_dev_info(oct_dev, "Initializing device %x:%x %02x:%02x.%01x\n",
254f173c2b7SSean Bruno 		     pci_get_vendor(device), pci_get_device(device), bus, dev,
255f173c2b7SSean Bruno 		     function);
256f173c2b7SSean Bruno 
257f173c2b7SSean Bruno 	if (lio_device_init(oct_dev)) {
258f173c2b7SSean Bruno 		lio_dev_err(oct_dev, "Failed to init device\n");
259f173c2b7SSean Bruno 		lio_detach(device);
260f173c2b7SSean Bruno 		return (-ENOMEM);
261f173c2b7SSean Bruno 	}
262f173c2b7SSean Bruno 
263f173c2b7SSean Bruno 	scratch1 = lio_read_csr64(oct_dev, LIO_CN23XX_SLI_SCRATCH1);
264f173c2b7SSean Bruno 	if (!(scratch1 & 4ULL)) {
265f173c2b7SSean Bruno 		/*
266f173c2b7SSean Bruno 		 * Bit 2 of SLI_SCRATCH_1 is a flag that indicates that
267f173c2b7SSean Bruno 		 * the lio watchdog kernel thread is running for this
268f173c2b7SSean Bruno 		 * NIC.  Each NIC gets one watchdog kernel thread.
269f173c2b7SSean Bruno 		 */
270f173c2b7SSean Bruno 		scratch1 |= 4ULL;
271f173c2b7SSean Bruno 		lio_write_csr64(oct_dev, LIO_CN23XX_SLI_SCRATCH1, scratch1);
272f173c2b7SSean Bruno 
273f173c2b7SSean Bruno 		error = kproc_create(lio_watchdog, oct_dev,
274f173c2b7SSean Bruno 				     &oct_dev->watchdog_task, 0, 0,
275f173c2b7SSean Bruno 				     "liowd/%02hhx:%02hhx.%hhx", bus,
276f173c2b7SSean Bruno 				     dev, function);
277f173c2b7SSean Bruno 		if (!error) {
278f173c2b7SSean Bruno 			kproc_resume(oct_dev->watchdog_task);
279f173c2b7SSean Bruno 		} else {
280f173c2b7SSean Bruno 			oct_dev->watchdog_task = NULL;
281f173c2b7SSean Bruno 			lio_dev_err(oct_dev,
282f173c2b7SSean Bruno 				    "failed to create kernel_thread\n");
283f173c2b7SSean Bruno 			lio_detach(device);
284f173c2b7SSean Bruno 			return (-1);
285f173c2b7SSean Bruno 		}
286f173c2b7SSean Bruno 	}
287f173c2b7SSean Bruno 	oct_dev->rx_pause = 1;
288f173c2b7SSean Bruno 	oct_dev->tx_pause = 1;
289f173c2b7SSean Bruno 
290f173c2b7SSean Bruno 	timeout = 0;
291f173c2b7SSean Bruno 	while (timeout < LIO_NIC_STARTER_TIMEOUT) {
292f173c2b7SSean Bruno 		lio_mdelay(LIO_STARTER_POLL_INTERVAL_MS);
293f173c2b7SSean Bruno 		timeout += LIO_STARTER_POLL_INTERVAL_MS;
294f173c2b7SSean Bruno 
295f173c2b7SSean Bruno 		/*
296f173c2b7SSean Bruno 		 * During the boot process interrupts are not available.
297f173c2b7SSean Bruno 		 * So polling for first control message from FW.
298f173c2b7SSean Bruno 		 */
299f173c2b7SSean Bruno 		if (cold)
300f173c2b7SSean Bruno 			lio_droq_bh(oct_dev->droq[0], 0);
301f173c2b7SSean Bruno 
302f173c2b7SSean Bruno 		if (atomic_load_acq_int(&oct_dev->status) == LIO_DEV_CORE_OK) {
303f173c2b7SSean Bruno 			ret = lio_nic_starter(oct_dev);
304f173c2b7SSean Bruno 			break;
305f173c2b7SSean Bruno 		}
306f173c2b7SSean Bruno 	}
307f173c2b7SSean Bruno 
308f173c2b7SSean Bruno 	if (ret) {
309f173c2b7SSean Bruno 		lio_dev_err(oct_dev, "Firmware failed to start\n");
310f173c2b7SSean Bruno 		lio_detach(device);
311f173c2b7SSean Bruno 		return (-EIO);
312f173c2b7SSean Bruno 	}
313f173c2b7SSean Bruno 
314f173c2b7SSean Bruno 	lio_dev_dbg(oct_dev, "Device is ready\n");
315f173c2b7SSean Bruno 
316f173c2b7SSean Bruno 	return (0);
317f173c2b7SSean Bruno }
318f173c2b7SSean Bruno 
319f173c2b7SSean Bruno static int
320f173c2b7SSean Bruno lio_detach(device_t dev)
321f173c2b7SSean Bruno {
322f173c2b7SSean Bruno 	struct octeon_device	*oct_dev = device_get_softc(dev);
323f173c2b7SSean Bruno 
324f173c2b7SSean Bruno 	lio_dev_dbg(oct_dev, "Stopping device\n");
325f173c2b7SSean Bruno 	if (oct_dev->watchdog_task) {
326f173c2b7SSean Bruno 		uint64_t	scratch1;
327f173c2b7SSean Bruno 
328f173c2b7SSean Bruno 		kproc_suspend(oct_dev->watchdog_task, 0);
329f173c2b7SSean Bruno 
330f173c2b7SSean Bruno 		scratch1 = lio_read_csr64(oct_dev, LIO_CN23XX_SLI_SCRATCH1);
331f173c2b7SSean Bruno 		scratch1 &= ~4ULL;
332f173c2b7SSean Bruno 		lio_write_csr64(oct_dev, LIO_CN23XX_SLI_SCRATCH1, scratch1);
333f173c2b7SSean Bruno 	}
334f173c2b7SSean Bruno 
335f173c2b7SSean Bruno 	if (oct_dev->app_mode && (oct_dev->app_mode == LIO_DRV_NIC_APP))
336f173c2b7SSean Bruno 		lio_stop_nic_module(oct_dev);
337f173c2b7SSean Bruno 
338f173c2b7SSean Bruno 	/*
339f173c2b7SSean Bruno 	 * Reset the octeon device and cleanup all memory allocated for
340f173c2b7SSean Bruno 	 * the octeon device by  driver.
341f173c2b7SSean Bruno 	 */
342f173c2b7SSean Bruno 	lio_destroy_resources(oct_dev);
343f173c2b7SSean Bruno 
344f173c2b7SSean Bruno 	lio_dev_info(oct_dev, "Device removed\n");
345f173c2b7SSean Bruno 
346f173c2b7SSean Bruno 	/*
347f173c2b7SSean Bruno 	 * This octeon device has been removed. Update the global
348f173c2b7SSean Bruno 	 * data structure to reflect this. Free the device structure.
349f173c2b7SSean Bruno 	 */
350f173c2b7SSean Bruno 	lio_free_device_mem(oct_dev);
351f173c2b7SSean Bruno 	return (0);
352f173c2b7SSean Bruno }
353f173c2b7SSean Bruno 
354f173c2b7SSean Bruno static int
355f173c2b7SSean Bruno lio_shutdown(device_t dev)
356f173c2b7SSean Bruno {
357f173c2b7SSean Bruno 	struct octeon_device	*oct_dev = device_get_softc(dev);
358f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(oct_dev->props.ifp);
359f173c2b7SSean Bruno 
360f173c2b7SSean Bruno 	lio_send_rx_ctrl_cmd(lio, 0);
361f173c2b7SSean Bruno 
362f173c2b7SSean Bruno 	return (0);
363f173c2b7SSean Bruno }
364f173c2b7SSean Bruno 
365f173c2b7SSean Bruno static int
366f173c2b7SSean Bruno lio_suspend(device_t dev)
367f173c2b7SSean Bruno {
368f173c2b7SSean Bruno 
369f173c2b7SSean Bruno 	return (ENXIO);
370f173c2b7SSean Bruno }
371f173c2b7SSean Bruno 
372f173c2b7SSean Bruno static int
373f173c2b7SSean Bruno lio_resume(device_t dev)
374f173c2b7SSean Bruno {
375f173c2b7SSean Bruno 
376f173c2b7SSean Bruno 	return (ENXIO);
377f173c2b7SSean Bruno }
378f173c2b7SSean Bruno 
379f173c2b7SSean Bruno static int
380f173c2b7SSean Bruno lio_event(struct module *mod, int event, void *junk)
381f173c2b7SSean Bruno {
382f173c2b7SSean Bruno 
383f173c2b7SSean Bruno 	switch (event) {
384f173c2b7SSean Bruno 	case MOD_LOAD:
385f173c2b7SSean Bruno 		lio_init_device_list(LIO_CFG_TYPE_DEFAULT);
386f173c2b7SSean Bruno 		break;
387f173c2b7SSean Bruno 	default:
388f173c2b7SSean Bruno 		break;
389f173c2b7SSean Bruno 	}
390f173c2b7SSean Bruno 
391f173c2b7SSean Bruno 	return (0);
392f173c2b7SSean Bruno }
393f173c2b7SSean Bruno 
394f173c2b7SSean Bruno /*********************************************************************
395f173c2b7SSean Bruno  *  FreeBSD Device Interface Entry Points
396f173c2b7SSean Bruno  * *******************************************************************/
397f173c2b7SSean Bruno static device_method_t lio_methods[] = {
398f173c2b7SSean Bruno 	/* Device interface */
399f173c2b7SSean Bruno 	DEVMETHOD(device_probe, lio_probe),
400f173c2b7SSean Bruno 	DEVMETHOD(device_attach, lio_attach),
401f173c2b7SSean Bruno 	DEVMETHOD(device_detach, lio_detach),
402f173c2b7SSean Bruno 	DEVMETHOD(device_shutdown, lio_shutdown),
403f173c2b7SSean Bruno 	DEVMETHOD(device_suspend, lio_suspend),
404f173c2b7SSean Bruno 	DEVMETHOD(device_resume, lio_resume),
405f173c2b7SSean Bruno 	DEVMETHOD_END
406f173c2b7SSean Bruno };
407f173c2b7SSean Bruno 
408f173c2b7SSean Bruno static driver_t lio_driver = {
409f173c2b7SSean Bruno 	LIO_DRV_NAME, lio_methods, sizeof(struct octeon_device),
410f173c2b7SSean Bruno };
411f173c2b7SSean Bruno 
4121cd1672fSJohn Baldwin DRIVER_MODULE(lio, pci, lio_driver, lio_event, NULL);
413f173c2b7SSean Bruno 
414f173c2b7SSean Bruno MODULE_DEPEND(lio, pci, 1, 1, 1);
415f173c2b7SSean Bruno MODULE_DEPEND(lio, ether, 1, 1, 1);
416f173c2b7SSean Bruno MODULE_DEPEND(lio, firmware, 1, 1, 1);
417f173c2b7SSean Bruno 
418f173c2b7SSean Bruno static bool
419f173c2b7SSean Bruno fw_type_is_none(void)
420f173c2b7SSean Bruno {
421f173c2b7SSean Bruno 	return strncmp(fw_type, LIO_FW_NAME_TYPE_NONE,
422f173c2b7SSean Bruno 		       sizeof(LIO_FW_NAME_TYPE_NONE)) == 0;
423f173c2b7SSean Bruno }
424f173c2b7SSean Bruno 
425f173c2b7SSean Bruno /*
426f173c2b7SSean Bruno  * \brief Device initialization for each Octeon device that is probed
427f173c2b7SSean Bruno  * @param octeon_dev  octeon device
428f173c2b7SSean Bruno  */
429f173c2b7SSean Bruno static int
430f173c2b7SSean Bruno lio_device_init(struct octeon_device *octeon_dev)
431f173c2b7SSean Bruno {
432f173c2b7SSean Bruno 	unsigned long	ddr_timeout = LIO_DDR_TIMEOUT;
433f173c2b7SSean Bruno 	char	*dbg_enb = NULL;
434f173c2b7SSean Bruno 	int	fw_loaded = 0;
435f173c2b7SSean Bruno 	int	i, j, ret;
436f173c2b7SSean Bruno 	uint8_t	bus, dev, function;
437f173c2b7SSean Bruno 	char	bootcmd[] = "\n";
438f173c2b7SSean Bruno 
439f173c2b7SSean Bruno 	bus = pci_get_bus(octeon_dev->device);
440f173c2b7SSean Bruno 	dev = pci_get_slot(octeon_dev->device);
441f173c2b7SSean Bruno 	function = pci_get_function(octeon_dev->device);
442f173c2b7SSean Bruno 
443f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status, LIO_DEV_BEGIN_STATE);
444f173c2b7SSean Bruno 
445f173c2b7SSean Bruno 	/* Enable access to the octeon device */
446f173c2b7SSean Bruno 	if (pci_enable_busmaster(octeon_dev->device)) {
447f173c2b7SSean Bruno 		lio_dev_err(octeon_dev, "pci_enable_device failed\n");
448f173c2b7SSean Bruno 		return (1);
449f173c2b7SSean Bruno 	}
450f173c2b7SSean Bruno 
451f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status, LIO_DEV_PCI_ENABLE_DONE);
452f173c2b7SSean Bruno 
453f173c2b7SSean Bruno 	/* Identify the Octeon type and map the BAR address space. */
454f173c2b7SSean Bruno 	if (lio_chip_specific_setup(octeon_dev)) {
455f173c2b7SSean Bruno 		lio_dev_err(octeon_dev, "Chip specific setup failed\n");
456f173c2b7SSean Bruno 		return (1);
457f173c2b7SSean Bruno 	}
458f173c2b7SSean Bruno 
459f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status, LIO_DEV_PCI_MAP_DONE);
460f173c2b7SSean Bruno 
461f173c2b7SSean Bruno 	/*
462f173c2b7SSean Bruno 	 * Only add a reference after setting status 'OCT_DEV_PCI_MAP_DONE',
463f173c2b7SSean Bruno 	 * since that is what is required for the reference to be removed
464f173c2b7SSean Bruno 	 * during de-initialization (see 'octeon_destroy_resources').
465f173c2b7SSean Bruno 	 */
466f173c2b7SSean Bruno 	lio_register_device(octeon_dev, bus, dev, function, true);
467f173c2b7SSean Bruno 
468f173c2b7SSean Bruno 
469f173c2b7SSean Bruno 	octeon_dev->app_mode = LIO_DRV_INVALID_APP;
470f173c2b7SSean Bruno 
471f173c2b7SSean Bruno 	if (!lio_cn23xx_pf_fw_loaded(octeon_dev) && !fw_type_is_none()) {
472f173c2b7SSean Bruno 		fw_loaded = 0;
473f173c2b7SSean Bruno 		/* Do a soft reset of the Octeon device. */
474f173c2b7SSean Bruno 		if (octeon_dev->fn_list.soft_reset(octeon_dev))
475f173c2b7SSean Bruno 			return (1);
476f173c2b7SSean Bruno 
477f173c2b7SSean Bruno 		/* things might have changed */
478f173c2b7SSean Bruno 		if (!lio_cn23xx_pf_fw_loaded(octeon_dev))
479f173c2b7SSean Bruno 			fw_loaded = 0;
480f173c2b7SSean Bruno 		else
481f173c2b7SSean Bruno 			fw_loaded = 1;
482f173c2b7SSean Bruno 	} else {
483f173c2b7SSean Bruno 		fw_loaded = 1;
484f173c2b7SSean Bruno 	}
485f173c2b7SSean Bruno 
486f173c2b7SSean Bruno 	/*
487f173c2b7SSean Bruno 	 * Initialize the dispatch mechanism used to push packets arriving on
488f173c2b7SSean Bruno 	 * Octeon Output queues.
489f173c2b7SSean Bruno 	 */
490f173c2b7SSean Bruno 	if (lio_init_dispatch_list(octeon_dev))
491f173c2b7SSean Bruno 		return (1);
492f173c2b7SSean Bruno 
493f173c2b7SSean Bruno 	lio_register_dispatch_fn(octeon_dev, LIO_OPCODE_NIC,
494f173c2b7SSean Bruno 				 LIO_OPCODE_NIC_CORE_DRV_ACTIVE,
495f173c2b7SSean Bruno 				 lio_core_drv_init, octeon_dev);
496f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status, LIO_DEV_DISPATCH_INIT_DONE);
497f173c2b7SSean Bruno 
498f173c2b7SSean Bruno 	ret = octeon_dev->fn_list.setup_device_regs(octeon_dev);
499f173c2b7SSean Bruno 	if (ret) {
500f173c2b7SSean Bruno 		lio_dev_err(octeon_dev,
501f173c2b7SSean Bruno 			    "Failed to configure device registers\n");
502f173c2b7SSean Bruno 		return (ret);
503f173c2b7SSean Bruno 	}
504f173c2b7SSean Bruno 
505f173c2b7SSean Bruno 	/* Initialize soft command buffer pool */
506f173c2b7SSean Bruno 	if (lio_setup_sc_buffer_pool(octeon_dev)) {
507f173c2b7SSean Bruno 		lio_dev_err(octeon_dev, "sc buffer pool allocation failed\n");
508f173c2b7SSean Bruno 		return (1);
509f173c2b7SSean Bruno 	}
510f173c2b7SSean Bruno 
511f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status,
512f173c2b7SSean Bruno 			     LIO_DEV_SC_BUFF_POOL_INIT_DONE);
513f173c2b7SSean Bruno 
514f173c2b7SSean Bruno 	if (lio_allocate_ioq_vector(octeon_dev)) {
515f173c2b7SSean Bruno 		lio_dev_err(octeon_dev,
516f173c2b7SSean Bruno 			    "IOQ vector allocation failed\n");
517f173c2b7SSean Bruno 		return (1);
518f173c2b7SSean Bruno 	}
519f173c2b7SSean Bruno 
520f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status,
521f173c2b7SSean Bruno 			     LIO_DEV_MSIX_ALLOC_VECTOR_DONE);
522f173c2b7SSean Bruno 
523f173c2b7SSean Bruno 	for (i = 0; i < LIO_MAX_POSSIBLE_INSTR_QUEUES; i++) {
524f173c2b7SSean Bruno 		octeon_dev->instr_queue[i] =
525f173c2b7SSean Bruno 			malloc(sizeof(struct lio_instr_queue),
526f173c2b7SSean Bruno 			       M_DEVBUF, M_NOWAIT | M_ZERO);
527f173c2b7SSean Bruno 		if (octeon_dev->instr_queue[i] == NULL)
528f173c2b7SSean Bruno 			return (1);
529f173c2b7SSean Bruno 	}
530f173c2b7SSean Bruno 
531f173c2b7SSean Bruno 	/* Setup the data structures that manage this Octeon's Input queues. */
532f173c2b7SSean Bruno 	if (lio_setup_instr_queue0(octeon_dev)) {
533f173c2b7SSean Bruno 		lio_dev_err(octeon_dev,
534f173c2b7SSean Bruno 			    "Instruction queue initialization failed\n");
535f173c2b7SSean Bruno 		return (1);
536f173c2b7SSean Bruno 	}
537f173c2b7SSean Bruno 
538f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status,
539f173c2b7SSean Bruno 			     LIO_DEV_INSTR_QUEUE_INIT_DONE);
540f173c2b7SSean Bruno 
541f173c2b7SSean Bruno 	/*
542f173c2b7SSean Bruno 	 * Initialize lists to manage the requests of different types that
543f173c2b7SSean Bruno 	 * arrive from user & kernel applications for this octeon device.
544f173c2b7SSean Bruno 	 */
545f173c2b7SSean Bruno 
546f173c2b7SSean Bruno 	if (lio_setup_response_list(octeon_dev)) {
547f173c2b7SSean Bruno 		lio_dev_err(octeon_dev, "Response list allocation failed\n");
548f173c2b7SSean Bruno 		return (1);
549f173c2b7SSean Bruno 	}
550f173c2b7SSean Bruno 
551f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status, LIO_DEV_RESP_LIST_INIT_DONE);
552f173c2b7SSean Bruno 
553f173c2b7SSean Bruno 	for (i = 0; i < LIO_MAX_POSSIBLE_OUTPUT_QUEUES; i++) {
554f173c2b7SSean Bruno 		octeon_dev->droq[i] = malloc(sizeof(*octeon_dev->droq[i]),
555f173c2b7SSean Bruno 					     M_DEVBUF, M_NOWAIT | M_ZERO);
556f173c2b7SSean Bruno 		if (octeon_dev->droq[i] == NULL)
557f173c2b7SSean Bruno 			return (1);
558f173c2b7SSean Bruno 	}
559f173c2b7SSean Bruno 
560f173c2b7SSean Bruno 	if (lio_setup_output_queue0(octeon_dev)) {
561f173c2b7SSean Bruno 		lio_dev_err(octeon_dev, "Output queue initialization failed\n");
562f173c2b7SSean Bruno 		return (1);
563f173c2b7SSean Bruno 	}
564f173c2b7SSean Bruno 
565f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status, LIO_DEV_DROQ_INIT_DONE);
566f173c2b7SSean Bruno 
567f173c2b7SSean Bruno 	/*
568f173c2b7SSean Bruno 	 * Setup the interrupt handler and record the INT SUM register address
569f173c2b7SSean Bruno 	 */
570f173c2b7SSean Bruno 	if (lio_setup_interrupt(octeon_dev,
571f173c2b7SSean Bruno 				octeon_dev->sriov_info.num_pf_rings))
572f173c2b7SSean Bruno 		return (1);
573f173c2b7SSean Bruno 
574f173c2b7SSean Bruno 	/* Enable Octeon device interrupts */
575f173c2b7SSean Bruno 	octeon_dev->fn_list.enable_interrupt(octeon_dev, OCTEON_ALL_INTR);
576f173c2b7SSean Bruno 
577f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status, LIO_DEV_INTR_SET_DONE);
578f173c2b7SSean Bruno 
579f173c2b7SSean Bruno 	/*
580f173c2b7SSean Bruno 	 * Send Credit for Octeon Output queues. Credits are always sent BEFORE
581f173c2b7SSean Bruno 	 * the output queue is enabled.
582f173c2b7SSean Bruno 	 * This ensures that we'll receive the f/w CORE DRV_ACTIVE message in
583f173c2b7SSean Bruno 	 * case we've configured CN23XX_SLI_GBL_CONTROL[NOPTR_D] = 0.
584f173c2b7SSean Bruno 	 * Otherwise, it is possible that the DRV_ACTIVE message will be sent
585f173c2b7SSean Bruno 	 * before any credits have been issued, causing the ring to be reset
586f173c2b7SSean Bruno 	 * (and the f/w appear to never have started).
587f173c2b7SSean Bruno 	 */
588f173c2b7SSean Bruno 	for (j = 0; j < octeon_dev->num_oqs; j++)
589f173c2b7SSean Bruno 		lio_write_csr32(octeon_dev,
590f173c2b7SSean Bruno 				octeon_dev->droq[j]->pkts_credit_reg,
591f173c2b7SSean Bruno 				octeon_dev->droq[j]->max_count);
592f173c2b7SSean Bruno 
593f173c2b7SSean Bruno 	/* Enable the input and output queues for this Octeon device */
594f173c2b7SSean Bruno 	ret = octeon_dev->fn_list.enable_io_queues(octeon_dev);
595f173c2b7SSean Bruno 	if (ret) {
596f173c2b7SSean Bruno 		lio_dev_err(octeon_dev, "Failed to enable input/output queues");
597f173c2b7SSean Bruno 		return (ret);
598f173c2b7SSean Bruno 	}
599f173c2b7SSean Bruno 
600f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status, LIO_DEV_IO_QUEUES_DONE);
601f173c2b7SSean Bruno 
602f173c2b7SSean Bruno 	if (!fw_loaded) {
603f173c2b7SSean Bruno 		lio_dev_dbg(octeon_dev, "Waiting for DDR initialization...\n");
604f173c2b7SSean Bruno 		if (!ddr_timeout) {
605f173c2b7SSean Bruno 			lio_dev_info(octeon_dev,
606f173c2b7SSean Bruno 				     "WAITING. Set ddr_timeout to non-zero value to proceed with initialization.\n");
607f173c2b7SSean Bruno 		}
608f173c2b7SSean Bruno 
609f173c2b7SSean Bruno 		lio_sleep_timeout(LIO_RESET_MSECS);
610f173c2b7SSean Bruno 
611f173c2b7SSean Bruno 		/*
612f173c2b7SSean Bruno 		 * Wait for the octeon to initialize DDR after the
613f173c2b7SSean Bruno 		 * soft-reset.
614f173c2b7SSean Bruno 		 */
615f173c2b7SSean Bruno 		while (!ddr_timeout) {
616f173c2b7SSean Bruno 			if (pause("-", lio_ms_to_ticks(100))) {
617f173c2b7SSean Bruno 				/* user probably pressed Control-C */
618f173c2b7SSean Bruno 				return (1);
619f173c2b7SSean Bruno 			}
620f173c2b7SSean Bruno 		}
621f173c2b7SSean Bruno 
622f173c2b7SSean Bruno 		ret = lio_wait_for_ddr_init(octeon_dev, &ddr_timeout);
623f173c2b7SSean Bruno 		if (ret) {
624f173c2b7SSean Bruno 			lio_dev_err(octeon_dev,
625f173c2b7SSean Bruno 				    "DDR not initialized. Please confirm that board is configured to boot from Flash, ret: %d\n",
626f173c2b7SSean Bruno 				    ret);
627f173c2b7SSean Bruno 			return (1);
628f173c2b7SSean Bruno 		}
629f173c2b7SSean Bruno 
630f173c2b7SSean Bruno 		if (lio_wait_for_bootloader(octeon_dev, 1100)) {
631f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "Board not responding\n");
632f173c2b7SSean Bruno 			return (1);
633f173c2b7SSean Bruno 		}
634f173c2b7SSean Bruno 
635f173c2b7SSean Bruno 		/* Divert uboot to take commands from host instead. */
636f173c2b7SSean Bruno 		ret = lio_console_send_cmd(octeon_dev, bootcmd, 50);
637f173c2b7SSean Bruno 
638f173c2b7SSean Bruno 		lio_dev_dbg(octeon_dev, "Initializing consoles\n");
639f173c2b7SSean Bruno 		ret = lio_init_consoles(octeon_dev);
640f173c2b7SSean Bruno 		if (ret) {
641f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "Could not access board consoles\n");
642f173c2b7SSean Bruno 			return (1);
643f173c2b7SSean Bruno 		}
644f173c2b7SSean Bruno 
645f173c2b7SSean Bruno 		/*
646f173c2b7SSean Bruno 		 * If console debug enabled, specify empty string to
647f173c2b7SSean Bruno 		 * use default enablement ELSE specify NULL string for
648f173c2b7SSean Bruno 		 * 'disabled'.
649f173c2b7SSean Bruno 		 */
650f173c2b7SSean Bruno 		dbg_enb = lio_console_debug_enabled(0) ? "" : NULL;
651f173c2b7SSean Bruno 		ret = lio_add_console(octeon_dev, 0, dbg_enb);
652f173c2b7SSean Bruno 
653f173c2b7SSean Bruno 		if (ret) {
654f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "Could not access board console\n");
655f173c2b7SSean Bruno 			return (1);
656f173c2b7SSean Bruno 		} else if (lio_console_debug_enabled(0)) {
657f173c2b7SSean Bruno 			/*
658f173c2b7SSean Bruno 			 * If console was added AND we're logging console output
659f173c2b7SSean Bruno 			 * then set our console print function.
660f173c2b7SSean Bruno 			 */
661f173c2b7SSean Bruno 			octeon_dev->console[0].print = lio_dbg_console_print;
662f173c2b7SSean Bruno 		}
663f173c2b7SSean Bruno 
664f173c2b7SSean Bruno 		atomic_store_rel_int(&octeon_dev->status,
665f173c2b7SSean Bruno 				     LIO_DEV_CONSOLE_INIT_DONE);
666f173c2b7SSean Bruno 
667f173c2b7SSean Bruno 		lio_dev_dbg(octeon_dev, "Loading firmware\n");
668f173c2b7SSean Bruno 
669f173c2b7SSean Bruno 		ret = lio_load_firmware(octeon_dev);
670f173c2b7SSean Bruno 		if (ret) {
671f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "Could not load firmware to board\n");
672f173c2b7SSean Bruno 			return (1);
673f173c2b7SSean Bruno 		}
674f173c2b7SSean Bruno 	}
675f173c2b7SSean Bruno 
676f173c2b7SSean Bruno 	atomic_store_rel_int(&octeon_dev->status, LIO_DEV_HOST_OK);
677f173c2b7SSean Bruno 
678f173c2b7SSean Bruno 	return (0);
679f173c2b7SSean Bruno }
680f173c2b7SSean Bruno 
681f173c2b7SSean Bruno /*
682f173c2b7SSean Bruno  * \brief PCI FLR for each Octeon device.
683f173c2b7SSean Bruno  * @param oct octeon device
684f173c2b7SSean Bruno  */
685f173c2b7SSean Bruno static void
686f173c2b7SSean Bruno lio_pci_flr(struct octeon_device *oct)
687f173c2b7SSean Bruno {
688f173c2b7SSean Bruno 	uint32_t	exppos, status;
689f173c2b7SSean Bruno 
690f173c2b7SSean Bruno 	pci_find_cap(oct->device, PCIY_EXPRESS, &exppos);
691f173c2b7SSean Bruno 
692f173c2b7SSean Bruno 	pci_save_state(oct->device);
693f173c2b7SSean Bruno 
694f173c2b7SSean Bruno 	/* Quiesce the device completely */
695f173c2b7SSean Bruno 	pci_write_config(oct->device, PCIR_COMMAND, PCIM_CMD_INTxDIS, 2);
696f173c2b7SSean Bruno 
697f173c2b7SSean Bruno 	/* Wait for Transaction Pending bit clean */
698f173c2b7SSean Bruno 	lio_mdelay(100);
699f173c2b7SSean Bruno 
700f173c2b7SSean Bruno 	status = pci_read_config(oct->device, exppos + PCIER_DEVICE_STA, 2);
701f173c2b7SSean Bruno 	if (status & PCIEM_STA_TRANSACTION_PND) {
702f173c2b7SSean Bruno 		lio_dev_info(oct, "Function reset incomplete after 100ms, sleeping for 5 seconds\n");
703f173c2b7SSean Bruno 		lio_mdelay(5);
704f173c2b7SSean Bruno 
705f173c2b7SSean Bruno 		status = pci_read_config(oct->device, exppos + PCIER_DEVICE_STA, 2);
706f173c2b7SSean Bruno 		if (status & PCIEM_STA_TRANSACTION_PND)
707f173c2b7SSean Bruno 			lio_dev_info(oct, "Function reset still incomplete after 5s, reset anyway\n");
708f173c2b7SSean Bruno 	}
709f173c2b7SSean Bruno 
710f173c2b7SSean Bruno 	pci_write_config(oct->device, exppos + PCIER_DEVICE_CTL, PCIEM_CTL_INITIATE_FLR, 2);
711f173c2b7SSean Bruno 	lio_mdelay(100);
712f173c2b7SSean Bruno 
713f173c2b7SSean Bruno 	pci_restore_state(oct->device);
714f173c2b7SSean Bruno }
715f173c2b7SSean Bruno 
716f173c2b7SSean Bruno /*
717f173c2b7SSean Bruno  * \brief Debug console print function
718f173c2b7SSean Bruno  * @param octeon_dev  octeon device
719f173c2b7SSean Bruno  * @param console_num console number
720f173c2b7SSean Bruno  * @param prefix      first portion of line to display
721f173c2b7SSean Bruno  * @param suffix      second portion of line to display
722f173c2b7SSean Bruno  *
723f173c2b7SSean Bruno  * The OCTEON debug console outputs entire lines (excluding '\n').
724f173c2b7SSean Bruno  * Normally, the line will be passed in the 'prefix' parameter.
725f173c2b7SSean Bruno  * However, due to buffering, it is possible for a line to be split into two
726f173c2b7SSean Bruno  * parts, in which case they will be passed as the 'prefix' parameter and
727f173c2b7SSean Bruno  * 'suffix' parameter.
728f173c2b7SSean Bruno  */
729f173c2b7SSean Bruno static int
730f173c2b7SSean Bruno lio_dbg_console_print(struct octeon_device *oct, uint32_t console_num,
731f173c2b7SSean Bruno 		      char *prefix, char *suffix)
732f173c2b7SSean Bruno {
733f173c2b7SSean Bruno 
734f173c2b7SSean Bruno 	if (prefix != NULL && suffix != NULL)
735f173c2b7SSean Bruno 		lio_dev_info(oct, "%u: %s%s\n", console_num, prefix, suffix);
736f173c2b7SSean Bruno 	else if (prefix != NULL)
737f173c2b7SSean Bruno 		lio_dev_info(oct, "%u: %s\n", console_num, prefix);
738f173c2b7SSean Bruno 	else if (suffix != NULL)
739f173c2b7SSean Bruno 		lio_dev_info(oct, "%u: %s\n", console_num, suffix);
740f173c2b7SSean Bruno 
741f173c2b7SSean Bruno 	return (0);
742f173c2b7SSean Bruno }
743f173c2b7SSean Bruno 
744f173c2b7SSean Bruno static void
745f173c2b7SSean Bruno lio_watchdog(void *param)
746f173c2b7SSean Bruno {
747f173c2b7SSean Bruno 	int		core_num;
748f173c2b7SSean Bruno 	uint16_t	mask_of_crashed_or_stuck_cores = 0;
749f173c2b7SSean Bruno 	struct octeon_device	*oct = param;
750f173c2b7SSean Bruno 	bool		err_msg_was_printed[12];
751f173c2b7SSean Bruno 
752f173c2b7SSean Bruno 	bzero(err_msg_was_printed, sizeof(err_msg_was_printed));
753f173c2b7SSean Bruno 
754f173c2b7SSean Bruno 	while (1) {
755f173c2b7SSean Bruno 		kproc_suspend_check(oct->watchdog_task);
756f173c2b7SSean Bruno 		mask_of_crashed_or_stuck_cores =
757f173c2b7SSean Bruno 			(uint16_t)lio_read_csr64(oct, LIO_CN23XX_SLI_SCRATCH2);
758f173c2b7SSean Bruno 
759f173c2b7SSean Bruno 		if (mask_of_crashed_or_stuck_cores) {
760f173c2b7SSean Bruno 			struct octeon_device *other_oct;
761f173c2b7SSean Bruno 
762f173c2b7SSean Bruno 			oct->cores_crashed = true;
763f173c2b7SSean Bruno 			other_oct = lio_get_other_octeon_device(oct);
764f173c2b7SSean Bruno 			if (other_oct != NULL)
765f173c2b7SSean Bruno 				other_oct->cores_crashed = true;
766f173c2b7SSean Bruno 
767f173c2b7SSean Bruno 			for (core_num = 0; core_num < LIO_MAX_CORES;
768f173c2b7SSean Bruno 			     core_num++) {
769f173c2b7SSean Bruno 				bool core_crashed_or_got_stuck;
770f173c2b7SSean Bruno 
771f173c2b7SSean Bruno 				core_crashed_or_got_stuck =
772f173c2b7SSean Bruno 				    (mask_of_crashed_or_stuck_cores >>
773f173c2b7SSean Bruno 				     core_num) & 1;
774f173c2b7SSean Bruno 				if (core_crashed_or_got_stuck &&
775f173c2b7SSean Bruno 				    !err_msg_was_printed[core_num]) {
776f173c2b7SSean Bruno 					lio_dev_err(oct,
777f173c2b7SSean Bruno 						    "ERROR: Octeon core %d crashed or got stuck! See oct-fwdump for details.\n",
778f173c2b7SSean Bruno 						    core_num);
779f173c2b7SSean Bruno 					err_msg_was_printed[core_num] = true;
780f173c2b7SSean Bruno 				}
781f173c2b7SSean Bruno 			}
782f173c2b7SSean Bruno 
783f173c2b7SSean Bruno 		}
784f173c2b7SSean Bruno 
785f173c2b7SSean Bruno 		/* sleep for two seconds */
786f173c2b7SSean Bruno 		pause("-", lio_ms_to_ticks(2000));
787f173c2b7SSean Bruno 	}
788f173c2b7SSean Bruno }
789f173c2b7SSean Bruno 
790f173c2b7SSean Bruno static int
791f173c2b7SSean Bruno lio_chip_specific_setup(struct octeon_device *oct)
792f173c2b7SSean Bruno {
793f173c2b7SSean Bruno 	char		*s;
7948af24219SJohn Baldwin 	uint32_t	dev_id;
795f173c2b7SSean Bruno 	int		ret = 1;
796f173c2b7SSean Bruno 
797f173c2b7SSean Bruno 	dev_id = lio_read_pci_cfg(oct, 0);
798f173c2b7SSean Bruno 	oct->subdevice_id = pci_get_subdevice(oct->device);
799f173c2b7SSean Bruno 
800f173c2b7SSean Bruno 	switch (dev_id) {
801f173c2b7SSean Bruno 	case LIO_CN23XX_PF_PCIID:
802f173c2b7SSean Bruno 		oct->chip_id = LIO_CN23XX_PF_VID;
803f173c2b7SSean Bruno 		if (pci_get_function(oct->device) == 0) {
804f173c2b7SSean Bruno 			if (num_queues_per_pf0 < 0) {
805f173c2b7SSean Bruno 				lio_dev_info(oct, "Invalid num_queues_per_pf0: %d, Setting it to default\n",
806f173c2b7SSean Bruno 					     num_queues_per_pf0);
807f173c2b7SSean Bruno 				num_queues_per_pf0 = 0;
808f173c2b7SSean Bruno 			}
809f173c2b7SSean Bruno 
810f173c2b7SSean Bruno 			oct->sriov_info.num_pf_rings = num_queues_per_pf0;
811f173c2b7SSean Bruno 		} else {
812f173c2b7SSean Bruno 			if (num_queues_per_pf1 < 0) {
813f173c2b7SSean Bruno 				lio_dev_info(oct, "Invalid num_queues_per_pf1: %d, Setting it to default\n",
814f173c2b7SSean Bruno 					     num_queues_per_pf1);
815f173c2b7SSean Bruno 				num_queues_per_pf1 = 0;
816f173c2b7SSean Bruno 			}
817f173c2b7SSean Bruno 
818f173c2b7SSean Bruno 			oct->sriov_info.num_pf_rings = num_queues_per_pf1;
819f173c2b7SSean Bruno 		}
820f173c2b7SSean Bruno 
821f173c2b7SSean Bruno 		ret = lio_cn23xx_pf_setup_device(oct);
822f173c2b7SSean Bruno 		s = "CN23XX";
823f173c2b7SSean Bruno 		break;
824f173c2b7SSean Bruno 
825f173c2b7SSean Bruno 	default:
826f173c2b7SSean Bruno 		s = "?";
827f173c2b7SSean Bruno 		lio_dev_err(oct, "Unknown device found (dev_id: %x)\n", dev_id);
828f173c2b7SSean Bruno 	}
829f173c2b7SSean Bruno 
830f173c2b7SSean Bruno 	if (!ret)
831f173c2b7SSean Bruno 		lio_dev_info(oct, "%s PASS%d.%d %s Version: %s\n", s,
832f173c2b7SSean Bruno 			     OCTEON_MAJOR_REV(oct), OCTEON_MINOR_REV(oct),
833f173c2b7SSean Bruno 			     lio_get_conf(oct)->card_name, LIO_VERSION);
834f173c2b7SSean Bruno 
835f173c2b7SSean Bruno 	return (ret);
836f173c2b7SSean Bruno }
837f173c2b7SSean Bruno 
838f173c2b7SSean Bruno static struct octeon_device *
839f173c2b7SSean Bruno lio_get_other_octeon_device(struct octeon_device *oct)
840f173c2b7SSean Bruno {
841f173c2b7SSean Bruno 	struct octeon_device	*other_oct;
842f173c2b7SSean Bruno 
843f173c2b7SSean Bruno 	other_oct = lio_get_device(oct->octeon_id + 1);
844f173c2b7SSean Bruno 
845f173c2b7SSean Bruno 	if ((other_oct != NULL) && other_oct->device) {
846f173c2b7SSean Bruno 		int	oct_busnum, other_oct_busnum;
847f173c2b7SSean Bruno 
848f173c2b7SSean Bruno 		oct_busnum = pci_get_bus(oct->device);
849f173c2b7SSean Bruno 		other_oct_busnum = pci_get_bus(other_oct->device);
850f173c2b7SSean Bruno 
851f173c2b7SSean Bruno 		if (oct_busnum == other_oct_busnum) {
852f173c2b7SSean Bruno 			int	oct_slot, other_oct_slot;
853f173c2b7SSean Bruno 
854f173c2b7SSean Bruno 			oct_slot = pci_get_slot(oct->device);
855f173c2b7SSean Bruno 			other_oct_slot = pci_get_slot(other_oct->device);
856f173c2b7SSean Bruno 
857f173c2b7SSean Bruno 			if (oct_slot == other_oct_slot)
858f173c2b7SSean Bruno 				return (other_oct);
859f173c2b7SSean Bruno 		}
860f173c2b7SSean Bruno 	}
861f173c2b7SSean Bruno 	return (NULL);
862f173c2b7SSean Bruno }
863f173c2b7SSean Bruno 
864f173c2b7SSean Bruno /*
865f173c2b7SSean Bruno  * \brief Load firmware to device
866f173c2b7SSean Bruno  * @param oct octeon device
867f173c2b7SSean Bruno  *
868f173c2b7SSean Bruno  * Maps device to firmware filename, requests firmware, and downloads it
869f173c2b7SSean Bruno  */
870f173c2b7SSean Bruno static int
871f173c2b7SSean Bruno lio_load_firmware(struct octeon_device *oct)
872f173c2b7SSean Bruno {
873f173c2b7SSean Bruno 	const struct firmware	*fw;
874f173c2b7SSean Bruno 	char	*tmp_fw_type = NULL;
875f173c2b7SSean Bruno 	int	ret = 0;
876f173c2b7SSean Bruno 	char	fw_name[LIO_MAX_FW_FILENAME_LEN];
877f173c2b7SSean Bruno 
878f173c2b7SSean Bruno 	if (fw_type[0] == '\0')
879f173c2b7SSean Bruno 		tmp_fw_type = LIO_FW_NAME_TYPE_NIC;
880f173c2b7SSean Bruno 	else
881f173c2b7SSean Bruno 		tmp_fw_type = fw_type;
882f173c2b7SSean Bruno 
883f173c2b7SSean Bruno 	sprintf(fw_name, "%s%s_%s%s", LIO_FW_BASE_NAME,
884f173c2b7SSean Bruno 		lio_get_conf(oct)->card_name, tmp_fw_type, LIO_FW_NAME_SUFFIX);
885f173c2b7SSean Bruno 
886f173c2b7SSean Bruno 	fw = firmware_get(fw_name);
887f173c2b7SSean Bruno 	if (fw == NULL) {
888f173c2b7SSean Bruno 		lio_dev_err(oct, "Request firmware failed. Could not find file %s.\n",
889f173c2b7SSean Bruno 			    fw_name);
890f173c2b7SSean Bruno 		return (EINVAL);
891f173c2b7SSean Bruno 	}
892f173c2b7SSean Bruno 
893f173c2b7SSean Bruno 	ret = lio_download_firmware(oct, fw->data, fw->datasize);
894f173c2b7SSean Bruno 
895f173c2b7SSean Bruno 	firmware_put(fw, FIRMWARE_UNLOAD);
896f173c2b7SSean Bruno 
897f173c2b7SSean Bruno 	return (ret);
898f173c2b7SSean Bruno }
899f173c2b7SSean Bruno 
900f173c2b7SSean Bruno static int
901f173c2b7SSean Bruno lio_nic_starter(struct octeon_device *oct)
902f173c2b7SSean Bruno {
903f173c2b7SSean Bruno 	int	ret = 0;
904f173c2b7SSean Bruno 
905f173c2b7SSean Bruno 	atomic_store_rel_int(&oct->status, LIO_DEV_RUNNING);
906f173c2b7SSean Bruno 
907f173c2b7SSean Bruno 	if (oct->app_mode && oct->app_mode == LIO_DRV_NIC_APP) {
908f173c2b7SSean Bruno 		if (lio_init_nic_module(oct)) {
909f173c2b7SSean Bruno 			lio_dev_err(oct, "NIC initialization failed\n");
910f173c2b7SSean Bruno 			ret = -1;
911f173c2b7SSean Bruno #ifdef CAVIUM_ONiLY_23XX_VF
912f173c2b7SSean Bruno 		} else {
913f173c2b7SSean Bruno 			if (octeon_enable_sriov(oct) < 0)
914f173c2b7SSean Bruno 				ret = -1;
915f173c2b7SSean Bruno #endif
916f173c2b7SSean Bruno 		}
917f173c2b7SSean Bruno 	} else {
918f173c2b7SSean Bruno 		lio_dev_err(oct,
919f173c2b7SSean Bruno 			    "Unexpected application running on NIC (%d). Check firmware.\n",
920f173c2b7SSean Bruno 			    oct->app_mode);
921f173c2b7SSean Bruno 		ret = -1;
922f173c2b7SSean Bruno 	}
923f173c2b7SSean Bruno 
924f173c2b7SSean Bruno 	return (ret);
925f173c2b7SSean Bruno }
926f173c2b7SSean Bruno 
927f173c2b7SSean Bruno static int
928f173c2b7SSean Bruno lio_init_nic_module(struct octeon_device *oct)
929f173c2b7SSean Bruno {
930f173c2b7SSean Bruno 	int	num_nic_ports = LIO_GET_NUM_NIC_PORTS_CFG(lio_get_conf(oct));
931f173c2b7SSean Bruno 	int	retval = 0;
932f173c2b7SSean Bruno 
933f173c2b7SSean Bruno 	lio_dev_dbg(oct, "Initializing network interfaces\n");
934f173c2b7SSean Bruno 
935f173c2b7SSean Bruno 	/*
936f173c2b7SSean Bruno 	 * only default iq and oq were initialized
937f173c2b7SSean Bruno 	 * initialize the rest as well
938f173c2b7SSean Bruno 	 */
939f173c2b7SSean Bruno 
940f173c2b7SSean Bruno 	/* run port_config command for each port */
941f173c2b7SSean Bruno 	oct->ifcount = num_nic_ports;
942f173c2b7SSean Bruno 
943f173c2b7SSean Bruno 	bzero(&oct->props, sizeof(struct lio_if_props));
944f173c2b7SSean Bruno 
945f173c2b7SSean Bruno 	oct->props.gmxport = -1;
946f173c2b7SSean Bruno 
947f173c2b7SSean Bruno 	retval = lio_setup_nic_devices(oct);
948f173c2b7SSean Bruno 	if (retval) {
949f173c2b7SSean Bruno 		lio_dev_err(oct, "Setup NIC devices failed\n");
950f173c2b7SSean Bruno 		goto lio_init_failure;
951f173c2b7SSean Bruno 	}
952f173c2b7SSean Bruno 
953f173c2b7SSean Bruno 	lio_dev_dbg(oct, "Network interfaces ready\n");
954f173c2b7SSean Bruno 
955f173c2b7SSean Bruno 	return (retval);
956f173c2b7SSean Bruno 
957f173c2b7SSean Bruno lio_init_failure:
958f173c2b7SSean Bruno 
959f173c2b7SSean Bruno 	oct->ifcount = 0;
960f173c2b7SSean Bruno 
961f173c2b7SSean Bruno 	return (retval);
962f173c2b7SSean Bruno }
963f173c2b7SSean Bruno 
964f173c2b7SSean Bruno static int
9652c50292dSJustin Hibbits lio_ifmedia_update(if_t ifp)
966f173c2b7SSean Bruno {
967f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
968f173c2b7SSean Bruno 	struct ifmedia	*ifm;
969f173c2b7SSean Bruno 
970f173c2b7SSean Bruno 	ifm = &lio->ifmedia;
971f173c2b7SSean Bruno 
972f173c2b7SSean Bruno 	/* We only support Ethernet media type. */
973f173c2b7SSean Bruno 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
974f173c2b7SSean Bruno 		return (EINVAL);
975f173c2b7SSean Bruno 
976f173c2b7SSean Bruno 	switch (IFM_SUBTYPE(ifm->ifm_media)) {
977f173c2b7SSean Bruno 	case IFM_AUTO:
978f173c2b7SSean Bruno 		break;
979f173c2b7SSean Bruno 	case IFM_10G_CX4:
980f173c2b7SSean Bruno 	case IFM_10G_SR:
981f173c2b7SSean Bruno 	case IFM_10G_T:
982f173c2b7SSean Bruno 	case IFM_10G_TWINAX:
983f173c2b7SSean Bruno 	default:
984f173c2b7SSean Bruno 		/* We don't support changing the media type. */
985f173c2b7SSean Bruno 		lio_dev_err(lio->oct_dev, "Invalid media type (%d)\n",
986f173c2b7SSean Bruno 			    IFM_SUBTYPE(ifm->ifm_media));
987f173c2b7SSean Bruno 		return (EINVAL);
988f173c2b7SSean Bruno 	}
989f173c2b7SSean Bruno 
990f173c2b7SSean Bruno 	return (0);
991f173c2b7SSean Bruno }
992f173c2b7SSean Bruno 
993f173c2b7SSean Bruno static int
994f173c2b7SSean Bruno lio_get_media_subtype(struct octeon_device *oct)
995f173c2b7SSean Bruno {
996f173c2b7SSean Bruno 
997f173c2b7SSean Bruno 	switch(oct->subdevice_id) {
998f173c2b7SSean Bruno 	case LIO_CN2350_10G_SUBDEVICE:
999f173c2b7SSean Bruno 	case LIO_CN2350_10G_SUBDEVICE1:
1000f173c2b7SSean Bruno 	case LIO_CN2360_10G_SUBDEVICE:
1001f173c2b7SSean Bruno 		return (IFM_10G_SR);
1002f173c2b7SSean Bruno 
1003f173c2b7SSean Bruno 	case LIO_CN2350_25G_SUBDEVICE:
1004f173c2b7SSean Bruno 	case LIO_CN2360_25G_SUBDEVICE:
1005f173c2b7SSean Bruno 		return (IFM_25G_SR);
1006f173c2b7SSean Bruno 	}
1007f173c2b7SSean Bruno 
1008f173c2b7SSean Bruno 	return (IFM_10G_SR);
1009f173c2b7SSean Bruno }
1010f173c2b7SSean Bruno 
10113de0952fSSean Bruno static uint64_t
1012f173c2b7SSean Bruno lio_get_baudrate(struct octeon_device *oct)
1013f173c2b7SSean Bruno {
1014f173c2b7SSean Bruno 
1015f173c2b7SSean Bruno 	switch(oct->subdevice_id) {
1016f173c2b7SSean Bruno 	case LIO_CN2350_10G_SUBDEVICE:
1017f173c2b7SSean Bruno 	case LIO_CN2350_10G_SUBDEVICE1:
1018f173c2b7SSean Bruno 	case LIO_CN2360_10G_SUBDEVICE:
1019f173c2b7SSean Bruno 		return (IF_Gbps(10));
1020f173c2b7SSean Bruno 
1021f173c2b7SSean Bruno 	case LIO_CN2350_25G_SUBDEVICE:
1022f173c2b7SSean Bruno 	case LIO_CN2360_25G_SUBDEVICE:
1023f173c2b7SSean Bruno 		return (IF_Gbps(25));
1024f173c2b7SSean Bruno 	}
1025f173c2b7SSean Bruno 
1026f173c2b7SSean Bruno 	return (IF_Gbps(10));
1027f173c2b7SSean Bruno }
1028f173c2b7SSean Bruno 
1029f173c2b7SSean Bruno static void
10302c50292dSJustin Hibbits lio_ifmedia_status(if_t ifp, struct ifmediareq *ifmr)
1031f173c2b7SSean Bruno {
1032f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
1033f173c2b7SSean Bruno 
1034f173c2b7SSean Bruno 	/* Report link down if the driver isn't running. */
1035f173c2b7SSean Bruno 	if (!lio_ifstate_check(lio, LIO_IFSTATE_RUNNING)) {
1036f173c2b7SSean Bruno 		ifmr->ifm_active |= IFM_NONE;
1037f173c2b7SSean Bruno 		return;
1038f173c2b7SSean Bruno 	}
1039f173c2b7SSean Bruno 
1040f173c2b7SSean Bruno 	/* Setup the default interface info. */
1041f173c2b7SSean Bruno 	ifmr->ifm_status = IFM_AVALID;
1042f173c2b7SSean Bruno 	ifmr->ifm_active = IFM_ETHER;
1043f173c2b7SSean Bruno 
1044f173c2b7SSean Bruno 	if (lio->linfo.link.s.link_up) {
1045f173c2b7SSean Bruno 		ifmr->ifm_status |= IFM_ACTIVE;
1046f173c2b7SSean Bruno 	} else {
1047f173c2b7SSean Bruno 		ifmr->ifm_active |= IFM_NONE;
1048f173c2b7SSean Bruno 		return;
1049f173c2b7SSean Bruno 	}
1050f173c2b7SSean Bruno 
1051f173c2b7SSean Bruno 	ifmr->ifm_active |= lio_get_media_subtype(lio->oct_dev);
1052f173c2b7SSean Bruno 
1053f173c2b7SSean Bruno 	if (lio->linfo.link.s.duplex)
1054f173c2b7SSean Bruno 		ifmr->ifm_active |= IFM_FDX;
1055f173c2b7SSean Bruno 	else
1056f173c2b7SSean Bruno 		ifmr->ifm_active |= IFM_HDX;
1057f173c2b7SSean Bruno }
1058f173c2b7SSean Bruno 
1059f173c2b7SSean Bruno static uint64_t
1060f173c2b7SSean Bruno lio_get_counter(if_t ifp, ift_counter cnt)
1061f173c2b7SSean Bruno {
1062f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
1063f173c2b7SSean Bruno 	struct octeon_device	*oct = lio->oct_dev;
1064f173c2b7SSean Bruno 	uint64_t	counter = 0;
1065f173c2b7SSean Bruno 	int		i, q_no;
1066f173c2b7SSean Bruno 
1067f173c2b7SSean Bruno 	switch (cnt) {
1068f173c2b7SSean Bruno 	case IFCOUNTER_IPACKETS:
1069f173c2b7SSean Bruno 		for (i = 0; i < oct->num_oqs; i++) {
1070f173c2b7SSean Bruno 			q_no = lio->linfo.rxpciq[i].s.q_no;
1071f173c2b7SSean Bruno 			counter += oct->droq[q_no]->stats.rx_pkts_received;
1072f173c2b7SSean Bruno 		}
1073f173c2b7SSean Bruno 		break;
1074f173c2b7SSean Bruno 	case IFCOUNTER_OPACKETS:
1075f173c2b7SSean Bruno 		for (i = 0; i < oct->num_iqs; i++) {
1076f173c2b7SSean Bruno 			q_no = lio->linfo.txpciq[i].s.q_no;
1077f173c2b7SSean Bruno 			counter += oct->instr_queue[q_no]->stats.tx_done;
1078f173c2b7SSean Bruno 		}
1079f173c2b7SSean Bruno 		break;
1080f173c2b7SSean Bruno 	case IFCOUNTER_IBYTES:
1081f173c2b7SSean Bruno 		for (i = 0; i < oct->num_oqs; i++) {
1082f173c2b7SSean Bruno 			q_no = lio->linfo.rxpciq[i].s.q_no;
1083f173c2b7SSean Bruno 			counter += oct->droq[q_no]->stats.rx_bytes_received;
1084f173c2b7SSean Bruno 		}
1085f173c2b7SSean Bruno 		break;
1086f173c2b7SSean Bruno 	case IFCOUNTER_OBYTES:
1087f173c2b7SSean Bruno 		for (i = 0; i < oct->num_iqs; i++) {
1088f173c2b7SSean Bruno 			q_no = lio->linfo.txpciq[i].s.q_no;
1089f173c2b7SSean Bruno 			counter += oct->instr_queue[q_no]->stats.tx_tot_bytes;
1090f173c2b7SSean Bruno 		}
1091f173c2b7SSean Bruno 		break;
1092f173c2b7SSean Bruno 	case IFCOUNTER_IQDROPS:
1093f173c2b7SSean Bruno 		for (i = 0; i < oct->num_oqs; i++) {
1094f173c2b7SSean Bruno 			q_no = lio->linfo.rxpciq[i].s.q_no;
1095f173c2b7SSean Bruno 			counter += oct->droq[q_no]->stats.rx_dropped;
1096f173c2b7SSean Bruno 		}
1097f173c2b7SSean Bruno 		break;
1098f173c2b7SSean Bruno 	case IFCOUNTER_OQDROPS:
1099f173c2b7SSean Bruno 		for (i = 0; i < oct->num_iqs; i++) {
1100f173c2b7SSean Bruno 			q_no = lio->linfo.txpciq[i].s.q_no;
1101f173c2b7SSean Bruno 			counter += oct->instr_queue[q_no]->stats.tx_dropped;
1102f173c2b7SSean Bruno 		}
1103f173c2b7SSean Bruno 		break;
1104f173c2b7SSean Bruno 	case IFCOUNTER_IMCASTS:
1105f173c2b7SSean Bruno 		counter = oct->link_stats.fromwire.total_mcst;
1106f173c2b7SSean Bruno 		break;
1107f173c2b7SSean Bruno 	case IFCOUNTER_OMCASTS:
1108f173c2b7SSean Bruno 		counter = oct->link_stats.fromhost.mcast_pkts_sent;
1109f173c2b7SSean Bruno 		break;
1110f173c2b7SSean Bruno 	case IFCOUNTER_COLLISIONS:
1111f173c2b7SSean Bruno 		counter = oct->link_stats.fromhost.total_collisions;
1112f173c2b7SSean Bruno 		break;
1113f173c2b7SSean Bruno 	case IFCOUNTER_IERRORS:
1114f173c2b7SSean Bruno 		counter = oct->link_stats.fromwire.fcs_err +
1115f173c2b7SSean Bruno 		    oct->link_stats.fromwire.l2_err +
1116f173c2b7SSean Bruno 		    oct->link_stats.fromwire.frame_err;
1117f173c2b7SSean Bruno 		break;
1118f173c2b7SSean Bruno 	default:
1119f173c2b7SSean Bruno 		return (if_get_counter_default(ifp, cnt));
1120f173c2b7SSean Bruno 	}
1121f173c2b7SSean Bruno 
1122f173c2b7SSean Bruno 	return (counter);
1123f173c2b7SSean Bruno }
1124f173c2b7SSean Bruno 
1125f173c2b7SSean Bruno static int
1126f173c2b7SSean Bruno lio_init_ifnet(struct lio *lio)
1127f173c2b7SSean Bruno {
1128f173c2b7SSean Bruno 	struct octeon_device	*oct = lio->oct_dev;
1129f173c2b7SSean Bruno 	if_t			ifp = lio->ifp;
1130f173c2b7SSean Bruno 
1131f173c2b7SSean Bruno 	/* ifconfig entrypoint for media type/status reporting */
1132f173c2b7SSean Bruno 	ifmedia_init(&lio->ifmedia, IFM_IMASK, lio_ifmedia_update,
1133f173c2b7SSean Bruno 		     lio_ifmedia_status);
1134f173c2b7SSean Bruno 
1135f173c2b7SSean Bruno 	/* set the default interface values */
1136f173c2b7SSean Bruno 	ifmedia_add(&lio->ifmedia,
1137f173c2b7SSean Bruno 		    (IFM_ETHER | IFM_FDX | lio_get_media_subtype(oct)),
1138f173c2b7SSean Bruno 		    0, NULL);
1139f173c2b7SSean Bruno 	ifmedia_add(&lio->ifmedia, (IFM_ETHER | IFM_AUTO), 0, NULL);
1140f173c2b7SSean Bruno 	ifmedia_set(&lio->ifmedia, (IFM_ETHER | IFM_AUTO));
1141f173c2b7SSean Bruno 
1142f173c2b7SSean Bruno 	lio->ifmedia.ifm_media = lio->ifmedia.ifm_cur->ifm_media;
1143f173c2b7SSean Bruno 	lio_dev_dbg(oct, "IFMEDIA flags : %x\n", lio->ifmedia.ifm_media);
1144f173c2b7SSean Bruno 
1145f173c2b7SSean Bruno 	if_initname(ifp, device_get_name(oct->device),
1146f173c2b7SSean Bruno 		    device_get_unit(oct->device));
1147f173c2b7SSean Bruno 	if_setflags(ifp, (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST));
1148f173c2b7SSean Bruno 	if_setioctlfn(ifp, lio_ioctl);
1149f173c2b7SSean Bruno 	if_setgetcounterfn(ifp, lio_get_counter);
1150f173c2b7SSean Bruno 	if_settransmitfn(ifp, lio_mq_start);
1151f173c2b7SSean Bruno 	if_setqflushfn(ifp, lio_qflush);
1152f173c2b7SSean Bruno 	if_setinitfn(ifp, lio_open);
1153f173c2b7SSean Bruno 	if_setmtu(ifp, lio->linfo.link.s.mtu);
1154f173c2b7SSean Bruno 	lio->mtu = lio->linfo.link.s.mtu;
1155f173c2b7SSean Bruno 	if_sethwassist(ifp, (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO |
1156f173c2b7SSean Bruno 			     CSUM_TCP_IPV6 | CSUM_UDP_IPV6));
1157f173c2b7SSean Bruno 
1158f173c2b7SSean Bruno 	if_setcapabilitiesbit(ifp, (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 |
1159f173c2b7SSean Bruno 				    IFCAP_TSO | IFCAP_LRO |
1160f173c2b7SSean Bruno 				    IFCAP_JUMBO_MTU | IFCAP_HWSTATS |
1161f173c2b7SSean Bruno 				    IFCAP_LINKSTATE | IFCAP_VLAN_HWFILTER |
1162f173c2b7SSean Bruno 				    IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTAGGING |
1163f173c2b7SSean Bruno 				    IFCAP_VLAN_HWTSO | IFCAP_VLAN_MTU), 0);
1164f173c2b7SSean Bruno 
1165f173c2b7SSean Bruno 	if_setcapenable(ifp, if_getcapabilities(ifp));
1166f173c2b7SSean Bruno 	if_setbaudrate(ifp, lio_get_baudrate(oct));
1167f173c2b7SSean Bruno 
1168f173c2b7SSean Bruno 	return (0);
1169f173c2b7SSean Bruno }
1170f173c2b7SSean Bruno 
1171f173c2b7SSean Bruno static void
11722c50292dSJustin Hibbits lio_tcp_lro_free(struct octeon_device *octeon_dev, if_t ifp)
1173f173c2b7SSean Bruno {
1174f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
1175f173c2b7SSean Bruno 	struct lio_droq	*droq;
1176f173c2b7SSean Bruno 	int		q_no;
1177f173c2b7SSean Bruno 	int		i;
1178f173c2b7SSean Bruno 
1179f173c2b7SSean Bruno 	for (i = 0; i < octeon_dev->num_oqs; i++) {
1180f173c2b7SSean Bruno 		q_no = lio->linfo.rxpciq[i].s.q_no;
1181f173c2b7SSean Bruno 		droq = octeon_dev->droq[q_no];
1182f173c2b7SSean Bruno 		if (droq->lro.ifp) {
1183f173c2b7SSean Bruno 			tcp_lro_free(&droq->lro);
1184f173c2b7SSean Bruno 			droq->lro.ifp = NULL;
1185f173c2b7SSean Bruno 		}
1186f173c2b7SSean Bruno 	}
1187f173c2b7SSean Bruno }
1188f173c2b7SSean Bruno 
1189f173c2b7SSean Bruno static int
11902c50292dSJustin Hibbits lio_tcp_lro_init(struct octeon_device *octeon_dev, if_t ifp)
1191f173c2b7SSean Bruno {
1192f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
1193f173c2b7SSean Bruno 	struct lio_droq	*droq;
1194f173c2b7SSean Bruno 	struct lro_ctrl	*lro;
1195f173c2b7SSean Bruno 	int		i, q_no, ret = 0;
1196f173c2b7SSean Bruno 
1197f173c2b7SSean Bruno 	for (i = 0; i < octeon_dev->num_oqs; i++) {
1198f173c2b7SSean Bruno 		q_no = lio->linfo.rxpciq[i].s.q_no;
1199f173c2b7SSean Bruno 		droq = octeon_dev->droq[q_no];
1200f173c2b7SSean Bruno 		lro = &droq->lro;
1201f173c2b7SSean Bruno 		ret = tcp_lro_init(lro);
1202f173c2b7SSean Bruno 		if (ret) {
1203f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "LRO Initialization failed ret %d\n",
1204f173c2b7SSean Bruno 				    ret);
1205f173c2b7SSean Bruno 			goto lro_init_failed;
1206f173c2b7SSean Bruno 		}
1207f173c2b7SSean Bruno 
1208f173c2b7SSean Bruno 		lro->ifp = ifp;
1209f173c2b7SSean Bruno 	}
1210f173c2b7SSean Bruno 
1211f173c2b7SSean Bruno 	return (ret);
1212f173c2b7SSean Bruno 
1213f173c2b7SSean Bruno lro_init_failed:
1214f173c2b7SSean Bruno 	lio_tcp_lro_free(octeon_dev, ifp);
1215f173c2b7SSean Bruno 
1216f173c2b7SSean Bruno 	return (ret);
1217f173c2b7SSean Bruno }
1218f173c2b7SSean Bruno 
1219f173c2b7SSean Bruno static int
1220f173c2b7SSean Bruno lio_setup_nic_devices(struct octeon_device *octeon_dev)
1221f173c2b7SSean Bruno {
1222f173c2b7SSean Bruno 	union		octeon_if_cfg if_cfg;
1223f173c2b7SSean Bruno 	struct lio	*lio = NULL;
12242c50292dSJustin Hibbits 	if_t		ifp = NULL;
1225f173c2b7SSean Bruno 	struct lio_version		*vdata;
1226f173c2b7SSean Bruno 	struct lio_soft_command		*sc;
1227f173c2b7SSean Bruno 	struct lio_if_cfg_context	*ctx;
1228f173c2b7SSean Bruno 	struct lio_if_cfg_resp		*resp;
1229f173c2b7SSean Bruno 	struct lio_if_props		*props;
1230f173c2b7SSean Bruno 	int		num_iqueues, num_oqueues, retval;
1231f173c2b7SSean Bruno 	unsigned int	base_queue;
1232f173c2b7SSean Bruno 	unsigned int	gmx_port_id;
1233f173c2b7SSean Bruno 	uint32_t	ctx_size, data_size;
1234f173c2b7SSean Bruno 	uint32_t	ifidx_or_pfnum, resp_size;
1235f173c2b7SSean Bruno 	uint8_t		mac[ETHER_HDR_LEN], i, j;
1236f173c2b7SSean Bruno 
1237f173c2b7SSean Bruno 	/* This is to handle link status changes */
1238f173c2b7SSean Bruno 	lio_register_dispatch_fn(octeon_dev, LIO_OPCODE_NIC,
1239f173c2b7SSean Bruno 				 LIO_OPCODE_NIC_INFO,
1240f173c2b7SSean Bruno 				 lio_link_info, octeon_dev);
1241f173c2b7SSean Bruno 
1242f173c2b7SSean Bruno 	for (i = 0; i < octeon_dev->ifcount; i++) {
1243f173c2b7SSean Bruno 		resp_size = sizeof(struct lio_if_cfg_resp);
1244f173c2b7SSean Bruno 		ctx_size = sizeof(struct lio_if_cfg_context);
1245f173c2b7SSean Bruno 		data_size = sizeof(struct lio_version);
1246f173c2b7SSean Bruno 		sc = lio_alloc_soft_command(octeon_dev, data_size, resp_size,
1247f173c2b7SSean Bruno 					    ctx_size);
1248f173c2b7SSean Bruno 		if (sc == NULL)
1249f173c2b7SSean Bruno 			return (ENOMEM);
1250f173c2b7SSean Bruno 
1251f173c2b7SSean Bruno 		resp = (struct lio_if_cfg_resp *)sc->virtrptr;
1252f173c2b7SSean Bruno 		ctx = (struct lio_if_cfg_context *)sc->ctxptr;
1253f173c2b7SSean Bruno 		vdata = (struct lio_version *)sc->virtdptr;
1254f173c2b7SSean Bruno 
1255f173c2b7SSean Bruno 		*((uint64_t *)vdata) = 0;
1256f173c2b7SSean Bruno 		vdata->major = htobe16(LIO_BASE_MAJOR_VERSION);
1257f173c2b7SSean Bruno 		vdata->minor = htobe16(LIO_BASE_MINOR_VERSION);
1258f173c2b7SSean Bruno 		vdata->micro = htobe16(LIO_BASE_MICRO_VERSION);
1259f173c2b7SSean Bruno 
1260f173c2b7SSean Bruno 		num_iqueues = octeon_dev->sriov_info.num_pf_rings;
1261f173c2b7SSean Bruno 		num_oqueues = octeon_dev->sriov_info.num_pf_rings;
1262f173c2b7SSean Bruno 		base_queue = octeon_dev->sriov_info.pf_srn;
1263f173c2b7SSean Bruno 
1264f173c2b7SSean Bruno 		gmx_port_id = octeon_dev->pf_num;
1265f173c2b7SSean Bruno 		ifidx_or_pfnum = octeon_dev->pf_num;
1266f173c2b7SSean Bruno 
1267f173c2b7SSean Bruno 		lio_dev_dbg(octeon_dev, "requesting config for interface %d, iqs %d, oqs %d\n",
1268f173c2b7SSean Bruno 			    ifidx_or_pfnum, num_iqueues, num_oqueues);
1269f173c2b7SSean Bruno 		ctx->cond = 0;
1270f173c2b7SSean Bruno 		ctx->octeon_id = lio_get_device_id(octeon_dev);
1271f173c2b7SSean Bruno 
1272f173c2b7SSean Bruno 		if_cfg.if_cfg64 = 0;
1273f173c2b7SSean Bruno 		if_cfg.s.num_iqueues = num_iqueues;
1274f173c2b7SSean Bruno 		if_cfg.s.num_oqueues = num_oqueues;
1275f173c2b7SSean Bruno 		if_cfg.s.base_queue = base_queue;
1276f173c2b7SSean Bruno 		if_cfg.s.gmx_port_id = gmx_port_id;
1277f173c2b7SSean Bruno 
1278f173c2b7SSean Bruno 		sc->iq_no = 0;
1279f173c2b7SSean Bruno 
1280f173c2b7SSean Bruno 		lio_prepare_soft_command(octeon_dev, sc, LIO_OPCODE_NIC,
1281f173c2b7SSean Bruno 					 LIO_OPCODE_NIC_IF_CFG, 0,
1282f173c2b7SSean Bruno 					 if_cfg.if_cfg64, 0);
1283f173c2b7SSean Bruno 
1284f173c2b7SSean Bruno 		sc->callback = lio_if_cfg_callback;
1285f173c2b7SSean Bruno 		sc->callback_arg = sc;
1286f173c2b7SSean Bruno 		sc->wait_time = 3000;
1287f173c2b7SSean Bruno 
1288f173c2b7SSean Bruno 		retval = lio_send_soft_command(octeon_dev, sc);
1289f173c2b7SSean Bruno 		if (retval == LIO_IQ_SEND_FAILED) {
1290f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "iq/oq config failed status: %x\n",
1291f173c2b7SSean Bruno 				    retval);
1292f173c2b7SSean Bruno 			/* Soft instr is freed by driver in case of failure. */
1293f173c2b7SSean Bruno 			goto setup_nic_dev_fail;
1294f173c2b7SSean Bruno 		}
1295f173c2b7SSean Bruno 
1296f173c2b7SSean Bruno 		/*
1297f173c2b7SSean Bruno 		 * Sleep on a wait queue till the cond flag indicates that the
1298f173c2b7SSean Bruno 		 * response arrived or timed-out.
1299f173c2b7SSean Bruno 		 */
1300f173c2b7SSean Bruno 		lio_sleep_cond(octeon_dev, &ctx->cond);
1301f173c2b7SSean Bruno 
1302f173c2b7SSean Bruno 		retval = resp->status;
1303f173c2b7SSean Bruno 		if (retval) {
1304f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "iq/oq config failed\n");
1305f173c2b7SSean Bruno 			goto setup_nic_dev_fail;
1306f173c2b7SSean Bruno 		}
1307f173c2b7SSean Bruno 
1308f173c2b7SSean Bruno 		lio_swap_8B_data((uint64_t *)(&resp->cfg_info),
1309f173c2b7SSean Bruno 				 (sizeof(struct octeon_if_cfg_info)) >> 3);
1310f173c2b7SSean Bruno 
1311f173c2b7SSean Bruno 		num_iqueues = bitcount64(resp->cfg_info.iqmask);
1312f173c2b7SSean Bruno 		num_oqueues = bitcount64(resp->cfg_info.oqmask);
1313f173c2b7SSean Bruno 
1314f173c2b7SSean Bruno 		if (!(num_iqueues) || !(num_oqueues)) {
1315f173c2b7SSean Bruno 			lio_dev_err(octeon_dev,
13163de0952fSSean Bruno 				    "Got bad iqueues (%016llX) or oqueues (%016llX) from firmware.\n",
13173de0952fSSean Bruno 				    LIO_CAST64(resp->cfg_info.iqmask),
13183de0952fSSean Bruno 				    LIO_CAST64(resp->cfg_info.oqmask));
1319f173c2b7SSean Bruno 			goto setup_nic_dev_fail;
1320f173c2b7SSean Bruno 		}
1321f173c2b7SSean Bruno 
1322f173c2b7SSean Bruno 		lio_dev_dbg(octeon_dev,
13233de0952fSSean Bruno 			    "interface %d, iqmask %016llx, oqmask %016llx, numiqueues %d, numoqueues %d\n",
13243de0952fSSean Bruno 			    i, LIO_CAST64(resp->cfg_info.iqmask),
13253de0952fSSean Bruno 			    LIO_CAST64(resp->cfg_info.oqmask),
1326f173c2b7SSean Bruno 			    num_iqueues, num_oqueues);
1327f173c2b7SSean Bruno 
1328f173c2b7SSean Bruno 		ifp = if_alloc(IFT_ETHER);
1329f173c2b7SSean Bruno 
1330f173c2b7SSean Bruno 		lio = malloc(sizeof(struct lio), M_DEVBUF, M_NOWAIT | M_ZERO);
1331f173c2b7SSean Bruno 
1332f173c2b7SSean Bruno 		if (lio == NULL) {
1333f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "Lio allocation failed\n");
1334f173c2b7SSean Bruno 			goto setup_nic_dev_fail;
1335f173c2b7SSean Bruno 		}
1336f173c2b7SSean Bruno 
1337f173c2b7SSean Bruno 		if_setsoftc(ifp, lio);
1338f173c2b7SSean Bruno 
13392c50292dSJustin Hibbits 		if_sethwtsomax(ifp, LIO_MAX_FRAME_SIZE);
13402c50292dSJustin Hibbits 		if_sethwtsomaxsegcount(ifp, LIO_MAX_SG);
13412c50292dSJustin Hibbits 		if_sethwtsomaxsegsize(ifp, PAGE_SIZE);
1342f173c2b7SSean Bruno 
1343f173c2b7SSean Bruno 		lio->ifidx = ifidx_or_pfnum;
1344f173c2b7SSean Bruno 
1345f173c2b7SSean Bruno 		props = &octeon_dev->props;
1346f173c2b7SSean Bruno 		props->gmxport = resp->cfg_info.linfo.gmxport;
1347f173c2b7SSean Bruno 		props->ifp = ifp;
1348f173c2b7SSean Bruno 
1349f173c2b7SSean Bruno 		lio->linfo.num_rxpciq = num_oqueues;
1350f173c2b7SSean Bruno 		lio->linfo.num_txpciq = num_iqueues;
1351f173c2b7SSean Bruno 		for (j = 0; j < num_oqueues; j++) {
1352f173c2b7SSean Bruno 			lio->linfo.rxpciq[j].rxpciq64 =
1353f173c2b7SSean Bruno 			    resp->cfg_info.linfo.rxpciq[j].rxpciq64;
1354f173c2b7SSean Bruno 		}
1355f173c2b7SSean Bruno 
1356f173c2b7SSean Bruno 		for (j = 0; j < num_iqueues; j++) {
1357f173c2b7SSean Bruno 			lio->linfo.txpciq[j].txpciq64 =
1358f173c2b7SSean Bruno 			    resp->cfg_info.linfo.txpciq[j].txpciq64;
1359f173c2b7SSean Bruno 		}
1360f173c2b7SSean Bruno 
1361f173c2b7SSean Bruno 		lio->linfo.hw_addr = resp->cfg_info.linfo.hw_addr;
1362f173c2b7SSean Bruno 		lio->linfo.gmxport = resp->cfg_info.linfo.gmxport;
1363f173c2b7SSean Bruno 		lio->linfo.link.link_status64 =
1364f173c2b7SSean Bruno 		    resp->cfg_info.linfo.link.link_status64;
1365f173c2b7SSean Bruno 
1366f173c2b7SSean Bruno 		/*
1367f173c2b7SSean Bruno 		 * Point to the properties for octeon device to which this
1368f173c2b7SSean Bruno 		 * interface belongs.
1369f173c2b7SSean Bruno 		 */
1370f173c2b7SSean Bruno 		lio->oct_dev = octeon_dev;
1371f173c2b7SSean Bruno 		lio->ifp = ifp;
1372f173c2b7SSean Bruno 
1373f173c2b7SSean Bruno 		lio_dev_dbg(octeon_dev, "if%d gmx: %d hw_addr: 0x%llx\n", i,
1374f173c2b7SSean Bruno 			    lio->linfo.gmxport, LIO_CAST64(lio->linfo.hw_addr));
1375f173c2b7SSean Bruno 		lio_init_ifnet(lio);
1376f173c2b7SSean Bruno 		/* 64-bit swap required on LE machines */
1377f173c2b7SSean Bruno 		lio_swap_8B_data(&lio->linfo.hw_addr, 1);
1378f173c2b7SSean Bruno 		for (j = 0; j < 6; j++)
1379f173c2b7SSean Bruno 			mac[j] = *((uint8_t *)(
1380f173c2b7SSean Bruno 				   ((uint8_t *)&lio->linfo.hw_addr) + 2 + j));
1381f173c2b7SSean Bruno 
1382f173c2b7SSean Bruno 		ether_ifattach(ifp, mac);
1383f173c2b7SSean Bruno 
1384f173c2b7SSean Bruno 		/*
1385f173c2b7SSean Bruno 		 * By default all interfaces on a single Octeon uses the same
1386f173c2b7SSean Bruno 		 * tx and rx queues
1387f173c2b7SSean Bruno 		 */
1388f173c2b7SSean Bruno 		lio->txq = lio->linfo.txpciq[0].s.q_no;
1389f173c2b7SSean Bruno 		lio->rxq = lio->linfo.rxpciq[0].s.q_no;
1390f173c2b7SSean Bruno 		if (lio_setup_io_queues(octeon_dev, i, lio->linfo.num_txpciq,
1391f173c2b7SSean Bruno 					lio->linfo.num_rxpciq)) {
1392f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "I/O queues creation failed\n");
1393f173c2b7SSean Bruno 			goto setup_nic_dev_fail;
1394f173c2b7SSean Bruno 		}
1395f173c2b7SSean Bruno 
1396f173c2b7SSean Bruno 		lio_ifstate_set(lio, LIO_IFSTATE_DROQ_OPS);
1397f173c2b7SSean Bruno 
1398f173c2b7SSean Bruno 		lio->tx_qsize = lio_get_tx_qsize(octeon_dev, lio->txq);
1399f173c2b7SSean Bruno 		lio->rx_qsize = lio_get_rx_qsize(octeon_dev, lio->rxq);
1400f173c2b7SSean Bruno 
1401f173c2b7SSean Bruno 		if (lio_setup_glists(octeon_dev, lio, num_iqueues)) {
1402f173c2b7SSean Bruno 			lio_dev_err(octeon_dev, "Gather list allocation failed\n");
1403f173c2b7SSean Bruno 			goto setup_nic_dev_fail;
1404f173c2b7SSean Bruno 		}
1405f173c2b7SSean Bruno 
1406f173c2b7SSean Bruno 		if ((lio_hwlro == 0) && lio_tcp_lro_init(octeon_dev, ifp))
1407f173c2b7SSean Bruno 			goto setup_nic_dev_fail;
1408f173c2b7SSean Bruno 
1409f173c2b7SSean Bruno 		if (lio_hwlro &&
1410f173c2b7SSean Bruno 		    (if_getcapenable(ifp) & IFCAP_LRO) &&
1411f173c2b7SSean Bruno 		    (if_getcapenable(ifp) & IFCAP_RXCSUM) &&
1412f173c2b7SSean Bruno 		    (if_getcapenable(ifp) & IFCAP_RXCSUM_IPV6))
1413f173c2b7SSean Bruno 			lio_set_feature(ifp, LIO_CMD_LRO_ENABLE,
1414f173c2b7SSean Bruno 					LIO_LROIPV4 | LIO_LROIPV6);
1415f173c2b7SSean Bruno 
1416f173c2b7SSean Bruno 		if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER))
1417f173c2b7SSean Bruno 			lio_set_feature(ifp, LIO_CMD_VLAN_FILTER_CTL, 1);
1418f173c2b7SSean Bruno 		else
1419f173c2b7SSean Bruno 			lio_set_feature(ifp, LIO_CMD_VLAN_FILTER_CTL, 0);
1420f173c2b7SSean Bruno 
1421f173c2b7SSean Bruno 		if (lio_setup_rx_oom_poll_fn(ifp))
1422f173c2b7SSean Bruno 			goto setup_nic_dev_fail;
1423f173c2b7SSean Bruno 
1424f173c2b7SSean Bruno 		lio_dev_dbg(octeon_dev, "Setup NIC ifidx:%d mac:%02x%02x%02x%02x%02x%02x\n",
1425f173c2b7SSean Bruno 			    i, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1426f173c2b7SSean Bruno 		lio->link_changes++;
1427f173c2b7SSean Bruno 
1428f173c2b7SSean Bruno 		lio_ifstate_set(lio, LIO_IFSTATE_REGISTERED);
1429f173c2b7SSean Bruno 
1430f173c2b7SSean Bruno 		/*
1431f173c2b7SSean Bruno 		 * Sending command to firmware to enable Rx checksum offload
1432f173c2b7SSean Bruno 		 * by default at the time of setup of Liquidio driver for
1433f173c2b7SSean Bruno 		 * this device
1434f173c2b7SSean Bruno 		 */
1435f173c2b7SSean Bruno 		lio_set_rxcsum_command(ifp, LIO_CMD_TNL_RX_CSUM_CTL,
1436f173c2b7SSean Bruno 				       LIO_CMD_RXCSUM_ENABLE);
1437f173c2b7SSean Bruno 		lio_set_feature(ifp, LIO_CMD_TNL_TX_CSUM_CTL,
1438f173c2b7SSean Bruno 				LIO_CMD_TXCSUM_ENABLE);
1439f173c2b7SSean Bruno 
1440f173c2b7SSean Bruno #ifdef RSS
1441f173c2b7SSean Bruno 		if (lio_rss) {
1442f173c2b7SSean Bruno 			if (lio_send_rss_param(lio))
1443f173c2b7SSean Bruno 				goto setup_nic_dev_fail;
1444f173c2b7SSean Bruno 		} else
1445f173c2b7SSean Bruno #endif	/* RSS */
1446f173c2b7SSean Bruno 
1447f173c2b7SSean Bruno 			lio_set_feature(ifp, LIO_CMD_SET_FNV,
1448f173c2b7SSean Bruno 					LIO_CMD_FNV_ENABLE);
1449f173c2b7SSean Bruno 
1450f173c2b7SSean Bruno 		lio_dev_dbg(octeon_dev, "NIC ifidx:%d Setup successful\n", i);
1451f173c2b7SSean Bruno 
1452f173c2b7SSean Bruno 		lio_free_soft_command(octeon_dev, sc);
1453f173c2b7SSean Bruno 		lio->vlan_attach =
1454f173c2b7SSean Bruno 		    EVENTHANDLER_REGISTER(vlan_config,
1455f173c2b7SSean Bruno 					  lio_vlan_rx_add_vid, lio,
1456f173c2b7SSean Bruno 					  EVENTHANDLER_PRI_FIRST);
1457f173c2b7SSean Bruno 		lio->vlan_detach =
1458f173c2b7SSean Bruno 		    EVENTHANDLER_REGISTER(vlan_unconfig,
1459f173c2b7SSean Bruno 					  lio_vlan_rx_kill_vid, lio,
1460f173c2b7SSean Bruno 					  EVENTHANDLER_PRI_FIRST);
1461f173c2b7SSean Bruno 
1462f173c2b7SSean Bruno 		/* Update stats periodically */
1463f173c2b7SSean Bruno 		callout_init(&lio->stats_timer, 0);
1464f173c2b7SSean Bruno 		lio->stats_interval = LIO_DEFAULT_STATS_INTERVAL;
1465f173c2b7SSean Bruno 
1466f173c2b7SSean Bruno 		lio_add_hw_stats(lio);
1467f173c2b7SSean Bruno 	}
1468f173c2b7SSean Bruno 
1469f173c2b7SSean Bruno 	return (0);
1470f173c2b7SSean Bruno 
1471f173c2b7SSean Bruno setup_nic_dev_fail:
1472f173c2b7SSean Bruno 
1473f173c2b7SSean Bruno 	lio_free_soft_command(octeon_dev, sc);
1474f173c2b7SSean Bruno 
1475f173c2b7SSean Bruno 	while (i--) {
1476f173c2b7SSean Bruno 		lio_dev_err(octeon_dev, "NIC ifidx:%d Setup failed\n", i);
1477f173c2b7SSean Bruno 		lio_destroy_nic_device(octeon_dev, i);
1478f173c2b7SSean Bruno 	}
1479f173c2b7SSean Bruno 
1480f173c2b7SSean Bruno 	return (ENODEV);
1481f173c2b7SSean Bruno }
1482f173c2b7SSean Bruno 
1483f173c2b7SSean Bruno static int
1484f173c2b7SSean Bruno lio_link_info(struct lio_recv_info *recv_info, void *ptr)
1485f173c2b7SSean Bruno {
1486f173c2b7SSean Bruno 	struct octeon_device	*oct = (struct octeon_device *)ptr;
1487f173c2b7SSean Bruno 	struct lio_recv_pkt	*recv_pkt = recv_info->recv_pkt;
1488f173c2b7SSean Bruno 	union octeon_link_status *ls;
1489f173c2b7SSean Bruno 	int	gmxport = 0, i;
1490f173c2b7SSean Bruno 
1491f173c2b7SSean Bruno 	lio_dev_dbg(oct, "%s Called\n", __func__);
1492f173c2b7SSean Bruno 	if (recv_pkt->buffer_size[0] != (sizeof(*ls) + LIO_DROQ_INFO_SIZE)) {
1493f173c2b7SSean Bruno 		lio_dev_err(oct, "Malformed NIC_INFO, len=%d, ifidx=%d\n",
1494f173c2b7SSean Bruno 			    recv_pkt->buffer_size[0],
1495f173c2b7SSean Bruno 			    recv_pkt->rh.r_nic_info.gmxport);
1496f173c2b7SSean Bruno 		goto nic_info_err;
1497f173c2b7SSean Bruno 	}
1498f173c2b7SSean Bruno 	gmxport = recv_pkt->rh.r_nic_info.gmxport;
1499f173c2b7SSean Bruno 	ls = (union octeon_link_status *)(recv_pkt->buffer_ptr[0]->m_data +
1500f173c2b7SSean Bruno 					  LIO_DROQ_INFO_SIZE);
1501f173c2b7SSean Bruno 	lio_swap_8B_data((uint64_t *)ls,
1502f173c2b7SSean Bruno 			 (sizeof(union octeon_link_status)) >> 3);
1503f173c2b7SSean Bruno 
1504f173c2b7SSean Bruno 	if (oct->props.gmxport == gmxport)
1505f173c2b7SSean Bruno 		lio_update_link_status(oct->props.ifp, ls);
1506f173c2b7SSean Bruno 
1507f173c2b7SSean Bruno nic_info_err:
1508f173c2b7SSean Bruno 	for (i = 0; i < recv_pkt->buffer_count; i++)
1509f173c2b7SSean Bruno 		lio_recv_buffer_free(recv_pkt->buffer_ptr[i]);
1510f173c2b7SSean Bruno 
1511f173c2b7SSean Bruno 	lio_free_recv_info(recv_info);
1512f173c2b7SSean Bruno 	return (0);
1513f173c2b7SSean Bruno }
1514f173c2b7SSean Bruno 
1515f173c2b7SSean Bruno void
1516f173c2b7SSean Bruno lio_free_mbuf(struct lio_instr_queue *iq, struct lio_mbuf_free_info *finfo)
1517f173c2b7SSean Bruno {
1518f173c2b7SSean Bruno 
1519f173c2b7SSean Bruno 	bus_dmamap_sync(iq->txtag, finfo->map, BUS_DMASYNC_POSTWRITE);
1520f173c2b7SSean Bruno 	bus_dmamap_unload(iq->txtag, finfo->map);
1521f173c2b7SSean Bruno 	m_freem(finfo->mb);
1522f173c2b7SSean Bruno }
1523f173c2b7SSean Bruno 
1524f173c2b7SSean Bruno void
1525f173c2b7SSean Bruno lio_free_sgmbuf(struct lio_instr_queue *iq, struct lio_mbuf_free_info *finfo)
1526f173c2b7SSean Bruno {
1527f173c2b7SSean Bruno 	struct lio_gather	*g;
1528f173c2b7SSean Bruno 	struct octeon_device	*oct;
1529f173c2b7SSean Bruno 	struct lio		*lio;
1530f173c2b7SSean Bruno 	int	iq_no;
1531f173c2b7SSean Bruno 
1532f173c2b7SSean Bruno 	g = finfo->g;
1533f173c2b7SSean Bruno 	iq_no = iq->txpciq.s.q_no;
1534f173c2b7SSean Bruno 	oct = iq->oct_dev;
1535f173c2b7SSean Bruno 	lio = if_getsoftc(oct->props.ifp);
1536f173c2b7SSean Bruno 
1537f173c2b7SSean Bruno 	mtx_lock(&lio->glist_lock[iq_no]);
1538f173c2b7SSean Bruno 	STAILQ_INSERT_TAIL(&lio->ghead[iq_no], &g->node, entries);
1539f173c2b7SSean Bruno 	mtx_unlock(&lio->glist_lock[iq_no]);
1540f173c2b7SSean Bruno 
1541f173c2b7SSean Bruno 	bus_dmamap_sync(iq->txtag, finfo->map, BUS_DMASYNC_POSTWRITE);
1542f173c2b7SSean Bruno 	bus_dmamap_unload(iq->txtag, finfo->map);
1543f173c2b7SSean Bruno 	m_freem(finfo->mb);
1544f173c2b7SSean Bruno }
1545f173c2b7SSean Bruno 
1546f173c2b7SSean Bruno static void
1547f173c2b7SSean Bruno lio_if_cfg_callback(struct octeon_device *oct, uint32_t status, void *buf)
1548f173c2b7SSean Bruno {
1549f173c2b7SSean Bruno 	struct lio_soft_command	*sc = (struct lio_soft_command *)buf;
1550f173c2b7SSean Bruno 	struct lio_if_cfg_resp	*resp;
1551f173c2b7SSean Bruno 	struct lio_if_cfg_context *ctx;
1552f173c2b7SSean Bruno 
1553f173c2b7SSean Bruno 	resp = (struct lio_if_cfg_resp *)sc->virtrptr;
1554f173c2b7SSean Bruno 	ctx = (struct lio_if_cfg_context *)sc->ctxptr;
1555f173c2b7SSean Bruno 
1556f173c2b7SSean Bruno 	oct = lio_get_device(ctx->octeon_id);
1557f173c2b7SSean Bruno 	if (resp->status)
1558f173c2b7SSean Bruno 		lio_dev_err(oct, "nic if cfg instruction failed. Status: %llx (0x%08x)\n",
1559f173c2b7SSean Bruno 			    LIO_CAST64(resp->status), status);
1560f173c2b7SSean Bruno 	ctx->cond = 1;
1561f173c2b7SSean Bruno 
1562f173c2b7SSean Bruno 	snprintf(oct->fw_info.lio_firmware_version, 32, "%s",
1563f173c2b7SSean Bruno 		 resp->cfg_info.lio_firmware_version);
1564f173c2b7SSean Bruno 
1565f173c2b7SSean Bruno 	/*
1566f173c2b7SSean Bruno 	 * This barrier is required to be sure that the response has been
1567f173c2b7SSean Bruno 	 * written fully before waking up the handler
1568f173c2b7SSean Bruno 	 */
1569f173c2b7SSean Bruno 	wmb();
1570f173c2b7SSean Bruno }
1571f173c2b7SSean Bruno 
1572f173c2b7SSean Bruno static int
1573f173c2b7SSean Bruno lio_is_mac_changed(uint8_t *new, uint8_t *old)
1574f173c2b7SSean Bruno {
1575f173c2b7SSean Bruno 
1576f173c2b7SSean Bruno 	return ((new[0] != old[0]) || (new[1] != old[1]) ||
1577f173c2b7SSean Bruno 		(new[2] != old[2]) || (new[3] != old[3]) ||
1578f173c2b7SSean Bruno 		(new[4] != old[4]) || (new[5] != old[5]));
1579f173c2b7SSean Bruno }
1580f173c2b7SSean Bruno 
1581f173c2b7SSean Bruno void
1582f173c2b7SSean Bruno lio_open(void *arg)
1583f173c2b7SSean Bruno {
1584f173c2b7SSean Bruno 	struct lio	*lio = arg;
15852c50292dSJustin Hibbits 	if_t		ifp = lio->ifp;
1586f173c2b7SSean Bruno 	struct octeon_device	*oct = lio->oct_dev;
1587f173c2b7SSean Bruno 	uint8_t	*mac_new, mac_old[ETHER_HDR_LEN];
1588f173c2b7SSean Bruno 	int	ret = 0;
1589f173c2b7SSean Bruno 
1590f173c2b7SSean Bruno 	lio_ifstate_set(lio, LIO_IFSTATE_RUNNING);
1591f173c2b7SSean Bruno 
1592f173c2b7SSean Bruno 	/* Ready for link status updates */
1593f173c2b7SSean Bruno 	lio->intf_open = 1;
1594f173c2b7SSean Bruno 
1595f173c2b7SSean Bruno 	lio_dev_info(oct, "Interface Open, ready for traffic\n");
1596f173c2b7SSean Bruno 
1597f173c2b7SSean Bruno 	/* tell Octeon to start forwarding packets to host */
1598f173c2b7SSean Bruno 	lio_send_rx_ctrl_cmd(lio, 1);
1599f173c2b7SSean Bruno 
16002c50292dSJustin Hibbits 	mac_new = if_getlladdr(ifp);
1601f173c2b7SSean Bruno 	memcpy(mac_old, ((uint8_t *)&lio->linfo.hw_addr) + 2, ETHER_HDR_LEN);
1602f173c2b7SSean Bruno 
1603f173c2b7SSean Bruno 	if (lio_is_mac_changed(mac_new, mac_old)) {
1604f173c2b7SSean Bruno 		ret = lio_set_mac(ifp, mac_new);
1605f173c2b7SSean Bruno 		if (ret)
1606f173c2b7SSean Bruno 			lio_dev_err(oct, "MAC change failed, error: %d\n", ret);
1607f173c2b7SSean Bruno 	}
1608f173c2b7SSean Bruno 
1609f173c2b7SSean Bruno 	/* Now inform the stack we're ready */
1610f173c2b7SSean Bruno 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
1611f173c2b7SSean Bruno 
1612f173c2b7SSean Bruno 	lio_dev_info(oct, "Interface is opened\n");
1613f173c2b7SSean Bruno }
1614f173c2b7SSean Bruno 
1615f173c2b7SSean Bruno static int
16162c50292dSJustin Hibbits lio_set_rxcsum_command(if_t ifp, int command, uint8_t rx_cmd)
1617f173c2b7SSean Bruno {
1618f173c2b7SSean Bruno 	struct lio_ctrl_pkt	nctrl;
1619f173c2b7SSean Bruno 	struct lio		*lio = if_getsoftc(ifp);
1620f173c2b7SSean Bruno 	struct octeon_device	*oct = lio->oct_dev;
1621f173c2b7SSean Bruno 	int	ret = 0;
1622f173c2b7SSean Bruno 
1623f173c2b7SSean Bruno 	nctrl.ncmd.cmd64 = 0;
1624f173c2b7SSean Bruno 	nctrl.ncmd.s.cmd = command;
1625f173c2b7SSean Bruno 	nctrl.ncmd.s.param1 = rx_cmd;
1626f173c2b7SSean Bruno 	nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
1627f173c2b7SSean Bruno 	nctrl.wait_time = 100;
1628f173c2b7SSean Bruno 	nctrl.lio = lio;
1629f173c2b7SSean Bruno 	nctrl.cb_fn = lio_ctrl_cmd_completion;
1630f173c2b7SSean Bruno 
1631f173c2b7SSean Bruno 	ret = lio_send_ctrl_pkt(lio->oct_dev, &nctrl);
1632f173c2b7SSean Bruno 	if (ret < 0) {
1633f173c2b7SSean Bruno 		lio_dev_err(oct, "DEVFLAGS RXCSUM change failed in core(ret:0x%x)\n",
1634f173c2b7SSean Bruno 			    ret);
1635f173c2b7SSean Bruno 	}
1636f173c2b7SSean Bruno 
1637f173c2b7SSean Bruno 	return (ret);
1638f173c2b7SSean Bruno }
1639f173c2b7SSean Bruno 
1640f173c2b7SSean Bruno static int
1641f173c2b7SSean Bruno lio_stop_nic_module(struct octeon_device *oct)
1642f173c2b7SSean Bruno {
1643f173c2b7SSean Bruno 	int		i, j;
1644f173c2b7SSean Bruno 	struct lio	*lio;
1645f173c2b7SSean Bruno 
1646f173c2b7SSean Bruno 	lio_dev_dbg(oct, "Stopping network interfaces\n");
1647f173c2b7SSean Bruno 	if (!oct->ifcount) {
1648f173c2b7SSean Bruno 		lio_dev_err(oct, "Init for Octeon was not completed\n");
1649f173c2b7SSean Bruno 		return (1);
1650f173c2b7SSean Bruno 	}
1651f173c2b7SSean Bruno 
1652f173c2b7SSean Bruno 	mtx_lock(&oct->cmd_resp_wqlock);
1653f173c2b7SSean Bruno 	oct->cmd_resp_state = LIO_DRV_OFFLINE;
1654f173c2b7SSean Bruno 	mtx_unlock(&oct->cmd_resp_wqlock);
1655f173c2b7SSean Bruno 
1656f173c2b7SSean Bruno 	for (i = 0; i < oct->ifcount; i++) {
1657f173c2b7SSean Bruno 		lio = if_getsoftc(oct->props.ifp);
1658f173c2b7SSean Bruno 		for (j = 0; j < oct->num_oqs; j++)
1659f173c2b7SSean Bruno 			lio_unregister_droq_ops(oct,
1660f173c2b7SSean Bruno 						lio->linfo.rxpciq[j].s.q_no);
1661f173c2b7SSean Bruno 	}
1662f173c2b7SSean Bruno 
1663f173c2b7SSean Bruno 	callout_drain(&lio->stats_timer);
1664f173c2b7SSean Bruno 
1665f173c2b7SSean Bruno 	for (i = 0; i < oct->ifcount; i++)
1666f173c2b7SSean Bruno 		lio_destroy_nic_device(oct, i);
1667f173c2b7SSean Bruno 
1668f173c2b7SSean Bruno 	lio_dev_dbg(oct, "Network interface stopped\n");
1669f173c2b7SSean Bruno 
1670f173c2b7SSean Bruno 	return (0);
1671f173c2b7SSean Bruno }
1672f173c2b7SSean Bruno 
1673f173c2b7SSean Bruno static void
1674f173c2b7SSean Bruno lio_delete_glists(struct octeon_device *oct, struct lio *lio)
1675f173c2b7SSean Bruno {
1676f173c2b7SSean Bruno 	struct lio_gather	*g;
1677f173c2b7SSean Bruno 	int	i;
1678f173c2b7SSean Bruno 
1679f173c2b7SSean Bruno 	if (lio->glist_lock != NULL) {
1680f173c2b7SSean Bruno 		free((void *)lio->glist_lock, M_DEVBUF);
1681f173c2b7SSean Bruno 		lio->glist_lock = NULL;
1682f173c2b7SSean Bruno 	}
1683f173c2b7SSean Bruno 
1684f173c2b7SSean Bruno 	if (lio->ghead == NULL)
1685f173c2b7SSean Bruno 		return;
1686f173c2b7SSean Bruno 
1687f173c2b7SSean Bruno 	for (i = 0; i < lio->linfo.num_txpciq; i++) {
1688f173c2b7SSean Bruno 		do {
1689f173c2b7SSean Bruno 			g = (struct lio_gather *)
1690f173c2b7SSean Bruno 			    lio_delete_first_node(&lio->ghead[i]);
1691f173c2b7SSean Bruno 			free(g, M_DEVBUF);
1692f173c2b7SSean Bruno 		} while (g);
1693f173c2b7SSean Bruno 
1694f173c2b7SSean Bruno 		if ((lio->glists_virt_base != NULL) &&
1695f173c2b7SSean Bruno 		    (lio->glists_virt_base[i] != NULL)) {
1696f173c2b7SSean Bruno 			lio_dma_free(lio->glist_entry_size * lio->tx_qsize,
1697f173c2b7SSean Bruno 				     lio->glists_virt_base[i]);
1698f173c2b7SSean Bruno 		}
1699f173c2b7SSean Bruno 	}
1700f173c2b7SSean Bruno 
1701f173c2b7SSean Bruno 	free(lio->glists_virt_base, M_DEVBUF);
1702f173c2b7SSean Bruno 	lio->glists_virt_base = NULL;
1703f173c2b7SSean Bruno 
1704f173c2b7SSean Bruno 	free(lio->glists_dma_base, M_DEVBUF);
1705f173c2b7SSean Bruno 	lio->glists_dma_base = NULL;
1706f173c2b7SSean Bruno 
1707f173c2b7SSean Bruno 	free(lio->ghead, M_DEVBUF);
1708f173c2b7SSean Bruno 	lio->ghead = NULL;
1709f173c2b7SSean Bruno }
1710f173c2b7SSean Bruno 
1711f173c2b7SSean Bruno static int
1712f173c2b7SSean Bruno lio_setup_glists(struct octeon_device *oct, struct lio *lio, int num_iqs)
1713f173c2b7SSean Bruno {
1714f173c2b7SSean Bruno 	struct lio_gather	*g;
1715f173c2b7SSean Bruno 	int	i, j;
1716f173c2b7SSean Bruno 
1717ac2fffa4SPedro F. Giffuni 	lio->glist_lock = malloc(num_iqs * sizeof(*lio->glist_lock), M_DEVBUF,
1718ac2fffa4SPedro F. Giffuni 				 M_NOWAIT | M_ZERO);
1719f173c2b7SSean Bruno 	if (lio->glist_lock == NULL)
1720f173c2b7SSean Bruno 		return (1);
1721f173c2b7SSean Bruno 
1722ac2fffa4SPedro F. Giffuni 	lio->ghead = malloc(num_iqs * sizeof(*lio->ghead), M_DEVBUF,
1723f173c2b7SSean Bruno 			    M_NOWAIT | M_ZERO);
1724f173c2b7SSean Bruno 	if (lio->ghead == NULL) {
1725f173c2b7SSean Bruno 		free((void *)lio->glist_lock, M_DEVBUF);
1726f173c2b7SSean Bruno 		lio->glist_lock = NULL;
1727f173c2b7SSean Bruno 		return (1);
1728f173c2b7SSean Bruno 	}
1729f173c2b7SSean Bruno 
1730f173c2b7SSean Bruno 	lio->glist_entry_size = ROUNDUP8((ROUNDUP4(LIO_MAX_SG) >> 2) *
1731f173c2b7SSean Bruno 					 LIO_SG_ENTRY_SIZE);
1732f173c2b7SSean Bruno 	/*
1733f173c2b7SSean Bruno 	 * allocate memory to store virtual and dma base address of
1734f173c2b7SSean Bruno 	 * per glist consistent memory
1735f173c2b7SSean Bruno 	 */
1736ac2fffa4SPedro F. Giffuni 	lio->glists_virt_base = malloc(num_iqs * sizeof(void *), M_DEVBUF,
1737f173c2b7SSean Bruno 				       M_NOWAIT | M_ZERO);
1738ac2fffa4SPedro F. Giffuni 	lio->glists_dma_base = malloc(num_iqs * sizeof(vm_paddr_t), M_DEVBUF,
1739ac2fffa4SPedro F. Giffuni 				      M_NOWAIT | M_ZERO);
1740f173c2b7SSean Bruno 	if ((lio->glists_virt_base == NULL) || (lio->glists_dma_base == NULL)) {
1741f173c2b7SSean Bruno 		lio_delete_glists(oct, lio);
1742f173c2b7SSean Bruno 		return (1);
1743f173c2b7SSean Bruno 	}
1744f173c2b7SSean Bruno 
1745f173c2b7SSean Bruno 	for (i = 0; i < num_iqs; i++) {
1746f173c2b7SSean Bruno 		mtx_init(&lio->glist_lock[i], "glist_lock", NULL, MTX_DEF);
1747f173c2b7SSean Bruno 
1748f173c2b7SSean Bruno 		STAILQ_INIT(&lio->ghead[i]);
1749f173c2b7SSean Bruno 
1750f173c2b7SSean Bruno 		lio->glists_virt_base[i] =
1751f173c2b7SSean Bruno 		    lio_dma_alloc(lio->glist_entry_size * lio->tx_qsize,
1752f173c2b7SSean Bruno 				  (vm_paddr_t *)&lio->glists_dma_base[i]);
1753f173c2b7SSean Bruno 		if (lio->glists_virt_base[i] == NULL) {
1754f173c2b7SSean Bruno 			lio_delete_glists(oct, lio);
1755f173c2b7SSean Bruno 			return (1);
1756f173c2b7SSean Bruno 		}
1757f173c2b7SSean Bruno 
1758f173c2b7SSean Bruno 		for (j = 0; j < lio->tx_qsize; j++) {
1759f173c2b7SSean Bruno 			g = malloc(sizeof(*g), M_DEVBUF, M_NOWAIT | M_ZERO);
1760f173c2b7SSean Bruno 			if (g == NULL)
1761f173c2b7SSean Bruno 				break;
1762f173c2b7SSean Bruno 
17632b6fe1b2SDimitry Andric 			g->sg = (struct lio_sg_entry *)(uintptr_t)
17642b6fe1b2SDimitry Andric 			    ((uint64_t)(uintptr_t)lio->glists_virt_base[i] +
1765f173c2b7SSean Bruno 			     (j * lio->glist_entry_size));
1766f173c2b7SSean Bruno 			g->sg_dma_ptr = (uint64_t)lio->glists_dma_base[i] +
1767f173c2b7SSean Bruno 				(j * lio->glist_entry_size);
1768f173c2b7SSean Bruno 			STAILQ_INSERT_TAIL(&lio->ghead[i], &g->node, entries);
1769f173c2b7SSean Bruno 		}
1770f173c2b7SSean Bruno 
1771f173c2b7SSean Bruno 		if (j != lio->tx_qsize) {
1772f173c2b7SSean Bruno 			lio_delete_glists(oct, lio);
1773f173c2b7SSean Bruno 			return (1);
1774f173c2b7SSean Bruno 		}
1775f173c2b7SSean Bruno 	}
1776f173c2b7SSean Bruno 
1777f173c2b7SSean Bruno 	return (0);
1778f173c2b7SSean Bruno }
1779f173c2b7SSean Bruno 
1780f173c2b7SSean Bruno void
17812c50292dSJustin Hibbits lio_stop(if_t ifp)
1782f173c2b7SSean Bruno {
1783f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
1784f173c2b7SSean Bruno 	struct octeon_device	*oct = lio->oct_dev;
1785f173c2b7SSean Bruno 
1786f173c2b7SSean Bruno 	lio_ifstate_reset(lio, LIO_IFSTATE_RUNNING);
1787f173c2b7SSean Bruno 	if_link_state_change(ifp, LINK_STATE_DOWN);
1788f173c2b7SSean Bruno 
1789f173c2b7SSean Bruno 	lio->intf_open = 0;
1790f173c2b7SSean Bruno 	lio->linfo.link.s.link_up = 0;
1791f173c2b7SSean Bruno 	lio->link_changes++;
1792f173c2b7SSean Bruno 
1793f173c2b7SSean Bruno 	lio_send_rx_ctrl_cmd(lio, 0);
1794f173c2b7SSean Bruno 
1795f173c2b7SSean Bruno 	/* Tell the stack that the interface is no longer active */
1796f173c2b7SSean Bruno 	if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
1797f173c2b7SSean Bruno 
1798f173c2b7SSean Bruno 	lio_dev_info(oct, "Interface is stopped\n");
1799f173c2b7SSean Bruno }
1800f173c2b7SSean Bruno 
1801f173c2b7SSean Bruno static void
1802f173c2b7SSean Bruno lio_check_rx_oom_status(struct lio *lio)
1803f173c2b7SSean Bruno {
1804f173c2b7SSean Bruno 	struct lio_droq	*droq;
1805f173c2b7SSean Bruno 	struct octeon_device *oct = lio->oct_dev;
1806f173c2b7SSean Bruno 	int	desc_refilled;
1807f173c2b7SSean Bruno 	int	q, q_no = 0;
1808f173c2b7SSean Bruno 
1809f173c2b7SSean Bruno 	for (q = 0; q < oct->num_oqs; q++) {
1810f173c2b7SSean Bruno 		q_no = lio->linfo.rxpciq[q].s.q_no;
1811f173c2b7SSean Bruno 		droq = oct->droq[q_no];
1812f173c2b7SSean Bruno 		if (droq == NULL)
1813f173c2b7SSean Bruno 			continue;
1814f173c2b7SSean Bruno 		if (lio_read_csr32(oct, droq->pkts_credit_reg) <= 0x40) {
1815f173c2b7SSean Bruno 			mtx_lock(&droq->lock);
1816f173c2b7SSean Bruno 			desc_refilled = lio_droq_refill(oct, droq);
1817f173c2b7SSean Bruno 			/*
1818f173c2b7SSean Bruno 			 * Flush the droq descriptor data to memory to be sure
1819f173c2b7SSean Bruno 			 * that when we update the credits the data in memory
1820f173c2b7SSean Bruno 			 * is accurate.
1821f173c2b7SSean Bruno 			 */
1822f173c2b7SSean Bruno 			wmb();
1823f173c2b7SSean Bruno 			lio_write_csr32(oct, droq->pkts_credit_reg,
1824f173c2b7SSean Bruno 					desc_refilled);
1825f173c2b7SSean Bruno 			/* make sure mmio write completes */
1826f173c2b7SSean Bruno 			__compiler_membar();
1827f173c2b7SSean Bruno 			mtx_unlock(&droq->lock);
1828f173c2b7SSean Bruno 		}
1829f173c2b7SSean Bruno 	}
1830f173c2b7SSean Bruno }
1831f173c2b7SSean Bruno 
1832f173c2b7SSean Bruno static void
1833f173c2b7SSean Bruno lio_poll_check_rx_oom_status(void *arg, int pending __unused)
1834f173c2b7SSean Bruno {
1835f173c2b7SSean Bruno 	struct lio_tq	*rx_status_tq = arg;
1836f173c2b7SSean Bruno 	struct lio	*lio = rx_status_tq->ctxptr;
1837f173c2b7SSean Bruno 
1838f173c2b7SSean Bruno 	if (lio_ifstate_check(lio, LIO_IFSTATE_RUNNING))
1839f173c2b7SSean Bruno 		lio_check_rx_oom_status(lio);
1840f173c2b7SSean Bruno 
1841f173c2b7SSean Bruno 	taskqueue_enqueue_timeout(rx_status_tq->tq, &rx_status_tq->work,
1842f173c2b7SSean Bruno 				  lio_ms_to_ticks(50));
1843f173c2b7SSean Bruno }
1844f173c2b7SSean Bruno 
1845f173c2b7SSean Bruno static int
18462c50292dSJustin Hibbits lio_setup_rx_oom_poll_fn(if_t ifp)
1847f173c2b7SSean Bruno {
1848f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
1849f173c2b7SSean Bruno 	struct octeon_device	*oct = lio->oct_dev;
1850f173c2b7SSean Bruno 	struct lio_tq	*rx_status_tq;
1851f173c2b7SSean Bruno 
1852f173c2b7SSean Bruno 	rx_status_tq = &lio->rx_status_tq;
1853f173c2b7SSean Bruno 
1854f173c2b7SSean Bruno 	rx_status_tq->tq = taskqueue_create("lio_rx_oom_status", M_WAITOK,
1855f173c2b7SSean Bruno 					    taskqueue_thread_enqueue,
1856f173c2b7SSean Bruno 					    &rx_status_tq->tq);
1857f173c2b7SSean Bruno 
1858f173c2b7SSean Bruno 	TIMEOUT_TASK_INIT(rx_status_tq->tq, &rx_status_tq->work, 0,
1859f173c2b7SSean Bruno 			  lio_poll_check_rx_oom_status, (void *)rx_status_tq);
1860f173c2b7SSean Bruno 
1861f173c2b7SSean Bruno 	rx_status_tq->ctxptr = lio;
1862f173c2b7SSean Bruno 
1863f173c2b7SSean Bruno 	taskqueue_start_threads(&rx_status_tq->tq, 1, PI_NET,
1864f173c2b7SSean Bruno 				"lio%d_rx_oom_status",
1865f173c2b7SSean Bruno 				oct->octeon_id);
1866f173c2b7SSean Bruno 
1867f173c2b7SSean Bruno 	taskqueue_enqueue_timeout(rx_status_tq->tq, &rx_status_tq->work,
1868f173c2b7SSean Bruno 				  lio_ms_to_ticks(50));
1869f173c2b7SSean Bruno 
1870f173c2b7SSean Bruno 	return (0);
1871f173c2b7SSean Bruno }
1872f173c2b7SSean Bruno 
1873f173c2b7SSean Bruno static void
18742c50292dSJustin Hibbits lio_cleanup_rx_oom_poll_fn(if_t ifp)
1875f173c2b7SSean Bruno {
1876f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
1877f173c2b7SSean Bruno 
1878f173c2b7SSean Bruno 	if (lio->rx_status_tq.tq != NULL) {
1879f173c2b7SSean Bruno 		while (taskqueue_cancel_timeout(lio->rx_status_tq.tq,
1880f173c2b7SSean Bruno 						&lio->rx_status_tq.work, NULL))
1881f173c2b7SSean Bruno 			taskqueue_drain_timeout(lio->rx_status_tq.tq,
1882f173c2b7SSean Bruno 						&lio->rx_status_tq.work);
1883f173c2b7SSean Bruno 
1884f173c2b7SSean Bruno 		taskqueue_free(lio->rx_status_tq.tq);
1885f173c2b7SSean Bruno 
1886f173c2b7SSean Bruno 		lio->rx_status_tq.tq = NULL;
1887f173c2b7SSean Bruno 	}
1888f173c2b7SSean Bruno }
1889f173c2b7SSean Bruno 
1890f173c2b7SSean Bruno static void
1891f173c2b7SSean Bruno lio_destroy_nic_device(struct octeon_device *oct, int ifidx)
1892f173c2b7SSean Bruno {
18932c50292dSJustin Hibbits 	if_t		ifp = oct->props.ifp;
1894f173c2b7SSean Bruno 	struct lio	*lio;
1895f173c2b7SSean Bruno 
1896f173c2b7SSean Bruno 	if (ifp == NULL) {
1897f173c2b7SSean Bruno 		lio_dev_err(oct, "%s No ifp ptr for index %d\n",
1898f173c2b7SSean Bruno 			    __func__, ifidx);
1899f173c2b7SSean Bruno 		return;
1900f173c2b7SSean Bruno 	}
1901f173c2b7SSean Bruno 
1902f173c2b7SSean Bruno 	lio = if_getsoftc(ifp);
1903f173c2b7SSean Bruno 
1904f173c2b7SSean Bruno 	lio_ifstate_set(lio, LIO_IFSTATE_DETACH);
1905f173c2b7SSean Bruno 
1906f173c2b7SSean Bruno 	lio_dev_dbg(oct, "NIC device cleanup\n");
1907f173c2b7SSean Bruno 
1908f173c2b7SSean Bruno 	if (atomic_load_acq_int(&lio->ifstate) & LIO_IFSTATE_RUNNING)
1909f173c2b7SSean Bruno 		lio_stop(ifp);
1910f173c2b7SSean Bruno 
1911f173c2b7SSean Bruno 	if (lio_wait_for_pending_requests(oct))
1912f173c2b7SSean Bruno 		lio_dev_err(oct, "There were pending requests\n");
1913f173c2b7SSean Bruno 
1914f173c2b7SSean Bruno 	if (lio_wait_for_instr_fetch(oct))
1915f173c2b7SSean Bruno 		lio_dev_err(oct, "IQ had pending instructions\n");
1916f173c2b7SSean Bruno 
1917f173c2b7SSean Bruno 	if (lio_wait_for_oq_pkts(oct))
1918f173c2b7SSean Bruno 		lio_dev_err(oct, "OQ had pending packets\n");
1919f173c2b7SSean Bruno 
1920f173c2b7SSean Bruno 	if (atomic_load_acq_int(&lio->ifstate) & LIO_IFSTATE_REGISTERED)
1921f173c2b7SSean Bruno 		ether_ifdetach(ifp);
1922f173c2b7SSean Bruno 
1923f173c2b7SSean Bruno 	lio_tcp_lro_free(oct, ifp);
1924f173c2b7SSean Bruno 
1925f173c2b7SSean Bruno 	lio_cleanup_rx_oom_poll_fn(ifp);
1926f173c2b7SSean Bruno 
1927f173c2b7SSean Bruno 	lio_delete_glists(oct, lio);
1928f173c2b7SSean Bruno 
1929f173c2b7SSean Bruno 	EVENTHANDLER_DEREGISTER(vlan_config, lio->vlan_attach);
1930f173c2b7SSean Bruno 	EVENTHANDLER_DEREGISTER(vlan_unconfig, lio->vlan_detach);
1931f173c2b7SSean Bruno 
1932f173c2b7SSean Bruno 	free(lio, M_DEVBUF);
1933f173c2b7SSean Bruno 
1934f173c2b7SSean Bruno 	if_free(ifp);
1935f173c2b7SSean Bruno 
1936f173c2b7SSean Bruno 	oct->props.gmxport = -1;
1937f173c2b7SSean Bruno 
1938f173c2b7SSean Bruno 	oct->props.ifp = NULL;
1939f173c2b7SSean Bruno }
1940f173c2b7SSean Bruno 
1941f173c2b7SSean Bruno static void
19422c50292dSJustin Hibbits print_link_info(if_t ifp)
1943f173c2b7SSean Bruno {
1944f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
1945f173c2b7SSean Bruno 
1946f173c2b7SSean Bruno 	if (!lio_ifstate_check(lio, LIO_IFSTATE_RESETTING) &&
1947f173c2b7SSean Bruno 	    lio_ifstate_check(lio, LIO_IFSTATE_REGISTERED)) {
1948f173c2b7SSean Bruno 		struct octeon_link_info *linfo = &lio->linfo;
1949f173c2b7SSean Bruno 
1950f173c2b7SSean Bruno 		if (linfo->link.s.link_up) {
1951f173c2b7SSean Bruno 			lio_dev_info(lio->oct_dev, "%d Mbps %s Duplex UP\n",
1952f173c2b7SSean Bruno 				     linfo->link.s.speed,
1953f173c2b7SSean Bruno 				     (linfo->link.s.duplex) ? "Full" : "Half");
1954f173c2b7SSean Bruno 		} else {
1955f173c2b7SSean Bruno 			lio_dev_info(lio->oct_dev, "Link Down\n");
1956f173c2b7SSean Bruno 		}
1957f173c2b7SSean Bruno 	}
1958f173c2b7SSean Bruno }
1959f173c2b7SSean Bruno 
1960f173c2b7SSean Bruno static inline void
19612c50292dSJustin Hibbits lio_update_link_status(if_t ifp, union octeon_link_status *ls)
1962f173c2b7SSean Bruno {
1963f173c2b7SSean Bruno 	struct lio	*lio = if_getsoftc(ifp);
1964f173c2b7SSean Bruno 	int	changed = (lio->linfo.link.link_status64 != ls->link_status64);
1965f173c2b7SSean Bruno 
1966f173c2b7SSean Bruno 	lio->linfo.link.link_status64 = ls->link_status64;
1967f173c2b7SSean Bruno 
1968f173c2b7SSean Bruno 	if ((lio->intf_open) && (changed)) {
1969f173c2b7SSean Bruno 		print_link_info(ifp);
1970f173c2b7SSean Bruno 		lio->link_changes++;
1971f173c2b7SSean Bruno 		if (lio->linfo.link.s.link_up)
1972f173c2b7SSean Bruno 			if_link_state_change(ifp, LINK_STATE_UP);
1973f173c2b7SSean Bruno 		else
1974f173c2b7SSean Bruno 			if_link_state_change(ifp, LINK_STATE_DOWN);
1975f173c2b7SSean Bruno 	}
1976f173c2b7SSean Bruno }
1977f173c2b7SSean Bruno 
1978f173c2b7SSean Bruno /*
1979f173c2b7SSean Bruno  * \brief Callback for rx ctrl
1980f173c2b7SSean Bruno  * @param status status of request
1981f173c2b7SSean Bruno  * @param buf pointer to resp structure
1982f173c2b7SSean Bruno  */
1983f173c2b7SSean Bruno static void
1984f173c2b7SSean Bruno lio_rx_ctl_callback(struct octeon_device *oct, uint32_t status, void *buf)
1985f173c2b7SSean Bruno {
1986f173c2b7SSean Bruno 	struct lio_soft_command	*sc = (struct lio_soft_command *)buf;
1987f173c2b7SSean Bruno 	struct lio_rx_ctl_context *ctx;
1988f173c2b7SSean Bruno 
1989f173c2b7SSean Bruno 	ctx = (struct lio_rx_ctl_context *)sc->ctxptr;
1990f173c2b7SSean Bruno 
1991f173c2b7SSean Bruno 	oct = lio_get_device(ctx->octeon_id);
1992f173c2b7SSean Bruno 	if (status)
1993f173c2b7SSean Bruno 		lio_dev_err(oct, "rx ctl instruction failed. Status: %llx\n",
1994f173c2b7SSean Bruno 			    LIO_CAST64(status));
1995f173c2b7SSean Bruno 	ctx->cond = 1;
1996f173c2b7SSean Bruno 
1997f173c2b7SSean Bruno 	/*
1998f173c2b7SSean Bruno 	 * This barrier is required to be sure that the response has been
1999f173c2b7SSean Bruno 	 * written fully before waking up the handler
2000f173c2b7SSean Bruno 	 */
2001f173c2b7SSean Bruno 	wmb();
2002f173c2b7SSean Bruno }
2003f173c2b7SSean Bruno 
2004f173c2b7SSean Bruno static void
2005f173c2b7SSean Bruno lio_send_rx_ctrl_cmd(struct lio *lio, int start_stop)
2006f173c2b7SSean Bruno {
2007f173c2b7SSean Bruno 	struct lio_soft_command	*sc;
2008f173c2b7SSean Bruno 	struct lio_rx_ctl_context *ctx;
2009f173c2b7SSean Bruno 	union octeon_cmd	*ncmd;
2010f173c2b7SSean Bruno 	struct octeon_device	*oct = (struct octeon_device *)lio->oct_dev;
2011f173c2b7SSean Bruno 	int	ctx_size = sizeof(struct lio_rx_ctl_context);
2012f173c2b7SSean Bruno 	int	retval;
2013f173c2b7SSean Bruno 
2014f173c2b7SSean Bruno 	if (oct->props.rx_on == start_stop)
2015f173c2b7SSean Bruno 		return;
2016f173c2b7SSean Bruno 
2017f173c2b7SSean Bruno 	sc = lio_alloc_soft_command(oct, OCTEON_CMD_SIZE, 16, ctx_size);
2018f173c2b7SSean Bruno 	if (sc == NULL)
2019f173c2b7SSean Bruno 		return;
2020f173c2b7SSean Bruno 
2021f173c2b7SSean Bruno 	ncmd = (union octeon_cmd *)sc->virtdptr;
2022f173c2b7SSean Bruno 	ctx = (struct lio_rx_ctl_context *)sc->ctxptr;
2023f173c2b7SSean Bruno 
2024f173c2b7SSean Bruno 	ctx->cond = 0;
2025f173c2b7SSean Bruno 	ctx->octeon_id = lio_get_device_id(oct);
2026f173c2b7SSean Bruno 	ncmd->cmd64 = 0;
2027f173c2b7SSean Bruno 	ncmd->s.cmd = LIO_CMD_RX_CTL;
2028f173c2b7SSean Bruno 	ncmd->s.param1 = start_stop;
2029f173c2b7SSean Bruno 
2030f173c2b7SSean Bruno 	lio_swap_8B_data((uint64_t *)ncmd, (OCTEON_CMD_SIZE >> 3));
2031f173c2b7SSean Bruno 
2032f173c2b7SSean Bruno 	sc->iq_no = lio->linfo.txpciq[0].s.q_no;
2033f173c2b7SSean Bruno 
2034f173c2b7SSean Bruno 	lio_prepare_soft_command(oct, sc, LIO_OPCODE_NIC, LIO_OPCODE_NIC_CMD, 0,
2035f173c2b7SSean Bruno 				 0, 0);
2036f173c2b7SSean Bruno 
2037f173c2b7SSean Bruno 	sc->callback = lio_rx_ctl_callback;
2038f173c2b7SSean Bruno 	sc->callback_arg = sc;
2039f173c2b7SSean Bruno 	sc->wait_time = 5000;
2040f173c2b7SSean Bruno 
2041f173c2b7SSean Bruno 	retval = lio_send_soft_command(oct, sc);
2042f173c2b7SSean Bruno 	if (retval == LIO_IQ_SEND_FAILED) {
2043f173c2b7SSean Bruno 		lio_dev_err(oct, "Failed to send RX Control message\n");
2044f173c2b7SSean Bruno 	} else {
2045f173c2b7SSean Bruno 		/*
2046f173c2b7SSean Bruno 		 * Sleep on a wait queue till the cond flag indicates that the
2047f173c2b7SSean Bruno 		 * response arrived or timed-out.
2048f173c2b7SSean Bruno 		 */
2049f173c2b7SSean Bruno 		lio_sleep_cond(oct, &ctx->cond);
2050f173c2b7SSean Bruno 		oct->props.rx_on = start_stop;
2051f173c2b7SSean Bruno 	}
2052f173c2b7SSean Bruno 
2053f173c2b7SSean Bruno 	lio_free_soft_command(oct, sc);
2054f173c2b7SSean Bruno }
2055f173c2b7SSean Bruno 
2056f173c2b7SSean Bruno static void
20572c50292dSJustin Hibbits lio_vlan_rx_add_vid(void *arg, if_t ifp, uint16_t vid)
2058f173c2b7SSean Bruno {
2059f173c2b7SSean Bruno 	struct lio_ctrl_pkt	nctrl;
2060f173c2b7SSean Bruno 	struct lio		*lio = if_getsoftc(ifp);
2061f173c2b7SSean Bruno 	struct octeon_device	*oct = lio->oct_dev;
2062f173c2b7SSean Bruno 	int	ret = 0;
2063f173c2b7SSean Bruno 
2064f173c2b7SSean Bruno 	if (if_getsoftc(ifp) != arg)	/* Not our event */
2065f173c2b7SSean Bruno 		return;
2066f173c2b7SSean Bruno 
2067f173c2b7SSean Bruno 	if ((vid == 0) || (vid > 4095))	/* Invalid */
2068f173c2b7SSean Bruno 		return;
2069f173c2b7SSean Bruno 
2070f173c2b7SSean Bruno 	bzero(&nctrl, sizeof(struct lio_ctrl_pkt));
2071f173c2b7SSean Bruno 
2072f173c2b7SSean Bruno 	nctrl.ncmd.cmd64 = 0;
2073f173c2b7SSean Bruno 	nctrl.ncmd.s.cmd = LIO_CMD_ADD_VLAN_FILTER;
2074f173c2b7SSean Bruno 	nctrl.ncmd.s.param1 = vid;
2075f173c2b7SSean Bruno 	nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
2076f173c2b7SSean Bruno 	nctrl.wait_time = 100;
2077f173c2b7SSean Bruno 	nctrl.lio = lio;
2078f173c2b7SSean Bruno 	nctrl.cb_fn = lio_ctrl_cmd_completion;
2079f173c2b7SSean Bruno 
2080f173c2b7SSean Bruno 	ret = lio_send_ctrl_pkt(lio->oct_dev, &nctrl);
2081f173c2b7SSean Bruno 	if (ret < 0) {
2082f173c2b7SSean Bruno 		lio_dev_err(oct, "Add VLAN filter failed in core (ret: 0x%x)\n",
2083f173c2b7SSean Bruno 			    ret);
2084f173c2b7SSean Bruno 	}
2085f173c2b7SSean Bruno }
2086f173c2b7SSean Bruno 
2087f173c2b7SSean Bruno static void
20882c50292dSJustin Hibbits lio_vlan_rx_kill_vid(void *arg, if_t ifp, uint16_t vid)
2089f173c2b7SSean Bruno {
2090f173c2b7SSean Bruno 	struct lio_ctrl_pkt	nctrl;
2091f173c2b7SSean Bruno 	struct lio		*lio = if_getsoftc(ifp);
2092f173c2b7SSean Bruno 	struct octeon_device	*oct = lio->oct_dev;
2093f173c2b7SSean Bruno 	int	ret = 0;
2094f173c2b7SSean Bruno 
2095f173c2b7SSean Bruno 	if (if_getsoftc(ifp) != arg)	/* Not our event */
2096f173c2b7SSean Bruno 		return;
2097f173c2b7SSean Bruno 
2098f173c2b7SSean Bruno 	if ((vid == 0) || (vid > 4095))	/* Invalid */
2099f173c2b7SSean Bruno 		return;
2100f173c2b7SSean Bruno 
2101f173c2b7SSean Bruno 	bzero(&nctrl, sizeof(struct lio_ctrl_pkt));
2102f173c2b7SSean Bruno 
2103f173c2b7SSean Bruno 	nctrl.ncmd.cmd64 = 0;
2104f173c2b7SSean Bruno 	nctrl.ncmd.s.cmd = LIO_CMD_DEL_VLAN_FILTER;
2105f173c2b7SSean Bruno 	nctrl.ncmd.s.param1 = vid;
2106f173c2b7SSean Bruno 	nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
2107f173c2b7SSean Bruno 	nctrl.wait_time = 100;
2108f173c2b7SSean Bruno 	nctrl.lio = lio;
2109f173c2b7SSean Bruno 	nctrl.cb_fn = lio_ctrl_cmd_completion;
2110f173c2b7SSean Bruno 
2111f173c2b7SSean Bruno 	ret = lio_send_ctrl_pkt(lio->oct_dev, &nctrl);
2112f173c2b7SSean Bruno 	if (ret < 0) {
2113f173c2b7SSean Bruno 		lio_dev_err(oct,
2114f173c2b7SSean Bruno 			    "Kill VLAN filter failed in core (ret: 0x%x)\n",
2115f173c2b7SSean Bruno 			    ret);
2116f173c2b7SSean Bruno 	}
2117f173c2b7SSean Bruno }
2118f173c2b7SSean Bruno 
2119f173c2b7SSean Bruno static int
2120f173c2b7SSean Bruno lio_wait_for_oq_pkts(struct octeon_device *oct)
2121f173c2b7SSean Bruno {
2122f173c2b7SSean Bruno 	int	i, pending_pkts, pkt_cnt = 0, retry = 100;
2123f173c2b7SSean Bruno 
2124f173c2b7SSean Bruno 	do {
2125f173c2b7SSean Bruno 		pending_pkts = 0;
2126f173c2b7SSean Bruno 
2127f173c2b7SSean Bruno 		for (i = 0; i < LIO_MAX_OUTPUT_QUEUES(oct); i++) {
2128f173c2b7SSean Bruno 			if (!(oct->io_qmask.oq & BIT_ULL(i)))
2129f173c2b7SSean Bruno 				continue;
2130f173c2b7SSean Bruno 
2131f173c2b7SSean Bruno 			pkt_cnt = lio_droq_check_hw_for_pkts(oct->droq[i]);
2132f173c2b7SSean Bruno 			if (pkt_cnt > 0) {
2133f173c2b7SSean Bruno 				pending_pkts += pkt_cnt;
2134f173c2b7SSean Bruno 				taskqueue_enqueue(oct->droq[i]->droq_taskqueue,
2135f173c2b7SSean Bruno 						  &oct->droq[i]->droq_task);
2136f173c2b7SSean Bruno 			}
2137f173c2b7SSean Bruno 		}
2138f173c2b7SSean Bruno 
2139f173c2b7SSean Bruno 		pkt_cnt = 0;
2140f173c2b7SSean Bruno 		lio_sleep_timeout(1);
2141f173c2b7SSean Bruno 	} while (retry-- && pending_pkts);
2142f173c2b7SSean Bruno 
2143f173c2b7SSean Bruno 	return (pkt_cnt);
2144f173c2b7SSean Bruno }
2145f173c2b7SSean Bruno 
2146f173c2b7SSean Bruno static void
2147f173c2b7SSean Bruno lio_destroy_resources(struct octeon_device *oct)
2148f173c2b7SSean Bruno {
2149f173c2b7SSean Bruno 	int i, refcount;
2150f173c2b7SSean Bruno 
2151f173c2b7SSean Bruno 	switch (atomic_load_acq_int(&oct->status)) {
2152f173c2b7SSean Bruno 	case LIO_DEV_RUNNING:
2153f173c2b7SSean Bruno 	case LIO_DEV_CORE_OK:
2154f173c2b7SSean Bruno 		/* No more instructions will be forwarded. */
2155f173c2b7SSean Bruno 		atomic_store_rel_int(&oct->status, LIO_DEV_IN_RESET);
2156f173c2b7SSean Bruno 
2157f173c2b7SSean Bruno 		oct->app_mode = LIO_DRV_INVALID_APP;
2158f173c2b7SSean Bruno 		lio_dev_dbg(oct, "Device state is now %s\n",
2159f173c2b7SSean Bruno 			    lio_get_state_string(&oct->status));
2160f173c2b7SSean Bruno 
2161f173c2b7SSean Bruno 		lio_sleep_timeout(100);
2162f173c2b7SSean Bruno 
2163f173c2b7SSean Bruno 		/* fallthrough */
2164f173c2b7SSean Bruno 	case LIO_DEV_HOST_OK:
2165f173c2b7SSean Bruno 
2166f173c2b7SSean Bruno 		/* fallthrough */
2167f173c2b7SSean Bruno 	case LIO_DEV_CONSOLE_INIT_DONE:
2168f173c2b7SSean Bruno 		/* Remove any consoles */
2169f173c2b7SSean Bruno 		lio_remove_consoles(oct);
2170f173c2b7SSean Bruno 
2171f173c2b7SSean Bruno 		/* fallthrough */
2172f173c2b7SSean Bruno 	case LIO_DEV_IO_QUEUES_DONE:
2173f173c2b7SSean Bruno 		if (lio_wait_for_pending_requests(oct))
2174f173c2b7SSean Bruno 			lio_dev_err(oct, "There were pending requests\n");
2175f173c2b7SSean Bruno 
2176f173c2b7SSean Bruno 		if (lio_wait_for_instr_fetch(oct))
2177f173c2b7SSean Bruno 			lio_dev_err(oct, "IQ had pending instructions\n");
2178f173c2b7SSean Bruno 
2179f173c2b7SSean Bruno 		/*
2180f173c2b7SSean Bruno 		 * Disable the input and output queues now. No more packets will
2181f173c2b7SSean Bruno 		 * arrive from Octeon, but we should wait for all packet
2182f173c2b7SSean Bruno 		 * processing to finish.
2183f173c2b7SSean Bruno 		 */
2184f173c2b7SSean Bruno 		oct->fn_list.disable_io_queues(oct);
2185f173c2b7SSean Bruno 
2186f173c2b7SSean Bruno 		if (lio_wait_for_oq_pkts(oct))
2187f173c2b7SSean Bruno 			lio_dev_err(oct, "OQ had pending packets\n");
2188f173c2b7SSean Bruno 
2189f173c2b7SSean Bruno 		/* fallthrough */
2190f173c2b7SSean Bruno 	case LIO_DEV_INTR_SET_DONE:
2191f173c2b7SSean Bruno 		/* Disable interrupts  */
2192f173c2b7SSean Bruno 		oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR);
2193f173c2b7SSean Bruno 
2194f173c2b7SSean Bruno 		if (oct->msix_on) {
2195f173c2b7SSean Bruno 			for (i = 0; i < oct->num_msix_irqs - 1; i++) {
2196f173c2b7SSean Bruno 				if (oct->ioq_vector[i].tag != NULL) {
2197f173c2b7SSean Bruno 					bus_teardown_intr(oct->device,
2198f173c2b7SSean Bruno 						  oct->ioq_vector[i].msix_res,
2199f173c2b7SSean Bruno 						      oct->ioq_vector[i].tag);
2200f173c2b7SSean Bruno 					oct->ioq_vector[i].tag = NULL;
2201f173c2b7SSean Bruno 				}
2202f173c2b7SSean Bruno 				if (oct->ioq_vector[i].msix_res != NULL) {
2203f173c2b7SSean Bruno 					bus_release_resource(oct->device,
2204f173c2b7SSean Bruno 						SYS_RES_IRQ,
2205f173c2b7SSean Bruno 						oct->ioq_vector[i].vector,
2206f173c2b7SSean Bruno 						oct->ioq_vector[i].msix_res);
2207f173c2b7SSean Bruno 					oct->ioq_vector[i].msix_res = NULL;
2208f173c2b7SSean Bruno 				}
2209f173c2b7SSean Bruno 			}
2210f173c2b7SSean Bruno 			/* non-iov vector's argument is oct struct */
2211f173c2b7SSean Bruno 			if (oct->tag != NULL) {
2212f173c2b7SSean Bruno 				bus_teardown_intr(oct->device, oct->msix_res,
2213f173c2b7SSean Bruno 						  oct->tag);
2214f173c2b7SSean Bruno 				oct->tag = NULL;
2215f173c2b7SSean Bruno 			}
2216f173c2b7SSean Bruno 
2217f173c2b7SSean Bruno 			if (oct->msix_res != NULL) {
2218f173c2b7SSean Bruno 				bus_release_resource(oct->device, SYS_RES_IRQ,
2219f173c2b7SSean Bruno 						     oct->aux_vector,
2220f173c2b7SSean Bruno 						     oct->msix_res);
2221f173c2b7SSean Bruno 				oct->msix_res = NULL;
2222f173c2b7SSean Bruno 			}
2223f173c2b7SSean Bruno 
2224f173c2b7SSean Bruno 			pci_release_msi(oct->device);
2225f173c2b7SSean Bruno 		}
2226f173c2b7SSean Bruno 		/* fallthrough */
2227f173c2b7SSean Bruno 	case LIO_DEV_IN_RESET:
2228f173c2b7SSean Bruno 	case LIO_DEV_DROQ_INIT_DONE:
2229f173c2b7SSean Bruno 		/* Wait for any pending operations */
2230f173c2b7SSean Bruno 		lio_mdelay(100);
2231f173c2b7SSean Bruno 		for (i = 0; i < LIO_MAX_OUTPUT_QUEUES(oct); i++) {
2232f173c2b7SSean Bruno 			if (!(oct->io_qmask.oq & BIT_ULL(i)))
2233f173c2b7SSean Bruno 				continue;
2234f173c2b7SSean Bruno 			lio_delete_droq(oct, i);
2235f173c2b7SSean Bruno 		}
2236f173c2b7SSean Bruno 
2237f173c2b7SSean Bruno 		/* fallthrough */
2238f173c2b7SSean Bruno 	case LIO_DEV_RESP_LIST_INIT_DONE:
2239f173c2b7SSean Bruno 		for (i = 0; i < LIO_MAX_POSSIBLE_OUTPUT_QUEUES; i++) {
2240f173c2b7SSean Bruno 			if (oct->droq[i] != NULL) {
2241f173c2b7SSean Bruno 				free(oct->droq[i], M_DEVBUF);
2242f173c2b7SSean Bruno 				oct->droq[i] = NULL;
2243f173c2b7SSean Bruno 			}
2244f173c2b7SSean Bruno 		}
2245f173c2b7SSean Bruno 		lio_delete_response_list(oct);
2246f173c2b7SSean Bruno 
2247f173c2b7SSean Bruno 		/* fallthrough */
2248f173c2b7SSean Bruno 	case LIO_DEV_INSTR_QUEUE_INIT_DONE:
2249f173c2b7SSean Bruno 		for (i = 0; i < LIO_MAX_INSTR_QUEUES(oct); i++) {
2250f173c2b7SSean Bruno 			if (!(oct->io_qmask.iq & BIT_ULL(i)))
2251f173c2b7SSean Bruno 				continue;
2252f173c2b7SSean Bruno 
2253f173c2b7SSean Bruno 			lio_delete_instr_queue(oct, i);
2254f173c2b7SSean Bruno 		}
2255f173c2b7SSean Bruno 
2256f173c2b7SSean Bruno 		/* fallthrough */
2257f173c2b7SSean Bruno 	case LIO_DEV_MSIX_ALLOC_VECTOR_DONE:
2258f173c2b7SSean Bruno 		for (i = 0; i < LIO_MAX_POSSIBLE_INSTR_QUEUES; i++) {
2259f173c2b7SSean Bruno 			if (oct->instr_queue[i] != NULL) {
2260f173c2b7SSean Bruno 				free(oct->instr_queue[i], M_DEVBUF);
2261f173c2b7SSean Bruno 				oct->instr_queue[i] = NULL;
2262f173c2b7SSean Bruno 			}
2263f173c2b7SSean Bruno 		}
2264f173c2b7SSean Bruno 		lio_free_ioq_vector(oct);
2265f173c2b7SSean Bruno 
2266f173c2b7SSean Bruno 		/* fallthrough */
2267f173c2b7SSean Bruno 	case LIO_DEV_SC_BUFF_POOL_INIT_DONE:
2268f173c2b7SSean Bruno 		lio_free_sc_buffer_pool(oct);
2269f173c2b7SSean Bruno 
2270f173c2b7SSean Bruno 		/* fallthrough */
2271f173c2b7SSean Bruno 	case LIO_DEV_DISPATCH_INIT_DONE:
2272f173c2b7SSean Bruno 		lio_delete_dispatch_list(oct);
2273f173c2b7SSean Bruno 
2274f173c2b7SSean Bruno 		/* fallthrough */
2275f173c2b7SSean Bruno 	case LIO_DEV_PCI_MAP_DONE:
2276f173c2b7SSean Bruno 		refcount = lio_deregister_device(oct);
2277f173c2b7SSean Bruno 
2278f173c2b7SSean Bruno 		if (fw_type_is_none())
2279f173c2b7SSean Bruno 			lio_pci_flr(oct);
2280f173c2b7SSean Bruno 
2281f173c2b7SSean Bruno 		if (!refcount)
2282f173c2b7SSean Bruno 			oct->fn_list.soft_reset(oct);
2283f173c2b7SSean Bruno 
2284f173c2b7SSean Bruno 		lio_unmap_pci_barx(oct, 0);
2285f173c2b7SSean Bruno 		lio_unmap_pci_barx(oct, 1);
2286f173c2b7SSean Bruno 
2287f173c2b7SSean Bruno 		/* fallthrough */
2288f173c2b7SSean Bruno 	case LIO_DEV_PCI_ENABLE_DONE:
2289f173c2b7SSean Bruno 		/* Disable the device, releasing the PCI INT */
2290f173c2b7SSean Bruno 		pci_disable_busmaster(oct->device);
2291f173c2b7SSean Bruno 
2292f173c2b7SSean Bruno 		/* fallthrough */
2293f173c2b7SSean Bruno 	case LIO_DEV_BEGIN_STATE:
2294f173c2b7SSean Bruno 		break;
2295f173c2b7SSean Bruno 	}	/* end switch (oct->status) */
2296f173c2b7SSean Bruno }
2297