1718cf2ccSPedro F. Giffuni /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4711bcba0SDavid C Somayajulu * Copyright (c) 2013-2014 Qlogic Corporation
5711bcba0SDavid C Somayajulu * All rights reserved.
6711bcba0SDavid C Somayajulu *
7711bcba0SDavid C Somayajulu * Redistribution and use in source and binary forms, with or without
8711bcba0SDavid C Somayajulu * modification, are permitted provided that the following conditions
9711bcba0SDavid C Somayajulu * are met:
10711bcba0SDavid C Somayajulu *
11711bcba0SDavid C Somayajulu * 1. Redistributions of source code must retain the above copyright
12711bcba0SDavid C Somayajulu * notice, this list of conditions and the following disclaimer.
13711bcba0SDavid C Somayajulu * 2. Redistributions in binary form must reproduce the above copyright
14711bcba0SDavid C Somayajulu * notice, this list of conditions and the following disclaimer in the
15711bcba0SDavid C Somayajulu * documentation and/or other materials provided with the distribution.
16711bcba0SDavid C Somayajulu *
17711bcba0SDavid C Somayajulu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18711bcba0SDavid C Somayajulu * and ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19711bcba0SDavid C Somayajulu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20711bcba0SDavid C Somayajulu * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21711bcba0SDavid C Somayajulu * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22711bcba0SDavid C Somayajulu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23711bcba0SDavid C Somayajulu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24711bcba0SDavid C Somayajulu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25711bcba0SDavid C Somayajulu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26711bcba0SDavid C Somayajulu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27711bcba0SDavid C Somayajulu * POSSIBILITY OF SUCH DAMAGE.
28711bcba0SDavid C Somayajulu */
29711bcba0SDavid C Somayajulu
30711bcba0SDavid C Somayajulu /*
31711bcba0SDavid C Somayajulu * File: qls_os.c
32711bcba0SDavid C Somayajulu * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
33711bcba0SDavid C Somayajulu */
34711bcba0SDavid C Somayajulu
35711bcba0SDavid C Somayajulu #include <sys/cdefs.h>
36711bcba0SDavid C Somayajulu #include "qls_os.h"
37711bcba0SDavid C Somayajulu #include "qls_hw.h"
38711bcba0SDavid C Somayajulu #include "qls_def.h"
39711bcba0SDavid C Somayajulu #include "qls_inline.h"
40711bcba0SDavid C Somayajulu #include "qls_ver.h"
41711bcba0SDavid C Somayajulu #include "qls_glbl.h"
42711bcba0SDavid C Somayajulu #include "qls_dbg.h"
43711bcba0SDavid C Somayajulu #include <sys/smp.h>
44711bcba0SDavid C Somayajulu
45711bcba0SDavid C Somayajulu /*
46711bcba0SDavid C Somayajulu * Some PCI Configuration Space Related Defines
47711bcba0SDavid C Somayajulu */
48711bcba0SDavid C Somayajulu
49711bcba0SDavid C Somayajulu #ifndef PCI_VENDOR_QLOGIC
50711bcba0SDavid C Somayajulu #define PCI_VENDOR_QLOGIC 0x1077
51711bcba0SDavid C Somayajulu #endif
52711bcba0SDavid C Somayajulu
53711bcba0SDavid C Somayajulu #ifndef PCI_DEVICE_QLOGIC_8000
54711bcba0SDavid C Somayajulu #define PCI_DEVICE_QLOGIC_8000 0x8000
55711bcba0SDavid C Somayajulu #endif
56711bcba0SDavid C Somayajulu
57711bcba0SDavid C Somayajulu #define PCI_QLOGIC_DEV8000 \
58711bcba0SDavid C Somayajulu ((PCI_DEVICE_QLOGIC_8000 << 16) | PCI_VENDOR_QLOGIC)
59711bcba0SDavid C Somayajulu
60711bcba0SDavid C Somayajulu /*
61711bcba0SDavid C Somayajulu * static functions
62711bcba0SDavid C Somayajulu */
63711bcba0SDavid C Somayajulu static int qls_alloc_parent_dma_tag(qla_host_t *ha);
64711bcba0SDavid C Somayajulu static void qls_free_parent_dma_tag(qla_host_t *ha);
65711bcba0SDavid C Somayajulu
66711bcba0SDavid C Somayajulu static void qls_flush_xmt_bufs(qla_host_t *ha);
67711bcba0SDavid C Somayajulu
68711bcba0SDavid C Somayajulu static int qls_alloc_rcv_bufs(qla_host_t *ha);
69711bcba0SDavid C Somayajulu static void qls_free_rcv_bufs(qla_host_t *ha);
70711bcba0SDavid C Somayajulu
71711bcba0SDavid C Somayajulu static void qls_init_ifnet(device_t dev, qla_host_t *ha);
72711bcba0SDavid C Somayajulu static void qls_release(qla_host_t *ha);
73711bcba0SDavid C Somayajulu static void qls_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs,
74711bcba0SDavid C Somayajulu int error);
75711bcba0SDavid C Somayajulu static void qls_stop(qla_host_t *ha);
76711bcba0SDavid C Somayajulu static int qls_send(qla_host_t *ha, struct mbuf **m_headp);
77711bcba0SDavid C Somayajulu static void qls_tx_done(void *context, int pending);
78711bcba0SDavid C Somayajulu
79711bcba0SDavid C Somayajulu static int qls_config_lro(qla_host_t *ha);
80711bcba0SDavid C Somayajulu static void qls_free_lro(qla_host_t *ha);
81711bcba0SDavid C Somayajulu
82711bcba0SDavid C Somayajulu static void qls_error_recovery(void *context, int pending);
83711bcba0SDavid C Somayajulu
84711bcba0SDavid C Somayajulu /*
85711bcba0SDavid C Somayajulu * Hooks to the Operating Systems
86711bcba0SDavid C Somayajulu */
87711bcba0SDavid C Somayajulu static int qls_pci_probe (device_t);
88711bcba0SDavid C Somayajulu static int qls_pci_attach (device_t);
89711bcba0SDavid C Somayajulu static int qls_pci_detach (device_t);
90711bcba0SDavid C Somayajulu
9164c618edSJustin Hibbits static void qls_start(if_t ifp);
92711bcba0SDavid C Somayajulu static void qls_init(void *arg);
9364c618edSJustin Hibbits static int qls_ioctl(if_t ifp, u_long cmd, caddr_t data);
9464c618edSJustin Hibbits static int qls_media_change(if_t ifp);
9564c618edSJustin Hibbits static void qls_media_status(if_t ifp, struct ifmediareq *ifmr);
96711bcba0SDavid C Somayajulu
97711bcba0SDavid C Somayajulu static device_method_t qla_pci_methods[] = {
98711bcba0SDavid C Somayajulu /* Device interface */
99711bcba0SDavid C Somayajulu DEVMETHOD(device_probe, qls_pci_probe),
100711bcba0SDavid C Somayajulu DEVMETHOD(device_attach, qls_pci_attach),
101711bcba0SDavid C Somayajulu DEVMETHOD(device_detach, qls_pci_detach),
102711bcba0SDavid C Somayajulu { 0, 0 }
103711bcba0SDavid C Somayajulu };
104711bcba0SDavid C Somayajulu
105711bcba0SDavid C Somayajulu static driver_t qla_pci_driver = {
106711bcba0SDavid C Somayajulu "ql", qla_pci_methods, sizeof (qla_host_t),
107711bcba0SDavid C Somayajulu };
108711bcba0SDavid C Somayajulu
1092f87208eSJohn Baldwin DRIVER_MODULE(qla8000, pci, qla_pci_driver, 0, 0);
110711bcba0SDavid C Somayajulu
111711bcba0SDavid C Somayajulu MODULE_DEPEND(qla8000, pci, 1, 1, 1);
112711bcba0SDavid C Somayajulu MODULE_DEPEND(qla8000, ether, 1, 1, 1);
113711bcba0SDavid C Somayajulu
114711bcba0SDavid C Somayajulu MALLOC_DEFINE(M_QLA8000BUF, "qla8000buf", "Buffers for qla8000 driver");
115711bcba0SDavid C Somayajulu
116711bcba0SDavid C Somayajulu static char dev_str[64];
117711bcba0SDavid C Somayajulu static char ver_str[64];
118711bcba0SDavid C Somayajulu
119711bcba0SDavid C Somayajulu /*
120711bcba0SDavid C Somayajulu * Name: qls_pci_probe
121711bcba0SDavid C Somayajulu * Function: Validate the PCI device to be a QLA80XX device
122711bcba0SDavid C Somayajulu */
123711bcba0SDavid C Somayajulu static int
qls_pci_probe(device_t dev)124711bcba0SDavid C Somayajulu qls_pci_probe(device_t dev)
125711bcba0SDavid C Somayajulu {
126711bcba0SDavid C Somayajulu switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
127711bcba0SDavid C Somayajulu case PCI_QLOGIC_DEV8000:
128711bcba0SDavid C Somayajulu snprintf(dev_str, sizeof(dev_str), "%s v%d.%d.%d",
129711bcba0SDavid C Somayajulu "Qlogic ISP 8000 PCI CNA Adapter-Ethernet Function",
130711bcba0SDavid C Somayajulu QLA_VERSION_MAJOR, QLA_VERSION_MINOR,
131711bcba0SDavid C Somayajulu QLA_VERSION_BUILD);
132711bcba0SDavid C Somayajulu snprintf(ver_str, sizeof(ver_str), "v%d.%d.%d",
133711bcba0SDavid C Somayajulu QLA_VERSION_MAJOR, QLA_VERSION_MINOR,
134711bcba0SDavid C Somayajulu QLA_VERSION_BUILD);
135711bcba0SDavid C Somayajulu device_set_desc(dev, dev_str);
136711bcba0SDavid C Somayajulu break;
137711bcba0SDavid C Somayajulu default:
138711bcba0SDavid C Somayajulu return (ENXIO);
139711bcba0SDavid C Somayajulu }
140711bcba0SDavid C Somayajulu
141711bcba0SDavid C Somayajulu if (bootverbose)
142711bcba0SDavid C Somayajulu printf("%s: %s\n ", __func__, dev_str);
143711bcba0SDavid C Somayajulu
144711bcba0SDavid C Somayajulu return (BUS_PROBE_DEFAULT);
145711bcba0SDavid C Somayajulu }
146711bcba0SDavid C Somayajulu
147711bcba0SDavid C Somayajulu static int
qls_sysctl_get_drvr_stats(SYSCTL_HANDLER_ARGS)148711bcba0SDavid C Somayajulu qls_sysctl_get_drvr_stats(SYSCTL_HANDLER_ARGS)
149711bcba0SDavid C Somayajulu {
150711bcba0SDavid C Somayajulu int err = 0, ret;
151711bcba0SDavid C Somayajulu qla_host_t *ha;
152711bcba0SDavid C Somayajulu uint32_t i;
153711bcba0SDavid C Somayajulu
154711bcba0SDavid C Somayajulu err = sysctl_handle_int(oidp, &ret, 0, req);
155711bcba0SDavid C Somayajulu
156711bcba0SDavid C Somayajulu if (err || !req->newptr)
157711bcba0SDavid C Somayajulu return (err);
158711bcba0SDavid C Somayajulu
159711bcba0SDavid C Somayajulu if (ret == 1) {
160711bcba0SDavid C Somayajulu ha = (qla_host_t *)arg1;
161711bcba0SDavid C Somayajulu
162711bcba0SDavid C Somayajulu for (i = 0; i < ha->num_tx_rings; i++) {
163*ae389777SFuqian Huang QL_DPRINT2((ha->pci_dev,
164711bcba0SDavid C Somayajulu "%s: tx_ring[%d].tx_frames= %p\n",
165711bcba0SDavid C Somayajulu __func__, i,
166*ae389777SFuqian Huang (void *)ha->tx_ring[i].tx_frames));
167711bcba0SDavid C Somayajulu
168*ae389777SFuqian Huang QL_DPRINT2((ha->pci_dev,
169711bcba0SDavid C Somayajulu "%s: tx_ring[%d].tx_tso_frames= %p\n",
170711bcba0SDavid C Somayajulu __func__, i,
171*ae389777SFuqian Huang (void *)ha->tx_ring[i].tx_tso_frames));
172711bcba0SDavid C Somayajulu
173*ae389777SFuqian Huang QL_DPRINT2((ha->pci_dev,
174711bcba0SDavid C Somayajulu "%s: tx_ring[%d].tx_vlan_frames= %p\n",
175711bcba0SDavid C Somayajulu __func__, i,
176*ae389777SFuqian Huang (void *)ha->tx_ring[i].tx_vlan_frames));
177711bcba0SDavid C Somayajulu
178711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
179711bcba0SDavid C Somayajulu "%s: tx_ring[%d].txr_free= 0x%08x\n",
180711bcba0SDavid C Somayajulu __func__, i,
181711bcba0SDavid C Somayajulu ha->tx_ring[i].txr_free);
182711bcba0SDavid C Somayajulu
183711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
184711bcba0SDavid C Somayajulu "%s: tx_ring[%d].txr_next= 0x%08x\n",
185711bcba0SDavid C Somayajulu __func__, i,
186711bcba0SDavid C Somayajulu ha->tx_ring[i].txr_next);
187711bcba0SDavid C Somayajulu
188711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
189711bcba0SDavid C Somayajulu "%s: tx_ring[%d].txr_done= 0x%08x\n",
190711bcba0SDavid C Somayajulu __func__, i,
191711bcba0SDavid C Somayajulu ha->tx_ring[i].txr_done);
192711bcba0SDavid C Somayajulu
193711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
194711bcba0SDavid C Somayajulu "%s: tx_ring[%d].txr_cons_idx= 0x%08x\n",
195711bcba0SDavid C Somayajulu __func__, i,
196711bcba0SDavid C Somayajulu *(ha->tx_ring[i].txr_cons_vaddr));
197711bcba0SDavid C Somayajulu }
198711bcba0SDavid C Somayajulu
199711bcba0SDavid C Somayajulu for (i = 0; i < ha->num_rx_rings; i++) {
200*ae389777SFuqian Huang QL_DPRINT2((ha->pci_dev,
201711bcba0SDavid C Somayajulu "%s: rx_ring[%d].rx_int= %p\n",
202711bcba0SDavid C Somayajulu __func__, i,
203*ae389777SFuqian Huang (void *)ha->rx_ring[i].rx_int));
204711bcba0SDavid C Somayajulu
205*ae389777SFuqian Huang QL_DPRINT2((ha->pci_dev,
206711bcba0SDavid C Somayajulu "%s: rx_ring[%d].rss_int= %p\n",
207711bcba0SDavid C Somayajulu __func__, i,
208*ae389777SFuqian Huang (void *)ha->rx_ring[i].rss_int));
209711bcba0SDavid C Somayajulu
210711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
211711bcba0SDavid C Somayajulu "%s: rx_ring[%d].lbq_next= 0x%08x\n",
212711bcba0SDavid C Somayajulu __func__, i,
213711bcba0SDavid C Somayajulu ha->rx_ring[i].lbq_next);
214711bcba0SDavid C Somayajulu
215711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
216711bcba0SDavid C Somayajulu "%s: rx_ring[%d].lbq_free= 0x%08x\n",
217711bcba0SDavid C Somayajulu __func__, i,
218711bcba0SDavid C Somayajulu ha->rx_ring[i].lbq_free);
219711bcba0SDavid C Somayajulu
220711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
221711bcba0SDavid C Somayajulu "%s: rx_ring[%d].lbq_in= 0x%08x\n",
222711bcba0SDavid C Somayajulu __func__, i,
223711bcba0SDavid C Somayajulu ha->rx_ring[i].lbq_in);
224711bcba0SDavid C Somayajulu
225711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
226711bcba0SDavid C Somayajulu "%s: rx_ring[%d].sbq_next= 0x%08x\n",
227711bcba0SDavid C Somayajulu __func__, i,
228711bcba0SDavid C Somayajulu ha->rx_ring[i].sbq_next);
229711bcba0SDavid C Somayajulu
230711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
231711bcba0SDavid C Somayajulu "%s: rx_ring[%d].sbq_free= 0x%08x\n",
232711bcba0SDavid C Somayajulu __func__, i,
233711bcba0SDavid C Somayajulu ha->rx_ring[i].sbq_free);
234711bcba0SDavid C Somayajulu
235711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
236711bcba0SDavid C Somayajulu "%s: rx_ring[%d].sbq_in= 0x%08x\n",
237711bcba0SDavid C Somayajulu __func__, i,
238711bcba0SDavid C Somayajulu ha->rx_ring[i].sbq_in);
239711bcba0SDavid C Somayajulu }
240711bcba0SDavid C Somayajulu
241711bcba0SDavid C Somayajulu device_printf(ha->pci_dev, "%s: err_m_getcl = 0x%08x\n",
242711bcba0SDavid C Somayajulu __func__, ha->err_m_getcl);
243711bcba0SDavid C Somayajulu device_printf(ha->pci_dev, "%s: err_m_getjcl = 0x%08x\n",
244711bcba0SDavid C Somayajulu __func__, ha->err_m_getjcl);
245711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
246711bcba0SDavid C Somayajulu "%s: err_tx_dmamap_create = 0x%08x\n",
247711bcba0SDavid C Somayajulu __func__, ha->err_tx_dmamap_create);
248711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
249711bcba0SDavid C Somayajulu "%s: err_tx_dmamap_load = 0x%08x\n",
250711bcba0SDavid C Somayajulu __func__, ha->err_tx_dmamap_load);
251711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
252711bcba0SDavid C Somayajulu "%s: err_tx_defrag = 0x%08x\n",
253711bcba0SDavid C Somayajulu __func__, ha->err_tx_defrag);
254711bcba0SDavid C Somayajulu }
255711bcba0SDavid C Somayajulu return (err);
256711bcba0SDavid C Somayajulu }
257711bcba0SDavid C Somayajulu
258711bcba0SDavid C Somayajulu static void
qls_add_sysctls(qla_host_t * ha)259711bcba0SDavid C Somayajulu qls_add_sysctls(qla_host_t *ha)
260711bcba0SDavid C Somayajulu {
261711bcba0SDavid C Somayajulu device_t dev = ha->pci_dev;
262711bcba0SDavid C Somayajulu
263711bcba0SDavid C Somayajulu SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev),
264711bcba0SDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
265711bcba0SDavid C Somayajulu OID_AUTO, "version", CTLFLAG_RD,
266711bcba0SDavid C Somayajulu ver_str, 0, "Driver Version");
267711bcba0SDavid C Somayajulu
268711bcba0SDavid C Somayajulu qls_dbg_level = 0;
269711bcba0SDavid C Somayajulu SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
270711bcba0SDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
271711bcba0SDavid C Somayajulu OID_AUTO, "debug", CTLFLAG_RW,
272711bcba0SDavid C Somayajulu &qls_dbg_level, qls_dbg_level, "Debug Level");
273711bcba0SDavid C Somayajulu
274711bcba0SDavid C Somayajulu SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
275711bcba0SDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
2767029da5cSPawel Biernacki OID_AUTO, "drvr_stats",
2777029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, (void *)ha, 0,
278711bcba0SDavid C Somayajulu qls_sysctl_get_drvr_stats, "I", "Driver Maintained Statistics");
279711bcba0SDavid C Somayajulu
280711bcba0SDavid C Somayajulu return;
281711bcba0SDavid C Somayajulu }
282711bcba0SDavid C Somayajulu
283711bcba0SDavid C Somayajulu static void
qls_watchdog(void * arg)284711bcba0SDavid C Somayajulu qls_watchdog(void *arg)
285711bcba0SDavid C Somayajulu {
286711bcba0SDavid C Somayajulu qla_host_t *ha = arg;
28764c618edSJustin Hibbits if_t ifp;
288711bcba0SDavid C Somayajulu
289711bcba0SDavid C Somayajulu ifp = ha->ifp;
290711bcba0SDavid C Somayajulu
291711bcba0SDavid C Somayajulu if (ha->flags.qla_watchdog_exit) {
292711bcba0SDavid C Somayajulu ha->qla_watchdog_exited = 1;
293711bcba0SDavid C Somayajulu return;
294711bcba0SDavid C Somayajulu }
295711bcba0SDavid C Somayajulu ha->qla_watchdog_exited = 0;
296711bcba0SDavid C Somayajulu
297711bcba0SDavid C Somayajulu if (!ha->flags.qla_watchdog_pause) {
298711bcba0SDavid C Somayajulu if (ha->qla_initiate_recovery) {
299711bcba0SDavid C Somayajulu ha->qla_watchdog_paused = 1;
300711bcba0SDavid C Somayajulu ha->qla_initiate_recovery = 0;
301711bcba0SDavid C Somayajulu ha->err_inject = 0;
302711bcba0SDavid C Somayajulu taskqueue_enqueue(ha->err_tq, &ha->err_task);
303711bcba0SDavid C Somayajulu
30464c618edSJustin Hibbits } else if (!if_sendq_empty(ifp) && QL_RUNNING(ifp)) {
305711bcba0SDavid C Somayajulu taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
306711bcba0SDavid C Somayajulu }
307711bcba0SDavid C Somayajulu
308711bcba0SDavid C Somayajulu ha->qla_watchdog_paused = 0;
309711bcba0SDavid C Somayajulu } else {
310711bcba0SDavid C Somayajulu ha->qla_watchdog_paused = 1;
311711bcba0SDavid C Somayajulu }
312711bcba0SDavid C Somayajulu
31382b5e644SConrad Meyer ha->watchdog_ticks = (ha->watchdog_ticks + 1) % 1000;
314711bcba0SDavid C Somayajulu callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
315711bcba0SDavid C Somayajulu qls_watchdog, ha);
316711bcba0SDavid C Somayajulu
317711bcba0SDavid C Somayajulu return;
318711bcba0SDavid C Somayajulu }
319711bcba0SDavid C Somayajulu
320711bcba0SDavid C Somayajulu /*
321711bcba0SDavid C Somayajulu * Name: qls_pci_attach
322711bcba0SDavid C Somayajulu * Function: attaches the device to the operating system
323711bcba0SDavid C Somayajulu */
324711bcba0SDavid C Somayajulu static int
qls_pci_attach(device_t dev)325711bcba0SDavid C Somayajulu qls_pci_attach(device_t dev)
326711bcba0SDavid C Somayajulu {
327711bcba0SDavid C Somayajulu qla_host_t *ha = NULL;
328711bcba0SDavid C Somayajulu int i;
329711bcba0SDavid C Somayajulu
330711bcba0SDavid C Somayajulu QL_DPRINT2((dev, "%s: enter\n", __func__));
331711bcba0SDavid C Somayajulu
332711bcba0SDavid C Somayajulu if ((ha = device_get_softc(dev)) == NULL) {
333711bcba0SDavid C Somayajulu device_printf(dev, "cannot get softc\n");
334711bcba0SDavid C Somayajulu return (ENOMEM);
335711bcba0SDavid C Somayajulu }
336711bcba0SDavid C Somayajulu
337711bcba0SDavid C Somayajulu memset(ha, 0, sizeof (qla_host_t));
338711bcba0SDavid C Somayajulu
339711bcba0SDavid C Somayajulu if (pci_get_device(dev) != PCI_DEVICE_QLOGIC_8000) {
340711bcba0SDavid C Somayajulu device_printf(dev, "device is not QLE8000\n");
341711bcba0SDavid C Somayajulu return (ENXIO);
342711bcba0SDavid C Somayajulu }
343711bcba0SDavid C Somayajulu
344711bcba0SDavid C Somayajulu ha->pci_func = pci_get_function(dev);
345711bcba0SDavid C Somayajulu
346711bcba0SDavid C Somayajulu ha->pci_dev = dev;
347711bcba0SDavid C Somayajulu
348711bcba0SDavid C Somayajulu pci_enable_busmaster(dev);
349711bcba0SDavid C Somayajulu
350711bcba0SDavid C Somayajulu ha->reg_rid = PCIR_BAR(1);
351711bcba0SDavid C Somayajulu ha->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ha->reg_rid,
352711bcba0SDavid C Somayajulu RF_ACTIVE);
353711bcba0SDavid C Somayajulu
354711bcba0SDavid C Somayajulu if (ha->pci_reg == NULL) {
355711bcba0SDavid C Somayajulu device_printf(dev, "unable to map any ports\n");
356711bcba0SDavid C Somayajulu goto qls_pci_attach_err;
357711bcba0SDavid C Somayajulu }
358711bcba0SDavid C Somayajulu
359711bcba0SDavid C Somayajulu ha->reg_rid1 = PCIR_BAR(3);
360711bcba0SDavid C Somayajulu ha->pci_reg1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
361711bcba0SDavid C Somayajulu &ha->reg_rid1, RF_ACTIVE);
362711bcba0SDavid C Somayajulu
363711bcba0SDavid C Somayajulu if (ha->pci_reg1 == NULL) {
364711bcba0SDavid C Somayajulu device_printf(dev, "unable to map any ports\n");
365711bcba0SDavid C Somayajulu goto qls_pci_attach_err;
366711bcba0SDavid C Somayajulu }
367711bcba0SDavid C Somayajulu
368711bcba0SDavid C Somayajulu mtx_init(&ha->hw_lock, "qla80xx_hw_lock", MTX_NETWORK_LOCK, MTX_DEF);
369711bcba0SDavid C Somayajulu mtx_init(&ha->tx_lock, "qla80xx_tx_lock", MTX_NETWORK_LOCK, MTX_DEF);
370711bcba0SDavid C Somayajulu
371711bcba0SDavid C Somayajulu qls_add_sysctls(ha);
372711bcba0SDavid C Somayajulu qls_hw_add_sysctls(ha);
373711bcba0SDavid C Somayajulu
374711bcba0SDavid C Somayajulu ha->flags.lock_init = 1;
375711bcba0SDavid C Somayajulu
376711bcba0SDavid C Somayajulu ha->msix_count = pci_msix_count(dev);
377711bcba0SDavid C Somayajulu
378711bcba0SDavid C Somayajulu if (ha->msix_count < qls_get_msix_count(ha)) {
379711bcba0SDavid C Somayajulu device_printf(dev, "%s: msix_count[%d] not enough\n", __func__,
380711bcba0SDavid C Somayajulu ha->msix_count);
381711bcba0SDavid C Somayajulu goto qls_pci_attach_err;
382711bcba0SDavid C Somayajulu }
383711bcba0SDavid C Somayajulu
384711bcba0SDavid C Somayajulu ha->msix_count = qls_get_msix_count(ha);
385711bcba0SDavid C Somayajulu
386*ae389777SFuqian Huang QL_DPRINT2((dev, "\n%s: ha %p pci_func 0x%x msix_count 0x%x"
387711bcba0SDavid C Somayajulu " pci_reg %p pci_reg1 %p\n", __func__, ha,
388*ae389777SFuqian Huang ha->pci_func, ha->msix_count, ha->pci_reg, ha->pci_reg1));
389711bcba0SDavid C Somayajulu
390711bcba0SDavid C Somayajulu if (pci_alloc_msix(dev, &ha->msix_count)) {
391711bcba0SDavid C Somayajulu device_printf(dev, "%s: pci_alloc_msi[%d] failed\n", __func__,
392711bcba0SDavid C Somayajulu ha->msix_count);
393711bcba0SDavid C Somayajulu ha->msix_count = 0;
394711bcba0SDavid C Somayajulu goto qls_pci_attach_err;
395711bcba0SDavid C Somayajulu }
396711bcba0SDavid C Somayajulu
397711bcba0SDavid C Somayajulu for (i = 0; i < ha->num_rx_rings; i++) {
398711bcba0SDavid C Somayajulu ha->irq_vec[i].cq_idx = i;
399711bcba0SDavid C Somayajulu ha->irq_vec[i].ha = ha;
400711bcba0SDavid C Somayajulu ha->irq_vec[i].irq_rid = 1 + i;
401711bcba0SDavid C Somayajulu
402711bcba0SDavid C Somayajulu ha->irq_vec[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
403711bcba0SDavid C Somayajulu &ha->irq_vec[i].irq_rid,
404711bcba0SDavid C Somayajulu (RF_ACTIVE | RF_SHAREABLE));
405711bcba0SDavid C Somayajulu
406711bcba0SDavid C Somayajulu if (ha->irq_vec[i].irq == NULL) {
407711bcba0SDavid C Somayajulu device_printf(dev, "could not allocate interrupt\n");
408711bcba0SDavid C Somayajulu goto qls_pci_attach_err;
409711bcba0SDavid C Somayajulu }
410711bcba0SDavid C Somayajulu
411711bcba0SDavid C Somayajulu if (bus_setup_intr(dev, ha->irq_vec[i].irq,
412711bcba0SDavid C Somayajulu (INTR_TYPE_NET | INTR_MPSAFE), NULL, qls_isr,
413711bcba0SDavid C Somayajulu &ha->irq_vec[i], &ha->irq_vec[i].handle)) {
414711bcba0SDavid C Somayajulu device_printf(dev,
415711bcba0SDavid C Somayajulu "could not setup interrupt\n");
416711bcba0SDavid C Somayajulu goto qls_pci_attach_err;
417711bcba0SDavid C Somayajulu }
418711bcba0SDavid C Somayajulu }
419711bcba0SDavid C Somayajulu
420711bcba0SDavid C Somayajulu qls_rd_nic_params(ha);
421711bcba0SDavid C Somayajulu
422711bcba0SDavid C Somayajulu /* allocate parent dma tag */
423711bcba0SDavid C Somayajulu if (qls_alloc_parent_dma_tag(ha)) {
424711bcba0SDavid C Somayajulu device_printf(dev, "%s: qls_alloc_parent_dma_tag failed\n",
425711bcba0SDavid C Somayajulu __func__);
426711bcba0SDavid C Somayajulu goto qls_pci_attach_err;
427711bcba0SDavid C Somayajulu }
428711bcba0SDavid C Somayajulu
429711bcba0SDavid C Somayajulu /* alloc all dma buffers */
430711bcba0SDavid C Somayajulu if (qls_alloc_dma(ha)) {
431711bcba0SDavid C Somayajulu device_printf(dev, "%s: qls_alloc_dma failed\n", __func__);
432711bcba0SDavid C Somayajulu goto qls_pci_attach_err;
433711bcba0SDavid C Somayajulu }
434711bcba0SDavid C Somayajulu
435711bcba0SDavid C Somayajulu /* create the o.s ethernet interface */
436711bcba0SDavid C Somayajulu qls_init_ifnet(dev, ha);
437711bcba0SDavid C Somayajulu
438711bcba0SDavid C Somayajulu ha->flags.qla_watchdog_active = 1;
439711bcba0SDavid C Somayajulu ha->flags.qla_watchdog_pause = 1;
440711bcba0SDavid C Somayajulu
441711bcba0SDavid C Somayajulu TASK_INIT(&ha->tx_task, 0, qls_tx_done, ha);
442711bcba0SDavid C Somayajulu ha->tx_tq = taskqueue_create_fast("qla_txq", M_NOWAIT,
443711bcba0SDavid C Somayajulu taskqueue_thread_enqueue, &ha->tx_tq);
444711bcba0SDavid C Somayajulu taskqueue_start_threads(&ha->tx_tq, 1, PI_NET, "%s txq",
445711bcba0SDavid C Somayajulu device_get_nameunit(ha->pci_dev));
446711bcba0SDavid C Somayajulu
447fd90e2edSJung-uk Kim callout_init(&ha->tx_callout, 1);
448711bcba0SDavid C Somayajulu ha->flags.qla_callout_init = 1;
449711bcba0SDavid C Somayajulu
450711bcba0SDavid C Somayajulu /* create ioctl device interface */
451711bcba0SDavid C Somayajulu if (qls_make_cdev(ha)) {
452711bcba0SDavid C Somayajulu device_printf(dev, "%s: qls_make_cdev failed\n", __func__);
453711bcba0SDavid C Somayajulu goto qls_pci_attach_err;
454711bcba0SDavid C Somayajulu }
455711bcba0SDavid C Somayajulu
456711bcba0SDavid C Somayajulu callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
457711bcba0SDavid C Somayajulu qls_watchdog, ha);
458711bcba0SDavid C Somayajulu
459711bcba0SDavid C Somayajulu TASK_INIT(&ha->err_task, 0, qls_error_recovery, ha);
460711bcba0SDavid C Somayajulu ha->err_tq = taskqueue_create_fast("qla_errq", M_NOWAIT,
461711bcba0SDavid C Somayajulu taskqueue_thread_enqueue, &ha->err_tq);
462711bcba0SDavid C Somayajulu taskqueue_start_threads(&ha->err_tq, 1, PI_NET, "%s errq",
463711bcba0SDavid C Somayajulu device_get_nameunit(ha->pci_dev));
464711bcba0SDavid C Somayajulu
465711bcba0SDavid C Somayajulu QL_DPRINT2((dev, "%s: exit 0\n", __func__));
466711bcba0SDavid C Somayajulu return (0);
467711bcba0SDavid C Somayajulu
468711bcba0SDavid C Somayajulu qls_pci_attach_err:
469711bcba0SDavid C Somayajulu
470711bcba0SDavid C Somayajulu qls_release(ha);
471711bcba0SDavid C Somayajulu
472711bcba0SDavid C Somayajulu QL_DPRINT2((dev, "%s: exit ENXIO\n", __func__));
473711bcba0SDavid C Somayajulu return (ENXIO);
474711bcba0SDavid C Somayajulu }
475711bcba0SDavid C Somayajulu
476711bcba0SDavid C Somayajulu /*
477711bcba0SDavid C Somayajulu * Name: qls_pci_detach
478711bcba0SDavid C Somayajulu * Function: Unhooks the device from the operating system
479711bcba0SDavid C Somayajulu */
480711bcba0SDavid C Somayajulu static int
qls_pci_detach(device_t dev)481711bcba0SDavid C Somayajulu qls_pci_detach(device_t dev)
482711bcba0SDavid C Somayajulu {
483711bcba0SDavid C Somayajulu qla_host_t *ha = NULL;
484711bcba0SDavid C Somayajulu
485711bcba0SDavid C Somayajulu QL_DPRINT2((dev, "%s: enter\n", __func__));
486711bcba0SDavid C Somayajulu
487711bcba0SDavid C Somayajulu if ((ha = device_get_softc(dev)) == NULL) {
488711bcba0SDavid C Somayajulu device_printf(dev, "cannot get softc\n");
489711bcba0SDavid C Somayajulu return (ENOMEM);
490711bcba0SDavid C Somayajulu }
491711bcba0SDavid C Somayajulu
492711bcba0SDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0);
493711bcba0SDavid C Somayajulu qls_stop(ha);
494711bcba0SDavid C Somayajulu QLA_UNLOCK(ha, __func__);
495711bcba0SDavid C Somayajulu
496711bcba0SDavid C Somayajulu qls_release(ha);
497711bcba0SDavid C Somayajulu
498711bcba0SDavid C Somayajulu QL_DPRINT2((dev, "%s: exit\n", __func__));
499711bcba0SDavid C Somayajulu
500711bcba0SDavid C Somayajulu return (0);
501711bcba0SDavid C Somayajulu }
502711bcba0SDavid C Somayajulu
503711bcba0SDavid C Somayajulu /*
504711bcba0SDavid C Somayajulu * Name: qls_release
505711bcba0SDavid C Somayajulu * Function: Releases the resources allocated for the device
506711bcba0SDavid C Somayajulu */
507711bcba0SDavid C Somayajulu static void
qls_release(qla_host_t * ha)508711bcba0SDavid C Somayajulu qls_release(qla_host_t *ha)
509711bcba0SDavid C Somayajulu {
510711bcba0SDavid C Somayajulu device_t dev;
511711bcba0SDavid C Somayajulu int i;
512711bcba0SDavid C Somayajulu
513711bcba0SDavid C Somayajulu dev = ha->pci_dev;
514711bcba0SDavid C Somayajulu
515711bcba0SDavid C Somayajulu if (ha->err_tq) {
516711bcba0SDavid C Somayajulu taskqueue_drain(ha->err_tq, &ha->err_task);
517711bcba0SDavid C Somayajulu taskqueue_free(ha->err_tq);
518711bcba0SDavid C Somayajulu }
519711bcba0SDavid C Somayajulu
520711bcba0SDavid C Somayajulu if (ha->tx_tq) {
521711bcba0SDavid C Somayajulu taskqueue_drain(ha->tx_tq, &ha->tx_task);
522711bcba0SDavid C Somayajulu taskqueue_free(ha->tx_tq);
523711bcba0SDavid C Somayajulu }
524711bcba0SDavid C Somayajulu
525711bcba0SDavid C Somayajulu qls_del_cdev(ha);
526711bcba0SDavid C Somayajulu
527711bcba0SDavid C Somayajulu if (ha->flags.qla_watchdog_active) {
528711bcba0SDavid C Somayajulu ha->flags.qla_watchdog_exit = 1;
529711bcba0SDavid C Somayajulu
530711bcba0SDavid C Somayajulu while (ha->qla_watchdog_exited == 0)
531711bcba0SDavid C Somayajulu qls_mdelay(__func__, 1);
532711bcba0SDavid C Somayajulu }
533711bcba0SDavid C Somayajulu
534711bcba0SDavid C Somayajulu if (ha->flags.qla_callout_init)
535711bcba0SDavid C Somayajulu callout_stop(&ha->tx_callout);
536711bcba0SDavid C Somayajulu
537711bcba0SDavid C Somayajulu if (ha->ifp != NULL)
538711bcba0SDavid C Somayajulu ether_ifdetach(ha->ifp);
539711bcba0SDavid C Somayajulu
540711bcba0SDavid C Somayajulu qls_free_dma(ha);
541711bcba0SDavid C Somayajulu qls_free_parent_dma_tag(ha);
542711bcba0SDavid C Somayajulu
543711bcba0SDavid C Somayajulu for (i = 0; i < ha->num_rx_rings; i++) {
544711bcba0SDavid C Somayajulu if (ha->irq_vec[i].handle) {
545711bcba0SDavid C Somayajulu (void)bus_teardown_intr(dev, ha->irq_vec[i].irq,
546711bcba0SDavid C Somayajulu ha->irq_vec[i].handle);
547711bcba0SDavid C Somayajulu }
548711bcba0SDavid C Somayajulu
549711bcba0SDavid C Somayajulu if (ha->irq_vec[i].irq) {
550711bcba0SDavid C Somayajulu (void)bus_release_resource(dev, SYS_RES_IRQ,
551711bcba0SDavid C Somayajulu ha->irq_vec[i].irq_rid,
552711bcba0SDavid C Somayajulu ha->irq_vec[i].irq);
553711bcba0SDavid C Somayajulu }
554711bcba0SDavid C Somayajulu }
555711bcba0SDavid C Somayajulu
556711bcba0SDavid C Somayajulu if (ha->msix_count)
557711bcba0SDavid C Somayajulu pci_release_msi(dev);
558711bcba0SDavid C Somayajulu
559711bcba0SDavid C Somayajulu if (ha->flags.lock_init) {
560711bcba0SDavid C Somayajulu mtx_destroy(&ha->tx_lock);
561711bcba0SDavid C Somayajulu mtx_destroy(&ha->hw_lock);
562711bcba0SDavid C Somayajulu }
563711bcba0SDavid C Somayajulu
564711bcba0SDavid C Somayajulu if (ha->pci_reg)
565711bcba0SDavid C Somayajulu (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid,
566711bcba0SDavid C Somayajulu ha->pci_reg);
567711bcba0SDavid C Somayajulu
568711bcba0SDavid C Somayajulu if (ha->pci_reg1)
569711bcba0SDavid C Somayajulu (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid1,
570711bcba0SDavid C Somayajulu ha->pci_reg1);
571711bcba0SDavid C Somayajulu }
572711bcba0SDavid C Somayajulu
573711bcba0SDavid C Somayajulu /*
574711bcba0SDavid C Somayajulu * DMA Related Functions
575711bcba0SDavid C Somayajulu */
576711bcba0SDavid C Somayajulu
577711bcba0SDavid C Somayajulu static void
qls_dmamap_callback(void * arg,bus_dma_segment_t * segs,int nsegs,int error)578711bcba0SDavid C Somayajulu qls_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
579711bcba0SDavid C Somayajulu {
580711bcba0SDavid C Somayajulu *((bus_addr_t *)arg) = 0;
581711bcba0SDavid C Somayajulu
582711bcba0SDavid C Somayajulu if (error) {
583711bcba0SDavid C Somayajulu printf("%s: bus_dmamap_load failed (%d)\n", __func__, error);
584711bcba0SDavid C Somayajulu return;
585711bcba0SDavid C Somayajulu }
586711bcba0SDavid C Somayajulu
587711bcba0SDavid C Somayajulu *((bus_addr_t *)arg) = segs[0].ds_addr;
588711bcba0SDavid C Somayajulu
589711bcba0SDavid C Somayajulu return;
590711bcba0SDavid C Somayajulu }
591711bcba0SDavid C Somayajulu
592711bcba0SDavid C Somayajulu int
qls_alloc_dmabuf(qla_host_t * ha,qla_dma_t * dma_buf)593711bcba0SDavid C Somayajulu qls_alloc_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
594711bcba0SDavid C Somayajulu {
595711bcba0SDavid C Somayajulu int ret = 0;
596711bcba0SDavid C Somayajulu device_t dev;
597711bcba0SDavid C Somayajulu bus_addr_t b_addr;
598711bcba0SDavid C Somayajulu
599711bcba0SDavid C Somayajulu dev = ha->pci_dev;
600711bcba0SDavid C Somayajulu
601711bcba0SDavid C Somayajulu QL_DPRINT2((dev, "%s: enter\n", __func__));
602711bcba0SDavid C Somayajulu
603711bcba0SDavid C Somayajulu ret = bus_dma_tag_create(
604711bcba0SDavid C Somayajulu ha->parent_tag,/* parent */
605711bcba0SDavid C Somayajulu dma_buf->alignment,
606711bcba0SDavid C Somayajulu ((bus_size_t)(1ULL << 32)),/* boundary */
607711bcba0SDavid C Somayajulu BUS_SPACE_MAXADDR, /* lowaddr */
608711bcba0SDavid C Somayajulu BUS_SPACE_MAXADDR, /* highaddr */
609711bcba0SDavid C Somayajulu NULL, NULL, /* filter, filterarg */
610711bcba0SDavid C Somayajulu dma_buf->size, /* maxsize */
611711bcba0SDavid C Somayajulu 1, /* nsegments */
612711bcba0SDavid C Somayajulu dma_buf->size, /* maxsegsize */
613711bcba0SDavid C Somayajulu 0, /* flags */
614711bcba0SDavid C Somayajulu NULL, NULL, /* lockfunc, lockarg */
615711bcba0SDavid C Somayajulu &dma_buf->dma_tag);
616711bcba0SDavid C Somayajulu
617711bcba0SDavid C Somayajulu if (ret) {
618711bcba0SDavid C Somayajulu device_printf(dev, "%s: could not create dma tag\n", __func__);
619711bcba0SDavid C Somayajulu goto qls_alloc_dmabuf_exit;
620711bcba0SDavid C Somayajulu }
621711bcba0SDavid C Somayajulu ret = bus_dmamem_alloc(dma_buf->dma_tag,
622711bcba0SDavid C Somayajulu (void **)&dma_buf->dma_b,
623711bcba0SDavid C Somayajulu (BUS_DMA_ZERO | BUS_DMA_COHERENT | BUS_DMA_NOWAIT),
624711bcba0SDavid C Somayajulu &dma_buf->dma_map);
625711bcba0SDavid C Somayajulu if (ret) {
626711bcba0SDavid C Somayajulu bus_dma_tag_destroy(dma_buf->dma_tag);
627711bcba0SDavid C Somayajulu device_printf(dev, "%s: bus_dmamem_alloc failed\n", __func__);
628711bcba0SDavid C Somayajulu goto qls_alloc_dmabuf_exit;
629711bcba0SDavid C Somayajulu }
630711bcba0SDavid C Somayajulu
631711bcba0SDavid C Somayajulu ret = bus_dmamap_load(dma_buf->dma_tag,
632711bcba0SDavid C Somayajulu dma_buf->dma_map,
633711bcba0SDavid C Somayajulu dma_buf->dma_b,
634711bcba0SDavid C Somayajulu dma_buf->size,
635711bcba0SDavid C Somayajulu qls_dmamap_callback,
636711bcba0SDavid C Somayajulu &b_addr, BUS_DMA_NOWAIT);
637711bcba0SDavid C Somayajulu
638711bcba0SDavid C Somayajulu if (ret || !b_addr) {
639711bcba0SDavid C Somayajulu bus_dma_tag_destroy(dma_buf->dma_tag);
640711bcba0SDavid C Somayajulu bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b,
641711bcba0SDavid C Somayajulu dma_buf->dma_map);
642711bcba0SDavid C Somayajulu ret = -1;
643711bcba0SDavid C Somayajulu goto qls_alloc_dmabuf_exit;
644711bcba0SDavid C Somayajulu }
645711bcba0SDavid C Somayajulu
646711bcba0SDavid C Somayajulu dma_buf->dma_addr = b_addr;
647711bcba0SDavid C Somayajulu
648711bcba0SDavid C Somayajulu qls_alloc_dmabuf_exit:
649711bcba0SDavid C Somayajulu QL_DPRINT2((dev, "%s: exit ret 0x%08x tag %p map %p b %p sz 0x%x\n",
650711bcba0SDavid C Somayajulu __func__, ret, (void *)dma_buf->dma_tag,
651711bcba0SDavid C Somayajulu (void *)dma_buf->dma_map, (void *)dma_buf->dma_b,
652711bcba0SDavid C Somayajulu dma_buf->size));
653711bcba0SDavid C Somayajulu
654711bcba0SDavid C Somayajulu return ret;
655711bcba0SDavid C Somayajulu }
656711bcba0SDavid C Somayajulu
657711bcba0SDavid C Somayajulu void
qls_free_dmabuf(qla_host_t * ha,qla_dma_t * dma_buf)658711bcba0SDavid C Somayajulu qls_free_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
659711bcba0SDavid C Somayajulu {
660aeeb653cSJohn Baldwin bus_dmamap_unload(dma_buf->dma_tag, dma_buf->dma_map);
661711bcba0SDavid C Somayajulu bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, dma_buf->dma_map);
662711bcba0SDavid C Somayajulu bus_dma_tag_destroy(dma_buf->dma_tag);
663711bcba0SDavid C Somayajulu }
664711bcba0SDavid C Somayajulu
665711bcba0SDavid C Somayajulu static int
qls_alloc_parent_dma_tag(qla_host_t * ha)666711bcba0SDavid C Somayajulu qls_alloc_parent_dma_tag(qla_host_t *ha)
667711bcba0SDavid C Somayajulu {
668711bcba0SDavid C Somayajulu int ret;
669711bcba0SDavid C Somayajulu device_t dev;
670711bcba0SDavid C Somayajulu
671711bcba0SDavid C Somayajulu dev = ha->pci_dev;
672711bcba0SDavid C Somayajulu
673711bcba0SDavid C Somayajulu /*
674711bcba0SDavid C Somayajulu * Allocate parent DMA Tag
675711bcba0SDavid C Somayajulu */
676711bcba0SDavid C Somayajulu ret = bus_dma_tag_create(
677711bcba0SDavid C Somayajulu bus_get_dma_tag(dev), /* parent */
678711bcba0SDavid C Somayajulu 1,((bus_size_t)(1ULL << 32)),/* alignment, boundary */
679711bcba0SDavid C Somayajulu BUS_SPACE_MAXADDR, /* lowaddr */
680711bcba0SDavid C Somayajulu BUS_SPACE_MAXADDR, /* highaddr */
681711bcba0SDavid C Somayajulu NULL, NULL, /* filter, filterarg */
682711bcba0SDavid C Somayajulu BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
683711bcba0SDavid C Somayajulu 0, /* nsegments */
684711bcba0SDavid C Somayajulu BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
685711bcba0SDavid C Somayajulu 0, /* flags */
686711bcba0SDavid C Somayajulu NULL, NULL, /* lockfunc, lockarg */
687711bcba0SDavid C Somayajulu &ha->parent_tag);
688711bcba0SDavid C Somayajulu
689711bcba0SDavid C Somayajulu if (ret) {
690711bcba0SDavid C Somayajulu device_printf(dev, "%s: could not create parent dma tag\n",
691711bcba0SDavid C Somayajulu __func__);
692711bcba0SDavid C Somayajulu return (-1);
693711bcba0SDavid C Somayajulu }
694711bcba0SDavid C Somayajulu
695711bcba0SDavid C Somayajulu ha->flags.parent_tag = 1;
696711bcba0SDavid C Somayajulu
697711bcba0SDavid C Somayajulu return (0);
698711bcba0SDavid C Somayajulu }
699711bcba0SDavid C Somayajulu
700711bcba0SDavid C Somayajulu static void
qls_free_parent_dma_tag(qla_host_t * ha)701711bcba0SDavid C Somayajulu qls_free_parent_dma_tag(qla_host_t *ha)
702711bcba0SDavid C Somayajulu {
703711bcba0SDavid C Somayajulu if (ha->flags.parent_tag) {
704711bcba0SDavid C Somayajulu bus_dma_tag_destroy(ha->parent_tag);
705711bcba0SDavid C Somayajulu ha->flags.parent_tag = 0;
706711bcba0SDavid C Somayajulu }
707711bcba0SDavid C Somayajulu }
708711bcba0SDavid C Somayajulu
709711bcba0SDavid C Somayajulu /*
710711bcba0SDavid C Somayajulu * Name: qls_init_ifnet
711711bcba0SDavid C Somayajulu * Function: Creates the Network Device Interface and Registers it with the O.S
712711bcba0SDavid C Somayajulu */
713711bcba0SDavid C Somayajulu
714711bcba0SDavid C Somayajulu static void
qls_init_ifnet(device_t dev,qla_host_t * ha)715711bcba0SDavid C Somayajulu qls_init_ifnet(device_t dev, qla_host_t *ha)
716711bcba0SDavid C Somayajulu {
71764c618edSJustin Hibbits if_t ifp;
718711bcba0SDavid C Somayajulu
719711bcba0SDavid C Somayajulu QL_DPRINT2((dev, "%s: enter\n", __func__));
720711bcba0SDavid C Somayajulu
721711bcba0SDavid C Somayajulu ifp = ha->ifp = if_alloc(IFT_ETHER);
722711bcba0SDavid C Somayajulu if_initname(ifp, device_get_name(dev), device_get_unit(dev));
72364c618edSJustin Hibbits if_setbaudrate(ifp, IF_Gbps(10));
72464c618edSJustin Hibbits if_setinitfn(ifp, qls_init);
72564c618edSJustin Hibbits if_setsoftc(ifp, ha);
72664c618edSJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
72764c618edSJustin Hibbits if_setioctlfn(ifp, qls_ioctl);
72864c618edSJustin Hibbits if_setstartfn(ifp, qls_start);
729711bcba0SDavid C Somayajulu
73064c618edSJustin Hibbits if_setsendqlen(ifp, qls_get_ifq_snd_maxlen(ha));
73164c618edSJustin Hibbits if_setsendqready(ifp);
732711bcba0SDavid C Somayajulu
73364c618edSJustin Hibbits ha->max_frame_size = if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
734711bcba0SDavid C Somayajulu if (ha->max_frame_size <= MCLBYTES) {
735711bcba0SDavid C Somayajulu ha->msize = MCLBYTES;
736711bcba0SDavid C Somayajulu } else if (ha->max_frame_size <= MJUMPAGESIZE) {
737711bcba0SDavid C Somayajulu ha->msize = MJUMPAGESIZE;
738711bcba0SDavid C Somayajulu } else
739711bcba0SDavid C Somayajulu ha->msize = MJUM9BYTES;
740711bcba0SDavid C Somayajulu
741711bcba0SDavid C Somayajulu ether_ifattach(ifp, qls_get_mac_addr(ha));
742711bcba0SDavid C Somayajulu
74364c618edSJustin Hibbits if_setcapabilities(ifp, IFCAP_JUMBO_MTU);
744711bcba0SDavid C Somayajulu
74564c618edSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_HWCSUM, 0);
74664c618edSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
747711bcba0SDavid C Somayajulu
74864c618edSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_TSO4, 0);
74964c618edSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING, 0);
75064c618edSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTSO, 0);
75164c618edSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_LINKSTATE, 0);
752711bcba0SDavid C Somayajulu
75364c618edSJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp));
754711bcba0SDavid C Somayajulu
75564c618edSJustin Hibbits if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
756711bcba0SDavid C Somayajulu
757711bcba0SDavid C Somayajulu ifmedia_init(&ha->media, IFM_IMASK, qls_media_change, qls_media_status);
758711bcba0SDavid C Somayajulu
759711bcba0SDavid C Somayajulu ifmedia_add(&ha->media, (IFM_ETHER | qls_get_optics(ha) | IFM_FDX), 0,
760711bcba0SDavid C Somayajulu NULL);
761711bcba0SDavid C Somayajulu ifmedia_add(&ha->media, (IFM_ETHER | IFM_AUTO), 0, NULL);
762711bcba0SDavid C Somayajulu
763711bcba0SDavid C Somayajulu ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO));
764711bcba0SDavid C Somayajulu
765711bcba0SDavid C Somayajulu QL_DPRINT2((dev, "%s: exit\n", __func__));
766711bcba0SDavid C Somayajulu
767711bcba0SDavid C Somayajulu return;
768711bcba0SDavid C Somayajulu }
769711bcba0SDavid C Somayajulu
770711bcba0SDavid C Somayajulu static void
qls_init_locked(qla_host_t * ha)771711bcba0SDavid C Somayajulu qls_init_locked(qla_host_t *ha)
772711bcba0SDavid C Somayajulu {
77364c618edSJustin Hibbits if_t ifp = ha->ifp;
774711bcba0SDavid C Somayajulu
775711bcba0SDavid C Somayajulu qls_stop(ha);
776711bcba0SDavid C Somayajulu
777711bcba0SDavid C Somayajulu qls_flush_xmt_bufs(ha);
778711bcba0SDavid C Somayajulu
779711bcba0SDavid C Somayajulu if (qls_alloc_rcv_bufs(ha) != 0)
780711bcba0SDavid C Somayajulu return;
781711bcba0SDavid C Somayajulu
782711bcba0SDavid C Somayajulu if (qls_config_lro(ha))
783711bcba0SDavid C Somayajulu return;
784711bcba0SDavid C Somayajulu
78564c618edSJustin Hibbits bcopy(if_getlladdr(ha->ifp), ha->mac_addr, ETHER_ADDR_LEN);
786711bcba0SDavid C Somayajulu
78764c618edSJustin Hibbits if_sethwassist(ifp, CSUM_IP);
78864c618edSJustin Hibbits if_sethwassistbits(ifp, CSUM_TCP, 0);
78964c618edSJustin Hibbits if_sethwassistbits(ifp, CSUM_UDP, 0);
79064c618edSJustin Hibbits if_sethwassistbits(ifp, CSUM_TSO, 0);
791711bcba0SDavid C Somayajulu
792711bcba0SDavid C Somayajulu if (qls_init_hw_if(ha) == 0) {
793711bcba0SDavid C Somayajulu ifp = ha->ifp;
79464c618edSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
79564c618edSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
796711bcba0SDavid C Somayajulu ha->flags.qla_watchdog_pause = 0;
797711bcba0SDavid C Somayajulu }
798711bcba0SDavid C Somayajulu
799711bcba0SDavid C Somayajulu return;
800711bcba0SDavid C Somayajulu }
801711bcba0SDavid C Somayajulu
802711bcba0SDavid C Somayajulu static void
qls_init(void * arg)803711bcba0SDavid C Somayajulu qls_init(void *arg)
804711bcba0SDavid C Somayajulu {
805711bcba0SDavid C Somayajulu qla_host_t *ha;
806711bcba0SDavid C Somayajulu
807711bcba0SDavid C Somayajulu ha = (qla_host_t *)arg;
808711bcba0SDavid C Somayajulu
809711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
810711bcba0SDavid C Somayajulu
811711bcba0SDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0);
812711bcba0SDavid C Somayajulu qls_init_locked(ha);
813711bcba0SDavid C Somayajulu QLA_UNLOCK(ha, __func__);
814711bcba0SDavid C Somayajulu
815711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
816711bcba0SDavid C Somayajulu }
817711bcba0SDavid C Somayajulu
8186dfd0870SGleb Smirnoff static u_int
qls_copy_maddr(void * arg,struct sockaddr_dl * sdl,u_int mcnt)8196dfd0870SGleb Smirnoff qls_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt)
8206dfd0870SGleb Smirnoff {
8216dfd0870SGleb Smirnoff uint8_t *mta = arg;
8226dfd0870SGleb Smirnoff
8236dfd0870SGleb Smirnoff if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS)
8246dfd0870SGleb Smirnoff return (0);
8256dfd0870SGleb Smirnoff
8266dfd0870SGleb Smirnoff bcopy(LLADDR(sdl), &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN);
8276dfd0870SGleb Smirnoff
8286dfd0870SGleb Smirnoff return (1);
8296dfd0870SGleb Smirnoff }
8306dfd0870SGleb Smirnoff
831711bcba0SDavid C Somayajulu static void
qls_set_multi(qla_host_t * ha,uint32_t add_multi)832711bcba0SDavid C Somayajulu qls_set_multi(qla_host_t *ha, uint32_t add_multi)
833711bcba0SDavid C Somayajulu {
834711bcba0SDavid C Somayajulu uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN];
83564c618edSJustin Hibbits if_t ifp = ha->ifp;
8366dfd0870SGleb Smirnoff int mcnt;
837711bcba0SDavid C Somayajulu
8386dfd0870SGleb Smirnoff mcnt = if_foreach_llmaddr(ifp, qls_copy_maddr, mta);
839711bcba0SDavid C Somayajulu
840711bcba0SDavid C Somayajulu if (QLA_LOCK(ha, __func__, 1) == 0) {
841711bcba0SDavid C Somayajulu qls_hw_set_multi(ha, mta, mcnt, add_multi);
842711bcba0SDavid C Somayajulu QLA_UNLOCK(ha, __func__);
843711bcba0SDavid C Somayajulu }
844711bcba0SDavid C Somayajulu
845711bcba0SDavid C Somayajulu return;
846711bcba0SDavid C Somayajulu }
847711bcba0SDavid C Somayajulu
848711bcba0SDavid C Somayajulu static int
qls_ioctl(if_t ifp,u_long cmd,caddr_t data)84964c618edSJustin Hibbits qls_ioctl(if_t ifp, u_long cmd, caddr_t data)
850711bcba0SDavid C Somayajulu {
851711bcba0SDavid C Somayajulu int ret = 0;
852711bcba0SDavid C Somayajulu struct ifreq *ifr = (struct ifreq *)data;
853618aa8cdSJohn Baldwin #ifdef INET
854711bcba0SDavid C Somayajulu struct ifaddr *ifa = (struct ifaddr *)data;
855618aa8cdSJohn Baldwin #endif
856711bcba0SDavid C Somayajulu qla_host_t *ha;
857711bcba0SDavid C Somayajulu
85864c618edSJustin Hibbits ha = (qla_host_t *)if_getsoftc(ifp);
859711bcba0SDavid C Somayajulu
860711bcba0SDavid C Somayajulu switch (cmd) {
861711bcba0SDavid C Somayajulu case SIOCSIFADDR:
862711bcba0SDavid C Somayajulu QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFADDR (0x%lx)\n",
863711bcba0SDavid C Somayajulu __func__, cmd));
864711bcba0SDavid C Somayajulu
865618aa8cdSJohn Baldwin #ifdef INET
866711bcba0SDavid C Somayajulu if (ifa->ifa_addr->sa_family == AF_INET) {
86764c618edSJustin Hibbits if_setflagbits(ifp, IFF_UP, 0);
86864c618edSJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
869711bcba0SDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0);
870711bcba0SDavid C Somayajulu qls_init_locked(ha);
871711bcba0SDavid C Somayajulu QLA_UNLOCK(ha, __func__);
872711bcba0SDavid C Somayajulu }
873711bcba0SDavid C Somayajulu QL_DPRINT4((ha->pci_dev,
874711bcba0SDavid C Somayajulu "%s: SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n",
875711bcba0SDavid C Somayajulu __func__, cmd,
876711bcba0SDavid C Somayajulu ntohl(IA_SIN(ifa)->sin_addr.s_addr)));
877711bcba0SDavid C Somayajulu
878711bcba0SDavid C Somayajulu arp_ifinit(ifp, ifa);
879618aa8cdSJohn Baldwin break;
880711bcba0SDavid C Somayajulu }
881618aa8cdSJohn Baldwin #endif
882618aa8cdSJohn Baldwin ether_ioctl(ifp, cmd, data);
883711bcba0SDavid C Somayajulu break;
884711bcba0SDavid C Somayajulu
885711bcba0SDavid C Somayajulu case SIOCSIFMTU:
886711bcba0SDavid C Somayajulu QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFMTU (0x%lx)\n",
887711bcba0SDavid C Somayajulu __func__, cmd));
888711bcba0SDavid C Somayajulu
889711bcba0SDavid C Somayajulu if (ifr->ifr_mtu > QLA_MAX_MTU) {
890711bcba0SDavid C Somayajulu ret = EINVAL;
891711bcba0SDavid C Somayajulu } else {
892711bcba0SDavid C Somayajulu (void) QLA_LOCK(ha, __func__, 0);
893711bcba0SDavid C Somayajulu
89464c618edSJustin Hibbits if_setmtu(ifp, ifr->ifr_mtu);
895711bcba0SDavid C Somayajulu ha->max_frame_size =
89664c618edSJustin Hibbits if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
897711bcba0SDavid C Somayajulu
898711bcba0SDavid C Somayajulu QLA_UNLOCK(ha, __func__);
899711bcba0SDavid C Somayajulu
900711bcba0SDavid C Somayajulu if (ret)
901711bcba0SDavid C Somayajulu ret = EINVAL;
902711bcba0SDavid C Somayajulu }
903711bcba0SDavid C Somayajulu
904711bcba0SDavid C Somayajulu break;
905711bcba0SDavid C Somayajulu
906711bcba0SDavid C Somayajulu case SIOCSIFFLAGS:
907711bcba0SDavid C Somayajulu QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFFLAGS (0x%lx)\n",
908711bcba0SDavid C Somayajulu __func__, cmd));
909711bcba0SDavid C Somayajulu
910711bcba0SDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0);
911711bcba0SDavid C Somayajulu
91264c618edSJustin Hibbits if (if_getflags(ifp) & IFF_UP) {
91364c618edSJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
91464c618edSJustin Hibbits if ((if_getflags(ifp) ^ ha->if_flags) &
915711bcba0SDavid C Somayajulu IFF_PROMISC) {
916711bcba0SDavid C Somayajulu ret = qls_set_promisc(ha);
91764c618edSJustin Hibbits } else if ((if_getflags(ifp) ^ ha->if_flags) &
918711bcba0SDavid C Somayajulu IFF_ALLMULTI) {
919711bcba0SDavid C Somayajulu ret = qls_set_allmulti(ha);
920711bcba0SDavid C Somayajulu }
921711bcba0SDavid C Somayajulu } else {
92264c618edSJustin Hibbits ha->max_frame_size = if_getmtu(ifp) +
923711bcba0SDavid C Somayajulu ETHER_HDR_LEN + ETHER_CRC_LEN;
924711bcba0SDavid C Somayajulu qls_init_locked(ha);
925711bcba0SDavid C Somayajulu }
926711bcba0SDavid C Somayajulu } else {
92764c618edSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
928711bcba0SDavid C Somayajulu qls_stop(ha);
92964c618edSJustin Hibbits ha->if_flags = if_getflags(ifp);
930711bcba0SDavid C Somayajulu }
931711bcba0SDavid C Somayajulu
932711bcba0SDavid C Somayajulu QLA_UNLOCK(ha, __func__);
933711bcba0SDavid C Somayajulu break;
934711bcba0SDavid C Somayajulu
935711bcba0SDavid C Somayajulu case SIOCADDMULTI:
936711bcba0SDavid C Somayajulu QL_DPRINT4((ha->pci_dev,
937711bcba0SDavid C Somayajulu "%s: %s (0x%lx)\n", __func__, "SIOCADDMULTI", cmd));
938711bcba0SDavid C Somayajulu
93964c618edSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
940711bcba0SDavid C Somayajulu qls_set_multi(ha, 1);
941711bcba0SDavid C Somayajulu }
942711bcba0SDavid C Somayajulu break;
943711bcba0SDavid C Somayajulu
944711bcba0SDavid C Somayajulu case SIOCDELMULTI:
945711bcba0SDavid C Somayajulu QL_DPRINT4((ha->pci_dev,
946711bcba0SDavid C Somayajulu "%s: %s (0x%lx)\n", __func__, "SIOCDELMULTI", cmd));
947711bcba0SDavid C Somayajulu
94864c618edSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
949711bcba0SDavid C Somayajulu qls_set_multi(ha, 0);
950711bcba0SDavid C Somayajulu }
951711bcba0SDavid C Somayajulu break;
952711bcba0SDavid C Somayajulu
953711bcba0SDavid C Somayajulu case SIOCSIFMEDIA:
954711bcba0SDavid C Somayajulu case SIOCGIFMEDIA:
955711bcba0SDavid C Somayajulu QL_DPRINT4((ha->pci_dev,
956711bcba0SDavid C Somayajulu "%s: SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n",
957711bcba0SDavid C Somayajulu __func__, cmd));
958711bcba0SDavid C Somayajulu ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd);
959711bcba0SDavid C Somayajulu break;
960711bcba0SDavid C Somayajulu
961711bcba0SDavid C Somayajulu case SIOCSIFCAP:
962711bcba0SDavid C Somayajulu {
96364c618edSJustin Hibbits int mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
964711bcba0SDavid C Somayajulu
965711bcba0SDavid C Somayajulu QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFCAP (0x%lx)\n",
966711bcba0SDavid C Somayajulu __func__, cmd));
967711bcba0SDavid C Somayajulu
968711bcba0SDavid C Somayajulu if (mask & IFCAP_HWCSUM)
96964c618edSJustin Hibbits if_togglecapenable(ifp, IFCAP_HWCSUM);
970711bcba0SDavid C Somayajulu if (mask & IFCAP_TSO4)
97164c618edSJustin Hibbits if_togglecapenable(ifp, IFCAP_TSO4);
972711bcba0SDavid C Somayajulu if (mask & IFCAP_VLAN_HWTAGGING)
97364c618edSJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
974711bcba0SDavid C Somayajulu if (mask & IFCAP_VLAN_HWTSO)
97564c618edSJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWTSO);
976711bcba0SDavid C Somayajulu
97764c618edSJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
978711bcba0SDavid C Somayajulu qls_init(ha);
979711bcba0SDavid C Somayajulu
980711bcba0SDavid C Somayajulu VLAN_CAPABILITIES(ifp);
981711bcba0SDavid C Somayajulu break;
982711bcba0SDavid C Somayajulu }
983711bcba0SDavid C Somayajulu
984711bcba0SDavid C Somayajulu default:
985711bcba0SDavid C Somayajulu QL_DPRINT4((ha->pci_dev, "%s: default (0x%lx)\n",
986711bcba0SDavid C Somayajulu __func__, cmd));
987711bcba0SDavid C Somayajulu ret = ether_ioctl(ifp, cmd, data);
988711bcba0SDavid C Somayajulu break;
989711bcba0SDavid C Somayajulu }
990711bcba0SDavid C Somayajulu
991711bcba0SDavid C Somayajulu return (ret);
992711bcba0SDavid C Somayajulu }
993711bcba0SDavid C Somayajulu
994711bcba0SDavid C Somayajulu static int
qls_media_change(if_t ifp)99564c618edSJustin Hibbits qls_media_change(if_t ifp)
996711bcba0SDavid C Somayajulu {
997711bcba0SDavid C Somayajulu qla_host_t *ha;
998711bcba0SDavid C Somayajulu struct ifmedia *ifm;
999711bcba0SDavid C Somayajulu int ret = 0;
1000711bcba0SDavid C Somayajulu
100164c618edSJustin Hibbits ha = (qla_host_t *)if_getsoftc(ifp);
1002711bcba0SDavid C Somayajulu
1003711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1004711bcba0SDavid C Somayajulu
1005711bcba0SDavid C Somayajulu ifm = &ha->media;
1006711bcba0SDavid C Somayajulu
1007711bcba0SDavid C Somayajulu if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1008711bcba0SDavid C Somayajulu ret = EINVAL;
1009711bcba0SDavid C Somayajulu
1010711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
1011711bcba0SDavid C Somayajulu
1012711bcba0SDavid C Somayajulu return (ret);
1013711bcba0SDavid C Somayajulu }
1014711bcba0SDavid C Somayajulu
1015711bcba0SDavid C Somayajulu static void
qls_media_status(if_t ifp,struct ifmediareq * ifmr)101664c618edSJustin Hibbits qls_media_status(if_t ifp, struct ifmediareq *ifmr)
1017711bcba0SDavid C Somayajulu {
1018711bcba0SDavid C Somayajulu qla_host_t *ha;
1019711bcba0SDavid C Somayajulu
102064c618edSJustin Hibbits ha = (qla_host_t *)if_getsoftc(ifp);
1021711bcba0SDavid C Somayajulu
1022711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1023711bcba0SDavid C Somayajulu
1024711bcba0SDavid C Somayajulu ifmr->ifm_status = IFM_AVALID;
1025711bcba0SDavid C Somayajulu ifmr->ifm_active = IFM_ETHER;
1026711bcba0SDavid C Somayajulu
1027711bcba0SDavid C Somayajulu qls_update_link_state(ha);
1028711bcba0SDavid C Somayajulu if (ha->link_up) {
1029711bcba0SDavid C Somayajulu ifmr->ifm_status |= IFM_ACTIVE;
1030711bcba0SDavid C Somayajulu ifmr->ifm_active |= (IFM_FDX | qls_get_optics(ha));
1031711bcba0SDavid C Somayajulu }
1032711bcba0SDavid C Somayajulu
1033711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: exit (%s)\n", __func__,\
1034711bcba0SDavid C Somayajulu (ha->link_up ? "link_up" : "link_down")));
1035711bcba0SDavid C Somayajulu
1036711bcba0SDavid C Somayajulu return;
1037711bcba0SDavid C Somayajulu }
1038711bcba0SDavid C Somayajulu
1039711bcba0SDavid C Somayajulu static void
qls_start(if_t ifp)104064c618edSJustin Hibbits qls_start(if_t ifp)
1041711bcba0SDavid C Somayajulu {
1042711bcba0SDavid C Somayajulu int i, ret = 0;
1043711bcba0SDavid C Somayajulu struct mbuf *m_head;
104464c618edSJustin Hibbits qla_host_t *ha = (qla_host_t *)if_getsoftc(ifp);
1045711bcba0SDavid C Somayajulu
1046711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
1047711bcba0SDavid C Somayajulu
1048711bcba0SDavid C Somayajulu if (!mtx_trylock(&ha->tx_lock)) {
1049711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev,
1050711bcba0SDavid C Somayajulu "%s: mtx_trylock(&ha->tx_lock) failed\n", __func__));
1051711bcba0SDavid C Somayajulu return;
1052711bcba0SDavid C Somayajulu }
1053711bcba0SDavid C Somayajulu
105464c618edSJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) ==
1055711bcba0SDavid C Somayajulu IFF_DRV_RUNNING) {
1056711bcba0SDavid C Somayajulu for (i = 0; i < ha->num_tx_rings; i++) {
1057711bcba0SDavid C Somayajulu ret |= qls_hw_tx_done(ha, i);
1058711bcba0SDavid C Somayajulu }
1059711bcba0SDavid C Somayajulu
1060711bcba0SDavid C Somayajulu if (ret == 0)
106164c618edSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
1062711bcba0SDavid C Somayajulu }
1063711bcba0SDavid C Somayajulu
106464c618edSJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1065711bcba0SDavid C Somayajulu IFF_DRV_RUNNING) {
1066711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
1067711bcba0SDavid C Somayajulu QLA_TX_UNLOCK(ha);
1068711bcba0SDavid C Somayajulu return;
1069711bcba0SDavid C Somayajulu }
1070711bcba0SDavid C Somayajulu
1071711bcba0SDavid C Somayajulu if (!ha->link_up) {
1072711bcba0SDavid C Somayajulu qls_update_link_state(ha);
1073711bcba0SDavid C Somayajulu if (!ha->link_up) {
1074711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: link down\n", __func__));
1075711bcba0SDavid C Somayajulu QLA_TX_UNLOCK(ha);
1076711bcba0SDavid C Somayajulu return;
1077711bcba0SDavid C Somayajulu }
1078711bcba0SDavid C Somayajulu }
1079711bcba0SDavid C Somayajulu
108064c618edSJustin Hibbits while (!if_sendq_empty(ifp)) {
108164c618edSJustin Hibbits m_head = if_dequeue(ifp);
1082711bcba0SDavid C Somayajulu
1083711bcba0SDavid C Somayajulu if (m_head == NULL) {
1084711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: m_head == NULL\n",
1085711bcba0SDavid C Somayajulu __func__));
1086711bcba0SDavid C Somayajulu break;
1087711bcba0SDavid C Somayajulu }
1088711bcba0SDavid C Somayajulu
1089711bcba0SDavid C Somayajulu if (qls_send(ha, &m_head)) {
1090711bcba0SDavid C Somayajulu if (m_head == NULL)
1091711bcba0SDavid C Somayajulu break;
1092711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: PREPEND\n", __func__));
109364c618edSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
109464c618edSJustin Hibbits if_sendq_prepend(ifp, m_head);
1095711bcba0SDavid C Somayajulu break;
1096711bcba0SDavid C Somayajulu }
1097711bcba0SDavid C Somayajulu /* Send a copy of the frame to the BPF listener */
1098711bcba0SDavid C Somayajulu ETHER_BPF_MTAP(ifp, m_head);
1099711bcba0SDavid C Somayajulu }
1100711bcba0SDavid C Somayajulu
1101711bcba0SDavid C Somayajulu QLA_TX_UNLOCK(ha);
1102711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
1103711bcba0SDavid C Somayajulu return;
1104711bcba0SDavid C Somayajulu }
1105711bcba0SDavid C Somayajulu
1106711bcba0SDavid C Somayajulu static int
qls_send(qla_host_t * ha,struct mbuf ** m_headp)1107711bcba0SDavid C Somayajulu qls_send(qla_host_t *ha, struct mbuf **m_headp)
1108711bcba0SDavid C Somayajulu {
1109711bcba0SDavid C Somayajulu bus_dma_segment_t segs[QLA_MAX_SEGMENTS];
1110711bcba0SDavid C Somayajulu bus_dmamap_t map;
1111711bcba0SDavid C Somayajulu int nsegs;
1112711bcba0SDavid C Somayajulu int ret = -1;
1113711bcba0SDavid C Somayajulu uint32_t tx_idx;
1114711bcba0SDavid C Somayajulu struct mbuf *m_head = *m_headp;
1115711bcba0SDavid C Somayajulu uint32_t txr_idx = 0;
1116711bcba0SDavid C Somayajulu
1117711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
1118711bcba0SDavid C Somayajulu
1119c2529042SHans Petter Selasky /* check if flowid is set */
1120c2529042SHans Petter Selasky if (M_HASHTYPE_GET(m_head) != M_HASHTYPE_NONE)
1121711bcba0SDavid C Somayajulu txr_idx = m_head->m_pkthdr.flowid & (ha->num_tx_rings - 1);
1122711bcba0SDavid C Somayajulu
1123711bcba0SDavid C Somayajulu tx_idx = ha->tx_ring[txr_idx].txr_next;
1124711bcba0SDavid C Somayajulu
1125711bcba0SDavid C Somayajulu map = ha->tx_ring[txr_idx].tx_buf[tx_idx].map;
1126711bcba0SDavid C Somayajulu
1127711bcba0SDavid C Somayajulu ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, segs, &nsegs,
1128711bcba0SDavid C Somayajulu BUS_DMA_NOWAIT);
1129711bcba0SDavid C Somayajulu
1130711bcba0SDavid C Somayajulu if (ret == EFBIG) {
1131711bcba0SDavid C Somayajulu struct mbuf *m;
1132711bcba0SDavid C Somayajulu
1133711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: EFBIG [%d]\n", __func__,
1134711bcba0SDavid C Somayajulu m_head->m_pkthdr.len));
1135711bcba0SDavid C Somayajulu
1136b8c83a19SGleb Smirnoff m = m_defrag(m_head, M_NOWAIT);
1137711bcba0SDavid C Somayajulu if (m == NULL) {
1138711bcba0SDavid C Somayajulu ha->err_tx_defrag++;
1139711bcba0SDavid C Somayajulu m_freem(m_head);
1140711bcba0SDavid C Somayajulu *m_headp = NULL;
1141711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
1142711bcba0SDavid C Somayajulu "%s: m_defrag() = NULL [%d]\n",
1143711bcba0SDavid C Somayajulu __func__, ret);
1144711bcba0SDavid C Somayajulu return (ENOBUFS);
1145711bcba0SDavid C Somayajulu }
1146711bcba0SDavid C Somayajulu m_head = m;
1147711bcba0SDavid C Somayajulu *m_headp = m_head;
1148711bcba0SDavid C Somayajulu
1149711bcba0SDavid C Somayajulu if ((ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head,
1150711bcba0SDavid C Somayajulu segs, &nsegs, BUS_DMA_NOWAIT))) {
1151711bcba0SDavid C Somayajulu ha->err_tx_dmamap_load++;
1152711bcba0SDavid C Somayajulu
1153711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
1154711bcba0SDavid C Somayajulu "%s: bus_dmamap_load_mbuf_sg failed0[%d, %d]\n",
1155711bcba0SDavid C Somayajulu __func__, ret, m_head->m_pkthdr.len);
1156711bcba0SDavid C Somayajulu
1157711bcba0SDavid C Somayajulu if (ret != ENOMEM) {
1158711bcba0SDavid C Somayajulu m_freem(m_head);
1159711bcba0SDavid C Somayajulu *m_headp = NULL;
1160711bcba0SDavid C Somayajulu }
1161711bcba0SDavid C Somayajulu return (ret);
1162711bcba0SDavid C Somayajulu }
1163711bcba0SDavid C Somayajulu
1164711bcba0SDavid C Somayajulu } else if (ret) {
1165711bcba0SDavid C Somayajulu ha->err_tx_dmamap_load++;
1166711bcba0SDavid C Somayajulu
1167711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
1168711bcba0SDavid C Somayajulu "%s: bus_dmamap_load_mbuf_sg failed1[%d, %d]\n",
1169711bcba0SDavid C Somayajulu __func__, ret, m_head->m_pkthdr.len);
1170711bcba0SDavid C Somayajulu
1171711bcba0SDavid C Somayajulu if (ret != ENOMEM) {
1172711bcba0SDavid C Somayajulu m_freem(m_head);
1173711bcba0SDavid C Somayajulu *m_headp = NULL;
1174711bcba0SDavid C Somayajulu }
1175711bcba0SDavid C Somayajulu return (ret);
1176711bcba0SDavid C Somayajulu }
1177711bcba0SDavid C Somayajulu
1178711bcba0SDavid C Somayajulu QL_ASSERT(ha, (nsegs != 0), ("qls_send: empty packet"));
1179711bcba0SDavid C Somayajulu
1180711bcba0SDavid C Somayajulu bus_dmamap_sync(ha->tx_tag, map, BUS_DMASYNC_PREWRITE);
1181711bcba0SDavid C Somayajulu
1182711bcba0SDavid C Somayajulu if (!(ret = qls_hw_send(ha, segs, nsegs, tx_idx, m_head, txr_idx))) {
1183711bcba0SDavid C Somayajulu ha->tx_ring[txr_idx].count++;
1184711bcba0SDavid C Somayajulu ha->tx_ring[txr_idx].tx_buf[tx_idx].m_head = m_head;
1185711bcba0SDavid C Somayajulu ha->tx_ring[txr_idx].tx_buf[tx_idx].map = map;
1186711bcba0SDavid C Somayajulu } else {
1187711bcba0SDavid C Somayajulu if (ret == EINVAL) {
1188711bcba0SDavid C Somayajulu if (m_head)
1189711bcba0SDavid C Somayajulu m_freem(m_head);
1190711bcba0SDavid C Somayajulu *m_headp = NULL;
1191711bcba0SDavid C Somayajulu }
1192711bcba0SDavid C Somayajulu }
1193711bcba0SDavid C Somayajulu
1194711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
1195711bcba0SDavid C Somayajulu return (ret);
1196711bcba0SDavid C Somayajulu }
1197711bcba0SDavid C Somayajulu
1198711bcba0SDavid C Somayajulu static void
qls_stop(qla_host_t * ha)1199711bcba0SDavid C Somayajulu qls_stop(qla_host_t *ha)
1200711bcba0SDavid C Somayajulu {
120164c618edSJustin Hibbits if_t ifp = ha->ifp;
1202711bcba0SDavid C Somayajulu
120364c618edSJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_OACTIVE | IFF_DRV_RUNNING));
1204711bcba0SDavid C Somayajulu
1205711bcba0SDavid C Somayajulu ha->flags.qla_watchdog_pause = 1;
1206711bcba0SDavid C Somayajulu
1207711bcba0SDavid C Somayajulu while (!ha->qla_watchdog_paused)
1208711bcba0SDavid C Somayajulu qls_mdelay(__func__, 1);
1209711bcba0SDavid C Somayajulu
1210711bcba0SDavid C Somayajulu qls_del_hw_if(ha);
1211711bcba0SDavid C Somayajulu
1212711bcba0SDavid C Somayajulu qls_free_lro(ha);
1213711bcba0SDavid C Somayajulu
1214711bcba0SDavid C Somayajulu qls_flush_xmt_bufs(ha);
1215711bcba0SDavid C Somayajulu qls_free_rcv_bufs(ha);
1216711bcba0SDavid C Somayajulu
1217711bcba0SDavid C Somayajulu return;
1218711bcba0SDavid C Somayajulu }
1219711bcba0SDavid C Somayajulu
1220711bcba0SDavid C Somayajulu /*
1221711bcba0SDavid C Somayajulu * Buffer Management Functions for Transmit and Receive Rings
1222711bcba0SDavid C Somayajulu */
1223711bcba0SDavid C Somayajulu /*
1224711bcba0SDavid C Somayajulu * Release mbuf after it sent on the wire
1225711bcba0SDavid C Somayajulu */
1226711bcba0SDavid C Somayajulu static void
qls_flush_tx_buf(qla_host_t * ha,qla_tx_buf_t * txb)1227711bcba0SDavid C Somayajulu qls_flush_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb)
1228711bcba0SDavid C Somayajulu {
1229711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1230711bcba0SDavid C Somayajulu
1231711bcba0SDavid C Somayajulu if (txb->m_head) {
1232711bcba0SDavid C Somayajulu bus_dmamap_unload(ha->tx_tag, txb->map);
1233711bcba0SDavid C Somayajulu
1234711bcba0SDavid C Somayajulu m_freem(txb->m_head);
1235711bcba0SDavid C Somayajulu txb->m_head = NULL;
1236711bcba0SDavid C Somayajulu }
1237711bcba0SDavid C Somayajulu
1238711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
1239711bcba0SDavid C Somayajulu }
1240711bcba0SDavid C Somayajulu
1241711bcba0SDavid C Somayajulu static void
qls_flush_xmt_bufs(qla_host_t * ha)1242711bcba0SDavid C Somayajulu qls_flush_xmt_bufs(qla_host_t *ha)
1243711bcba0SDavid C Somayajulu {
1244711bcba0SDavid C Somayajulu int i, j;
1245711bcba0SDavid C Somayajulu
1246711bcba0SDavid C Somayajulu for (j = 0; j < ha->num_tx_rings; j++) {
1247711bcba0SDavid C Somayajulu for (i = 0; i < NUM_TX_DESCRIPTORS; i++)
1248711bcba0SDavid C Somayajulu qls_flush_tx_buf(ha, &ha->tx_ring[j].tx_buf[i]);
1249711bcba0SDavid C Somayajulu }
1250711bcba0SDavid C Somayajulu
1251711bcba0SDavid C Somayajulu return;
1252711bcba0SDavid C Somayajulu }
1253711bcba0SDavid C Somayajulu
1254711bcba0SDavid C Somayajulu static int
qls_alloc_rcv_mbufs(qla_host_t * ha,int r)1255711bcba0SDavid C Somayajulu qls_alloc_rcv_mbufs(qla_host_t *ha, int r)
1256711bcba0SDavid C Somayajulu {
1257711bcba0SDavid C Somayajulu int i, j, ret = 0;
1258711bcba0SDavid C Somayajulu qla_rx_buf_t *rxb;
1259711bcba0SDavid C Somayajulu qla_rx_ring_t *rx_ring;
1260711bcba0SDavid C Somayajulu volatile q81_bq_addr_e_t *sbq_e;
1261711bcba0SDavid C Somayajulu
1262711bcba0SDavid C Somayajulu rx_ring = &ha->rx_ring[r];
1263711bcba0SDavid C Somayajulu
1264711bcba0SDavid C Somayajulu for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1265711bcba0SDavid C Somayajulu rxb = &rx_ring->rx_buf[i];
1266711bcba0SDavid C Somayajulu
1267711bcba0SDavid C Somayajulu ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, &rxb->map);
1268711bcba0SDavid C Somayajulu
1269711bcba0SDavid C Somayajulu if (ret) {
1270711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
1271711bcba0SDavid C Somayajulu "%s: dmamap[%d, %d] failed\n", __func__, r, i);
1272711bcba0SDavid C Somayajulu
1273711bcba0SDavid C Somayajulu for (j = 0; j < i; j++) {
1274711bcba0SDavid C Somayajulu rxb = &rx_ring->rx_buf[j];
1275711bcba0SDavid C Somayajulu bus_dmamap_destroy(ha->rx_tag, rxb->map);
1276711bcba0SDavid C Somayajulu }
1277711bcba0SDavid C Somayajulu goto qls_alloc_rcv_mbufs_err;
1278711bcba0SDavid C Somayajulu }
1279711bcba0SDavid C Somayajulu }
1280711bcba0SDavid C Somayajulu
1281711bcba0SDavid C Somayajulu rx_ring = &ha->rx_ring[r];
1282711bcba0SDavid C Somayajulu
1283711bcba0SDavid C Somayajulu sbq_e = rx_ring->sbq_vaddr;
1284711bcba0SDavid C Somayajulu
1285711bcba0SDavid C Somayajulu rxb = &rx_ring->rx_buf[0];
1286711bcba0SDavid C Somayajulu
1287711bcba0SDavid C Somayajulu for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1288711bcba0SDavid C Somayajulu if (!(ret = qls_get_mbuf(ha, rxb, NULL))) {
1289711bcba0SDavid C Somayajulu /*
1290711bcba0SDavid C Somayajulu * set the physical address in the
1291711bcba0SDavid C Somayajulu * corresponding descriptor entry in the
1292711bcba0SDavid C Somayajulu * receive ring/queue for the hba
1293711bcba0SDavid C Somayajulu */
1294711bcba0SDavid C Somayajulu
1295711bcba0SDavid C Somayajulu sbq_e->addr_lo = rxb->paddr & 0xFFFFFFFF;
1296711bcba0SDavid C Somayajulu sbq_e->addr_hi = (rxb->paddr >> 32) & 0xFFFFFFFF;
1297711bcba0SDavid C Somayajulu
1298711bcba0SDavid C Somayajulu } else {
1299711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
1300711bcba0SDavid C Somayajulu "%s: qls_get_mbuf [%d, %d] failed\n",
1301711bcba0SDavid C Somayajulu __func__, r, i);
1302711bcba0SDavid C Somayajulu bus_dmamap_destroy(ha->rx_tag, rxb->map);
1303711bcba0SDavid C Somayajulu goto qls_alloc_rcv_mbufs_err;
1304711bcba0SDavid C Somayajulu }
1305711bcba0SDavid C Somayajulu
1306711bcba0SDavid C Somayajulu rxb++;
1307711bcba0SDavid C Somayajulu sbq_e++;
1308711bcba0SDavid C Somayajulu }
1309711bcba0SDavid C Somayajulu return 0;
1310711bcba0SDavid C Somayajulu
1311711bcba0SDavid C Somayajulu qls_alloc_rcv_mbufs_err:
1312711bcba0SDavid C Somayajulu return (-1);
1313711bcba0SDavid C Somayajulu }
1314711bcba0SDavid C Somayajulu
1315711bcba0SDavid C Somayajulu static void
qls_free_rcv_bufs(qla_host_t * ha)1316711bcba0SDavid C Somayajulu qls_free_rcv_bufs(qla_host_t *ha)
1317711bcba0SDavid C Somayajulu {
1318711bcba0SDavid C Somayajulu int i, r;
1319711bcba0SDavid C Somayajulu qla_rx_buf_t *rxb;
1320711bcba0SDavid C Somayajulu qla_rx_ring_t *rxr;
1321711bcba0SDavid C Somayajulu
1322711bcba0SDavid C Somayajulu for (r = 0; r < ha->num_rx_rings; r++) {
1323711bcba0SDavid C Somayajulu rxr = &ha->rx_ring[r];
1324711bcba0SDavid C Somayajulu
1325711bcba0SDavid C Somayajulu for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1326711bcba0SDavid C Somayajulu rxb = &rxr->rx_buf[i];
1327711bcba0SDavid C Somayajulu
1328711bcba0SDavid C Somayajulu if (rxb->m_head != NULL) {
1329711bcba0SDavid C Somayajulu bus_dmamap_unload(ha->rx_tag, rxb->map);
1330711bcba0SDavid C Somayajulu bus_dmamap_destroy(ha->rx_tag, rxb->map);
1331711bcba0SDavid C Somayajulu m_freem(rxb->m_head);
1332711bcba0SDavid C Somayajulu }
1333711bcba0SDavid C Somayajulu }
1334711bcba0SDavid C Somayajulu bzero(rxr->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
1335711bcba0SDavid C Somayajulu }
1336711bcba0SDavid C Somayajulu return;
1337711bcba0SDavid C Somayajulu }
1338711bcba0SDavid C Somayajulu
1339711bcba0SDavid C Somayajulu static int
qls_alloc_rcv_bufs(qla_host_t * ha)1340711bcba0SDavid C Somayajulu qls_alloc_rcv_bufs(qla_host_t *ha)
1341711bcba0SDavid C Somayajulu {
1342711bcba0SDavid C Somayajulu int r, ret = 0;
1343711bcba0SDavid C Somayajulu qla_rx_ring_t *rxr;
1344711bcba0SDavid C Somayajulu
1345711bcba0SDavid C Somayajulu for (r = 0; r < ha->num_rx_rings; r++) {
1346711bcba0SDavid C Somayajulu rxr = &ha->rx_ring[r];
1347711bcba0SDavid C Somayajulu bzero(rxr->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
1348711bcba0SDavid C Somayajulu }
1349711bcba0SDavid C Somayajulu
1350711bcba0SDavid C Somayajulu for (r = 0; r < ha->num_rx_rings; r++) {
1351711bcba0SDavid C Somayajulu ret = qls_alloc_rcv_mbufs(ha, r);
1352711bcba0SDavid C Somayajulu
1353711bcba0SDavid C Somayajulu if (ret)
1354711bcba0SDavid C Somayajulu qls_free_rcv_bufs(ha);
1355711bcba0SDavid C Somayajulu }
1356711bcba0SDavid C Somayajulu
1357711bcba0SDavid C Somayajulu return (ret);
1358711bcba0SDavid C Somayajulu }
1359711bcba0SDavid C Somayajulu
1360711bcba0SDavid C Somayajulu int
qls_get_mbuf(qla_host_t * ha,qla_rx_buf_t * rxb,struct mbuf * nmp)1361711bcba0SDavid C Somayajulu qls_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp)
1362711bcba0SDavid C Somayajulu {
13633e85b721SEd Maste struct mbuf *mp = nmp;
1364711bcba0SDavid C Somayajulu int ret = 0;
1365711bcba0SDavid C Somayajulu uint32_t offset;
1366711bcba0SDavid C Somayajulu bus_dma_segment_t segs[1];
1367711bcba0SDavid C Somayajulu int nsegs;
1368711bcba0SDavid C Somayajulu
1369711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1370711bcba0SDavid C Somayajulu
1371711bcba0SDavid C Somayajulu if (mp == NULL) {
1372b8c83a19SGleb Smirnoff mp = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ha->msize);
1373711bcba0SDavid C Somayajulu
1374711bcba0SDavid C Somayajulu if (mp == NULL) {
1375711bcba0SDavid C Somayajulu if (ha->msize == MCLBYTES)
1376711bcba0SDavid C Somayajulu ha->err_m_getcl++;
1377711bcba0SDavid C Somayajulu else
1378711bcba0SDavid C Somayajulu ha->err_m_getjcl++;
1379711bcba0SDavid C Somayajulu
1380711bcba0SDavid C Somayajulu ret = ENOBUFS;
1381711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
1382711bcba0SDavid C Somayajulu "%s: m_getcl failed\n", __func__);
1383711bcba0SDavid C Somayajulu goto exit_qls_get_mbuf;
1384711bcba0SDavid C Somayajulu }
1385711bcba0SDavid C Somayajulu mp->m_len = mp->m_pkthdr.len = ha->msize;
1386711bcba0SDavid C Somayajulu } else {
1387711bcba0SDavid C Somayajulu mp->m_len = mp->m_pkthdr.len = ha->msize;
1388711bcba0SDavid C Somayajulu mp->m_data = mp->m_ext.ext_buf;
1389711bcba0SDavid C Somayajulu mp->m_next = NULL;
1390711bcba0SDavid C Somayajulu }
1391711bcba0SDavid C Somayajulu
1392711bcba0SDavid C Somayajulu /* align the receive buffers to 8 byte boundary */
1393711bcba0SDavid C Somayajulu offset = (uint32_t)((unsigned long long)mp->m_data & 0x7ULL);
1394711bcba0SDavid C Somayajulu if (offset) {
1395711bcba0SDavid C Somayajulu offset = 8 - offset;
1396711bcba0SDavid C Somayajulu m_adj(mp, offset);
1397711bcba0SDavid C Somayajulu }
1398711bcba0SDavid C Somayajulu
1399711bcba0SDavid C Somayajulu /*
1400711bcba0SDavid C Somayajulu * Using memory from the mbuf cluster pool, invoke the bus_dma
1401711bcba0SDavid C Somayajulu * machinery to arrange the memory mapping.
1402711bcba0SDavid C Somayajulu */
1403711bcba0SDavid C Somayajulu ret = bus_dmamap_load_mbuf_sg(ha->rx_tag, rxb->map,
1404711bcba0SDavid C Somayajulu mp, segs, &nsegs, BUS_DMA_NOWAIT);
1405711bcba0SDavid C Somayajulu rxb->paddr = segs[0].ds_addr;
1406711bcba0SDavid C Somayajulu
1407711bcba0SDavid C Somayajulu if (ret || !rxb->paddr || (nsegs != 1)) {
1408711bcba0SDavid C Somayajulu m_freem(mp);
1409711bcba0SDavid C Somayajulu rxb->m_head = NULL;
1410711bcba0SDavid C Somayajulu device_printf(ha->pci_dev,
1411711bcba0SDavid C Somayajulu "%s: bus_dmamap_load failed[%d, 0x%016llx, %d]\n",
1412711bcba0SDavid C Somayajulu __func__, ret, (long long unsigned int)rxb->paddr,
1413711bcba0SDavid C Somayajulu nsegs);
1414711bcba0SDavid C Somayajulu ret = -1;
1415711bcba0SDavid C Somayajulu goto exit_qls_get_mbuf;
1416711bcba0SDavid C Somayajulu }
1417711bcba0SDavid C Somayajulu rxb->m_head = mp;
1418711bcba0SDavid C Somayajulu bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_PREREAD);
1419711bcba0SDavid C Somayajulu
1420711bcba0SDavid C Somayajulu exit_qls_get_mbuf:
1421711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: exit ret = 0x%08x\n", __func__, ret));
1422711bcba0SDavid C Somayajulu return (ret);
1423711bcba0SDavid C Somayajulu }
1424711bcba0SDavid C Somayajulu
1425711bcba0SDavid C Somayajulu static void
qls_tx_done(void * context,int pending)1426711bcba0SDavid C Somayajulu qls_tx_done(void *context, int pending)
1427711bcba0SDavid C Somayajulu {
1428711bcba0SDavid C Somayajulu qla_host_t *ha = context;
142964c618edSJustin Hibbits if_t ifp;
1430711bcba0SDavid C Somayajulu
1431711bcba0SDavid C Somayajulu ifp = ha->ifp;
1432711bcba0SDavid C Somayajulu
1433711bcba0SDavid C Somayajulu if (!ifp)
1434711bcba0SDavid C Somayajulu return;
1435711bcba0SDavid C Somayajulu
143664c618edSJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
1437711bcba0SDavid C Somayajulu QL_DPRINT8((ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
1438711bcba0SDavid C Somayajulu return;
1439711bcba0SDavid C Somayajulu }
1440711bcba0SDavid C Somayajulu
1441711bcba0SDavid C Somayajulu qls_start(ha->ifp);
1442711bcba0SDavid C Somayajulu return;
1443711bcba0SDavid C Somayajulu }
1444711bcba0SDavid C Somayajulu
1445711bcba0SDavid C Somayajulu static int
qls_config_lro(qla_host_t * ha)1446711bcba0SDavid C Somayajulu qls_config_lro(qla_host_t *ha)
1447711bcba0SDavid C Somayajulu {
1448618aa8cdSJohn Baldwin #if defined(INET) || defined(INET6)
1449711bcba0SDavid C Somayajulu int i;
1450711bcba0SDavid C Somayajulu struct lro_ctrl *lro;
1451711bcba0SDavid C Somayajulu
1452711bcba0SDavid C Somayajulu for (i = 0; i < ha->num_rx_rings; i++) {
1453711bcba0SDavid C Somayajulu lro = &ha->rx_ring[i].lro;
1454711bcba0SDavid C Somayajulu if (tcp_lro_init(lro)) {
1455711bcba0SDavid C Somayajulu device_printf(ha->pci_dev, "%s: tcp_lro_init failed\n",
1456711bcba0SDavid C Somayajulu __func__);
1457711bcba0SDavid C Somayajulu return (-1);
1458711bcba0SDavid C Somayajulu }
1459711bcba0SDavid C Somayajulu lro->ifp = ha->ifp;
1460711bcba0SDavid C Somayajulu }
1461711bcba0SDavid C Somayajulu ha->flags.lro_init = 1;
1462711bcba0SDavid C Somayajulu
1463711bcba0SDavid C Somayajulu QL_DPRINT2((ha->pci_dev, "%s: LRO initialized\n", __func__));
1464618aa8cdSJohn Baldwin #endif
1465711bcba0SDavid C Somayajulu return (0);
1466711bcba0SDavid C Somayajulu }
1467711bcba0SDavid C Somayajulu
1468711bcba0SDavid C Somayajulu static void
qls_free_lro(qla_host_t * ha)1469711bcba0SDavid C Somayajulu qls_free_lro(qla_host_t *ha)
1470711bcba0SDavid C Somayajulu {
1471618aa8cdSJohn Baldwin #if defined(INET) || defined(INET6)
1472711bcba0SDavid C Somayajulu int i;
1473711bcba0SDavid C Somayajulu struct lro_ctrl *lro;
1474711bcba0SDavid C Somayajulu
1475711bcba0SDavid C Somayajulu if (!ha->flags.lro_init)
1476711bcba0SDavid C Somayajulu return;
1477711bcba0SDavid C Somayajulu
1478711bcba0SDavid C Somayajulu for (i = 0; i < ha->num_rx_rings; i++) {
1479711bcba0SDavid C Somayajulu lro = &ha->rx_ring[i].lro;
1480711bcba0SDavid C Somayajulu tcp_lro_free(lro);
1481711bcba0SDavid C Somayajulu }
1482711bcba0SDavid C Somayajulu ha->flags.lro_init = 0;
1483618aa8cdSJohn Baldwin #endif
1484711bcba0SDavid C Somayajulu }
1485711bcba0SDavid C Somayajulu
1486711bcba0SDavid C Somayajulu static void
qls_error_recovery(void * context,int pending)1487711bcba0SDavid C Somayajulu qls_error_recovery(void *context, int pending)
1488711bcba0SDavid C Somayajulu {
1489711bcba0SDavid C Somayajulu qla_host_t *ha = context;
1490711bcba0SDavid C Somayajulu
1491711bcba0SDavid C Somayajulu qls_init(ha);
1492711bcba0SDavid C Somayajulu
1493711bcba0SDavid C Somayajulu return;
1494711bcba0SDavid C Somayajulu }
1495