1171095Ssam/*-
2171095Ssam * Copyright (c) 2002-2007 Neterion, Inc.
3171095Ssam * All rights reserved.
4171095Ssam *
5171095Ssam * Redistribution and use in source and binary forms, with or without
6171095Ssam * modification, are permitted provided that the following conditions
7171095Ssam * are met:
8171095Ssam * 1. Redistributions of source code must retain the above copyright
9171095Ssam *    notice, this list of conditions and the following disclaimer.
10171095Ssam * 2. Redistributions in binary form must reproduce the above copyright
11171095Ssam *    notice, this list of conditions and the following disclaimer in the
12171095Ssam *    documentation and/or other materials provided with the distribution.
13171095Ssam *
14171095Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15171095Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16171095Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17171095Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18171095Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19171095Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20171095Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21171095Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22171095Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23171095Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24171095Ssam * SUCH DAMAGE.
25171095Ssam *
26171095Ssam * $FreeBSD: stable/10/sys/dev/nxge/if_nxge.c 332280 2018-04-08 15:35:57Z brooks $
27171095Ssam */
28171095Ssam
29171095Ssam#include <dev/nxge/if_nxge.h>
30171095Ssam#include <dev/nxge/xge-osdep.h>
31171095Ssam#include <net/if_arp.h>
32171095Ssam#include <sys/types.h>
33171095Ssam#include <net/if.h>
34171095Ssam#include <net/if_vlan_var.h>
35171095Ssam
36171095Ssamint       copyright_print       = 0;
37171095Ssamint       hal_driver_init_count = 0;
38171095Ssamsize_t    size                  = sizeof(int);
39171095Ssam
40173139Srwatsonstatic void inline xge_flush_txds(xge_hal_channel_h);
41173139Srwatson
42173139Srwatson/**
43171095Ssam * xge_probe
44173139Srwatson * Probes for Xframe devices
45173139Srwatson *
46173139Srwatson * @dev Device handle
47173139Srwatson *
48173139Srwatson * Returns
49173139Srwatson * BUS_PROBE_DEFAULT if device is supported
50173139Srwatson * ENXIO if device is not supported
51173139Srwatson */
52171095Ssamint
53171095Ssamxge_probe(device_t dev)
54171095Ssam{
55171095Ssam	int  devid    = pci_get_device(dev);
56171095Ssam	int  vendorid = pci_get_vendor(dev);
57171095Ssam	int  retValue = ENXIO;
58171095Ssam
59171095Ssam	if(vendorid == XGE_PCI_VENDOR_ID) {
60171095Ssam	    if((devid == XGE_PCI_DEVICE_ID_XENA_2) ||
61171095Ssam	        (devid == XGE_PCI_DEVICE_ID_HERC_2)) {
62171095Ssam	        if(!copyright_print) {
63173139Srwatson	            xge_os_printf(XGE_COPYRIGHT);
64171095Ssam	            copyright_print = 1;
65171095Ssam	        }
66171095Ssam	        device_set_desc_copy(dev,
67171095Ssam	            "Neterion Xframe 10 Gigabit Ethernet Adapter");
68171095Ssam	        retValue = BUS_PROBE_DEFAULT;
69171095Ssam	    }
70171095Ssam	}
71171095Ssam
72171095Ssam	return retValue;
73171095Ssam}
74171095Ssam
75173139Srwatson/**
76171095Ssam * xge_init_params
77173139Srwatson * Sets HAL parameter values (from kenv).
78173139Srwatson *
79173139Srwatson * @dconfig Device Configuration
80173139Srwatson * @dev Device Handle
81173139Srwatson */
82171095Ssamvoid
83171095Ssamxge_init_params(xge_hal_device_config_t *dconfig, device_t dev)
84171095Ssam{
85173139Srwatson	int qindex, tindex, revision;
86171095Ssam	device_t checkdev;
87173139Srwatson	xge_lldev_t *lldev = (xge_lldev_t *)device_get_softc(dev);
88171095Ssam
89171095Ssam	dconfig->mtu                   = XGE_DEFAULT_INITIAL_MTU;
90171095Ssam	dconfig->pci_freq_mherz        = XGE_DEFAULT_USER_HARDCODED;
91171095Ssam	dconfig->device_poll_millis    = XGE_HAL_DEFAULT_DEVICE_POLL_MILLIS;
92171095Ssam	dconfig->link_stability_period = XGE_HAL_DEFAULT_LINK_STABILITY_PERIOD;
93171095Ssam	dconfig->mac.rmac_bcast_en     = XGE_DEFAULT_MAC_RMAC_BCAST_EN;
94171095Ssam	dconfig->fifo.alignment_size   = XGE_DEFAULT_FIFO_ALIGNMENT_SIZE;
95171095Ssam
96173139Srwatson	XGE_GET_PARAM("hw.xge.enable_tso", (*lldev), enabled_tso,
97173139Srwatson	    XGE_DEFAULT_ENABLED_TSO);
98173139Srwatson	XGE_GET_PARAM("hw.xge.enable_lro", (*lldev), enabled_lro,
99173139Srwatson	    XGE_DEFAULT_ENABLED_LRO);
100173139Srwatson	XGE_GET_PARAM("hw.xge.enable_msi", (*lldev), enabled_msi,
101173139Srwatson	    XGE_DEFAULT_ENABLED_MSI);
102173139Srwatson
103173139Srwatson	XGE_GET_PARAM("hw.xge.latency_timer", (*dconfig), latency_timer,
104171095Ssam	    XGE_DEFAULT_LATENCY_TIMER);
105173139Srwatson	XGE_GET_PARAM("hw.xge.max_splits_trans", (*dconfig), max_splits_trans,
106171095Ssam	    XGE_DEFAULT_MAX_SPLITS_TRANS);
107173139Srwatson	XGE_GET_PARAM("hw.xge.mmrb_count", (*dconfig), mmrb_count,
108171095Ssam	    XGE_DEFAULT_MMRB_COUNT);
109173139Srwatson	XGE_GET_PARAM("hw.xge.shared_splits", (*dconfig), shared_splits,
110171095Ssam	    XGE_DEFAULT_SHARED_SPLITS);
111173139Srwatson	XGE_GET_PARAM("hw.xge.isr_polling_cnt", (*dconfig), isr_polling_cnt,
112171095Ssam	    XGE_DEFAULT_ISR_POLLING_CNT);
113173139Srwatson	XGE_GET_PARAM("hw.xge.stats_refresh_time_sec", (*dconfig),
114171095Ssam	    stats_refresh_time_sec, XGE_DEFAULT_STATS_REFRESH_TIME_SEC);
115171095Ssam
116173139Srwatson	XGE_GET_PARAM_MAC("hw.xge.mac_tmac_util_period", tmac_util_period,
117171095Ssam	    XGE_DEFAULT_MAC_TMAC_UTIL_PERIOD);
118173139Srwatson	XGE_GET_PARAM_MAC("hw.xge.mac_rmac_util_period", rmac_util_period,
119171095Ssam	    XGE_DEFAULT_MAC_RMAC_UTIL_PERIOD);
120173139Srwatson	XGE_GET_PARAM_MAC("hw.xge.mac_rmac_pause_gen_en", rmac_pause_gen_en,
121171095Ssam	    XGE_DEFAULT_MAC_RMAC_PAUSE_GEN_EN);
122173139Srwatson	XGE_GET_PARAM_MAC("hw.xge.mac_rmac_pause_rcv_en", rmac_pause_rcv_en,
123171095Ssam	    XGE_DEFAULT_MAC_RMAC_PAUSE_RCV_EN);
124173139Srwatson	XGE_GET_PARAM_MAC("hw.xge.mac_rmac_pause_time", rmac_pause_time,
125171095Ssam	    XGE_DEFAULT_MAC_RMAC_PAUSE_TIME);
126173139Srwatson	XGE_GET_PARAM_MAC("hw.xge.mac_mc_pause_threshold_q0q3",
127171095Ssam	    mc_pause_threshold_q0q3, XGE_DEFAULT_MAC_MC_PAUSE_THRESHOLD_Q0Q3);
128173139Srwatson	XGE_GET_PARAM_MAC("hw.xge.mac_mc_pause_threshold_q4q7",
129171095Ssam	    mc_pause_threshold_q4q7, XGE_DEFAULT_MAC_MC_PAUSE_THRESHOLD_Q4Q7);
130171095Ssam
131173139Srwatson	XGE_GET_PARAM_FIFO("hw.xge.fifo_memblock_size", memblock_size,
132171095Ssam	    XGE_DEFAULT_FIFO_MEMBLOCK_SIZE);
133173139Srwatson	XGE_GET_PARAM_FIFO("hw.xge.fifo_reserve_threshold", reserve_threshold,
134171095Ssam	    XGE_DEFAULT_FIFO_RESERVE_THRESHOLD);
135173139Srwatson	XGE_GET_PARAM_FIFO("hw.xge.fifo_max_frags", max_frags,
136171095Ssam	    XGE_DEFAULT_FIFO_MAX_FRAGS);
137171095Ssam
138173139Srwatson	for(qindex = 0; qindex < XGE_FIFO_COUNT; qindex++) {
139173139Srwatson	    XGE_GET_PARAM_FIFO_QUEUE("hw.xge.fifo_queue_intr", intr, qindex,
140173139Srwatson	        XGE_DEFAULT_FIFO_QUEUE_INTR);
141173139Srwatson	    XGE_GET_PARAM_FIFO_QUEUE("hw.xge.fifo_queue_max", max, qindex,
142173139Srwatson	        XGE_DEFAULT_FIFO_QUEUE_MAX);
143173139Srwatson	    XGE_GET_PARAM_FIFO_QUEUE("hw.xge.fifo_queue_initial", initial,
144173139Srwatson	        qindex, XGE_DEFAULT_FIFO_QUEUE_INITIAL);
145171095Ssam
146173139Srwatson	    for (tindex = 0; tindex < XGE_HAL_MAX_FIFO_TTI_NUM; tindex++) {
147173139Srwatson	        dconfig->fifo.queue[qindex].tti[tindex].enabled  = 1;
148173139Srwatson	        dconfig->fifo.queue[qindex].configured = 1;
149171095Ssam
150173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_urange_a",
151173139Srwatson	            urange_a, qindex, tindex,
152173139Srwatson	            XGE_DEFAULT_FIFO_QUEUE_TTI_URANGE_A);
153173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_urange_b",
154173139Srwatson	            urange_b, qindex, tindex,
155173139Srwatson	            XGE_DEFAULT_FIFO_QUEUE_TTI_URANGE_B);
156173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_urange_c",
157173139Srwatson	            urange_c, qindex, tindex,
158173139Srwatson	            XGE_DEFAULT_FIFO_QUEUE_TTI_URANGE_C);
159173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_ufc_a",
160173139Srwatson	            ufc_a, qindex, tindex, XGE_DEFAULT_FIFO_QUEUE_TTI_UFC_A);
161173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_ufc_b",
162173139Srwatson	            ufc_b, qindex, tindex, XGE_DEFAULT_FIFO_QUEUE_TTI_UFC_B);
163173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_ufc_c",
164173139Srwatson	            ufc_c, qindex, tindex, XGE_DEFAULT_FIFO_QUEUE_TTI_UFC_C);
165173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_ufc_d",
166173139Srwatson	            ufc_d, qindex, tindex, XGE_DEFAULT_FIFO_QUEUE_TTI_UFC_D);
167173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI(
168173139Srwatson	            "hw.xge.fifo_queue_tti_timer_ci_en", timer_ci_en, qindex,
169173139Srwatson	            tindex, XGE_DEFAULT_FIFO_QUEUE_TTI_TIMER_CI_EN);
170173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI(
171173139Srwatson	            "hw.xge.fifo_queue_tti_timer_ac_en", timer_ac_en, qindex,
172173139Srwatson	            tindex, XGE_DEFAULT_FIFO_QUEUE_TTI_TIMER_AC_EN);
173173139Srwatson	        XGE_GET_PARAM_FIFO_QUEUE_TTI(
174173139Srwatson	            "hw.xge.fifo_queue_tti_timer_val_us", timer_val_us, qindex,
175173139Srwatson	            tindex, XGE_DEFAULT_FIFO_QUEUE_TTI_TIMER_VAL_US);
176173139Srwatson	    }
177171095Ssam	}
178171095Ssam
179173139Srwatson	XGE_GET_PARAM_RING("hw.xge.ring_memblock_size", memblock_size,
180171095Ssam	    XGE_DEFAULT_RING_MEMBLOCK_SIZE);
181173139Srwatson
182173139Srwatson	XGE_GET_PARAM_RING("hw.xge.ring_strip_vlan_tag", strip_vlan_tag,
183171095Ssam	    XGE_DEFAULT_RING_STRIP_VLAN_TAG);
184171095Ssam
185173139Srwatson	XGE_GET_PARAM("hw.xge.buffer_mode", (*lldev), buffer_mode,
186173139Srwatson	    XGE_DEFAULT_BUFFER_MODE);
187173139Srwatson	if((lldev->buffer_mode < XGE_HAL_RING_QUEUE_BUFFER_MODE_1) ||
188173139Srwatson	    (lldev->buffer_mode > XGE_HAL_RING_QUEUE_BUFFER_MODE_2)) {
189173139Srwatson	    xge_trace(XGE_ERR, "Supported buffer modes are 1 and 2");
190173139Srwatson	    lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_1;
191173139Srwatson	}
192173139Srwatson
193173139Srwatson	for (qindex = 0; qindex < XGE_RING_COUNT; qindex++) {
194173139Srwatson	    dconfig->ring.queue[qindex].max_frm_len  = XGE_HAL_RING_USE_MTU;
195173139Srwatson	    dconfig->ring.queue[qindex].priority     = 0;
196173139Srwatson	    dconfig->ring.queue[qindex].configured   = 1;
197173139Srwatson	    dconfig->ring.queue[qindex].buffer_mode  =
198173139Srwatson	        (lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_2) ?
199173139Srwatson	        XGE_HAL_RING_QUEUE_BUFFER_MODE_3 : lldev->buffer_mode;
200173139Srwatson
201173139Srwatson	    XGE_GET_PARAM_RING_QUEUE("hw.xge.ring_queue_max", max, qindex,
202171095Ssam	        XGE_DEFAULT_RING_QUEUE_MAX);
203173139Srwatson	    XGE_GET_PARAM_RING_QUEUE("hw.xge.ring_queue_initial", initial,
204173139Srwatson	        qindex, XGE_DEFAULT_RING_QUEUE_INITIAL);
205173139Srwatson	    XGE_GET_PARAM_RING_QUEUE("hw.xge.ring_queue_dram_size_mb",
206173139Srwatson	        dram_size_mb, qindex, XGE_DEFAULT_RING_QUEUE_DRAM_SIZE_MB);
207173139Srwatson	    XGE_GET_PARAM_RING_QUEUE("hw.xge.ring_queue_indicate_max_pkts",
208173139Srwatson	        indicate_max_pkts, qindex,
209171095Ssam	        XGE_DEFAULT_RING_QUEUE_INDICATE_MAX_PKTS);
210173139Srwatson	    XGE_GET_PARAM_RING_QUEUE("hw.xge.ring_queue_backoff_interval_us",
211173139Srwatson	        backoff_interval_us, qindex,
212171095Ssam	        XGE_DEFAULT_RING_QUEUE_BACKOFF_INTERVAL_US);
213171095Ssam
214173139Srwatson	    XGE_GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_ufc_a", ufc_a,
215173139Srwatson	        qindex, XGE_DEFAULT_RING_QUEUE_RTI_UFC_A);
216173139Srwatson	    XGE_GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_ufc_b", ufc_b,
217173139Srwatson	        qindex, XGE_DEFAULT_RING_QUEUE_RTI_UFC_B);
218173139Srwatson	    XGE_GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_ufc_c", ufc_c,
219173139Srwatson	        qindex, XGE_DEFAULT_RING_QUEUE_RTI_UFC_C);
220173139Srwatson	    XGE_GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_ufc_d", ufc_d,
221173139Srwatson	        qindex, XGE_DEFAULT_RING_QUEUE_RTI_UFC_D);
222173139Srwatson	    XGE_GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_timer_ac_en",
223173139Srwatson	        timer_ac_en, qindex, XGE_DEFAULT_RING_QUEUE_RTI_TIMER_AC_EN);
224173139Srwatson	    XGE_GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_timer_val_us",
225173139Srwatson	        timer_val_us, qindex, XGE_DEFAULT_RING_QUEUE_RTI_TIMER_VAL_US);
226173139Srwatson	    XGE_GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_urange_a",
227173139Srwatson	        urange_a, qindex, XGE_DEFAULT_RING_QUEUE_RTI_URANGE_A);
228173139Srwatson	    XGE_GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_urange_b",
229173139Srwatson	        urange_b, qindex, XGE_DEFAULT_RING_QUEUE_RTI_URANGE_B);
230173139Srwatson	    XGE_GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_urange_c",
231173139Srwatson	        urange_c, qindex, XGE_DEFAULT_RING_QUEUE_RTI_URANGE_C);
232171095Ssam	}
233171095Ssam
234171095Ssam	if(dconfig->fifo.max_frags > (PAGE_SIZE/32)) {
235173139Srwatson	    xge_os_printf("fifo_max_frags = %d", dconfig->fifo.max_frags)
236171095Ssam	    xge_os_printf("fifo_max_frags should be <= (PAGE_SIZE / 32) = %d",
237173139Srwatson	        (int)(PAGE_SIZE / 32))
238173139Srwatson	    xge_os_printf("Using fifo_max_frags = %d", (int)(PAGE_SIZE / 32))
239171095Ssam	    dconfig->fifo.max_frags = (PAGE_SIZE / 32);
240171095Ssam	}
241171095Ssam
242171095Ssam	checkdev = pci_find_device(VENDOR_ID_AMD, DEVICE_ID_8131_PCI_BRIDGE);
243171095Ssam	if(checkdev != NULL) {
244171095Ssam	    /* Check Revision for 0x12 */
245173139Srwatson	    revision = pci_read_config(checkdev,
246171095Ssam	        xge_offsetof(xge_hal_pci_config_t, revision), 1);
247171095Ssam	    if(revision <= 0x12) {
248171095Ssam	        /* Set mmrb_count to 1k and max splits = 2 */
249171095Ssam	        dconfig->mmrb_count       = 1;
250171095Ssam	        dconfig->max_splits_trans = XGE_HAL_THREE_SPLIT_TRANSACTION;
251171095Ssam	    }
252171095Ssam	}
253173139Srwatson}
254171095Ssam
255173139Srwatson/**
256173139Srwatson * xge_buffer_sizes_set
257173139Srwatson * Set buffer sizes based on Rx buffer mode
258173139Srwatson *
259173139Srwatson * @lldev Per-adapter Data
260173139Srwatson * @buffer_mode Rx Buffer Mode
261173139Srwatson */
262173139Srwatsonvoid
263173139Srwatsonxge_rx_buffer_sizes_set(xge_lldev_t *lldev, int buffer_mode, int mtu)
264173139Srwatson{
265173139Srwatson	int index = 0;
266173139Srwatson	int frame_header = XGE_HAL_MAC_HEADER_MAX_SIZE;
267173139Srwatson	int buffer_size = mtu + frame_header;
268171095Ssam
269173139Srwatson	xge_os_memzero(lldev->rxd_mbuf_len, sizeof(lldev->rxd_mbuf_len));
270173139Srwatson
271173139Srwatson	if(buffer_mode != XGE_HAL_RING_QUEUE_BUFFER_MODE_5)
272173139Srwatson	    lldev->rxd_mbuf_len[buffer_mode - 1] = mtu;
273173139Srwatson
274173139Srwatson	lldev->rxd_mbuf_len[0] = (buffer_mode == 1) ? buffer_size:frame_header;
275173139Srwatson
276173139Srwatson	if(buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_5)
277173139Srwatson	    lldev->rxd_mbuf_len[1] = XGE_HAL_TCPIP_HEADER_MAX_SIZE;
278173139Srwatson
279173139Srwatson	if(buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_5) {
280173139Srwatson	    index = 2;
281173139Srwatson	    buffer_size -= XGE_HAL_TCPIP_HEADER_MAX_SIZE;
282173139Srwatson	    while(buffer_size > MJUMPAGESIZE) {
283173139Srwatson	        lldev->rxd_mbuf_len[index++] = MJUMPAGESIZE;
284173139Srwatson	        buffer_size -= MJUMPAGESIZE;
285173139Srwatson	    }
286173139Srwatson	    XGE_ALIGN_TO(buffer_size, 128);
287173139Srwatson	    lldev->rxd_mbuf_len[index] = buffer_size;
288173139Srwatson	    lldev->rxd_mbuf_cnt = index + 1;
289173139Srwatson	}
290173139Srwatson
291173139Srwatson	for(index = 0; index < buffer_mode; index++)
292173139Srwatson	    xge_trace(XGE_TRACE, "Buffer[%d] %d\n", index,
293173139Srwatson	        lldev->rxd_mbuf_len[index]);
294171095Ssam}
295171095Ssam
296173139Srwatson/**
297173139Srwatson * xge_buffer_mode_init
298173139Srwatson * Init Rx buffer mode
299173139Srwatson *
300173139Srwatson * @lldev Per-adapter Data
301173139Srwatson * @mtu Interface MTU
302173139Srwatson */
303173139Srwatsonvoid
304173139Srwatsonxge_buffer_mode_init(xge_lldev_t *lldev, int mtu)
305173139Srwatson{
306173139Srwatson	int index = 0, buffer_size = 0;
307173139Srwatson	xge_hal_ring_config_t *ring_config = &((lldev->devh)->config.ring);
308173139Srwatson
309173139Srwatson	buffer_size = mtu + XGE_HAL_MAC_HEADER_MAX_SIZE;
310173139Srwatson
311173139Srwatson	if(lldev->enabled_lro)
312173139Srwatson	    (lldev->ifnetp)->if_capenable |= IFCAP_LRO;
313173139Srwatson	else
314173139Srwatson	    (lldev->ifnetp)->if_capenable &= ~IFCAP_LRO;
315173139Srwatson
316173139Srwatson	lldev->rxd_mbuf_cnt = lldev->buffer_mode;
317173139Srwatson	if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_2) {
318173139Srwatson	    XGE_SET_BUFFER_MODE_IN_RINGS(XGE_HAL_RING_QUEUE_BUFFER_MODE_3);
319173139Srwatson	    ring_config->scatter_mode = XGE_HAL_RING_QUEUE_SCATTER_MODE_B;
320173139Srwatson	}
321173139Srwatson	else {
322173139Srwatson	    XGE_SET_BUFFER_MODE_IN_RINGS(lldev->buffer_mode);
323173139Srwatson	    ring_config->scatter_mode = XGE_HAL_RING_QUEUE_SCATTER_MODE_A;
324173139Srwatson	}
325173139Srwatson	xge_rx_buffer_sizes_set(lldev, lldev->buffer_mode, mtu);
326173139Srwatson
327173139Srwatson	xge_os_printf("%s: TSO %s", device_get_nameunit(lldev->device),
328173139Srwatson	    ((lldev->enabled_tso) ? "Enabled":"Disabled"));
329173139Srwatson	xge_os_printf("%s: LRO %s", device_get_nameunit(lldev->device),
330173139Srwatson	    ((lldev->ifnetp)->if_capenable & IFCAP_LRO) ? "Enabled":"Disabled");
331173139Srwatson	xge_os_printf("%s: Rx %d Buffer Mode Enabled",
332173139Srwatson	    device_get_nameunit(lldev->device), lldev->buffer_mode);
333173139Srwatson}
334173139Srwatson
335173139Srwatson/**
336171095Ssam * xge_driver_initialize
337173139Srwatson * Initializes HAL driver (common for all devices)
338173139Srwatson *
339173139Srwatson * Returns
340173139Srwatson * XGE_HAL_OK if success
341173139Srwatson * XGE_HAL_ERR_BAD_DRIVER_CONFIG if driver configuration parameters are invalid
342173139Srwatson */
343171095Ssamint
344171095Ssamxge_driver_initialize(void)
345171095Ssam{
346171095Ssam	xge_hal_uld_cbs_t       uld_callbacks;
347171095Ssam	xge_hal_driver_config_t driver_config;
348171095Ssam	xge_hal_status_e        status = XGE_HAL_OK;
349171095Ssam
350171095Ssam	/* Initialize HAL driver */
351171095Ssam	if(!hal_driver_init_count) {
352171095Ssam	    xge_os_memzero(&uld_callbacks, sizeof(xge_hal_uld_cbs_t));
353173139Srwatson	    xge_os_memzero(&driver_config, sizeof(xge_hal_driver_config_t));
354171095Ssam
355171095Ssam	    /*
356171095Ssam	     * Initial and maximum size of the queue used to store the events
357171095Ssam	     * like Link up/down (xge_hal_event_e)
358171095Ssam	     */
359173139Srwatson	    driver_config.queue_size_initial = XGE_HAL_MIN_QUEUE_SIZE_INITIAL;
360173139Srwatson	    driver_config.queue_size_max     = XGE_HAL_MAX_QUEUE_SIZE_MAX;
361171095Ssam
362173139Srwatson	    uld_callbacks.link_up   = xge_callback_link_up;
363173139Srwatson	    uld_callbacks.link_down = xge_callback_link_down;
364173139Srwatson	    uld_callbacks.crit_err  = xge_callback_crit_err;
365173139Srwatson	    uld_callbacks.event     = xge_callback_event;
366171095Ssam
367171095Ssam	    status = xge_hal_driver_initialize(&driver_config, &uld_callbacks);
368171095Ssam	    if(status != XGE_HAL_OK) {
369173139Srwatson	        XGE_EXIT_ON_ERR("xgeX: Initialization of HAL driver failed",
370173139Srwatson	            xdi_out, status);
371171095Ssam	    }
372171095Ssam	}
373171095Ssam	hal_driver_init_count = hal_driver_init_count + 1;
374171095Ssam
375171095Ssam	xge_hal_driver_debug_module_mask_set(0xffffffff);
376171095Ssam	xge_hal_driver_debug_level_set(XGE_TRACE);
377171095Ssam
378171095Ssamxdi_out:
379171095Ssam	return status;
380171095Ssam}
381171095Ssam
382173139Srwatson/**
383173139Srwatson * xge_media_init
384173139Srwatson * Initializes, adds and sets media
385173139Srwatson *
386173139Srwatson * @devc Device Handle
387173139Srwatson */
388171095Ssamvoid
389171095Ssamxge_media_init(device_t devc)
390171095Ssam{
391173139Srwatson	xge_lldev_t *lldev = (xge_lldev_t *)device_get_softc(devc);
392171095Ssam
393171095Ssam	/* Initialize Media */
394173139Srwatson	ifmedia_init(&lldev->media, IFM_IMASK, xge_ifmedia_change,
395171095Ssam	    xge_ifmedia_status);
396171095Ssam
397171095Ssam	/* Add supported media */
398173139Srwatson	ifmedia_add(&lldev->media, IFM_ETHER | IFM_1000_SX | IFM_FDX, 0, NULL);
399173139Srwatson	ifmedia_add(&lldev->media, IFM_ETHER | IFM_1000_SX, 0, NULL);
400173139Srwatson	ifmedia_add(&lldev->media, IFM_ETHER | IFM_AUTO,    0, NULL);
401173139Srwatson	ifmedia_add(&lldev->media, IFM_ETHER | IFM_10G_SR,  0, NULL);
402173139Srwatson	ifmedia_add(&lldev->media, IFM_ETHER | IFM_10G_LR,  0, NULL);
403171095Ssam
404171095Ssam	/* Set media */
405173139Srwatson	ifmedia_set(&lldev->media, IFM_ETHER | IFM_AUTO);
406171095Ssam}
407171095Ssam
408173139Srwatson/**
409171095Ssam * xge_pci_space_save
410171095Ssam * Save PCI configuration space
411173139Srwatson *
412173139Srwatson * @dev Device Handle
413171095Ssam */
414171095Ssamvoid
415171095Ssamxge_pci_space_save(device_t dev)
416171095Ssam{
417171095Ssam	struct pci_devinfo *dinfo = NULL;
418171095Ssam
419171095Ssam	dinfo = device_get_ivars(dev);
420171095Ssam	xge_trace(XGE_TRACE, "Saving PCI configuration space");
421171095Ssam	pci_cfg_save(dev, dinfo, 0);
422171095Ssam}
423171095Ssam
424173139Srwatson/**
425171095Ssam * xge_pci_space_restore
426171095Ssam * Restore saved PCI configuration space
427173139Srwatson *
428173139Srwatson * @dev Device Handle
429171095Ssam */
430171095Ssamvoid
431171095Ssamxge_pci_space_restore(device_t dev)
432171095Ssam{
433171095Ssam	struct pci_devinfo *dinfo = NULL;
434171095Ssam
435171095Ssam	dinfo = device_get_ivars(dev);
436171095Ssam	xge_trace(XGE_TRACE, "Restoring PCI configuration space");
437171095Ssam	pci_cfg_restore(dev, dinfo);
438173139Srwatson}
439171095Ssam
440173139Srwatson/**
441173139Srwatson * xge_msi_info_save
442173139Srwatson * Save MSI info
443173139Srwatson *
444173139Srwatson * @lldev Per-adapter Data
445173139Srwatson */
446173139Srwatsonvoid
447173139Srwatsonxge_msi_info_save(xge_lldev_t * lldev)
448173139Srwatson{
449173139Srwatson	xge_os_pci_read16(lldev->pdev, NULL,
450173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_control),
451173139Srwatson	    &lldev->msi_info.msi_control);
452173139Srwatson	xge_os_pci_read32(lldev->pdev, NULL,
453173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_lower_address),
454173139Srwatson	    &lldev->msi_info.msi_lower_address);
455173139Srwatson	xge_os_pci_read32(lldev->pdev, NULL,
456173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_higher_address),
457173139Srwatson	    &lldev->msi_info.msi_higher_address);
458173139Srwatson	xge_os_pci_read16(lldev->pdev, NULL,
459173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_data),
460173139Srwatson	    &lldev->msi_info.msi_data);
461171095Ssam}
462171095Ssam
463173139Srwatson/**
464173139Srwatson * xge_msi_info_restore
465173139Srwatson * Restore saved MSI info
466173139Srwatson *
467173139Srwatson * @dev Device Handle
468173139Srwatson */
469173139Srwatsonvoid
470173139Srwatsonxge_msi_info_restore(xge_lldev_t *lldev)
471173139Srwatson{
472173139Srwatson	/*
473173139Srwatson	 * If interface is made down and up, traffic fails. It was observed that
474173139Srwatson	 * MSI information were getting reset on down. Restoring them.
475173139Srwatson	 */
476173139Srwatson	xge_os_pci_write16(lldev->pdev, NULL,
477173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_control),
478173139Srwatson	    lldev->msi_info.msi_control);
479173139Srwatson
480173139Srwatson	xge_os_pci_write32(lldev->pdev, NULL,
481173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_lower_address),
482173139Srwatson	    lldev->msi_info.msi_lower_address);
483173139Srwatson
484173139Srwatson	xge_os_pci_write32(lldev->pdev, NULL,
485173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_higher_address),
486173139Srwatson	    lldev->msi_info.msi_higher_address);
487173139Srwatson
488173139Srwatson	xge_os_pci_write16(lldev->pdev, NULL,
489173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_data),
490173139Srwatson	    lldev->msi_info.msi_data);
491173139Srwatson}
492173139Srwatson
493173139Srwatson/**
494173139Srwatson * xge_init_mutex
495173139Srwatson * Initializes mutexes used in driver
496173139Srwatson *
497173139Srwatson * @lldev  Per-adapter Data
498173139Srwatson */
499173139Srwatsonvoid
500173139Srwatsonxge_mutex_init(xge_lldev_t *lldev)
501173139Srwatson{
502173139Srwatson	int qindex;
503173139Srwatson
504173139Srwatson	sprintf(lldev->mtx_name_drv, "%s_drv",
505173139Srwatson	    device_get_nameunit(lldev->device));
506173139Srwatson	mtx_init(&lldev->mtx_drv, lldev->mtx_name_drv, MTX_NETWORK_LOCK,
507173139Srwatson	    MTX_DEF);
508173139Srwatson
509173139Srwatson	for(qindex = 0; qindex < XGE_FIFO_COUNT; qindex++) {
510173139Srwatson	    sprintf(lldev->mtx_name_tx[qindex], "%s_tx_%d",
511173139Srwatson	        device_get_nameunit(lldev->device), qindex);
512173139Srwatson	    mtx_init(&lldev->mtx_tx[qindex], lldev->mtx_name_tx[qindex], NULL,
513173139Srwatson	        MTX_DEF);
514173139Srwatson	}
515173139Srwatson}
516173139Srwatson
517173139Srwatson/**
518173139Srwatson * xge_mutex_destroy
519173139Srwatson * Destroys mutexes used in driver
520173139Srwatson *
521173139Srwatson * @lldev Per-adapter Data
522173139Srwatson */
523173139Srwatsonvoid
524173139Srwatsonxge_mutex_destroy(xge_lldev_t *lldev)
525173139Srwatson{
526173139Srwatson	int qindex;
527173139Srwatson
528173139Srwatson	for(qindex = 0; qindex < XGE_FIFO_COUNT; qindex++)
529173139Srwatson	    mtx_destroy(&lldev->mtx_tx[qindex]);
530173139Srwatson	mtx_destroy(&lldev->mtx_drv);
531173139Srwatson}
532173139Srwatson
533173139Srwatson/**
534173139Srwatson * xge_print_info
535173139Srwatson * Print device and driver information
536173139Srwatson *
537173139Srwatson * @lldev Per-adapter Data
538173139Srwatson */
539173139Srwatsonvoid
540173139Srwatsonxge_print_info(xge_lldev_t *lldev)
541173139Srwatson{
542173139Srwatson	device_t dev = lldev->device;
543173139Srwatson	xge_hal_device_t *hldev = lldev->devh;
544173139Srwatson	xge_hal_status_e status = XGE_HAL_OK;
545173139Srwatson	u64 val64 = 0;
546173139Srwatson	const char *xge_pci_bus_speeds[17] = {
547173139Srwatson	    "PCI 33MHz Bus",
548173139Srwatson	    "PCI 66MHz Bus",
549173139Srwatson	    "PCIX(M1) 66MHz Bus",
550173139Srwatson	    "PCIX(M1) 100MHz Bus",
551173139Srwatson	    "PCIX(M1) 133MHz Bus",
552173139Srwatson	    "PCIX(M2) 133MHz Bus",
553173139Srwatson	    "PCIX(M2) 200MHz Bus",
554173139Srwatson	    "PCIX(M2) 266MHz Bus",
555173139Srwatson	    "PCIX(M1) Reserved",
556173139Srwatson	    "PCIX(M1) 66MHz Bus (Not Supported)",
557173139Srwatson	    "PCIX(M1) 100MHz Bus (Not Supported)",
558173139Srwatson	    "PCIX(M1) 133MHz Bus (Not Supported)",
559173139Srwatson	    "PCIX(M2) Reserved",
560173139Srwatson	    "PCIX 533 Reserved",
561173139Srwatson	    "PCI Basic Mode",
562173139Srwatson	    "PCIX Basic Mode",
563173139Srwatson	    "PCI Invalid Mode"
564173139Srwatson	};
565173139Srwatson
566173139Srwatson	xge_os_printf("%s: Xframe%s %s Revision %d Driver v%s",
567173139Srwatson	    device_get_nameunit(dev),
568173139Srwatson	    ((hldev->device_id == XGE_PCI_DEVICE_ID_XENA_2) ? "I" : "II"),
569173139Srwatson	    hldev->vpd_data.product_name, hldev->revision, XGE_DRIVER_VERSION);
570173139Srwatson	xge_os_printf("%s: Serial Number %s",
571173139Srwatson	    device_get_nameunit(dev), hldev->vpd_data.serial_num);
572173139Srwatson
573173139Srwatson	if(pci_get_device(dev) == XGE_PCI_DEVICE_ID_HERC_2) {
574173139Srwatson	    status = xge_hal_mgmt_reg_read(hldev, 0,
575173139Srwatson	        xge_offsetof(xge_hal_pci_bar0_t, pci_info), &val64);
576173139Srwatson	    if(status != XGE_HAL_OK)
577173139Srwatson	        xge_trace(XGE_ERR, "Error for getting bus speed");
578173139Srwatson
579173139Srwatson	    xge_os_printf("%s: Adapter is on %s bit %s",
580173139Srwatson	        device_get_nameunit(dev), ((val64 & BIT(8)) ? "32":"64"),
581173139Srwatson	        (xge_pci_bus_speeds[((val64 & XGE_HAL_PCI_INFO) >> 60)]));
582173139Srwatson	}
583173139Srwatson
584173139Srwatson	xge_os_printf("%s: Using %s Interrupts",
585173139Srwatson	    device_get_nameunit(dev),
586173139Srwatson	    (lldev->enabled_msi == XGE_HAL_INTR_MODE_MSI) ? "MSI":"Line");
587173139Srwatson}
588173139Srwatson
589173139Srwatson/**
590173139Srwatson * xge_create_dma_tags
591173139Srwatson * Creates DMA tags for both Tx and Rx
592173139Srwatson *
593173139Srwatson * @dev Device Handle
594173139Srwatson *
595173139Srwatson * Returns XGE_HAL_OK or XGE_HAL_FAIL (if errors)
596173139Srwatson */
597173139Srwatsonxge_hal_status_e
598173139Srwatsonxge_create_dma_tags(device_t dev)
599173139Srwatson{
600173139Srwatson	xge_lldev_t *lldev = (xge_lldev_t *)device_get_softc(dev);
601173139Srwatson	xge_hal_status_e status = XGE_HAL_FAIL;
602173139Srwatson	int mtu = (lldev->ifnetp)->if_mtu, maxsize;
603173139Srwatson
604173139Srwatson	/* DMA tag for Tx */
605173139Srwatson	status = bus_dma_tag_create(
606173139Srwatson	    bus_get_dma_tag(dev),                /* Parent                    */
607173139Srwatson	    PAGE_SIZE,                           /* Alignment                 */
608173139Srwatson	    0,                                   /* Bounds                    */
609173139Srwatson	    BUS_SPACE_MAXADDR,                   /* Low Address               */
610173139Srwatson	    BUS_SPACE_MAXADDR,                   /* High Address              */
611173139Srwatson	    NULL,                                /* Filter Function           */
612173139Srwatson	    NULL,                                /* Filter Function Arguments */
613173139Srwatson	    MCLBYTES * XGE_MAX_SEGS,             /* Maximum Size              */
614173139Srwatson	    XGE_MAX_SEGS,                        /* Number of Segments        */
615173139Srwatson	    MCLBYTES,                            /* Maximum Segment Size      */
616173139Srwatson	    BUS_DMA_ALLOCNOW,                    /* Flags                     */
617173139Srwatson	    NULL,                                /* Lock Function             */
618173139Srwatson	    NULL,                                /* Lock Function Arguments   */
619173139Srwatson	    (&lldev->dma_tag_tx));               /* DMA Tag                   */
620173139Srwatson	if(status != 0)
621173139Srwatson	    goto _exit;
622173139Srwatson
623173139Srwatson	maxsize = mtu + XGE_HAL_MAC_HEADER_MAX_SIZE;
624173139Srwatson	if(maxsize <= MCLBYTES) {
625173139Srwatson	    maxsize = MCLBYTES;
626173139Srwatson	}
627173139Srwatson	else {
628173139Srwatson	    if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_5)
629173139Srwatson	        maxsize = MJUMPAGESIZE;
630173139Srwatson	    else
631173139Srwatson	        maxsize = (maxsize <= MJUMPAGESIZE) ? MJUMPAGESIZE : MJUM9BYTES;
632173139Srwatson	}
633173139Srwatson
634173139Srwatson	/* DMA tag for Rx */
635173139Srwatson	status = bus_dma_tag_create(
636173139Srwatson	    bus_get_dma_tag(dev),                /* Parent                    */
637173139Srwatson	    PAGE_SIZE,                           /* Alignment                 */
638173139Srwatson	    0,                                   /* Bounds                    */
639173139Srwatson	    BUS_SPACE_MAXADDR,                   /* Low Address               */
640173139Srwatson	    BUS_SPACE_MAXADDR,                   /* High Address              */
641173139Srwatson	    NULL,                                /* Filter Function           */
642173139Srwatson	    NULL,                                /* Filter Function Arguments */
643173139Srwatson	    maxsize,                             /* Maximum Size              */
644173139Srwatson	    1,                                   /* Number of Segments        */
645173139Srwatson	    maxsize,                             /* Maximum Segment Size      */
646173139Srwatson	    BUS_DMA_ALLOCNOW,                    /* Flags                     */
647173139Srwatson	    NULL,                                /* Lock Function             */
648173139Srwatson	    NULL,                                /* Lock Function Arguments   */
649173139Srwatson	    (&lldev->dma_tag_rx));               /* DMA Tag                   */
650173139Srwatson	if(status != 0)
651173139Srwatson	    goto _exit1;
652173139Srwatson
653173139Srwatson	status = bus_dmamap_create(lldev->dma_tag_rx, BUS_DMA_NOWAIT,
654173139Srwatson	    &lldev->extra_dma_map);
655173139Srwatson	if(status != 0)
656173139Srwatson	    goto _exit2;
657173139Srwatson
658173139Srwatson	status = XGE_HAL_OK;
659173139Srwatson	goto _exit;
660173139Srwatson
661173139Srwatson_exit2:
662173139Srwatson	status = bus_dma_tag_destroy(lldev->dma_tag_rx);
663173139Srwatson	if(status != 0)
664173139Srwatson	    xge_trace(XGE_ERR, "Rx DMA tag destroy failed");
665173139Srwatson_exit1:
666173139Srwatson	status = bus_dma_tag_destroy(lldev->dma_tag_tx);
667173139Srwatson	if(status != 0)
668173139Srwatson	    xge_trace(XGE_ERR, "Tx DMA tag destroy failed");
669173139Srwatson	status = XGE_HAL_FAIL;
670173139Srwatson_exit:
671173139Srwatson	return status;
672173139Srwatson}
673173139Srwatson
674173139Srwatson/**
675173139Srwatson * xge_confirm_changes
676173139Srwatson * Disables and Enables interface to apply requested change
677173139Srwatson *
678173139Srwatson * @lldev Per-adapter Data
679173139Srwatson * @mtu_set Is it called for changing MTU? (Yes: 1, No: 0)
680173139Srwatson *
681173139Srwatson * Returns 0 or Error Number
682173139Srwatson */
683173139Srwatsonvoid
684173139Srwatsonxge_confirm_changes(xge_lldev_t *lldev, xge_option_e option)
685173139Srwatson{
686173139Srwatson	if(lldev->initialized == 0) goto _exit1;
687173139Srwatson
688173139Srwatson	mtx_lock(&lldev->mtx_drv);
689173139Srwatson	if_down(lldev->ifnetp);
690173139Srwatson	xge_device_stop(lldev, XGE_HAL_CHANNEL_OC_NORMAL);
691173139Srwatson
692173139Srwatson	if(option == XGE_SET_MTU)
693173139Srwatson	    (lldev->ifnetp)->if_mtu = lldev->mtu;
694173139Srwatson	else
695173139Srwatson	    xge_buffer_mode_init(lldev, lldev->mtu);
696173139Srwatson
697173139Srwatson	xge_device_init(lldev, XGE_HAL_CHANNEL_OC_NORMAL);
698173139Srwatson	if_up(lldev->ifnetp);
699173139Srwatson	mtx_unlock(&lldev->mtx_drv);
700173139Srwatson	goto _exit;
701173139Srwatson
702173139Srwatson_exit1:
703173139Srwatson	/* Request was to change MTU and device not initialized */
704173139Srwatson	if(option == XGE_SET_MTU) {
705173139Srwatson	    (lldev->ifnetp)->if_mtu = lldev->mtu;
706173139Srwatson	    xge_buffer_mode_init(lldev, lldev->mtu);
707173139Srwatson	}
708173139Srwatson_exit:
709173139Srwatson	return;
710173139Srwatson}
711173139Srwatson
712173139Srwatson/**
713173139Srwatson * xge_change_lro_status
714173139Srwatson * Enable/Disable LRO feature
715173139Srwatson *
716173139Srwatson * @SYSCTL_HANDLER_ARGS sysctl_oid structure with arguments
717173139Srwatson *
718173139Srwatson * Returns 0 or error number.
719173139Srwatson */
720173139Srwatsonstatic int
721173139Srwatsonxge_change_lro_status(SYSCTL_HANDLER_ARGS)
722173139Srwatson{
723173139Srwatson	xge_lldev_t *lldev = (xge_lldev_t *)arg1;
724173139Srwatson	int request = lldev->enabled_lro, status = XGE_HAL_OK;
725173139Srwatson
726173139Srwatson	status = sysctl_handle_int(oidp, &request, arg2, req);
727173139Srwatson	if((status != XGE_HAL_OK) || (!req->newptr))
728173139Srwatson	    goto _exit;
729173139Srwatson
730173139Srwatson	if((request < 0) || (request > 1)) {
731173139Srwatson	    status = EINVAL;
732173139Srwatson	    goto _exit;
733173139Srwatson	}
734173139Srwatson
735173139Srwatson	/* Return if current and requested states are same */
736173139Srwatson	if(request == lldev->enabled_lro){
737173139Srwatson	    xge_trace(XGE_ERR, "LRO is already %s",
738173139Srwatson	        ((request) ? "enabled" : "disabled"));
739173139Srwatson	    goto _exit;
740173139Srwatson	}
741173139Srwatson
742173139Srwatson	lldev->enabled_lro = request;
743173139Srwatson	xge_confirm_changes(lldev, XGE_CHANGE_LRO);
744173139Srwatson	arg2 = lldev->enabled_lro;
745173139Srwatson
746173139Srwatson_exit:
747173139Srwatson	return status;
748173139Srwatson}
749173139Srwatson
750173139Srwatson/**
751173139Srwatson * xge_add_sysctl_handlers
752173139Srwatson * Registers sysctl parameter value update handlers
753173139Srwatson *
754173139Srwatson * @lldev Per-adapter data
755173139Srwatson */
756173139Srwatsonvoid
757173139Srwatsonxge_add_sysctl_handlers(xge_lldev_t *lldev)
758173139Srwatson{
759173139Srwatson	struct sysctl_ctx_list *context_list =
760173139Srwatson	    device_get_sysctl_ctx(lldev->device);
761173139Srwatson	struct sysctl_oid *oid = device_get_sysctl_tree(lldev->device);
762173139Srwatson
763173139Srwatson	SYSCTL_ADD_PROC(context_list, SYSCTL_CHILDREN(oid), OID_AUTO,
764173139Srwatson	    "enable_lro", CTLTYPE_INT | CTLFLAG_RW, lldev, 0,
765173139Srwatson	    xge_change_lro_status, "I", "Enable or disable LRO feature");
766173139Srwatson}
767173139Srwatson
768173139Srwatson/**
769171095Ssam * xge_attach
770173139Srwatson * Connects driver to the system if probe was success
771173139Srwatson *
772173139Srwatson * @dev Device Handle
773173139Srwatson */
774171095Ssamint
775171095Ssamxge_attach(device_t dev)
776171095Ssam{
777171095Ssam	xge_hal_device_config_t *device_config;
778171095Ssam	xge_hal_device_attr_t   attr;
779173139Srwatson	xge_lldev_t             *lldev;
780171095Ssam	xge_hal_device_t        *hldev;
781173139Srwatson	xge_pci_info_t          *pci_info;
782171095Ssam	struct ifnet            *ifnetp;
783173139Srwatson	int                     rid, rid0, rid1, error;
784173139Srwatson	int                     msi_count = 0, status = XGE_HAL_OK;
785173139Srwatson	int                     enable_msi = XGE_HAL_INTR_MODE_IRQLINE;
786171095Ssam
787173139Srwatson	device_config = xge_os_malloc(NULL, sizeof(xge_hal_device_config_t));
788171095Ssam	if(!device_config) {
789173139Srwatson	    XGE_EXIT_ON_ERR("Memory allocation for device configuration failed",
790173139Srwatson	        attach_out_config, ENOMEM);
791171095Ssam	}
792171095Ssam
793173139Srwatson	lldev = (xge_lldev_t *) device_get_softc(dev);
794171095Ssam	if(!lldev) {
795173139Srwatson	    XGE_EXIT_ON_ERR("Adapter softc is NULL", attach_out, ENOMEM);
796171095Ssam	}
797171095Ssam	lldev->device = dev;
798171095Ssam
799173139Srwatson	xge_mutex_init(lldev);
800171095Ssam
801171095Ssam	error = xge_driver_initialize();
802171095Ssam	if(error != XGE_HAL_OK) {
803173139Srwatson	    xge_resources_free(dev, xge_free_mutex);
804173139Srwatson	    XGE_EXIT_ON_ERR("Initializing driver failed", attach_out, ENXIO);
805171095Ssam	}
806171095Ssam
807171095Ssam	/* HAL device */
808173139Srwatson	hldev =
809173139Srwatson	    (xge_hal_device_t *)xge_os_malloc(NULL, sizeof(xge_hal_device_t));
810171095Ssam	if(!hldev) {
811173139Srwatson	    xge_resources_free(dev, xge_free_terminate_hal_driver);
812173139Srwatson	    XGE_EXIT_ON_ERR("Memory allocation for HAL device failed",
813173139Srwatson	        attach_out, ENOMEM);
814171095Ssam	}
815171095Ssam	lldev->devh = hldev;
816171095Ssam
817171095Ssam	/* Our private structure */
818173139Srwatson	pci_info =
819173139Srwatson	    (xge_pci_info_t*) xge_os_malloc(NULL, sizeof(xge_pci_info_t));
820171095Ssam	if(!pci_info) {
821173139Srwatson	    xge_resources_free(dev, xge_free_hal_device);
822173139Srwatson	    XGE_EXIT_ON_ERR("Memory allocation for PCI info. failed",
823173139Srwatson	        attach_out, ENOMEM);
824171095Ssam	}
825171095Ssam	lldev->pdev      = pci_info;
826171095Ssam	pci_info->device = dev;
827171095Ssam
828171095Ssam	/* Set bus master */
829171095Ssam	pci_enable_busmaster(dev);
830171095Ssam
831171095Ssam	/* Get virtual address for BAR0 */
832171095Ssam	rid0 = PCIR_BAR(0);
833171095Ssam	pci_info->regmap0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid0,
834171095Ssam	    RF_ACTIVE);
835171095Ssam	if(pci_info->regmap0 == NULL) {
836173139Srwatson	    xge_resources_free(dev, xge_free_pci_info);
837173139Srwatson	    XGE_EXIT_ON_ERR("Bus resource allocation for BAR0 failed",
838173139Srwatson	        attach_out, ENOMEM);
839171095Ssam	}
840171095Ssam	attr.bar0 = (char *)pci_info->regmap0;
841171095Ssam
842173139Srwatson	pci_info->bar0resource = (xge_bus_resource_t*)
843173139Srwatson	    xge_os_malloc(NULL, sizeof(xge_bus_resource_t));
844171095Ssam	if(pci_info->bar0resource == NULL) {
845173139Srwatson	    xge_resources_free(dev, xge_free_bar0);
846173139Srwatson	    XGE_EXIT_ON_ERR("Memory allocation for BAR0 Resources failed",
847173139Srwatson	        attach_out, ENOMEM);
848171095Ssam	}
849173139Srwatson	((xge_bus_resource_t *)(pci_info->bar0resource))->bus_tag =
850171095Ssam	    rman_get_bustag(pci_info->regmap0);
851173139Srwatson	((xge_bus_resource_t *)(pci_info->bar0resource))->bus_handle =
852171095Ssam	    rman_get_bushandle(pci_info->regmap0);
853173139Srwatson	((xge_bus_resource_t *)(pci_info->bar0resource))->bar_start_addr =
854171095Ssam	    pci_info->regmap0;
855171095Ssam
856171095Ssam	/* Get virtual address for BAR1 */
857171095Ssam	rid1 = PCIR_BAR(2);
858171095Ssam	pci_info->regmap1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid1,
859171095Ssam	    RF_ACTIVE);
860171095Ssam	if(pci_info->regmap1 == NULL) {
861173139Srwatson	    xge_resources_free(dev, xge_free_bar0_resource);
862173139Srwatson	    XGE_EXIT_ON_ERR("Bus resource allocation for BAR1 failed",
863173139Srwatson	        attach_out, ENOMEM);
864171095Ssam	}
865171095Ssam	attr.bar1 = (char *)pci_info->regmap1;
866171095Ssam
867173139Srwatson	pci_info->bar1resource = (xge_bus_resource_t*)
868173139Srwatson	    xge_os_malloc(NULL, sizeof(xge_bus_resource_t));
869171095Ssam	if(pci_info->bar1resource == NULL) {
870173139Srwatson	    xge_resources_free(dev, xge_free_bar1);
871173139Srwatson	    XGE_EXIT_ON_ERR("Memory allocation for BAR1 Resources failed",
872173139Srwatson	        attach_out, ENOMEM);
873171095Ssam	}
874173139Srwatson	((xge_bus_resource_t *)(pci_info->bar1resource))->bus_tag =
875171095Ssam	    rman_get_bustag(pci_info->regmap1);
876173139Srwatson	((xge_bus_resource_t *)(pci_info->bar1resource))->bus_handle =
877171095Ssam	    rman_get_bushandle(pci_info->regmap1);
878173139Srwatson	((xge_bus_resource_t *)(pci_info->bar1resource))->bar_start_addr =
879171095Ssam	    pci_info->regmap1;
880171095Ssam
881171095Ssam	/* Save PCI config space */
882171095Ssam	xge_pci_space_save(dev);
883171095Ssam
884173139Srwatson	attr.regh0 = (xge_bus_resource_t *) pci_info->bar0resource;
885173139Srwatson	attr.regh1 = (xge_bus_resource_t *) pci_info->bar1resource;
886171095Ssam	attr.irqh  = lldev->irqhandle;
887171095Ssam	attr.cfgh  = pci_info;
888171095Ssam	attr.pdev  = pci_info;
889171095Ssam
890171095Ssam	/* Initialize device configuration parameters */
891171095Ssam	xge_init_params(device_config, dev);
892171095Ssam
893173139Srwatson	rid = 0;
894173139Srwatson	if(lldev->enabled_msi) {
895173139Srwatson	    /* Number of MSI messages supported by device */
896173139Srwatson	    msi_count = pci_msi_count(dev);
897173139Srwatson	    if(msi_count > 1) {
898173139Srwatson	        /* Device supports MSI */
899173139Srwatson	        if(bootverbose) {
900173139Srwatson	            xge_trace(XGE_ERR, "MSI count: %d", msi_count);
901173139Srwatson	            xge_trace(XGE_ERR, "Now, driver supporting 1 message");
902173139Srwatson	        }
903173139Srwatson	        msi_count = 1;
904173139Srwatson	        error = pci_alloc_msi(dev, &msi_count);
905173139Srwatson	        if(error == 0) {
906173139Srwatson	            if(bootverbose)
907173139Srwatson	                xge_trace(XGE_ERR, "Allocated messages: %d", msi_count);
908173139Srwatson	            enable_msi = XGE_HAL_INTR_MODE_MSI;
909173139Srwatson	            rid = 1;
910173139Srwatson	        }
911173139Srwatson	        else {
912173139Srwatson	            if(bootverbose)
913173139Srwatson	                xge_trace(XGE_ERR, "pci_alloc_msi failed, %d", error);
914173139Srwatson	        }
915171095Ssam	    }
916171095Ssam	}
917173139Srwatson	lldev->enabled_msi = enable_msi;
918171095Ssam
919173139Srwatson	/* Allocate resource for irq */
920173139Srwatson	lldev->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
921173139Srwatson	    (RF_SHAREABLE | RF_ACTIVE));
922173139Srwatson	if(lldev->irq == NULL) {
923173139Srwatson	    xge_trace(XGE_ERR, "Allocating irq resource for %s failed",
924173139Srwatson	        ((rid == 0) ? "line interrupt" : "MSI"));
925173139Srwatson	    if(rid == 1) {
926173139Srwatson	        error = pci_release_msi(dev);
927173139Srwatson	        if(error != 0) {
928173139Srwatson	            xge_trace(XGE_ERR, "Releasing MSI resources failed %d",
929173139Srwatson	                error);
930173139Srwatson	            xge_trace(XGE_ERR, "Requires reboot to use MSI again");
931173139Srwatson	        }
932173139Srwatson	        xge_trace(XGE_ERR, "Trying line interrupts");
933173139Srwatson	        rid = 0;
934173139Srwatson	        lldev->enabled_msi = XGE_HAL_INTR_MODE_IRQLINE;
935173139Srwatson	        lldev->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
936173139Srwatson	            (RF_SHAREABLE | RF_ACTIVE));
937171095Ssam	    }
938173139Srwatson	    if(lldev->irq == NULL) {
939173139Srwatson	        xge_trace(XGE_ERR, "Allocating irq resource failed");
940173139Srwatson	        xge_resources_free(dev, xge_free_bar1_resource);
941173139Srwatson	        status = ENOMEM;
942171095Ssam	        goto attach_out;
943171095Ssam	    }
944173139Srwatson	}
945171095Ssam
946173139Srwatson	device_config->intr_mode = lldev->enabled_msi;
947173139Srwatson	if(bootverbose) {
948173139Srwatson	    xge_trace(XGE_TRACE, "rid: %d, Mode: %d, MSI count: %d", rid,
949173139Srwatson	        lldev->enabled_msi, msi_count);
950173139Srwatson	}
951171095Ssam
952173139Srwatson	/* Initialize HAL device */
953173139Srwatson	error = xge_hal_device_initialize(hldev, &attr, device_config);
954173139Srwatson	if(error != XGE_HAL_OK) {
955173139Srwatson	    xge_resources_free(dev, xge_free_irq_resource);
956173139Srwatson	    XGE_EXIT_ON_ERR("Initializing HAL device failed", attach_out,
957173139Srwatson	        ENXIO);
958171095Ssam	}
959171095Ssam
960171095Ssam	xge_hal_device_private_set(hldev, lldev);
961171095Ssam
962171095Ssam	error = xge_interface_setup(dev);
963171095Ssam	if(error != 0) {
964173139Srwatson	    status = error;
965171095Ssam	    goto attach_out;
966171095Ssam	}
967171095Ssam
968171095Ssam	ifnetp         = lldev->ifnetp;
969171095Ssam	ifnetp->if_mtu = device_config->mtu;
970171095Ssam
971171095Ssam	xge_media_init(dev);
972171095Ssam
973171095Ssam	/* Associate interrupt handler with the device */
974173139Srwatson	if(lldev->enabled_msi == XGE_HAL_INTR_MODE_MSI) {
975173139Srwatson	    error = bus_setup_intr(dev, lldev->irq,
976173139Srwatson	        (INTR_TYPE_NET | INTR_MPSAFE),
977171095Ssam#if __FreeBSD_version > 700030
978173139Srwatson	        NULL,
979171095Ssam#endif
980173139Srwatson	        xge_isr_msi, lldev, &lldev->irqhandle);
981173139Srwatson	    xge_msi_info_save(lldev);
982171095Ssam	}
983173139Srwatson	else {
984173139Srwatson	    error = bus_setup_intr(dev, lldev->irq,
985173139Srwatson	        (INTR_TYPE_NET | INTR_MPSAFE),
986173139Srwatson#if __FreeBSD_version > 700030
987173139Srwatson	        xge_isr_filter,
988173139Srwatson#endif
989173139Srwatson	        xge_isr_line, lldev, &lldev->irqhandle);
990171095Ssam	}
991171095Ssam	if(error != 0) {
992173139Srwatson	    xge_resources_free(dev, xge_free_media_interface);
993173139Srwatson	    XGE_EXIT_ON_ERR("Associating interrupt handler with device failed",
994173139Srwatson	        attach_out, ENXIO);
995171095Ssam	}
996171095Ssam
997173139Srwatson	xge_print_info(lldev);
998171095Ssam
999173139Srwatson	xge_add_sysctl_handlers(lldev);
1000171095Ssam
1001173139Srwatson	xge_buffer_mode_init(lldev, device_config->mtu);
1002171095Ssam
1003171095Ssamattach_out:
1004173139Srwatson	xge_os_free(NULL, device_config, sizeof(xge_hal_device_config_t));
1005171095Ssamattach_out_config:
1006173139Srwatson	return status;
1007171095Ssam}
1008171095Ssam
1009173139Srwatson/**
1010173139Srwatson * xge_resources_free
1011173139Srwatson * Undo what-all we did during load/attach
1012173139Srwatson *
1013173139Srwatson * @dev Device Handle
1014173139Srwatson * @error Identifies what-all to undo
1015173139Srwatson */
1016171095Ssamvoid
1017173139Srwatsonxge_resources_free(device_t dev, xge_lables_e error)
1018171095Ssam{
1019173139Srwatson	xge_lldev_t *lldev;
1020173139Srwatson	xge_pci_info_t *pci_info;
1021171095Ssam	xge_hal_device_t *hldev;
1022171095Ssam	int rid, status;
1023171095Ssam
1024171095Ssam	/* LL Device */
1025173139Srwatson	lldev = (xge_lldev_t *) device_get_softc(dev);
1026171095Ssam	pci_info = lldev->pdev;
1027171095Ssam
1028171095Ssam	/* HAL Device */
1029171095Ssam	hldev = lldev->devh;
1030171095Ssam
1031171095Ssam	switch(error) {
1032173139Srwatson	    case xge_free_all:
1033171095Ssam	        /* Teardown interrupt handler - device association */
1034171095Ssam	        bus_teardown_intr(dev, lldev->irq, lldev->irqhandle);
1035171095Ssam
1036173139Srwatson	    case xge_free_media_interface:
1037171095Ssam	        /* Media */
1038173139Srwatson	        ifmedia_removeall(&lldev->media);
1039171095Ssam
1040171095Ssam	        /* Detach Ether */
1041171095Ssam	        ether_ifdetach(lldev->ifnetp);
1042171095Ssam	        if_free(lldev->ifnetp);
1043171095Ssam
1044171095Ssam	        xge_hal_device_private_set(hldev, NULL);
1045171095Ssam	        xge_hal_device_disable(hldev);
1046171095Ssam
1047173139Srwatson	    case xge_free_terminate_hal_device:
1048171095Ssam	        /* HAL Device */
1049171095Ssam	        xge_hal_device_terminate(hldev);
1050171095Ssam
1051173139Srwatson	    case xge_free_irq_resource:
1052173139Srwatson	        /* Release IRQ resource */
1053173139Srwatson	        bus_release_resource(dev, SYS_RES_IRQ,
1054173139Srwatson	            ((lldev->enabled_msi == XGE_HAL_INTR_MODE_IRQLINE) ? 0:1),
1055173139Srwatson	            lldev->irq);
1056173139Srwatson
1057173139Srwatson	        if(lldev->enabled_msi == XGE_HAL_INTR_MODE_MSI) {
1058173139Srwatson	            status = pci_release_msi(dev);
1059173139Srwatson	            if(status != 0) {
1060173139Srwatson	                if(bootverbose) {
1061173139Srwatson	                    xge_trace(XGE_ERR,
1062173139Srwatson	                        "pci_release_msi returned %d", status);
1063173139Srwatson	                }
1064173139Srwatson	            }
1065173139Srwatson	        }
1066173139Srwatson
1067173139Srwatson	    case xge_free_bar1_resource:
1068171095Ssam	        /* Restore PCI configuration space */
1069171095Ssam	        xge_pci_space_restore(dev);
1070171095Ssam
1071171095Ssam	        /* Free bar1resource */
1072173139Srwatson	        xge_os_free(NULL, pci_info->bar1resource,
1073173139Srwatson	            sizeof(xge_bus_resource_t));
1074171095Ssam
1075173139Srwatson	    case xge_free_bar1:
1076171095Ssam	        /* Release BAR1 */
1077171095Ssam	        rid = PCIR_BAR(2);
1078171095Ssam	        bus_release_resource(dev, SYS_RES_MEMORY, rid,
1079171095Ssam	            pci_info->regmap1);
1080171095Ssam
1081173139Srwatson	    case xge_free_bar0_resource:
1082171095Ssam	        /* Free bar0resource */
1083173139Srwatson	        xge_os_free(NULL, pci_info->bar0resource,
1084173139Srwatson	            sizeof(xge_bus_resource_t));
1085171095Ssam
1086173139Srwatson	    case xge_free_bar0:
1087171095Ssam	        /* Release BAR0 */
1088171095Ssam	        rid = PCIR_BAR(0);
1089171095Ssam	        bus_release_resource(dev, SYS_RES_MEMORY, rid,
1090171095Ssam	            pci_info->regmap0);
1091171095Ssam
1092173139Srwatson	    case xge_free_pci_info:
1093171095Ssam	        /* Disable Bus Master */
1094171095Ssam	        pci_disable_busmaster(dev);
1095171095Ssam
1096171095Ssam	        /* Free pci_info_t */
1097171095Ssam	        lldev->pdev = NULL;
1098173139Srwatson	        xge_os_free(NULL, pci_info, sizeof(xge_pci_info_t));
1099171095Ssam
1100173139Srwatson	    case xge_free_hal_device:
1101171095Ssam	        /* Free device configuration struct and HAL device */
1102173139Srwatson	        xge_os_free(NULL, hldev, sizeof(xge_hal_device_t));
1103171095Ssam
1104173139Srwatson	    case xge_free_terminate_hal_driver:
1105171095Ssam	        /* Terminate HAL driver */
1106171095Ssam	        hal_driver_init_count = hal_driver_init_count - 1;
1107171095Ssam	        if(!hal_driver_init_count) {
1108171095Ssam	            xge_hal_driver_terminate();
1109171095Ssam	        }
1110171095Ssam
1111173139Srwatson	    case xge_free_mutex:
1112173139Srwatson	        xge_mutex_destroy(lldev);
1113171095Ssam	}
1114171095Ssam}
1115171095Ssam
1116173139Srwatson/**
1117171095Ssam * xge_detach
1118173139Srwatson * Detaches driver from the Kernel subsystem
1119173139Srwatson *
1120173139Srwatson * @dev Device Handle
1121173139Srwatson */
1122171095Ssamint
1123171095Ssamxge_detach(device_t dev)
1124171095Ssam{
1125173139Srwatson	xge_lldev_t *lldev = (xge_lldev_t *)device_get_softc(dev);
1126171095Ssam
1127173139Srwatson	if(lldev->in_detach == 0) {
1128173139Srwatson	    lldev->in_detach = 1;
1129173139Srwatson	    xge_stop(lldev);
1130173139Srwatson	    xge_resources_free(dev, xge_free_all);
1131173139Srwatson	}
1132171095Ssam
1133171095Ssam	return 0;
1134171095Ssam}
1135171095Ssam
1136173139Srwatson/**
1137171095Ssam * xge_shutdown
1138173139Srwatson * To shutdown device before system shutdown
1139173139Srwatson *
1140173139Srwatson * @dev Device Handle
1141173139Srwatson */
1142171095Ssamint
1143171095Ssamxge_shutdown(device_t dev)
1144171095Ssam{
1145173139Srwatson	xge_lldev_t *lldev = (xge_lldev_t *) device_get_softc(dev);
1146173139Srwatson	xge_stop(lldev);
1147171095Ssam
1148171095Ssam	return 0;
1149171095Ssam}
1150171095Ssam
1151173139Srwatson/**
1152173139Srwatson * xge_interface_setup
1153173139Srwatson * Setup interface
1154173139Srwatson *
1155173139Srwatson * @dev Device Handle
1156173139Srwatson *
1157173139Srwatson * Returns 0 on success, ENXIO/ENOMEM on failure
1158173139Srwatson */
1159171095Ssamint
1160171095Ssamxge_interface_setup(device_t dev)
1161171095Ssam{
1162171095Ssam	u8 mcaddr[ETHER_ADDR_LEN];
1163173139Srwatson	xge_hal_status_e status;
1164173139Srwatson	xge_lldev_t *lldev = (xge_lldev_t *)device_get_softc(dev);
1165171095Ssam	struct ifnet *ifnetp;
1166171095Ssam	xge_hal_device_t *hldev = lldev->devh;
1167171095Ssam
1168171095Ssam	/* Get the MAC address of the device */
1169173139Srwatson	status = xge_hal_device_macaddr_get(hldev, 0, &mcaddr);
1170173139Srwatson	if(status != XGE_HAL_OK) {
1171173139Srwatson	    xge_resources_free(dev, xge_free_terminate_hal_device);
1172173139Srwatson	    XGE_EXIT_ON_ERR("Getting MAC address failed", ifsetup_out, ENXIO);
1173171095Ssam	}
1174171095Ssam
1175171095Ssam	/* Get interface ifnet structure for this Ether device */
1176171095Ssam	ifnetp = lldev->ifnetp = if_alloc(IFT_ETHER);
1177171095Ssam	if(ifnetp == NULL) {
1178173139Srwatson	    xge_resources_free(dev, xge_free_terminate_hal_device);
1179173139Srwatson	    XGE_EXIT_ON_ERR("Allocation ifnet failed", ifsetup_out, ENOMEM);
1180171095Ssam	}
1181171095Ssam
1182171095Ssam	/* Initialize interface ifnet structure */
1183171095Ssam	if_initname(ifnetp, device_get_name(dev), device_get_unit(dev));
1184173139Srwatson	ifnetp->if_mtu      = XGE_HAL_DEFAULT_MTU;
1185173139Srwatson	ifnetp->if_baudrate = XGE_BAUDRATE;
1186171095Ssam	ifnetp->if_init     = xge_init;
1187171095Ssam	ifnetp->if_softc    = lldev;
1188171095Ssam	ifnetp->if_flags    = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1189171095Ssam	ifnetp->if_ioctl    = xge_ioctl;
1190171095Ssam	ifnetp->if_start    = xge_send;
1191171095Ssam
1192171095Ssam	/* TODO: Check and assign optimal value */
1193207554Ssobomax	ifnetp->if_snd.ifq_maxlen = ifqmaxlen;
1194171095Ssam
1195173139Srwatson	ifnetp->if_capabilities = IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU |
1196171095Ssam	    IFCAP_HWCSUM;
1197173139Srwatson	if(lldev->enabled_tso)
1198173139Srwatson	    ifnetp->if_capabilities |= IFCAP_TSO4;
1199173139Srwatson	if(lldev->enabled_lro)
1200173139Srwatson	    ifnetp->if_capabilities |= IFCAP_LRO;
1201171095Ssam
1202171095Ssam	ifnetp->if_capenable = ifnetp->if_capabilities;
1203171095Ssam
1204171095Ssam	/* Attach the interface */
1205171095Ssam	ether_ifattach(ifnetp, mcaddr);
1206171095Ssam
1207171095Ssamifsetup_out:
1208173139Srwatson	return status;
1209171095Ssam}
1210171095Ssam
1211173139Srwatson/**
1212173139Srwatson * xge_callback_link_up
1213173139Srwatson * Callback for Link-up indication from HAL
1214173139Srwatson *
1215173139Srwatson * @userdata Per-adapter data
1216173139Srwatson */
1217171095Ssamvoid
1218173139Srwatsonxge_callback_link_up(void *userdata)
1219171095Ssam{
1220173139Srwatson	xge_lldev_t  *lldev  = (xge_lldev_t *)userdata;
1221171095Ssam	struct ifnet *ifnetp = lldev->ifnetp;
1222171095Ssam
1223171095Ssam	ifnetp->if_flags  &= ~IFF_DRV_OACTIVE;
1224171095Ssam	if_link_state_change(ifnetp, LINK_STATE_UP);
1225171095Ssam}
1226171095Ssam
1227173139Srwatson/**
1228173139Srwatson * xge_callback_link_down
1229173139Srwatson * Callback for Link-down indication from HAL
1230173139Srwatson *
1231173139Srwatson * @userdata Per-adapter data
1232173139Srwatson */
1233171095Ssamvoid
1234173139Srwatsonxge_callback_link_down(void *userdata)
1235171095Ssam{
1236173139Srwatson	xge_lldev_t  *lldev  = (xge_lldev_t *)userdata;
1237171095Ssam	struct ifnet *ifnetp = lldev->ifnetp;
1238171095Ssam
1239171095Ssam	ifnetp->if_flags  |= IFF_DRV_OACTIVE;
1240171095Ssam	if_link_state_change(ifnetp, LINK_STATE_DOWN);
1241171095Ssam}
1242171095Ssam
1243173139Srwatson/**
1244173139Srwatson * xge_callback_crit_err
1245173139Srwatson * Callback for Critical error indication from HAL
1246173139Srwatson *
1247173139Srwatson * @userdata Per-adapter data
1248173139Srwatson * @type Event type (Enumerated hardware error)
1249173139Srwatson * @serr_data Hardware status
1250173139Srwatson */
1251171095Ssamvoid
1252173139Srwatsonxge_callback_crit_err(void *userdata, xge_hal_event_e type, u64 serr_data)
1253171095Ssam{
1254171095Ssam	xge_trace(XGE_ERR, "Critical Error");
1255173139Srwatson	xge_reset(userdata);
1256171095Ssam}
1257171095Ssam
1258173139Srwatson/**
1259173139Srwatson * xge_callback_event
1260173139Srwatson * Callback from HAL indicating that some event has been queued
1261173139Srwatson *
1262173139Srwatson * @item Queued event item
1263173139Srwatson */
1264171095Ssamvoid
1265173139Srwatsonxge_callback_event(xge_queue_item_t *item)
1266171095Ssam{
1267173139Srwatson	xge_lldev_t      *lldev  = NULL;
1268171095Ssam	xge_hal_device_t *hldev  = NULL;
1269171095Ssam	struct ifnet     *ifnetp = NULL;
1270171095Ssam
1271171095Ssam	hldev  = item->context;
1272171095Ssam	lldev  = xge_hal_device_private(hldev);
1273171095Ssam	ifnetp = lldev->ifnetp;
1274171095Ssam
1275234506Sdim	switch((int)item->event_type) {
1276173139Srwatson	    case XGE_LL_EVENT_TRY_XMIT_AGAIN:
1277173139Srwatson	        if(lldev->initialized) {
1278173139Srwatson	            if(xge_hal_channel_dtr_count(lldev->fifo_channel[0]) > 0) {
1279173139Srwatson	                ifnetp->if_flags  &= ~IFF_DRV_OACTIVE;
1280173139Srwatson	            }
1281173139Srwatson	            else {
1282173139Srwatson	                xge_queue_produce_context(
1283173139Srwatson	                    xge_hal_device_queue(lldev->devh),
1284173139Srwatson	                    XGE_LL_EVENT_TRY_XMIT_AGAIN, lldev->devh);
1285173139Srwatson	            }
1286171095Ssam	        }
1287173139Srwatson	        break;
1288173139Srwatson
1289173139Srwatson	    case XGE_LL_EVENT_DEVICE_RESETTING:
1290173139Srwatson	        xge_reset(item->context);
1291173139Srwatson	        break;
1292173139Srwatson
1293173139Srwatson	    default:
1294173139Srwatson	        break;
1295171095Ssam	}
1296171095Ssam}
1297171095Ssam
1298173139Srwatson/**
1299173139Srwatson * xge_ifmedia_change
1300173139Srwatson * Media change driver callback
1301173139Srwatson *
1302173139Srwatson * @ifnetp Interface Handle
1303173139Srwatson *
1304173139Srwatson * Returns 0 if media is Ether else EINVAL
1305173139Srwatson */
1306171095Ssamint
1307171095Ssamxge_ifmedia_change(struct ifnet *ifnetp)
1308171095Ssam{
1309173139Srwatson	xge_lldev_t    *lldev    = ifnetp->if_softc;
1310173139Srwatson	struct ifmedia *ifmediap = &lldev->media;
1311171095Ssam
1312171095Ssam	return (IFM_TYPE(ifmediap->ifm_media) != IFM_ETHER) ?  EINVAL:0;
1313171095Ssam}
1314171095Ssam
1315173139Srwatson/**
1316173139Srwatson * xge_ifmedia_status
1317173139Srwatson * Media status driver callback
1318173139Srwatson *
1319173139Srwatson * @ifnetp Interface Handle
1320173139Srwatson * @ifmr Interface Media Settings
1321173139Srwatson */
1322171095Ssamvoid
1323171095Ssamxge_ifmedia_status(struct ifnet *ifnetp, struct ifmediareq *ifmr)
1324171095Ssam{
1325171095Ssam	xge_hal_status_e status;
1326171095Ssam	u64              regvalue;
1327173139Srwatson	xge_lldev_t      *lldev = ifnetp->if_softc;
1328171095Ssam	xge_hal_device_t *hldev = lldev->devh;
1329171095Ssam
1330171095Ssam	ifmr->ifm_status = IFM_AVALID;
1331171095Ssam	ifmr->ifm_active = IFM_ETHER;
1332171095Ssam
1333171095Ssam	status = xge_hal_mgmt_reg_read(hldev, 0,
1334171095Ssam	    xge_offsetof(xge_hal_pci_bar0_t, adapter_status), &regvalue);
1335171095Ssam	if(status != XGE_HAL_OK) {
1336173139Srwatson	    xge_trace(XGE_TRACE, "Getting adapter status failed");
1337173139Srwatson	    goto _exit;
1338171095Ssam	}
1339171095Ssam
1340171095Ssam	if((regvalue & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
1341171095Ssam	    XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)) == 0) {
1342171095Ssam	    ifmr->ifm_status |= IFM_ACTIVE;
1343171095Ssam	    ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
1344171095Ssam	    if_link_state_change(ifnetp, LINK_STATE_UP);
1345171095Ssam	}
1346171095Ssam	else {
1347171095Ssam	    if_link_state_change(ifnetp, LINK_STATE_DOWN);
1348171095Ssam	}
1349173139Srwatson_exit:
1350173139Srwatson	return;
1351173139Srwatson}
1352171095Ssam
1353173139Srwatson/**
1354173139Srwatson * xge_ioctl_stats
1355173139Srwatson * IOCTL to get statistics
1356173139Srwatson *
1357173139Srwatson * @lldev Per-adapter data
1358173139Srwatson * @ifreqp Interface request
1359173139Srwatson */
1360173139Srwatsonint
1361173139Srwatsonxge_ioctl_stats(xge_lldev_t *lldev, struct ifreq *ifreqp)
1362173139Srwatson{
1363173139Srwatson	xge_hal_status_e status = XGE_HAL_OK;
1364332280Sbrooks	char cmd, mode;
1365173139Srwatson	void *info = NULL;
1366332280Sbrooks	int retValue;
1367173139Srwatson
1368332280Sbrooks	cmd = retValue = fubyte(ifreqp->ifr_data);
1369332280Sbrooks	if (retValue == -1)
1370332280Sbrooks		return (EFAULT);
1371332280Sbrooks
1372332280Sbrooks	retValue = EINVAL;
1373332280Sbrooks	switch(cmd) {
1374173139Srwatson	    case XGE_QUERY_STATS:
1375173139Srwatson	        mtx_lock(&lldev->mtx_drv);
1376173139Srwatson	        status = xge_hal_stats_hw(lldev->devh,
1377173139Srwatson	            (xge_hal_stats_hw_info_t **)&info);
1378173139Srwatson	        mtx_unlock(&lldev->mtx_drv);
1379173139Srwatson	        if(status == XGE_HAL_OK) {
1380173139Srwatson	            if(copyout(info, ifreqp->ifr_data,
1381173139Srwatson	                sizeof(xge_hal_stats_hw_info_t)) == 0)
1382173139Srwatson	                retValue = 0;
1383173139Srwatson	        }
1384173139Srwatson	        else {
1385173139Srwatson	            xge_trace(XGE_ERR, "Getting statistics failed (Status: %d)",
1386173139Srwatson	                status);
1387173139Srwatson	        }
1388173139Srwatson	        break;
1389173139Srwatson
1390173139Srwatson	    case XGE_QUERY_PCICONF:
1391173139Srwatson	        info = xge_os_malloc(NULL, sizeof(xge_hal_pci_config_t));
1392173139Srwatson	        if(info != NULL) {
1393173139Srwatson	            mtx_lock(&lldev->mtx_drv);
1394173139Srwatson	            status = xge_hal_mgmt_pci_config(lldev->devh, info,
1395173139Srwatson	                sizeof(xge_hal_pci_config_t));
1396173139Srwatson	            mtx_unlock(&lldev->mtx_drv);
1397173139Srwatson	            if(status == XGE_HAL_OK) {
1398173139Srwatson	                if(copyout(info, ifreqp->ifr_data,
1399173139Srwatson	                    sizeof(xge_hal_pci_config_t)) == 0)
1400173139Srwatson	                    retValue = 0;
1401173139Srwatson	            }
1402173139Srwatson	            else {
1403173139Srwatson	                xge_trace(XGE_ERR,
1404173139Srwatson	                    "Getting PCI configuration failed (%d)", status);
1405173139Srwatson	            }
1406173139Srwatson	            xge_os_free(NULL, info, sizeof(xge_hal_pci_config_t));
1407173139Srwatson	        }
1408173139Srwatson	        break;
1409173139Srwatson
1410173139Srwatson	    case XGE_QUERY_DEVSTATS:
1411173139Srwatson	        info = xge_os_malloc(NULL, sizeof(xge_hal_stats_device_info_t));
1412173139Srwatson	        if(info != NULL) {
1413173139Srwatson	            mtx_lock(&lldev->mtx_drv);
1414173139Srwatson	            status =xge_hal_mgmt_device_stats(lldev->devh, info,
1415173139Srwatson	                sizeof(xge_hal_stats_device_info_t));
1416173139Srwatson	            mtx_unlock(&lldev->mtx_drv);
1417173139Srwatson	            if(status == XGE_HAL_OK) {
1418173139Srwatson	                if(copyout(info, ifreqp->ifr_data,
1419173139Srwatson	                    sizeof(xge_hal_stats_device_info_t)) == 0)
1420173139Srwatson	                    retValue = 0;
1421173139Srwatson	            }
1422173139Srwatson	            else {
1423173139Srwatson	                xge_trace(XGE_ERR, "Getting device info failed (%d)",
1424173139Srwatson	                    status);
1425173139Srwatson	            }
1426173139Srwatson	            xge_os_free(NULL, info,
1427173139Srwatson	                sizeof(xge_hal_stats_device_info_t));
1428173139Srwatson	        }
1429173139Srwatson	        break;
1430173139Srwatson
1431173139Srwatson	    case XGE_QUERY_SWSTATS:
1432173139Srwatson	        info = xge_os_malloc(NULL, sizeof(xge_hal_stats_sw_err_t));
1433173139Srwatson	        if(info != NULL) {
1434173139Srwatson	            mtx_lock(&lldev->mtx_drv);
1435173139Srwatson	            status =xge_hal_mgmt_sw_stats(lldev->devh, info,
1436173139Srwatson	                sizeof(xge_hal_stats_sw_err_t));
1437173139Srwatson	            mtx_unlock(&lldev->mtx_drv);
1438173139Srwatson	            if(status == XGE_HAL_OK) {
1439173139Srwatson	                if(copyout(info, ifreqp->ifr_data,
1440173139Srwatson	                    sizeof(xge_hal_stats_sw_err_t)) == 0)
1441173139Srwatson	                    retValue = 0;
1442173139Srwatson	            }
1443173139Srwatson	            else {
1444173139Srwatson	                xge_trace(XGE_ERR,
1445173139Srwatson	                    "Getting tcode statistics failed (%d)", status);
1446173139Srwatson	            }
1447173139Srwatson	            xge_os_free(NULL, info, sizeof(xge_hal_stats_sw_err_t));
1448173139Srwatson	        }
1449173139Srwatson	        break;
1450173139Srwatson
1451173139Srwatson	    case XGE_QUERY_DRIVERSTATS:
1452173139Srwatson		if(copyout(&lldev->driver_stats, ifreqp->ifr_data,
1453173139Srwatson	            sizeof(xge_driver_stats_t)) == 0) {
1454173139Srwatson	            retValue = 0;
1455173139Srwatson	        }
1456173139Srwatson	        else {
1457173139Srwatson	            xge_trace(XGE_ERR,
1458173139Srwatson	                "Copyout of driver statistics failed (%d)", status);
1459173139Srwatson	        }
1460173139Srwatson	        break;
1461173139Srwatson
1462173139Srwatson	    case XGE_READ_VERSION:
1463173139Srwatson	        info = xge_os_malloc(NULL, XGE_BUFFER_SIZE);
1464173139Srwatson	        if(version != NULL) {
1465173139Srwatson	            strcpy(info, XGE_DRIVER_VERSION);
1466173139Srwatson	            if(copyout(info, ifreqp->ifr_data, XGE_BUFFER_SIZE) == 0)
1467173139Srwatson	                retValue = 0;
1468173139Srwatson	            xge_os_free(NULL, info, XGE_BUFFER_SIZE);
1469173139Srwatson	        }
1470173139Srwatson	        break;
1471173139Srwatson
1472173139Srwatson	    case XGE_QUERY_DEVCONF:
1473173139Srwatson	        info = xge_os_malloc(NULL, sizeof(xge_hal_device_config_t));
1474173139Srwatson	        if(info != NULL) {
1475173139Srwatson	            mtx_lock(&lldev->mtx_drv);
1476173139Srwatson	            status = xge_hal_mgmt_device_config(lldev->devh, info,
1477173139Srwatson	                sizeof(xge_hal_device_config_t));
1478173139Srwatson	            mtx_unlock(&lldev->mtx_drv);
1479173139Srwatson	            if(status == XGE_HAL_OK) {
1480173139Srwatson	                if(copyout(info, ifreqp->ifr_data,
1481173139Srwatson	                    sizeof(xge_hal_device_config_t)) == 0)
1482173139Srwatson	                    retValue = 0;
1483173139Srwatson	            }
1484173139Srwatson	            else {
1485173139Srwatson	                xge_trace(XGE_ERR, "Getting devconfig failed (%d)",
1486173139Srwatson	                    status);
1487173139Srwatson	            }
1488173139Srwatson	            xge_os_free(NULL, info, sizeof(xge_hal_device_config_t));
1489173139Srwatson	        }
1490173139Srwatson	        break;
1491173139Srwatson
1492173139Srwatson	    case XGE_QUERY_BUFFER_MODE:
1493173139Srwatson	        if(copyout(&lldev->buffer_mode, ifreqp->ifr_data,
1494173139Srwatson	            sizeof(int)) == 0)
1495173139Srwatson	            retValue = 0;
1496173139Srwatson	        break;
1497173139Srwatson
1498173139Srwatson	    case XGE_SET_BUFFER_MODE_1:
1499173139Srwatson	    case XGE_SET_BUFFER_MODE_2:
1500173139Srwatson	    case XGE_SET_BUFFER_MODE_5:
1501332280Sbrooks	        mode = (cmd == XGE_SET_BUFFER_MODE_1) ? 'Y':'N';
1502332280Sbrooks	        if(copyout(&mode, ifreqp->ifr_data, sizeof(mode)) == 0)
1503173139Srwatson	            retValue = 0;
1504173139Srwatson	        break;
1505173139Srwatson	    default:
1506173139Srwatson	        xge_trace(XGE_TRACE, "Nothing is matching");
1507173139Srwatson	        retValue = ENOTTY;
1508173139Srwatson	        break;
1509173139Srwatson	}
1510173139Srwatson	return retValue;
1511171095Ssam}
1512171095Ssam
1513173139Srwatson/**
1514173139Srwatson * xge_ioctl_registers
1515173139Srwatson * IOCTL to get registers
1516173139Srwatson *
1517173139Srwatson * @lldev Per-adapter data
1518173139Srwatson * @ifreqp Interface request
1519173139Srwatson */
1520171095Ssamint
1521173139Srwatsonxge_ioctl_registers(xge_lldev_t *lldev, struct ifreq *ifreqp)
1522173139Srwatson{
1523332280Sbrooks	xge_register_t tmpdata;
1524332280Sbrooks	xge_register_t *data;
1525173139Srwatson	xge_hal_status_e status = XGE_HAL_OK;
1526173139Srwatson	int retValue = EINVAL, offset = 0, index = 0;
1527332280Sbrooks	int error;
1528173139Srwatson	u64 val64 = 0;
1529173139Srwatson
1530332280Sbrooks	error = copyin(ifreqp->ifr_data, &tmpdata, sizeof(tmpdata));
1531332280Sbrooks	if (error != 0)
1532332280Sbrooks		return (error);
1533332280Sbrooks	data = &tmpdata;
1534332280Sbrooks
1535173139Srwatson	/* Reading a register */
1536173139Srwatson	if(strcmp(data->option, "-r") == 0) {
1537173139Srwatson	    data->value = 0x0000;
1538173139Srwatson	    mtx_lock(&lldev->mtx_drv);
1539173139Srwatson	    status = xge_hal_mgmt_reg_read(lldev->devh, 0, data->offset,
1540173139Srwatson	        &data->value);
1541173139Srwatson	    mtx_unlock(&lldev->mtx_drv);
1542173139Srwatson	    if(status == XGE_HAL_OK) {
1543173139Srwatson	        if(copyout(data, ifreqp->ifr_data, sizeof(xge_register_t)) == 0)
1544173139Srwatson	            retValue = 0;
1545173139Srwatson	    }
1546173139Srwatson	}
1547173139Srwatson	/* Writing to a register */
1548173139Srwatson	else if(strcmp(data->option, "-w") == 0) {
1549173139Srwatson	    mtx_lock(&lldev->mtx_drv);
1550173139Srwatson	    status = xge_hal_mgmt_reg_write(lldev->devh, 0, data->offset,
1551173139Srwatson	        data->value);
1552173139Srwatson	    if(status == XGE_HAL_OK) {
1553173139Srwatson	        val64 = 0x0000;
1554173139Srwatson	        status = xge_hal_mgmt_reg_read(lldev->devh, 0, data->offset,
1555173139Srwatson	            &val64);
1556173139Srwatson	        if(status != XGE_HAL_OK) {
1557173139Srwatson	            xge_trace(XGE_ERR, "Reading back updated register failed");
1558173139Srwatson	        }
1559173139Srwatson	        else {
1560173139Srwatson	            if(val64 != data->value) {
1561173139Srwatson	                xge_trace(XGE_ERR,
1562173139Srwatson	                    "Read and written register values mismatched");
1563173139Srwatson	            }
1564173139Srwatson	            else retValue = 0;
1565173139Srwatson	        }
1566173139Srwatson	    }
1567173139Srwatson	    else {
1568173139Srwatson	        xge_trace(XGE_ERR, "Getting register value failed");
1569173139Srwatson	    }
1570173139Srwatson	    mtx_unlock(&lldev->mtx_drv);
1571173139Srwatson	}
1572173139Srwatson	else {
1573173139Srwatson	    mtx_lock(&lldev->mtx_drv);
1574173139Srwatson	    for(index = 0, offset = 0; offset <= XGE_OFFSET_OF_LAST_REG;
1575173139Srwatson	        index++, offset += 0x0008) {
1576173139Srwatson	        val64 = 0;
1577173139Srwatson	        status = xge_hal_mgmt_reg_read(lldev->devh, 0, offset, &val64);
1578173139Srwatson	        if(status != XGE_HAL_OK) {
1579173139Srwatson	            xge_trace(XGE_ERR, "Getting register value failed");
1580173139Srwatson	            break;
1581173139Srwatson	        }
1582173139Srwatson	        *((u64 *)((u64 *)data + index)) = val64;
1583173139Srwatson	        retValue = 0;
1584173139Srwatson	    }
1585173139Srwatson	    mtx_unlock(&lldev->mtx_drv);
1586173139Srwatson
1587173139Srwatson	    if(retValue == 0) {
1588173139Srwatson	        if(copyout(data, ifreqp->ifr_data,
1589173139Srwatson	            sizeof(xge_hal_pci_bar0_t)) != 0) {
1590173139Srwatson	            xge_trace(XGE_ERR, "Copyout of register values failed");
1591173139Srwatson	            retValue = EINVAL;
1592173139Srwatson	        }
1593173139Srwatson	    }
1594173139Srwatson	    else {
1595173139Srwatson	        xge_trace(XGE_ERR, "Getting register values failed");
1596173139Srwatson	    }
1597173139Srwatson	}
1598173139Srwatson	return retValue;
1599173139Srwatson}
1600173139Srwatson
1601173139Srwatson/**
1602173139Srwatson * xge_ioctl
1603173139Srwatson * Callback to control the device - Interface configuration
1604173139Srwatson *
1605173139Srwatson * @ifnetp Interface Handle
1606173139Srwatson * @command Device control command
1607173139Srwatson * @data Parameters associated with command (if any)
1608173139Srwatson */
1609173139Srwatsonint
1610171095Ssamxge_ioctl(struct ifnet *ifnetp, unsigned long command, caddr_t data)
1611171095Ssam{
1612173139Srwatson	struct ifreq   *ifreqp   = (struct ifreq *)data;
1613173139Srwatson	xge_lldev_t    *lldev    = ifnetp->if_softc;
1614173139Srwatson	struct ifmedia *ifmediap = &lldev->media;
1615173139Srwatson	int             retValue = 0, mask = 0;
1616171095Ssam
1617171095Ssam	if(lldev->in_detach) {
1618171095Ssam	    return retValue;
1619171095Ssam	}
1620171095Ssam
1621171095Ssam	switch(command) {
1622171095Ssam	    /* Set/Get ifnet address */
1623171095Ssam	    case SIOCSIFADDR:
1624171095Ssam	    case SIOCGIFADDR:
1625171095Ssam	        ether_ioctl(ifnetp, command, data);
1626171095Ssam	        break;
1627171095Ssam
1628171095Ssam	    /* Set ifnet MTU */
1629171095Ssam	    case SIOCSIFMTU:
1630173139Srwatson	        retValue = xge_change_mtu(lldev, ifreqp->ifr_mtu);
1631171095Ssam	        break;
1632171095Ssam
1633171095Ssam	    /* Set ifnet flags */
1634171095Ssam	    case SIOCSIFFLAGS:
1635171095Ssam	        if(ifnetp->if_flags & IFF_UP) {
1636171095Ssam	            /* Link status is UP */
1637171095Ssam	            if(!(ifnetp->if_drv_flags & IFF_DRV_RUNNING)) {
1638173139Srwatson	                xge_init(lldev);
1639171095Ssam	            }
1640171095Ssam	            xge_disable_promisc(lldev);
1641171095Ssam	            xge_enable_promisc(lldev);
1642171095Ssam	        }
1643171095Ssam	        else {
1644171095Ssam	            /* Link status is DOWN */
1645171095Ssam	            /* If device is in running, make it down */
1646171095Ssam	            if(ifnetp->if_drv_flags & IFF_DRV_RUNNING) {
1647171095Ssam	                xge_stop(lldev);
1648171095Ssam	            }
1649171095Ssam	        }
1650171095Ssam	        break;
1651171095Ssam
1652171095Ssam	    /* Add/delete multicast address */
1653171095Ssam	    case SIOCADDMULTI:
1654171095Ssam	    case SIOCDELMULTI:
1655171095Ssam	        if(ifnetp->if_drv_flags & IFF_DRV_RUNNING) {
1656171095Ssam	            xge_setmulti(lldev);
1657171095Ssam	        }
1658171095Ssam	        break;
1659171095Ssam
1660171095Ssam	    /* Set/Get net media */
1661171095Ssam	    case SIOCSIFMEDIA:
1662171095Ssam	    case SIOCGIFMEDIA:
1663171095Ssam	        retValue = ifmedia_ioctl(ifnetp, ifreqp, ifmediap, command);
1664171095Ssam	        break;
1665171095Ssam
1666171095Ssam	    /* Set capabilities */
1667171095Ssam	    case SIOCSIFCAP:
1668173139Srwatson	        mtx_lock(&lldev->mtx_drv);
1669171095Ssam	        mask = ifreqp->ifr_reqcap ^ ifnetp->if_capenable;
1670173139Srwatson	        if(mask & IFCAP_TXCSUM) {
1671173139Srwatson	            if(ifnetp->if_capenable & IFCAP_TXCSUM) {
1672173139Srwatson	                ifnetp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TXCSUM);
1673173139Srwatson	                ifnetp->if_hwassist &=
1674173139Srwatson	                    ~(CSUM_TCP | CSUM_UDP | CSUM_TSO);
1675173139Srwatson	            }
1676173139Srwatson	            else {
1677173139Srwatson	                ifnetp->if_capenable |= IFCAP_TXCSUM;
1678173139Srwatson	                ifnetp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
1679173139Srwatson	            }
1680173139Srwatson	        }
1681171095Ssam	        if(mask & IFCAP_TSO4) {
1682171095Ssam	            if(ifnetp->if_capenable & IFCAP_TSO4) {
1683171095Ssam	                ifnetp->if_capenable &= ~IFCAP_TSO4;
1684171095Ssam	                ifnetp->if_hwassist  &= ~CSUM_TSO;
1685173139Srwatson
1686173139Srwatson	                xge_os_printf("%s: TSO Disabled",
1687173139Srwatson	                    device_get_nameunit(lldev->device));
1688171095Ssam	            }
1689173139Srwatson	            else if(ifnetp->if_capenable & IFCAP_TXCSUM) {
1690171095Ssam	                ifnetp->if_capenable |= IFCAP_TSO4;
1691171095Ssam	                ifnetp->if_hwassist  |= CSUM_TSO;
1692173139Srwatson
1693173139Srwatson	                xge_os_printf("%s: TSO Enabled",
1694173139Srwatson	                    device_get_nameunit(lldev->device));
1695171095Ssam	            }
1696171095Ssam	        }
1697173139Srwatson
1698173139Srwatson	        mtx_unlock(&lldev->mtx_drv);
1699171095Ssam	        break;
1700171095Ssam
1701173139Srwatson	    /* Custom IOCTL 0 */
1702171095Ssam	    case SIOCGPRIVATE_0:
1703173139Srwatson	        retValue = xge_ioctl_stats(lldev, ifreqp);
1704171095Ssam	        break;
1705171095Ssam
1706173139Srwatson	    /* Custom IOCTL 1 */
1707171095Ssam	    case SIOCGPRIVATE_1:
1708173139Srwatson	        retValue = xge_ioctl_registers(lldev, ifreqp);
1709171095Ssam	        break;
1710171095Ssam
1711171095Ssam	    default:
1712171095Ssam	        retValue = EINVAL;
1713171095Ssam	        break;
1714171095Ssam	}
1715171095Ssam	return retValue;
1716171095Ssam}
1717171095Ssam
1718173139Srwatson/**
1719173139Srwatson * xge_init
1720173139Srwatson * Initialize the interface
1721173139Srwatson *
1722173139Srwatson * @plldev Per-adapter Data
1723173139Srwatson */
1724171095Ssamvoid
1725171095Ssamxge_init(void *plldev)
1726171095Ssam{
1727173139Srwatson	xge_lldev_t *lldev = (xge_lldev_t *)plldev;
1728171095Ssam
1729173139Srwatson	mtx_lock(&lldev->mtx_drv);
1730173139Srwatson	xge_os_memzero(&lldev->driver_stats, sizeof(xge_driver_stats_t));
1731173139Srwatson	xge_device_init(lldev, XGE_HAL_CHANNEL_OC_NORMAL);
1732173139Srwatson	mtx_unlock(&lldev->mtx_drv);
1733171095Ssam}
1734171095Ssam
1735173139Srwatson/**
1736173139Srwatson * xge_device_init
1737173139Srwatson * Initialize the interface (called by holding lock)
1738173139Srwatson *
1739173139Srwatson * @pdevin Per-adapter Data
1740173139Srwatson */
1741171095Ssamvoid
1742173139Srwatsonxge_device_init(xge_lldev_t *lldev, xge_hal_channel_reopen_e option)
1743171095Ssam{
1744173139Srwatson	struct ifnet     *ifnetp = lldev->ifnetp;
1745173139Srwatson	xge_hal_device_t *hldev  = lldev->devh;
1746173139Srwatson	struct ifaddr      *ifaddrp;
1747173139Srwatson	unsigned char      *macaddr;
1748173139Srwatson	struct sockaddr_dl *sockaddrp;
1749173139Srwatson	int                 status   = XGE_HAL_OK;
1750171095Ssam
1751173139Srwatson	mtx_assert((&lldev->mtx_drv), MA_OWNED);
1752171095Ssam
1753171095Ssam	/* If device is in running state, initializing is not required */
1754173139Srwatson	if(ifnetp->if_drv_flags & IFF_DRV_RUNNING)
1755171095Ssam	    return;
1756171095Ssam
1757171095Ssam	/* Initializing timer */
1758314667Savg	callout_init(&lldev->timer, 1);
1759171095Ssam
1760173139Srwatson	xge_trace(XGE_TRACE, "Set MTU size");
1761173139Srwatson	status = xge_hal_device_mtu_set(hldev, ifnetp->if_mtu);
1762173139Srwatson	if(status != XGE_HAL_OK) {
1763173139Srwatson	    xge_trace(XGE_ERR, "Setting MTU in HAL device failed");
1764173139Srwatson	    goto _exit;
1765173139Srwatson	}
1766171095Ssam
1767173139Srwatson	/* Enable HAL device */
1768173139Srwatson	xge_hal_device_enable(hldev);
1769173139Srwatson
1770173139Srwatson	/* Get MAC address and update in HAL */
1771173139Srwatson	ifaddrp             = ifnetp->if_addr;
1772173139Srwatson	sockaddrp           = (struct sockaddr_dl *)ifaddrp->ifa_addr;
1773173139Srwatson	sockaddrp->sdl_type = IFT_ETHER;
1774173139Srwatson	sockaddrp->sdl_alen = ifnetp->if_addrlen;
1775173139Srwatson	macaddr             = LLADDR(sockaddrp);
1776173139Srwatson	xge_trace(XGE_TRACE,
1777173139Srwatson	    "Setting MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
1778173139Srwatson	    *macaddr, *(macaddr + 1), *(macaddr + 2), *(macaddr + 3),
1779173139Srwatson	    *(macaddr + 4), *(macaddr + 5));
1780173139Srwatson	status = xge_hal_device_macaddr_set(hldev, 0, macaddr);
1781173139Srwatson	if(status != XGE_HAL_OK)
1782173139Srwatson	    xge_trace(XGE_ERR, "Setting MAC address failed (%d)", status);
1783173139Srwatson
1784173139Srwatson	/* Opening channels */
1785173139Srwatson	mtx_unlock(&lldev->mtx_drv);
1786173139Srwatson	status = xge_channel_open(lldev, option);
1787173139Srwatson	mtx_lock(&lldev->mtx_drv);
1788173139Srwatson	if(status != XGE_HAL_OK)
1789173139Srwatson	    goto _exit;
1790173139Srwatson
1791173139Srwatson	/* Set appropriate flags */
1792173139Srwatson	ifnetp->if_drv_flags  |=  IFF_DRV_RUNNING;
1793173139Srwatson	ifnetp->if_flags &= ~IFF_DRV_OACTIVE;
1794173139Srwatson
1795173139Srwatson	/* Checksum capability */
1796173139Srwatson	ifnetp->if_hwassist = (ifnetp->if_capenable & IFCAP_TXCSUM) ?
1797173139Srwatson	    (CSUM_TCP | CSUM_UDP) : 0;
1798173139Srwatson
1799173139Srwatson	if((lldev->enabled_tso) && (ifnetp->if_capenable & IFCAP_TSO4))
1800173139Srwatson	    ifnetp->if_hwassist |= CSUM_TSO;
1801173139Srwatson
1802173139Srwatson	/* Enable interrupts */
1803173139Srwatson	xge_hal_device_intr_enable(hldev);
1804173139Srwatson
1805173139Srwatson	callout_reset(&lldev->timer, 10*hz, xge_timer, lldev);
1806173139Srwatson
1807173139Srwatson	/* Disable promiscuous mode */
1808173139Srwatson	xge_trace(XGE_TRACE, "If opted, enable promiscuous mode");
1809173139Srwatson	xge_enable_promisc(lldev);
1810173139Srwatson
1811173139Srwatson	/* Device is initialized */
1812173139Srwatson	lldev->initialized = 1;
1813173139Srwatson	xge_os_mdelay(1000);
1814173139Srwatson
1815173139Srwatson_exit:
1816173139Srwatson	return;
1817171095Ssam}
1818171095Ssam
1819173139Srwatson/**
1820173139Srwatson * xge_timer
1821173139Srwatson * Timer timeout function to handle link status
1822173139Srwatson *
1823173139Srwatson * @devp Per-adapter Data
1824173139Srwatson */
1825171095Ssamvoid
1826171095Ssamxge_timer(void *devp)
1827171095Ssam{
1828173139Srwatson	xge_lldev_t      *lldev = (xge_lldev_t *)devp;
1829171095Ssam	xge_hal_device_t *hldev = lldev->devh;
1830171095Ssam
1831171095Ssam	/* Poll for changes */
1832171095Ssam	xge_hal_device_poll(hldev);
1833171095Ssam
1834171095Ssam	/* Reset timer */
1835171095Ssam	callout_reset(&lldev->timer, hz, xge_timer, lldev);
1836171095Ssam
1837171095Ssam	return;
1838171095Ssam}
1839171095Ssam
1840173139Srwatson/**
1841173139Srwatson * xge_stop
1842173139Srwatson * De-activate the interface
1843173139Srwatson *
1844173139Srwatson * @lldev Per-adater Data
1845173139Srwatson */
1846171095Ssamvoid
1847173139Srwatsonxge_stop(xge_lldev_t *lldev)
1848171095Ssam{
1849173139Srwatson	mtx_lock(&lldev->mtx_drv);
1850173139Srwatson	xge_device_stop(lldev, XGE_HAL_CHANNEL_OC_NORMAL);
1851173139Srwatson	mtx_unlock(&lldev->mtx_drv);
1852171095Ssam}
1853171095Ssam
1854173139Srwatson/**
1855173139Srwatson * xge_isr_filter
1856173139Srwatson * ISR filter function - to filter interrupts from other devices (shared)
1857173139Srwatson *
1858173139Srwatson * @handle Per-adapter Data
1859173139Srwatson *
1860173139Srwatson * Returns
1861173139Srwatson * FILTER_STRAY if interrupt is from other device
1862173139Srwatson * FILTER_SCHEDULE_THREAD if interrupt is from Xframe device
1863171095Ssam */
1864171095Ssamint
1865173139Srwatsonxge_isr_filter(void *handle)
1866171095Ssam{
1867173139Srwatson	xge_lldev_t *lldev       = (xge_lldev_t *)handle;
1868173139Srwatson	xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)((lldev->devh)->bar0);
1869171095Ssam	u16 retValue = FILTER_STRAY;
1870171095Ssam	u64 val64    = 0;
1871171095Ssam
1872173139Srwatson	XGE_DRV_STATS(isr_filter);
1873171095Ssam
1874173139Srwatson	val64 = xge_os_pio_mem_read64(lldev->pdev, (lldev->devh)->regh0,
1875171095Ssam	    &bar0->general_int_status);
1876171095Ssam	retValue = (!val64) ? FILTER_STRAY : FILTER_SCHEDULE_THREAD;
1877171095Ssam
1878171095Ssam	return retValue;
1879171095Ssam}
1880171095Ssam
1881173139Srwatson/**
1882173139Srwatson * xge_isr_line
1883173139Srwatson * Interrupt service routine for Line interrupts
1884173139Srwatson *
1885173139Srwatson * @plldev Per-adapter Data
1886173139Srwatson */
1887171095Ssamvoid
1888173139Srwatsonxge_isr_line(void *plldev)
1889171095Ssam{
1890171095Ssam	xge_hal_status_e status;
1891173139Srwatson	xge_lldev_t      *lldev   = (xge_lldev_t *)plldev;
1892171095Ssam	xge_hal_device_t *hldev   = (xge_hal_device_t *)lldev->devh;
1893171095Ssam	struct ifnet     *ifnetp  = lldev->ifnetp;
1894171095Ssam
1895173139Srwatson	XGE_DRV_STATS(isr_line);
1896173139Srwatson
1897171095Ssam	if(ifnetp->if_drv_flags & IFF_DRV_RUNNING) {
1898171095Ssam	    status = xge_hal_device_handle_irq(hldev);
1899173139Srwatson	    if(!(IFQ_DRV_IS_EMPTY(&ifnetp->if_snd)))
1900173139Srwatson	        xge_send(ifnetp);
1901171095Ssam	}
1902171095Ssam}
1903171095Ssam
1904173139Srwatson/*
1905173139Srwatson * xge_isr_msi
1906173139Srwatson * ISR for Message signaled interrupts
1907173139Srwatson */
1908173139Srwatsonvoid
1909173139Srwatsonxge_isr_msi(void *plldev)
1910173139Srwatson{
1911173139Srwatson	xge_lldev_t *lldev = (xge_lldev_t *)plldev;
1912173139Srwatson	XGE_DRV_STATS(isr_msi);
1913173139Srwatson	xge_hal_device_continue_irq(lldev->devh);
1914173139Srwatson}
1915173139Srwatson
1916173139Srwatson/**
1917173139Srwatson * xge_rx_open
1918173139Srwatson * Initiate and open all Rx channels
1919173139Srwatson *
1920173139Srwatson * @qid Ring Index
1921173139Srwatson * @lldev Per-adapter Data
1922173139Srwatson * @rflag Channel open/close/reopen flag
1923173139Srwatson *
1924173139Srwatson * Returns 0 or Error Number
1925173139Srwatson */
1926171095Ssamint
1927173139Srwatsonxge_rx_open(int qid, xge_lldev_t *lldev, xge_hal_channel_reopen_e rflag)
1928171095Ssam{
1929171095Ssam	u64 adapter_status = 0x0;
1930173139Srwatson	xge_hal_status_e status = XGE_HAL_FAIL;
1931171095Ssam
1932171095Ssam	xge_hal_channel_attr_t attr = {
1933171095Ssam	    .post_qid      = qid,
1934171095Ssam	    .compl_qid     = 0,
1935173139Srwatson	    .callback      = xge_rx_compl,
1936173139Srwatson	    .per_dtr_space = sizeof(xge_rx_priv_t),
1937171095Ssam	    .flags         = 0,
1938171095Ssam	    .type          = XGE_HAL_CHANNEL_TYPE_RING,
1939171095Ssam	    .userdata      = lldev,
1940173139Srwatson	    .dtr_init      = xge_rx_initial_replenish,
1941173139Srwatson	    .dtr_term      = xge_rx_term
1942171095Ssam	};
1943171095Ssam
1944171095Ssam	/* If device is not ready, return */
1945173139Srwatson	status = xge_hal_device_status(lldev->devh, &adapter_status);
1946173139Srwatson	if(status != XGE_HAL_OK) {
1947173139Srwatson	    xge_os_printf("Adapter Status: 0x%llx", (long long) adapter_status);
1948173139Srwatson	    XGE_EXIT_ON_ERR("Device is not ready", _exit, XGE_HAL_FAIL);
1949171095Ssam	}
1950173139Srwatson	else {
1951173139Srwatson	    status = xge_hal_channel_open(lldev->devh, &attr,
1952173139Srwatson	        &lldev->ring_channel[qid], rflag);
1953171095Ssam	}
1954171095Ssam
1955173139Srwatson_exit:
1956173139Srwatson	return status;
1957171095Ssam}
1958171095Ssam
1959173139Srwatson/**
1960173139Srwatson * xge_tx_open
1961173139Srwatson * Initialize and open all Tx channels
1962173139Srwatson *
1963173139Srwatson * @lldev Per-adapter Data
1964173139Srwatson * @tflag Channel open/close/reopen flag
1965173139Srwatson *
1966173139Srwatson * Returns 0 or Error Number
1967173139Srwatson */
1968171095Ssamint
1969173139Srwatsonxge_tx_open(xge_lldev_t *lldev, xge_hal_channel_reopen_e tflag)
1970171095Ssam{
1971173139Srwatson	xge_hal_status_e status = XGE_HAL_FAIL;
1972171095Ssam	u64 adapter_status = 0x0;
1973173139Srwatson	int qindex, index;
1974171095Ssam
1975171095Ssam	xge_hal_channel_attr_t attr = {
1976171095Ssam	    .compl_qid     = 0,
1977173139Srwatson	    .callback      = xge_tx_compl,
1978173139Srwatson	    .per_dtr_space = sizeof(xge_tx_priv_t),
1979171095Ssam	    .flags         = 0,
1980171095Ssam	    .type          = XGE_HAL_CHANNEL_TYPE_FIFO,
1981171095Ssam	    .userdata      = lldev,
1982173139Srwatson	    .dtr_init      = xge_tx_initial_replenish,
1983173139Srwatson	    .dtr_term      = xge_tx_term
1984171095Ssam	};
1985171095Ssam
1986171095Ssam	/* If device is not ready, return */
1987173139Srwatson	status = xge_hal_device_status(lldev->devh, &adapter_status);
1988173139Srwatson	if(status != XGE_HAL_OK) {
1989173139Srwatson	    xge_os_printf("Adapter Status: 0x%llx", (long long) adapter_status);
1990173139Srwatson	    XGE_EXIT_ON_ERR("Device is not ready", _exit, XGE_HAL_FAIL);
1991171095Ssam	}
1992171095Ssam
1993173139Srwatson	for(qindex = 0; qindex < XGE_FIFO_COUNT; qindex++) {
1994173139Srwatson	    attr.post_qid = qindex,
1995173139Srwatson	    status = xge_hal_channel_open(lldev->devh, &attr,
1996173139Srwatson	        &lldev->fifo_channel[qindex], tflag);
1997173139Srwatson	    if(status != XGE_HAL_OK) {
1998173139Srwatson	        for(index = 0; index < qindex; index++)
1999173139Srwatson	            xge_hal_channel_close(lldev->fifo_channel[index], tflag);
2000173139Srwatson	    }
2001171095Ssam	}
2002171095Ssam
2003173139Srwatson_exit:
2004173139Srwatson	return status;
2005173139Srwatson}
2006171095Ssam
2007173139Srwatson/**
2008173139Srwatson * xge_enable_msi
2009173139Srwatson * Enables MSI
2010173139Srwatson *
2011173139Srwatson * @lldev Per-adapter Data
2012173139Srwatson */
2013173139Srwatsonvoid
2014173139Srwatsonxge_enable_msi(xge_lldev_t *lldev)
2015173139Srwatson{
2016173139Srwatson	xge_list_t        *item    = NULL;
2017173139Srwatson	xge_hal_device_t  *hldev   = lldev->devh;
2018173139Srwatson	xge_hal_channel_t *channel = NULL;
2019173139Srwatson	u16 offset = 0, val16 = 0;
2020173139Srwatson
2021173139Srwatson	xge_os_pci_read16(lldev->pdev, NULL,
2022173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_control), &val16);
2023173139Srwatson
2024173139Srwatson	/* Update msi_data */
2025173139Srwatson	offset = (val16 & 0x80) ? 0x4c : 0x48;
2026173139Srwatson	xge_os_pci_read16(lldev->pdev, NULL, offset, &val16);
2027173139Srwatson	if(val16 & 0x1)
2028173139Srwatson	    val16 &= 0xfffe;
2029173139Srwatson	else
2030173139Srwatson	    val16 |= 0x1;
2031173139Srwatson	xge_os_pci_write16(lldev->pdev, NULL, offset, val16);
2032173139Srwatson
2033173139Srwatson	/* Update msi_control */
2034173139Srwatson	xge_os_pci_read16(lldev->pdev, NULL,
2035173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_control), &val16);
2036173139Srwatson	val16 |= 0x10;
2037173139Srwatson	xge_os_pci_write16(lldev->pdev, NULL,
2038173139Srwatson	    xge_offsetof(xge_hal_pci_config_le_t, msi_control), val16);
2039173139Srwatson
2040173139Srwatson	/* Set TxMAT and RxMAT registers with MSI */
2041173139Srwatson	xge_list_for_each(item, &hldev->free_channels) {
2042173139Srwatson	    channel = xge_container_of(item, xge_hal_channel_t, item);
2043173139Srwatson	    xge_hal_channel_msi_set(channel, 1, (u32)val16);
2044173139Srwatson	}
2045171095Ssam}
2046171095Ssam
2047173139Srwatson/**
2048173139Srwatson * xge_channel_open
2049173139Srwatson * Open both Tx and Rx channels
2050173139Srwatson *
2051173139Srwatson * @lldev Per-adapter Data
2052173139Srwatson * @option Channel reopen option
2053173139Srwatson */
2054171095Ssamint
2055173139Srwatsonxge_channel_open(xge_lldev_t *lldev, xge_hal_channel_reopen_e option)
2056171095Ssam{
2057173139Srwatson	xge_lro_entry_t *lro_session = NULL;
2058173139Srwatson	xge_hal_status_e status   = XGE_HAL_OK;
2059173139Srwatson	int index = 0, index2 = 0;
2060171095Ssam
2061173139Srwatson	if(lldev->enabled_msi == XGE_HAL_INTR_MODE_MSI) {
2062173139Srwatson	    xge_msi_info_restore(lldev);
2063173139Srwatson	    xge_enable_msi(lldev);
2064173139Srwatson	}
2065171095Ssam
2066173139Srwatson_exit2:
2067173139Srwatson	status = xge_create_dma_tags(lldev->device);
2068173139Srwatson	if(status != XGE_HAL_OK)
2069173139Srwatson	    XGE_EXIT_ON_ERR("DMA tag creation failed", _exit, status);
2070173139Srwatson
2071171095Ssam	/* Open ring (Rx) channel */
2072171095Ssam	for(index = 0; index < XGE_RING_COUNT; index++) {
2073173139Srwatson	    status = xge_rx_open(index, lldev, option);
2074173139Srwatson	    if(status != XGE_HAL_OK) {
2075173139Srwatson	        /*
2076173139Srwatson	         * DMA mapping fails in the unpatched Kernel which can't
2077173139Srwatson	         * allocate contiguous memory for Jumbo frames.
2078173139Srwatson	         * Try using 5 buffer mode.
2079173139Srwatson	         */
2080173139Srwatson	        if((lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) &&
2081173139Srwatson	            (((lldev->ifnetp)->if_mtu + XGE_HAL_MAC_HEADER_MAX_SIZE) >
2082173139Srwatson	            MJUMPAGESIZE)) {
2083173139Srwatson	            /* Close so far opened channels */
2084173139Srwatson	            for(index2 = 0; index2 < index; index2++) {
2085173139Srwatson	                xge_hal_channel_close(lldev->ring_channel[index2],
2086173139Srwatson	                    option);
2087173139Srwatson	            }
2088173139Srwatson
2089173139Srwatson	            /* Destroy DMA tags intended to use for 1 buffer mode */
2090173139Srwatson	            if(bus_dmamap_destroy(lldev->dma_tag_rx,
2091173139Srwatson	                lldev->extra_dma_map)) {
2092173139Srwatson	                xge_trace(XGE_ERR, "Rx extra DMA map destroy failed");
2093173139Srwatson	            }
2094173139Srwatson	            if(bus_dma_tag_destroy(lldev->dma_tag_rx))
2095173139Srwatson	                xge_trace(XGE_ERR, "Rx DMA tag destroy failed");
2096173139Srwatson	            if(bus_dma_tag_destroy(lldev->dma_tag_tx))
2097173139Srwatson	                xge_trace(XGE_ERR, "Tx DMA tag destroy failed");
2098173139Srwatson
2099173139Srwatson	            /* Switch to 5 buffer mode */
2100173139Srwatson	            lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_5;
2101173139Srwatson	            xge_buffer_mode_init(lldev, (lldev->ifnetp)->if_mtu);
2102173139Srwatson
2103173139Srwatson	            /* Restart init */
2104173139Srwatson	            goto _exit2;
2105171095Ssam	        }
2106173139Srwatson	        else {
2107173139Srwatson	            XGE_EXIT_ON_ERR("Opening Rx channel failed", _exit1,
2108173139Srwatson	                status);
2109173139Srwatson	        }
2110171095Ssam	    }
2111171095Ssam	}
2112171095Ssam
2113173139Srwatson	if(lldev->enabled_lro) {
2114173139Srwatson	    SLIST_INIT(&lldev->lro_free);
2115173139Srwatson	    SLIST_INIT(&lldev->lro_active);
2116173139Srwatson	    lldev->lro_num = XGE_LRO_DEFAULT_ENTRIES;
2117173139Srwatson
2118173139Srwatson	    for(index = 0; index < lldev->lro_num; index++) {
2119173139Srwatson	        lro_session = (xge_lro_entry_t *)
2120173139Srwatson	            xge_os_malloc(NULL, sizeof(xge_lro_entry_t));
2121173139Srwatson	        if(lro_session == NULL) {
2122173139Srwatson	            lldev->lro_num = index;
2123173139Srwatson	            break;
2124173139Srwatson	        }
2125173139Srwatson	        SLIST_INSERT_HEAD(&lldev->lro_free, lro_session, next);
2126171095Ssam	    }
2127171095Ssam	}
2128171095Ssam
2129173139Srwatson	/* Open FIFO (Tx) channel */
2130173139Srwatson	status = xge_tx_open(lldev, option);
2131173139Srwatson	if(status != XGE_HAL_OK)
2132173139Srwatson	    XGE_EXIT_ON_ERR("Opening Tx channel failed", _exit1, status);
2133173139Srwatson
2134173139Srwatson	goto _exit;
2135173139Srwatson
2136173139Srwatson_exit1:
2137173139Srwatson	/*
2138173139Srwatson	 * Opening Rx channel(s) failed (index is <last ring index - 1>) or
2139173139Srwatson	 * Initialization of LRO failed (index is XGE_RING_COUNT)
2140173139Srwatson	 * Opening Tx channel failed    (index is XGE_RING_COUNT)
2141173139Srwatson	 */
2142173139Srwatson	for(index2 = 0; index2 < index; index2++)
2143173139Srwatson	    xge_hal_channel_close(lldev->ring_channel[index2], option);
2144173139Srwatson
2145173139Srwatson_exit:
2146171095Ssam	return status;
2147171095Ssam}
2148171095Ssam
2149173139Srwatson/**
2150173139Srwatson * xge_channel_close
2151173139Srwatson * Close both Tx and Rx channels
2152173139Srwatson *
2153173139Srwatson * @lldev Per-adapter Data
2154173139Srwatson * @option Channel reopen option
2155173139Srwatson *
2156173139Srwatson */
2157173139Srwatsonvoid
2158173139Srwatsonxge_channel_close(xge_lldev_t *lldev, xge_hal_channel_reopen_e option)
2159171095Ssam{
2160173139Srwatson	int qindex = 0;
2161171095Ssam
2162171095Ssam	DELAY(1000 * 1000);
2163171095Ssam
2164171095Ssam	/* Close FIFO (Tx) channel */
2165173139Srwatson	for(qindex = 0; qindex < XGE_FIFO_COUNT; qindex++)
2166173139Srwatson	    xge_hal_channel_close(lldev->fifo_channel[qindex], option);
2167171095Ssam
2168173139Srwatson	/* Close Ring (Rx) channels */
2169173139Srwatson	for(qindex = 0; qindex < XGE_RING_COUNT; qindex++)
2170173139Srwatson	    xge_hal_channel_close(lldev->ring_channel[qindex], option);
2171171095Ssam
2172173139Srwatson	if(bus_dmamap_destroy(lldev->dma_tag_rx, lldev->extra_dma_map))
2173173139Srwatson	    xge_trace(XGE_ERR, "Rx extra map destroy failed");
2174173139Srwatson	if(bus_dma_tag_destroy(lldev->dma_tag_rx))
2175173139Srwatson	    xge_trace(XGE_ERR, "Rx DMA tag destroy failed");
2176173139Srwatson	if(bus_dma_tag_destroy(lldev->dma_tag_tx))
2177173139Srwatson	    xge_trace(XGE_ERR, "Tx DMA tag destroy failed");
2178171095Ssam}
2179171095Ssam
2180173139Srwatson/**
2181173139Srwatson * dmamap_cb
2182173139Srwatson * DMA map callback
2183173139Srwatson *
2184173139Srwatson * @arg Parameter passed from dmamap
2185173139Srwatson * @segs Segments
2186173139Srwatson * @nseg Number of segments
2187173139Srwatson * @error Error
2188173139Srwatson */
2189171095Ssamvoid
2190171095Ssamdmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2191171095Ssam{
2192171095Ssam	if(!error) {
2193171095Ssam	    *(bus_addr_t *) arg = segs->ds_addr;
2194171095Ssam	}
2195171095Ssam}
2196171095Ssam
2197173139Srwatson/**
2198173139Srwatson * xge_reset
2199173139Srwatson * Device Reset
2200173139Srwatson *
2201173139Srwatson * @lldev Per-adapter Data
2202173139Srwatson */
2203171095Ssamvoid
2204173139Srwatsonxge_reset(xge_lldev_t *lldev)
2205171095Ssam{
2206171095Ssam	xge_trace(XGE_TRACE, "Reseting the chip");
2207171095Ssam
2208171095Ssam	/* If the device is not initialized, return */
2209173139Srwatson	if(lldev->initialized) {
2210173139Srwatson	    mtx_lock(&lldev->mtx_drv);
2211173139Srwatson	    xge_device_stop(lldev, XGE_HAL_CHANNEL_OC_NORMAL);
2212173139Srwatson	    xge_device_init(lldev, XGE_HAL_CHANNEL_OC_NORMAL);
2213173139Srwatson	    mtx_unlock(&lldev->mtx_drv);
2214171095Ssam	}
2215171095Ssam
2216171095Ssam	return;
2217171095Ssam}
2218171095Ssam
2219173139Srwatson/**
2220173139Srwatson * xge_setmulti
2221173139Srwatson * Set an address as a multicast address
2222173139Srwatson *
2223173139Srwatson * @lldev Per-adapter Data
2224173139Srwatson */
2225171095Ssamvoid
2226173139Srwatsonxge_setmulti(xge_lldev_t *lldev)
2227171095Ssam{
2228171095Ssam	struct ifmultiaddr *ifma;
2229171095Ssam	u8                 *lladdr;
2230171095Ssam	xge_hal_device_t   *hldev        = (xge_hal_device_t *)lldev->devh;
2231171095Ssam	struct ifnet       *ifnetp       = lldev->ifnetp;
2232171095Ssam	int                index         = 0;
2233171095Ssam	int                offset        = 1;
2234171095Ssam	int                table_size    = 47;
2235171095Ssam	xge_hal_status_e   status        = XGE_HAL_OK;
2236171095Ssam	u8                 initial_addr[]= {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2237171095Ssam
2238171095Ssam	if((ifnetp->if_flags & IFF_MULTICAST) && (!lldev->all_multicast)) {
2239171095Ssam	    status = xge_hal_device_mcast_enable(hldev);
2240171095Ssam	    lldev->all_multicast = 1;
2241171095Ssam	}
2242171095Ssam	else if((ifnetp->if_flags & IFF_MULTICAST) && (lldev->all_multicast)) {
2243171095Ssam	    status = xge_hal_device_mcast_disable(hldev);
2244171095Ssam	    lldev->all_multicast = 0;
2245171095Ssam	}
2246171095Ssam
2247171095Ssam	if(status != XGE_HAL_OK) {
2248173139Srwatson	    xge_trace(XGE_ERR, "Enabling/disabling multicast failed");
2249173139Srwatson	    goto _exit;
2250171095Ssam	}
2251171095Ssam
2252171095Ssam	/* Updating address list */
2253195049Srwatson	if_maddr_rlock(ifnetp);
2254171095Ssam	index = 0;
2255171095Ssam	TAILQ_FOREACH(ifma, &ifnetp->if_multiaddrs, ifma_link) {
2256171095Ssam	    if(ifma->ifma_addr->sa_family != AF_LINK) {
2257171095Ssam	        continue;
2258171095Ssam	    }
2259171095Ssam	    lladdr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2260171095Ssam	    index += 1;
2261171095Ssam	}
2262195049Srwatson	if_maddr_runlock(ifnetp);
2263171095Ssam
2264171095Ssam	if((!lldev->all_multicast) && (index)) {
2265171095Ssam	    lldev->macaddr_count = (index + 1);
2266171095Ssam	    if(lldev->macaddr_count > table_size) {
2267173139Srwatson	        goto _exit;
2268171095Ssam	    }
2269171095Ssam
2270171095Ssam	    /* Clear old addresses */
2271171095Ssam	    for(index = 0; index < 48; index++) {
2272171095Ssam	        xge_hal_device_macaddr_set(hldev, (offset + index),
2273171095Ssam	            initial_addr);
2274171095Ssam	    }
2275171095Ssam	}
2276171095Ssam
2277171095Ssam	/* Add new addresses */
2278195049Srwatson	if_maddr_rlock(ifnetp);
2279171095Ssam	index = 0;
2280171095Ssam	TAILQ_FOREACH(ifma, &ifnetp->if_multiaddrs, ifma_link) {
2281171095Ssam	    if(ifma->ifma_addr->sa_family != AF_LINK) {
2282171095Ssam	        continue;
2283171095Ssam	    }
2284171095Ssam	    lladdr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2285171095Ssam	    xge_hal_device_macaddr_set(hldev, (offset + index), lladdr);
2286171095Ssam	    index += 1;
2287171095Ssam	}
2288195049Srwatson	if_maddr_runlock(ifnetp);
2289171095Ssam
2290173139Srwatson_exit:
2291173139Srwatson	return;
2292171095Ssam}
2293171095Ssam
2294173139Srwatson/**
2295173139Srwatson * xge_enable_promisc
2296173139Srwatson * Enable Promiscuous Mode
2297173139Srwatson *
2298173139Srwatson * @lldev Per-adapter Data
2299173139Srwatson */
2300171095Ssamvoid
2301173139Srwatsonxge_enable_promisc(xge_lldev_t *lldev)
2302171095Ssam{
2303171095Ssam	struct ifnet *ifnetp = lldev->ifnetp;
2304171095Ssam	xge_hal_device_t *hldev = lldev->devh;
2305171095Ssam	xge_hal_pci_bar0_t *bar0 = NULL;
2306171095Ssam	u64 val64 = 0;
2307171095Ssam
2308171095Ssam	bar0 = (xge_hal_pci_bar0_t *) hldev->bar0;
2309171095Ssam
2310171095Ssam	if(ifnetp->if_flags & IFF_PROMISC) {
2311171095Ssam	    xge_hal_device_promisc_enable(lldev->devh);
2312173139Srwatson
2313171095Ssam	    /*
2314171095Ssam	     * When operating in promiscuous mode, don't strip the VLAN tag
2315171095Ssam	     */
2316171095Ssam	    val64 = xge_os_pio_mem_read64(lldev->pdev, hldev->regh0,
2317171095Ssam	        &bar0->rx_pa_cfg);
2318171095Ssam	    val64 &= ~XGE_HAL_RX_PA_CFG_STRIP_VLAN_TAG_MODE(1);
2319171095Ssam	    val64 |= XGE_HAL_RX_PA_CFG_STRIP_VLAN_TAG_MODE(0);
2320171095Ssam	    xge_os_pio_mem_write64(lldev->pdev, hldev->regh0, val64,
2321171095Ssam	        &bar0->rx_pa_cfg);
2322171095Ssam
2323171095Ssam	    xge_trace(XGE_TRACE, "Promiscuous mode ON");
2324171095Ssam	}
2325171095Ssam}
2326171095Ssam
2327173139Srwatson/**
2328173139Srwatson * xge_disable_promisc
2329173139Srwatson * Disable Promiscuous Mode
2330173139Srwatson *
2331173139Srwatson * @lldev Per-adapter Data
2332173139Srwatson */
2333171095Ssamvoid
2334173139Srwatsonxge_disable_promisc(xge_lldev_t *lldev)
2335171095Ssam{
2336171095Ssam	xge_hal_device_t *hldev = lldev->devh;
2337171095Ssam	xge_hal_pci_bar0_t *bar0 = NULL;
2338171095Ssam	u64 val64 = 0;
2339171095Ssam
2340171095Ssam	bar0 = (xge_hal_pci_bar0_t *) hldev->bar0;
2341171095Ssam
2342171095Ssam	xge_hal_device_promisc_disable(lldev->devh);
2343171095Ssam
2344171095Ssam	/*
2345171095Ssam	 * Strip VLAN tag when operating in non-promiscuous mode
2346171095Ssam	 */
2347171095Ssam	val64 = xge_os_pio_mem_read64(lldev->pdev, hldev->regh0,
2348171095Ssam	    &bar0->rx_pa_cfg);
2349171095Ssam	val64 &= ~XGE_HAL_RX_PA_CFG_STRIP_VLAN_TAG_MODE(1);
2350171095Ssam	val64 |= XGE_HAL_RX_PA_CFG_STRIP_VLAN_TAG_MODE(1);
2351171095Ssam	xge_os_pio_mem_write64(lldev->pdev, hldev->regh0, val64,
2352171095Ssam	    &bar0->rx_pa_cfg);
2353171095Ssam
2354171095Ssam	xge_trace(XGE_TRACE, "Promiscuous mode OFF");
2355171095Ssam}
2356171095Ssam
2357173139Srwatson/**
2358173139Srwatson * xge_change_mtu
2359173139Srwatson * Change interface MTU to a requested valid size
2360171095Ssam *
2361173139Srwatson * @lldev Per-adapter Data
2362173139Srwatson * @NewMtu Requested MTU
2363171095Ssam *
2364173139Srwatson * Returns 0 or Error Number
2365173139Srwatson */
2366173139Srwatsonint
2367173139Srwatsonxge_change_mtu(xge_lldev_t *lldev, int new_mtu)
2368171095Ssam{
2369173139Srwatson	int status = XGE_HAL_OK;
2370171095Ssam
2371173139Srwatson	/* Check requested MTU size for boundary */
2372173139Srwatson	if(xge_hal_device_mtu_check(lldev->devh, new_mtu) != XGE_HAL_OK) {
2373173139Srwatson	    XGE_EXIT_ON_ERR("Invalid MTU", _exit, EINVAL);
2374171095Ssam	}
2375171095Ssam
2376173139Srwatson	lldev->mtu = new_mtu;
2377173139Srwatson	xge_confirm_changes(lldev, XGE_SET_MTU);
2378171095Ssam
2379173139Srwatson_exit:
2380173139Srwatson	return status;
2381171095Ssam}
2382171095Ssam
2383173139Srwatson/**
2384173139Srwatson * xge_device_stop
2385171095Ssam *
2386173139Srwatson * Common code for both stop and part of reset. Disables device, interrupts and
2387173139Srwatson * closes channels
2388171095Ssam *
2389173139Srwatson * @dev Device Handle
2390173139Srwatson * @option Channel normal/reset option
2391173139Srwatson */
2392173139Srwatsonvoid
2393173139Srwatsonxge_device_stop(xge_lldev_t *lldev, xge_hal_channel_reopen_e option)
2394171095Ssam{
2395171095Ssam	xge_hal_device_t *hldev  = lldev->devh;
2396171095Ssam	struct ifnet     *ifnetp = lldev->ifnetp;
2397173139Srwatson	u64               val64  = 0;
2398171095Ssam
2399173139Srwatson	mtx_assert((&lldev->mtx_drv), MA_OWNED);
2400173139Srwatson
2401173139Srwatson	/* If device is not in "Running" state, return */
2402173139Srwatson	if (!(ifnetp->if_drv_flags & IFF_DRV_RUNNING))
2403173139Srwatson	    goto _exit;
2404173139Srwatson
2405171095Ssam	/* Set appropriate flags */
2406171095Ssam	ifnetp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2407171095Ssam
2408171095Ssam	/* Stop timer */
2409171095Ssam	callout_stop(&lldev->timer);
2410171095Ssam
2411171095Ssam	/* Disable interrupts */
2412171095Ssam	xge_hal_device_intr_disable(hldev);
2413171095Ssam
2414173139Srwatson	mtx_unlock(&lldev->mtx_drv);
2415171095Ssam	xge_queue_flush(xge_hal_device_queue(lldev->devh));
2416173139Srwatson	mtx_lock(&lldev->mtx_drv);
2417171095Ssam
2418171095Ssam	/* Disable HAL device */
2419171095Ssam	if(xge_hal_device_disable(hldev) != XGE_HAL_OK) {
2420171095Ssam	    xge_trace(XGE_ERR, "Disabling HAL device failed");
2421173139Srwatson	    xge_hal_device_status(hldev, &val64);
2422173139Srwatson	    xge_trace(XGE_ERR, "Adapter Status: 0x%llx", (long long)val64);
2423171095Ssam	}
2424171095Ssam
2425171095Ssam	/* Close Tx and Rx channels */
2426173139Srwatson	xge_channel_close(lldev, option);
2427171095Ssam
2428171095Ssam	/* Reset HAL device */
2429171095Ssam	xge_hal_device_reset(hldev);
2430171095Ssam
2431171095Ssam	xge_os_mdelay(1000);
2432171095Ssam	lldev->initialized = 0;
2433171095Ssam
2434171095Ssam	if_link_state_change(ifnetp, LINK_STATE_DOWN);
2435171095Ssam
2436173139Srwatson_exit:
2437173139Srwatson	return;
2438171095Ssam}
2439171095Ssam
2440173139Srwatson/**
2441173139Srwatson * xge_set_mbuf_cflags
2442173139Srwatson * set checksum flag for the mbuf
2443173139Srwatson *
2444173139Srwatson * @pkt Packet
2445173139Srwatson */
2446173139Srwatsonvoid
2447173139Srwatsonxge_set_mbuf_cflags(mbuf_t pkt)
2448171095Ssam{
2449171095Ssam	pkt->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
2450171095Ssam	pkt->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2451171095Ssam	pkt->m_pkthdr.csum_flags |= (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
2452171095Ssam	pkt->m_pkthdr.csum_data = htons(0xffff);
2453171095Ssam}
2454171095Ssam
2455173139Srwatson/**
2456173139Srwatson * xge_lro_flush_sessions
2457173139Srwatson * Flush LRO session and send accumulated LRO packet to upper layer
2458173139Srwatson *
2459173139Srwatson * @lldev Per-adapter Data
2460173139Srwatson */
2461173139Srwatsonvoid
2462173139Srwatsonxge_lro_flush_sessions(xge_lldev_t *lldev)
2463171095Ssam{
2464173139Srwatson	xge_lro_entry_t *lro_session = NULL;
2465171095Ssam
2466173139Srwatson	while(!SLIST_EMPTY(&lldev->lro_active)) {
2467173139Srwatson	    lro_session = SLIST_FIRST(&lldev->lro_active);
2468173139Srwatson	    SLIST_REMOVE_HEAD(&lldev->lro_active, next);
2469173139Srwatson	    xge_lro_flush(lldev, lro_session);
2470173139Srwatson	}
2471173139Srwatson}
2472171095Ssam
2473173139Srwatson/**
2474173139Srwatson * xge_lro_flush
2475173139Srwatson * Flush LRO session. Send accumulated LRO packet to upper layer
2476173139Srwatson *
2477173139Srwatson * @lldev Per-adapter Data
2478173139Srwatson * @lro LRO session to be flushed
2479173139Srwatson */
2480173139Srwatsonstatic void
2481173139Srwatsonxge_lro_flush(xge_lldev_t *lldev, xge_lro_entry_t *lro_session)
2482173139Srwatson{
2483173139Srwatson	struct ip *header_ip;
2484173139Srwatson	struct tcphdr *header_tcp;
2485173139Srwatson	u32 *ptr;
2486171095Ssam
2487173139Srwatson	if(lro_session->append_cnt) {
2488173139Srwatson	    header_ip = lro_session->lro_header_ip;
2489173139Srwatson	    header_ip->ip_len = htons(lro_session->len - ETHER_HDR_LEN);
2490173139Srwatson	    lro_session->m_head->m_pkthdr.len = lro_session->len;
2491173139Srwatson	    header_tcp = (struct tcphdr *)(header_ip + 1);
2492173139Srwatson	    header_tcp->th_ack = lro_session->ack_seq;
2493173139Srwatson	    header_tcp->th_win = lro_session->window;
2494173139Srwatson	    if(lro_session->timestamp) {
2495173139Srwatson	        ptr = (u32 *)(header_tcp + 1);
2496173139Srwatson	        ptr[1] = htonl(lro_session->tsval);
2497173139Srwatson	        ptr[2] = lro_session->tsecr;
2498173139Srwatson	    }
2499171095Ssam	}
2500173139Srwatson
2501173139Srwatson	(*lldev->ifnetp->if_input)(lldev->ifnetp, lro_session->m_head);
2502173139Srwatson	lro_session->m_head = NULL;
2503173139Srwatson	lro_session->timestamp = 0;
2504173139Srwatson	lro_session->append_cnt = 0;
2505173139Srwatson	SLIST_INSERT_HEAD(&lldev->lro_free, lro_session, next);
2506171095Ssam}
2507171095Ssam
2508173139Srwatson/**
2509173139Srwatson * xge_lro_accumulate
2510173139Srwatson * Accumulate packets to form a large LRO packet based on various conditions
2511173139Srwatson *
2512173139Srwatson * @lldev Per-adapter Data
2513173139Srwatson * @m_head Current Packet
2514173139Srwatson *
2515173139Srwatson * Returns XGE_HAL_OK or XGE_HAL_FAIL (failure)
2516173139Srwatson */
2517173139Srwatsonstatic int
2518173139Srwatsonxge_lro_accumulate(xge_lldev_t *lldev, struct mbuf *m_head)
2519171095Ssam{
2520173139Srwatson	struct ether_header *header_ethernet;
2521173139Srwatson	struct ip *header_ip;
2522173139Srwatson	struct tcphdr *header_tcp;
2523173139Srwatson	u32 seq, *ptr;
2524173139Srwatson	struct mbuf *buffer_next, *buffer_tail;
2525173139Srwatson	xge_lro_entry_t *lro_session;
2526173139Srwatson	xge_hal_status_e status = XGE_HAL_FAIL;
2527173139Srwatson	int hlen, ip_len, tcp_hdr_len, tcp_data_len, tot_len, tcp_options;
2528173139Srwatson	int trim;
2529171095Ssam
2530173139Srwatson	/* Get Ethernet header */
2531173139Srwatson	header_ethernet = mtod(m_head, struct ether_header *);
2532171095Ssam
2533173139Srwatson	/* Return if it is not IP packet */
2534173139Srwatson	if(header_ethernet->ether_type != htons(ETHERTYPE_IP))
2535173139Srwatson	    goto _exit;
2536171095Ssam
2537173139Srwatson	/* Get IP header */
2538173139Srwatson	header_ip = lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1 ?
2539173139Srwatson	    (struct ip *)(header_ethernet + 1) :
2540173139Srwatson	    mtod(m_head->m_next, struct ip *);
2541173139Srwatson
2542173139Srwatson	/* Return if it is not TCP packet */
2543173139Srwatson	if(header_ip->ip_p != IPPROTO_TCP)
2544173139Srwatson	    goto _exit;
2545173139Srwatson
2546173139Srwatson	/* Return if packet has options */
2547173139Srwatson	if((header_ip->ip_hl << 2) != sizeof(*header_ip))
2548173139Srwatson	    goto _exit;
2549173139Srwatson
2550173139Srwatson	/* Return if packet is fragmented */
2551173139Srwatson	if(header_ip->ip_off & htons(IP_MF | IP_OFFMASK))
2552173139Srwatson	    goto _exit;
2553173139Srwatson
2554173139Srwatson	/* Get TCP header */
2555173139Srwatson	header_tcp = (struct tcphdr *)(header_ip + 1);
2556173139Srwatson
2557173139Srwatson	/* Return if not ACK or PUSH */
2558173139Srwatson	if((header_tcp->th_flags & ~(TH_ACK | TH_PUSH)) != 0)
2559173139Srwatson	    goto _exit;
2560173139Srwatson
2561173139Srwatson	/* Only timestamp option is handled */
2562173139Srwatson	tcp_options = (header_tcp->th_off << 2) - sizeof(*header_tcp);
2563173139Srwatson	tcp_hdr_len = sizeof(*header_tcp) + tcp_options;
2564173139Srwatson	ptr = (u32 *)(header_tcp + 1);
2565173139Srwatson	if(tcp_options != 0) {
2566173139Srwatson	    if(__predict_false(tcp_options != TCPOLEN_TSTAMP_APPA) ||
2567173139Srwatson	        (*ptr != ntohl(TCPOPT_NOP << 24 | TCPOPT_NOP << 16 |
2568173139Srwatson	        TCPOPT_TIMESTAMP << 8 | TCPOLEN_TIMESTAMP))) {
2569173139Srwatson	        goto _exit;
2570173139Srwatson	    }
2571171095Ssam	}
2572171095Ssam
2573173139Srwatson	/* Total length of packet (IP) */
2574173139Srwatson	ip_len = ntohs(header_ip->ip_len);
2575171095Ssam
2576173139Srwatson	/* TCP data size */
2577173139Srwatson	tcp_data_len = ip_len - (header_tcp->th_off << 2) - sizeof(*header_ip);
2578171095Ssam
2579173139Srwatson	/* If the frame is padded, trim it */
2580173139Srwatson	tot_len = m_head->m_pkthdr.len;
2581173139Srwatson	trim = tot_len - (ip_len + ETHER_HDR_LEN);
2582173139Srwatson	if(trim != 0) {
2583173139Srwatson	    if(trim < 0)
2584173139Srwatson	        goto _exit;
2585173139Srwatson	    m_adj(m_head, -trim);
2586173139Srwatson	    tot_len = m_head->m_pkthdr.len;
2587171095Ssam	}
2588171095Ssam
2589173139Srwatson	buffer_next = m_head;
2590173139Srwatson	buffer_tail = NULL;
2591173139Srwatson	while(buffer_next != NULL) {
2592173139Srwatson	    buffer_tail = buffer_next;
2593173139Srwatson	    buffer_next = buffer_tail->m_next;
2594173139Srwatson	}
2595171095Ssam
2596173139Srwatson	/* Total size of only headers */
2597173139Srwatson	hlen = ip_len + ETHER_HDR_LEN - tcp_data_len;
2598171095Ssam
2599173139Srwatson	/* Get sequence number */
2600173139Srwatson	seq = ntohl(header_tcp->th_seq);
2601173139Srwatson
2602173139Srwatson	SLIST_FOREACH(lro_session, &lldev->lro_active, next) {
2603173139Srwatson	    if(lro_session->source_port == header_tcp->th_sport &&
2604173139Srwatson	        lro_session->dest_port == header_tcp->th_dport &&
2605173139Srwatson	        lro_session->source_ip == header_ip->ip_src.s_addr &&
2606173139Srwatson	        lro_session->dest_ip == header_ip->ip_dst.s_addr) {
2607173139Srwatson
2608173139Srwatson	        /* Unmatched sequence number, flush LRO session */
2609173139Srwatson	        if(__predict_false(seq != lro_session->next_seq)) {
2610173139Srwatson	            SLIST_REMOVE(&lldev->lro_active, lro_session,
2611173139Srwatson	                xge_lro_entry_t, next);
2612173139Srwatson	            xge_lro_flush(lldev, lro_session);
2613173139Srwatson	            goto _exit;
2614173139Srwatson	        }
2615173139Srwatson
2616173139Srwatson	        /* Handle timestamp option */
2617173139Srwatson	        if(tcp_options) {
2618173139Srwatson	            u32 tsval = ntohl(*(ptr + 1));
2619173139Srwatson	            if(__predict_false(lro_session->tsval > tsval ||
2620173139Srwatson	                *(ptr + 2) == 0)) {
2621173139Srwatson	                goto _exit;
2622173139Srwatson	            }
2623173139Srwatson	            lro_session->tsval = tsval;
2624173139Srwatson	            lro_session->tsecr = *(ptr + 2);
2625173139Srwatson	        }
2626173139Srwatson
2627173139Srwatson	        lro_session->next_seq += tcp_data_len;
2628173139Srwatson	        lro_session->ack_seq = header_tcp->th_ack;
2629173139Srwatson	        lro_session->window = header_tcp->th_win;
2630173139Srwatson
2631173139Srwatson	        /* If TCP data/payload is of 0 size, free mbuf */
2632173139Srwatson	        if(tcp_data_len == 0) {
2633173139Srwatson	            m_freem(m_head);
2634173139Srwatson	            status = XGE_HAL_OK;
2635173139Srwatson	            goto _exit;
2636173139Srwatson	        }
2637173139Srwatson
2638173139Srwatson	        lro_session->append_cnt++;
2639173139Srwatson	        lro_session->len += tcp_data_len;
2640173139Srwatson
2641173139Srwatson	        /* Adjust mbuf so that m_data points to payload than headers */
2642173139Srwatson	        m_adj(m_head, hlen);
2643173139Srwatson
2644173139Srwatson	        /* Append this packet to LRO accumulated packet */
2645173139Srwatson	        lro_session->m_tail->m_next = m_head;
2646173139Srwatson	        lro_session->m_tail = buffer_tail;
2647173139Srwatson
2648173139Srwatson	        /* Flush if LRO packet is exceeding maximum size */
2649173139Srwatson	        if(lro_session->len >
2650173139Srwatson	            (XGE_HAL_LRO_DEFAULT_FRM_LEN - lldev->ifnetp->if_mtu)) {
2651173139Srwatson	            SLIST_REMOVE(&lldev->lro_active, lro_session,
2652173139Srwatson	                xge_lro_entry_t, next);
2653173139Srwatson	            xge_lro_flush(lldev, lro_session);
2654173139Srwatson	        }
2655173139Srwatson	        status = XGE_HAL_OK;
2656173139Srwatson	        goto _exit;
2657173139Srwatson	    }
2658171095Ssam	}
2659171095Ssam
2660173139Srwatson	if(SLIST_EMPTY(&lldev->lro_free))
2661173139Srwatson	    goto _exit;
2662171095Ssam
2663173139Srwatson	/* Start a new LRO session */
2664173139Srwatson	lro_session = SLIST_FIRST(&lldev->lro_free);
2665173139Srwatson	SLIST_REMOVE_HEAD(&lldev->lro_free, next);
2666173139Srwatson	SLIST_INSERT_HEAD(&lldev->lro_active, lro_session, next);
2667173139Srwatson	lro_session->source_port = header_tcp->th_sport;
2668173139Srwatson	lro_session->dest_port = header_tcp->th_dport;
2669173139Srwatson	lro_session->source_ip = header_ip->ip_src.s_addr;
2670173139Srwatson	lro_session->dest_ip = header_ip->ip_dst.s_addr;
2671173139Srwatson	lro_session->next_seq = seq + tcp_data_len;
2672173139Srwatson	lro_session->mss = tcp_data_len;
2673173139Srwatson	lro_session->ack_seq = header_tcp->th_ack;
2674173139Srwatson	lro_session->window = header_tcp->th_win;
2675173139Srwatson
2676173139Srwatson	lro_session->lro_header_ip = header_ip;
2677173139Srwatson
2678173139Srwatson	/* Handle timestamp option */
2679173139Srwatson	if(tcp_options) {
2680173139Srwatson	    lro_session->timestamp = 1;
2681173139Srwatson	    lro_session->tsval = ntohl(*(ptr + 1));
2682173139Srwatson	    lro_session->tsecr = *(ptr + 2);
2683171095Ssam	}
2684171095Ssam
2685173139Srwatson	lro_session->len = tot_len;
2686173139Srwatson	lro_session->m_head = m_head;
2687173139Srwatson	lro_session->m_tail = buffer_tail;
2688173139Srwatson	status = XGE_HAL_OK;
2689173139Srwatson
2690173139Srwatson_exit:
2691173139Srwatson	return status;
2692173139Srwatson}
2693173139Srwatson
2694173139Srwatson/**
2695173139Srwatson * xge_accumulate_large_rx
2696173139Srwatson * Accumulate packets to form a large LRO packet based on various conditions
2697173139Srwatson *
2698173139Srwatson * @lldev Per-adapter Data
2699173139Srwatson * @pkt Current packet
2700173139Srwatson * @pkt_length Packet Length
2701173139Srwatson * @rxd_priv Rx Descriptor Private Data
2702173139Srwatson */
2703173139Srwatsonvoid
2704173139Srwatsonxge_accumulate_large_rx(xge_lldev_t *lldev, struct mbuf *pkt, int pkt_length,
2705173139Srwatson	xge_rx_priv_t *rxd_priv)
2706173139Srwatson{
2707173139Srwatson	if(xge_lro_accumulate(lldev, pkt) != XGE_HAL_OK) {
2708171095Ssam	    bus_dmamap_sync(lldev->dma_tag_rx, rxd_priv->dmainfo[0].dma_map,
2709171095Ssam	        BUS_DMASYNC_POSTREAD);
2710173139Srwatson	    (*lldev->ifnetp->if_input)(lldev->ifnetp, pkt);
2711171095Ssam	}
2712171095Ssam}
2713171095Ssam
2714173139Srwatson/**
2715173139Srwatson * xge_rx_compl
2716173139Srwatson * If the interrupt is due to received frame (Rx completion), send it up
2717173139Srwatson *
2718173139Srwatson * @channelh Ring Channel Handle
2719173139Srwatson * @dtr Current Descriptor
2720173139Srwatson * @t_code Transfer Code indicating success or error
2721173139Srwatson * @userdata Per-adapter Data
2722173139Srwatson *
2723173139Srwatson * Returns XGE_HAL_OK or HAL error enums
2724173139Srwatson */
2725171095Ssamxge_hal_status_e
2726173139Srwatsonxge_rx_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
2727171095Ssam	void *userdata)
2728171095Ssam{
2729171095Ssam	struct ifnet       *ifnetp;
2730173139Srwatson	xge_rx_priv_t      *rxd_priv = NULL;
2731173139Srwatson	mbuf_t              mbuf_up  = NULL;
2732173139Srwatson	xge_hal_status_e    status   = XGE_HAL_OK;
2733173139Srwatson	xge_hal_dtr_info_t  ext_info;
2734173139Srwatson	int                 index;
2735173139Srwatson	u16                 vlan_tag;
2736171095Ssam
2737171095Ssam	/*get the user data portion*/
2738173139Srwatson	xge_lldev_t *lldev = xge_hal_channel_userdata(channelh);
2739171095Ssam	if(!lldev) {
2740173139Srwatson	    XGE_EXIT_ON_ERR("Failed to get user data", _exit, XGE_HAL_FAIL);
2741171095Ssam	}
2742171095Ssam
2743173139Srwatson	XGE_DRV_STATS(rx_completions);
2744171095Ssam
2745171095Ssam	/* get the interface pointer */
2746171095Ssam	ifnetp = lldev->ifnetp;
2747171095Ssam
2748171095Ssam	do {
2749173139Srwatson	    XGE_DRV_STATS(rx_desc_compl);
2750173139Srwatson
2751171095Ssam	    if(!(ifnetp->if_drv_flags & IFF_DRV_RUNNING)) {
2752173139Srwatson	        status = XGE_HAL_FAIL;
2753173139Srwatson	        goto _exit;
2754171095Ssam	    }
2755171095Ssam
2756171095Ssam	    if(t_code) {
2757171095Ssam	        xge_trace(XGE_TRACE, "Packet dropped because of %d", t_code);
2758173139Srwatson	        XGE_DRV_STATS(rx_tcode);
2759171095Ssam	        xge_hal_device_handle_tcode(channelh, dtr, t_code);
2760171095Ssam	        xge_hal_ring_dtr_post(channelh,dtr);
2761171095Ssam	        continue;
2762171095Ssam	    }
2763171095Ssam
2764171095Ssam	    /* Get the private data for this descriptor*/
2765173139Srwatson	    rxd_priv = (xge_rx_priv_t *) xge_hal_ring_dtr_private(channelh,
2766171095Ssam	        dtr);
2767171095Ssam	    if(!rxd_priv) {
2768173139Srwatson	        XGE_EXIT_ON_ERR("Failed to get descriptor private data", _exit,
2769173139Srwatson	            XGE_HAL_FAIL);
2770171095Ssam	    }
2771171095Ssam
2772173139Srwatson	    /*
2773173139Srwatson	     * Prepare one buffer to send it to upper layer -- since the upper
2774173139Srwatson	     * layer frees the buffer do not use rxd_priv->buffer. Meanwhile
2775173139Srwatson	     * prepare a new buffer, do mapping, use it in the current
2776173139Srwatson	     * descriptor and post descriptor back to ring channel
2777173139Srwatson	     */
2778171095Ssam	    mbuf_up = rxd_priv->bufferArray[0];
2779171095Ssam
2780171095Ssam	    /* Gets details of mbuf i.e., packet length */
2781171095Ssam	    xge_ring_dtr_get(mbuf_up, channelh, dtr, lldev, rxd_priv);
2782171095Ssam
2783173139Srwatson	    status =
2784171095Ssam	        (lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) ?
2785173139Srwatson	        xge_get_buf(dtr, rxd_priv, lldev, 0) :
2786173139Srwatson	        xge_get_buf_3b_5b(dtr, rxd_priv, lldev);
2787171095Ssam
2788173139Srwatson	    if(status != XGE_HAL_OK) {
2789171095Ssam	        xge_trace(XGE_ERR, "No memory");
2790173139Srwatson	        XGE_DRV_STATS(rx_no_buf);
2791171095Ssam
2792171095Ssam	        /*
2793173139Srwatson	         * Unable to allocate buffer. Instead of discarding, post
2794173139Srwatson	         * descriptor back to channel for future processing of same
2795173139Srwatson	         * packet.
2796171095Ssam	         */
2797171095Ssam	        xge_hal_ring_dtr_post(channelh, dtr);
2798171095Ssam	        continue;
2799171095Ssam	    }
2800171095Ssam
2801171095Ssam	    /* Get the extended information */
2802171095Ssam	    xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info);
2803171095Ssam
2804173139Srwatson	    /*
2805173139Srwatson	     * As we have allocated a new mbuf for this descriptor, post this
2806173139Srwatson	     * descriptor with new mbuf back to ring channel
2807173139Srwatson	     */
2808173139Srwatson	    vlan_tag = ext_info.vlan;
2809173139Srwatson	    xge_hal_ring_dtr_post(channelh, dtr);
2810173139Srwatson	    if ((!(ext_info.proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED) &&
2811173139Srwatson	        (ext_info.proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) &&
2812173139Srwatson	        (ext_info.l3_cksum == XGE_HAL_L3_CKSUM_OK) &&
2813173139Srwatson	        (ext_info.l4_cksum == XGE_HAL_L4_CKSUM_OK))) {
2814171095Ssam
2815173139Srwatson	        /* set Checksum Flag */
2816173139Srwatson	        xge_set_mbuf_cflags(mbuf_up);
2817173139Srwatson
2818173139Srwatson	        if(lldev->enabled_lro) {
2819173139Srwatson	            xge_accumulate_large_rx(lldev, mbuf_up, mbuf_up->m_len,
2820173139Srwatson	                rxd_priv);
2821171095Ssam	        }
2822171095Ssam	        else {
2823173139Srwatson	            /* Post-Read sync for buffers*/
2824173139Srwatson	            for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
2825173139Srwatson	                bus_dmamap_sync(lldev->dma_tag_rx,
2826173139Srwatson	                    rxd_priv->dmainfo[0].dma_map, BUS_DMASYNC_POSTREAD);
2827171095Ssam	            }
2828173139Srwatson	            (*ifnetp->if_input)(ifnetp, mbuf_up);
2829171095Ssam	        }
2830171095Ssam	    }
2831171095Ssam	    else {
2832171095Ssam	        /*
2833173139Srwatson	         * Packet with erroneous checksum , let the upper layer deal
2834173139Srwatson	         * with it
2835171095Ssam	         */
2836171095Ssam
2837173139Srwatson	        /* Post-Read sync for buffers*/
2838173139Srwatson	        for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
2839173139Srwatson	            bus_dmamap_sync(lldev->dma_tag_rx,
2840173139Srwatson	                 rxd_priv->dmainfo[0].dma_map, BUS_DMASYNC_POSTREAD);
2841171095Ssam	        }
2842171095Ssam
2843173139Srwatson	        if(vlan_tag) {
2844173139Srwatson	            mbuf_up->m_pkthdr.ether_vtag = vlan_tag;
2845173139Srwatson	            mbuf_up->m_flags |= M_VLANTAG;
2846171095Ssam	        }
2847173139Srwatson
2848173139Srwatson	        if(lldev->enabled_lro)
2849173139Srwatson	            xge_lro_flush_sessions(lldev);
2850173139Srwatson
2851173139Srwatson	        (*ifnetp->if_input)(ifnetp, mbuf_up);
2852171095Ssam	    }
2853171095Ssam	} while(xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code)
2854171095Ssam	    == XGE_HAL_OK);
2855171095Ssam
2856173139Srwatson	if(lldev->enabled_lro)
2857173139Srwatson	    xge_lro_flush_sessions(lldev);
2858171095Ssam
2859173139Srwatson_exit:
2860173139Srwatson	return status;
2861171095Ssam}
2862171095Ssam
2863173139Srwatson/**
2864173139Srwatson * xge_ring_dtr_get
2865173139Srwatson * Get descriptors
2866173139Srwatson *
2867173139Srwatson * @mbuf_up Packet to send up
2868173139Srwatson * @channelh Ring Channel Handle
2869173139Srwatson * @dtr Descriptor
2870173139Srwatson * @lldev Per-adapter Data
2871173139Srwatson * @rxd_priv Rx Descriptor Private Data
2872173139Srwatson *
2873173139Srwatson * Returns XGE_HAL_OK or HAL error enums
2874173139Srwatson */
2875171095Ssamint
2876171095Ssamxge_ring_dtr_get(mbuf_t mbuf_up, xge_hal_channel_h channelh, xge_hal_dtr_h dtr,
2877173139Srwatson	xge_lldev_t *lldev, xge_rx_priv_t *rxd_priv)
2878171095Ssam{
2879171095Ssam	mbuf_t           m;
2880171095Ssam	int              pkt_length[5]={0,0}, pkt_len=0;
2881171095Ssam	dma_addr_t       dma_data[5];
2882171095Ssam	int              index;
2883171095Ssam
2884171095Ssam	m = mbuf_up;
2885171095Ssam	pkt_len = 0;
2886171095Ssam
2887171095Ssam	if(lldev->buffer_mode != XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
2888171095Ssam	    xge_os_memzero(pkt_length, sizeof(pkt_length));
2889171095Ssam
2890171095Ssam	    /*
2891171095Ssam	     * Retrieve data of interest from the completed descriptor -- This
2892171095Ssam	     * returns the packet length
2893171095Ssam	     */
2894171095Ssam	    if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_5) {
2895171095Ssam	        xge_hal_ring_dtr_5b_get(channelh, dtr, dma_data, pkt_length);
2896171095Ssam	    }
2897171095Ssam	    else {
2898171095Ssam	        xge_hal_ring_dtr_3b_get(channelh, dtr, dma_data, pkt_length);
2899171095Ssam	    }
2900171095Ssam
2901171095Ssam	    for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
2902171095Ssam	        m->m_len  = pkt_length[index];
2903171095Ssam
2904171095Ssam	        if(index < (lldev->rxd_mbuf_cnt-1)) {
2905171095Ssam	            m->m_next = rxd_priv->bufferArray[index + 1];
2906171095Ssam	            m = m->m_next;
2907171095Ssam	        }
2908171095Ssam	        else {
2909171095Ssam	            m->m_next = NULL;
2910171095Ssam	        }
2911171095Ssam	        pkt_len+=pkt_length[index];
2912171095Ssam	    }
2913171095Ssam
2914171095Ssam	    /*
2915171095Ssam	     * Since 2 buffer mode is an exceptional case where data is in 3rd
2916171095Ssam	     * buffer but not in 2nd buffer
2917171095Ssam	     */
2918171095Ssam	    if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_2) {
2919171095Ssam	        m->m_len = pkt_length[2];
2920171095Ssam	        pkt_len+=pkt_length[2];
2921171095Ssam	    }
2922171095Ssam
2923171095Ssam	    /*
2924171095Ssam	     * Update length of newly created buffer to be sent up with packet
2925171095Ssam	     * length
2926171095Ssam	     */
2927171095Ssam	    mbuf_up->m_pkthdr.len = pkt_len;
2928171095Ssam	}
2929171095Ssam	else {
2930171095Ssam	    /*
2931171095Ssam	     * Retrieve data of interest from the completed descriptor -- This
2932171095Ssam	     * returns the packet length
2933171095Ssam	     */
2934171095Ssam	    xge_hal_ring_dtr_1b_get(channelh, dtr,&dma_data[0], &pkt_length[0]);
2935171095Ssam
2936171095Ssam	    /*
2937171095Ssam	     * Update length of newly created buffer to be sent up with packet
2938171095Ssam	     * length
2939171095Ssam	     */
2940171095Ssam	    mbuf_up->m_len =  mbuf_up->m_pkthdr.len = pkt_length[0];
2941171095Ssam	}
2942171095Ssam
2943173139Srwatson	return XGE_HAL_OK;
2944171095Ssam}
2945171095Ssam
2946173139Srwatson/**
2947173139Srwatson * xge_flush_txds
2948173139Srwatson * Flush Tx descriptors
2949173139Srwatson *
2950173139Srwatson * @channelh Channel handle
2951173139Srwatson */
2952173139Srwatsonstatic void inline
2953173139Srwatsonxge_flush_txds(xge_hal_channel_h channelh)
2954173139Srwatson{
2955173139Srwatson	xge_lldev_t *lldev = xge_hal_channel_userdata(channelh);
2956173139Srwatson	xge_hal_dtr_h tx_dtr;
2957173139Srwatson	xge_tx_priv_t *tx_priv;
2958173139Srwatson	u8 t_code;
2959171095Ssam
2960173139Srwatson	while(xge_hal_fifo_dtr_next_completed(channelh, &tx_dtr, &t_code)
2961173139Srwatson	    == XGE_HAL_OK) {
2962173139Srwatson	    XGE_DRV_STATS(tx_desc_compl);
2963173139Srwatson	    if(t_code) {
2964173139Srwatson	        xge_trace(XGE_TRACE, "Tx descriptor with t_code %d", t_code);
2965173139Srwatson	        XGE_DRV_STATS(tx_tcode);
2966173139Srwatson	        xge_hal_device_handle_tcode(channelh, tx_dtr, t_code);
2967173139Srwatson	    }
2968173139Srwatson
2969173139Srwatson	    tx_priv = xge_hal_fifo_dtr_private(tx_dtr);
2970173139Srwatson	    bus_dmamap_unload(lldev->dma_tag_tx, tx_priv->dma_map);
2971173139Srwatson	    m_freem(tx_priv->buffer);
2972173139Srwatson	    tx_priv->buffer = NULL;
2973173139Srwatson	    xge_hal_fifo_dtr_free(channelh, tx_dtr);
2974173139Srwatson	}
2975173139Srwatson}
2976173139Srwatson
2977173139Srwatson/**
2978173139Srwatson * xge_send
2979173139Srwatson * Transmit function
2980173139Srwatson *
2981173139Srwatson * @ifnetp Interface Handle
2982173139Srwatson */
2983171095Ssamvoid
2984171095Ssamxge_send(struct ifnet *ifnetp)
2985171095Ssam{
2986173139Srwatson	int qindex = 0;
2987173139Srwatson	xge_lldev_t *lldev = ifnetp->if_softc;
2988171095Ssam
2989173139Srwatson	for(qindex = 0; qindex < XGE_FIFO_COUNT; qindex++) {
2990173139Srwatson	    if(mtx_trylock(&lldev->mtx_tx[qindex]) == 0) {
2991173139Srwatson	        XGE_DRV_STATS(tx_lock_fail);
2992173139Srwatson	        break;
2993173139Srwatson	    }
2994173139Srwatson	    xge_send_locked(ifnetp, qindex);
2995173139Srwatson	    mtx_unlock(&lldev->mtx_tx[qindex]);
2996173139Srwatson	}
2997171095Ssam}
2998171095Ssam
2999173139Srwatsonstatic void inline
3000173139Srwatsonxge_send_locked(struct ifnet *ifnetp, int qindex)
3001171095Ssam{
3002171095Ssam	xge_hal_dtr_h            dtr;
3003173139Srwatson	static bus_dma_segment_t segs[XGE_MAX_SEGS];
3004173139Srwatson	xge_hal_status_e         status;
3005171095Ssam	unsigned int             max_fragments;
3006173139Srwatson	xge_lldev_t              *lldev          = ifnetp->if_softc;
3007173139Srwatson	xge_hal_channel_h        channelh        = lldev->fifo_channel[qindex];
3008171095Ssam	mbuf_t                   m_head          = NULL;
3009171095Ssam	mbuf_t                   m_buf           = NULL;
3010173139Srwatson	xge_tx_priv_t            *ll_tx_priv     = NULL;
3011171095Ssam	register unsigned int    count           = 0;
3012171095Ssam	unsigned int             nsegs           = 0;
3013171095Ssam	u16                      vlan_tag;
3014171095Ssam
3015171095Ssam	max_fragments = ((xge_hal_fifo_t *)channelh)->config->max_frags;
3016171095Ssam
3017171095Ssam	/* If device is not initialized, return */
3018173139Srwatson	if((!lldev->initialized) || (!(ifnetp->if_drv_flags & IFF_DRV_RUNNING)))
3019199554Sjhb	    return;
3020171095Ssam
3021173139Srwatson	XGE_DRV_STATS(tx_calls);
3022173139Srwatson
3023171095Ssam	/*
3024173139Srwatson	 * This loop will be executed for each packet in the kernel maintained
3025173139Srwatson	 * queue -- each packet can be with fragments as an mbuf chain
3026171095Ssam	 */
3027173139Srwatson	for(;;) {
3028171095Ssam	    IF_DEQUEUE(&ifnetp->if_snd, m_head);
3029199554Sjhb	    if (m_head == NULL) {
3030199554Sjhb		ifnetp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
3031199554Sjhb		return;
3032199554Sjhb	    }
3033171095Ssam
3034173139Srwatson	    for(m_buf = m_head; m_buf != NULL; m_buf = m_buf->m_next) {
3035173139Srwatson	        if(m_buf->m_len) count += 1;
3036171095Ssam	    }
3037171095Ssam
3038171095Ssam	    if(count >= max_fragments) {
3039243857Sglebius	        m_buf = m_defrag(m_head, M_NOWAIT);
3040173139Srwatson	        if(m_buf != NULL) m_head = m_buf;
3041173139Srwatson	        XGE_DRV_STATS(tx_defrag);
3042171095Ssam	    }
3043171095Ssam
3044171095Ssam	    /* Reserve descriptors */
3045173139Srwatson	    status = xge_hal_fifo_dtr_reserve(channelh, &dtr);
3046173139Srwatson	    if(status != XGE_HAL_OK) {
3047173139Srwatson	        XGE_DRV_STATS(tx_no_txd);
3048173139Srwatson	        xge_flush_txds(channelh);
3049199554Sjhb		break;
3050171095Ssam	    }
3051171095Ssam
3052173139Srwatson	    vlan_tag =
3053173139Srwatson	        (m_head->m_flags & M_VLANTAG) ? m_head->m_pkthdr.ether_vtag : 0;
3054171095Ssam	    xge_hal_fifo_dtr_vlan_set(dtr, vlan_tag);
3055171095Ssam
3056171095Ssam	    /* Update Tx private structure for this descriptor */
3057171095Ssam	    ll_tx_priv         = xge_hal_fifo_dtr_private(dtr);
3058171095Ssam	    ll_tx_priv->buffer = m_head;
3059171095Ssam
3060171095Ssam	    /*
3061171095Ssam	     * Do mapping -- Required DMA tag has been created in xge_init
3062171095Ssam	     * function and DMA maps have already been created in the
3063171095Ssam	     * xgell_tx_replenish function.
3064171095Ssam	     * Returns number of segments through nsegs
3065171095Ssam	     */
3066171095Ssam	    if(bus_dmamap_load_mbuf_sg(lldev->dma_tag_tx,
3067171095Ssam	        ll_tx_priv->dma_map, m_head, segs, &nsegs, BUS_DMA_NOWAIT)) {
3068173139Srwatson	        xge_trace(XGE_TRACE, "DMA map load failed");
3069173139Srwatson	        XGE_DRV_STATS(tx_map_fail);
3070199554Sjhb		break;
3071171095Ssam	    }
3072171095Ssam
3073173139Srwatson	    if(lldev->driver_stats.tx_max_frags < nsegs)
3074173139Srwatson	        lldev->driver_stats.tx_max_frags = nsegs;
3075173139Srwatson
3076171095Ssam	    /* Set descriptor buffer for header and each fragment/segment */
3077171095Ssam	    count = 0;
3078171095Ssam	    do {
3079171095Ssam	        xge_hal_fifo_dtr_buffer_set(channelh, dtr, count,
3080171095Ssam	            (dma_addr_t)htole64(segs[count].ds_addr),
3081171095Ssam	            segs[count].ds_len);
3082173139Srwatson	        count++;
3083171095Ssam	    } while(count < nsegs);
3084171095Ssam
3085171095Ssam	    /* Pre-write Sync of mapping */
3086171095Ssam	    bus_dmamap_sync(lldev->dma_tag_tx, ll_tx_priv->dma_map,
3087171095Ssam	        BUS_DMASYNC_PREWRITE);
3088171095Ssam
3089173139Srwatson	    if((lldev->enabled_tso) &&
3090173139Srwatson	        (m_head->m_pkthdr.csum_flags & CSUM_TSO)) {
3091173139Srwatson	        XGE_DRV_STATS(tx_tso);
3092173139Srwatson	        xge_hal_fifo_dtr_mss_set(dtr, m_head->m_pkthdr.tso_segsz);
3093173139Srwatson	    }
3094173139Srwatson
3095171095Ssam	    /* Checksum */
3096171095Ssam	    if(ifnetp->if_hwassist > 0) {
3097171095Ssam	        xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_IPV4_EN
3098171095Ssam	            | XGE_HAL_TXD_TX_CKO_TCP_EN | XGE_HAL_TXD_TX_CKO_UDP_EN);
3099171095Ssam	    }
3100171095Ssam
3101171095Ssam	    /* Post descriptor to FIFO channel */
3102171095Ssam	    xge_hal_fifo_dtr_post(channelh, dtr);
3103173139Srwatson	    XGE_DRV_STATS(tx_posted);
3104171095Ssam
3105171095Ssam	    /* Send the same copy of mbuf packet to BPF (Berkely Packet Filter)
3106171095Ssam	     * listener so that we can use tools like tcpdump */
3107171095Ssam	    ETHER_BPF_MTAP(ifnetp, m_head);
3108171095Ssam	}
3109199554Sjhb
3110171095Ssam	/* Prepend the packet back to queue */
3111171095Ssam	IF_PREPEND(&ifnetp->if_snd, m_head);
3112173139Srwatson	ifnetp->if_drv_flags |= IFF_DRV_OACTIVE;
3113173139Srwatson
3114173139Srwatson	xge_queue_produce_context(xge_hal_device_queue(lldev->devh),
3115173139Srwatson	    XGE_LL_EVENT_TRY_XMIT_AGAIN, lldev->devh);
3116173139Srwatson	XGE_DRV_STATS(tx_again);
3117171095Ssam}
3118171095Ssam
3119173139Srwatson/**
3120173139Srwatson * xge_get_buf
3121173139Srwatson * Allocates new mbufs to be placed into descriptors
3122173139Srwatson *
3123173139Srwatson * @dtrh Descriptor Handle
3124173139Srwatson * @rxd_priv Rx Descriptor Private Data
3125173139Srwatson * @lldev Per-adapter Data
3126173139Srwatson * @index Buffer Index (if multi-buffer mode)
3127173139Srwatson *
3128173139Srwatson * Returns XGE_HAL_OK or HAL error enums
3129173139Srwatson */
3130171095Ssamint
3131173139Srwatsonxge_get_buf(xge_hal_dtr_h dtrh, xge_rx_priv_t *rxd_priv,
3132173139Srwatson	xge_lldev_t *lldev, int index)
3133171095Ssam{
3134171095Ssam	register mbuf_t mp            = NULL;
3135171095Ssam	struct          ifnet *ifnetp = lldev->ifnetp;
3136173139Srwatson	int             status        = XGE_HAL_OK;
3137173139Srwatson	int             buffer_size = 0, cluster_size = 0, count;
3138173139Srwatson	bus_dmamap_t    map = rxd_priv->dmainfo[index].dma_map;
3139173139Srwatson	bus_dma_segment_t segs[3];
3140171095Ssam
3141173139Srwatson	buffer_size = (lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) ?
3142173139Srwatson	    ifnetp->if_mtu + XGE_HAL_MAC_HEADER_MAX_SIZE :
3143173139Srwatson	    lldev->rxd_mbuf_len[index];
3144173139Srwatson
3145173139Srwatson	if(buffer_size <= MCLBYTES) {
3146173139Srwatson	    cluster_size = MCLBYTES;
3147243857Sglebius	    mp = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
3148171095Ssam	}
3149171095Ssam	else {
3150173139Srwatson	    cluster_size = MJUMPAGESIZE;
3151173139Srwatson	    if((lldev->buffer_mode != XGE_HAL_RING_QUEUE_BUFFER_MODE_5) &&
3152173139Srwatson	        (buffer_size > MJUMPAGESIZE)) {
3153173139Srwatson	        cluster_size = MJUM9BYTES;
3154171095Ssam	    }
3155243857Sglebius	    mp = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, cluster_size);
3156171095Ssam	}
3157171095Ssam	if(!mp) {
3158171095Ssam	    xge_trace(XGE_ERR, "Out of memory to allocate mbuf");
3159173139Srwatson	    status = XGE_HAL_FAIL;
3160171095Ssam	    goto getbuf_out;
3161171095Ssam	}
3162171095Ssam
3163171095Ssam	/* Update mbuf's length, packet length and receive interface */
3164173139Srwatson	mp->m_len = mp->m_pkthdr.len = buffer_size;
3165171095Ssam	mp->m_pkthdr.rcvif = ifnetp;
3166171095Ssam
3167171095Ssam	/* Load DMA map */
3168173139Srwatson	if(bus_dmamap_load_mbuf_sg(lldev->dma_tag_rx, lldev->extra_dma_map,
3169173139Srwatson	    mp, segs, &count, BUS_DMA_NOWAIT)) {
3170173139Srwatson	    XGE_DRV_STATS(rx_map_fail);
3171171095Ssam	    m_freem(mp);
3172173139Srwatson	    XGE_EXIT_ON_ERR("DMA map load failed", getbuf_out, XGE_HAL_FAIL);
3173171095Ssam	}
3174171095Ssam
3175171095Ssam	/* Update descriptor private data */
3176171095Ssam	rxd_priv->bufferArray[index]         = mp;
3177173139Srwatson	rxd_priv->dmainfo[index].dma_phyaddr = htole64(segs->ds_addr);
3178173139Srwatson	rxd_priv->dmainfo[index].dma_map     = lldev->extra_dma_map;
3179173139Srwatson	lldev->extra_dma_map = map;
3180171095Ssam
3181171095Ssam	/* Pre-Read/Write sync */
3182173139Srwatson	bus_dmamap_sync(lldev->dma_tag_rx, map, BUS_DMASYNC_POSTREAD);
3183171095Ssam
3184173139Srwatson	/* Unload DMA map of mbuf in current descriptor */
3185173139Srwatson	bus_dmamap_unload(lldev->dma_tag_rx, map);
3186173139Srwatson
3187171095Ssam	/* Set descriptor buffer */
3188171095Ssam	if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
3189171095Ssam	    xge_hal_ring_dtr_1b_set(dtrh, rxd_priv->dmainfo[0].dma_phyaddr,
3190173139Srwatson	        cluster_size);
3191171095Ssam	}
3192171095Ssam
3193171095Ssamgetbuf_out:
3194173139Srwatson	return status;
3195171095Ssam}
3196171095Ssam
3197173139Srwatson/**
3198173139Srwatson * xge_get_buf_3b_5b
3199173139Srwatson * Allocates new mbufs to be placed into descriptors (in multi-buffer modes)
3200173139Srwatson *
3201173139Srwatson * @dtrh Descriptor Handle
3202173139Srwatson * @rxd_priv Rx Descriptor Private Data
3203173139Srwatson * @lldev Per-adapter Data
3204173139Srwatson *
3205173139Srwatson * Returns XGE_HAL_OK or HAL error enums
3206173139Srwatson */
3207171095Ssamint
3208173139Srwatsonxge_get_buf_3b_5b(xge_hal_dtr_h dtrh, xge_rx_priv_t *rxd_priv,
3209173139Srwatson	xge_lldev_t *lldev)
3210171095Ssam{
3211171095Ssam	bus_addr_t  dma_pointers[5];
3212171095Ssam	int         dma_sizes[5];
3213173139Srwatson	int         status = XGE_HAL_OK, index;
3214171095Ssam	int         newindex = 0;
3215171095Ssam
3216171095Ssam	for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
3217173139Srwatson	    status = xge_get_buf(dtrh, rxd_priv, lldev, index);
3218173139Srwatson	    if(status != XGE_HAL_OK) {
3219171095Ssam	        for(newindex = 0; newindex < index; newindex++) {
3220171095Ssam	            m_freem(rxd_priv->bufferArray[newindex]);
3221171095Ssam	        }
3222173139Srwatson	        XGE_EXIT_ON_ERR("mbuf allocation failed", _exit, status);
3223171095Ssam	    }
3224171095Ssam	}
3225171095Ssam
3226171095Ssam	for(index = 0; index < lldev->buffer_mode; index++) {
3227171095Ssam	    if(lldev->rxd_mbuf_len[index] != 0) {
3228171095Ssam	        dma_pointers[index] = rxd_priv->dmainfo[index].dma_phyaddr;
3229171095Ssam	        dma_sizes[index]    = lldev->rxd_mbuf_len[index];
3230171095Ssam	    }
3231171095Ssam	    else {
3232171095Ssam	        dma_pointers[index] = rxd_priv->dmainfo[index-1].dma_phyaddr;
3233171095Ssam	        dma_sizes[index]    = 1;
3234171095Ssam	    }
3235171095Ssam	}
3236171095Ssam
3237171095Ssam	/* Assigning second buffer to third pointer in 2 buffer mode */
3238171095Ssam	if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_2) {
3239171095Ssam	    dma_pointers[2] = dma_pointers[1];
3240171095Ssam	    dma_sizes[2]    = dma_sizes[1];
3241171095Ssam	    dma_sizes[1]    = 1;
3242171095Ssam	}
3243171095Ssam
3244171095Ssam	if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_5) {
3245171095Ssam	    xge_hal_ring_dtr_5b_set(dtrh, dma_pointers, dma_sizes);
3246171095Ssam	}
3247171095Ssam	else {
3248171095Ssam	    xge_hal_ring_dtr_3b_set(dtrh, dma_pointers, dma_sizes);
3249171095Ssam	}
3250171095Ssam
3251173139Srwatson_exit:
3252173139Srwatson	return status;
3253171095Ssam}
3254171095Ssam
3255173139Srwatson/**
3256173139Srwatson * xge_tx_compl
3257173139Srwatson * If the interrupt is due to Tx completion, free the sent buffer
3258173139Srwatson *
3259173139Srwatson * @channelh Channel Handle
3260173139Srwatson * @dtr Descriptor
3261173139Srwatson * @t_code Transfer Code indicating success or error
3262173139Srwatson * @userdata Per-adapter Data
3263173139Srwatson *
3264173139Srwatson * Returns XGE_HAL_OK or HAL error enum
3265173139Srwatson */
3266171095Ssamxge_hal_status_e
3267173139Srwatsonxge_tx_compl(xge_hal_channel_h channelh,
3268171095Ssam	xge_hal_dtr_h dtr, u8 t_code, void *userdata)
3269171095Ssam{
3270173139Srwatson	xge_tx_priv_t *ll_tx_priv = NULL;
3271173139Srwatson	xge_lldev_t   *lldev  = (xge_lldev_t *)userdata;
3272173139Srwatson	struct ifnet  *ifnetp = lldev->ifnetp;
3273173139Srwatson	mbuf_t         m_buffer = NULL;
3274173139Srwatson	int            qindex   = xge_hal_channel_id(channelh);
3275171095Ssam
3276173139Srwatson	mtx_lock(&lldev->mtx_tx[qindex]);
3277173139Srwatson
3278173139Srwatson	XGE_DRV_STATS(tx_completions);
3279173139Srwatson
3280173139Srwatson	/*
3281173139Srwatson	 * For each completed descriptor: Get private structure, free buffer,
3282173139Srwatson	 * do unmapping, and free descriptor
3283173139Srwatson	 */
3284171095Ssam	do {
3285173139Srwatson	    XGE_DRV_STATS(tx_desc_compl);
3286173139Srwatson
3287171095Ssam	    if(t_code) {
3288173139Srwatson	        XGE_DRV_STATS(tx_tcode);
3289171095Ssam	        xge_trace(XGE_TRACE, "t_code %d", t_code);
3290171095Ssam	        xge_hal_device_handle_tcode(channelh, dtr, t_code);
3291171095Ssam	    }
3292171095Ssam
3293171095Ssam	    ll_tx_priv = xge_hal_fifo_dtr_private(dtr);
3294171095Ssam	    m_buffer   = ll_tx_priv->buffer;
3295171095Ssam	    bus_dmamap_unload(lldev->dma_tag_tx, ll_tx_priv->dma_map);
3296171095Ssam	    m_freem(m_buffer);
3297171095Ssam	    ll_tx_priv->buffer = NULL;
3298171095Ssam	    xge_hal_fifo_dtr_free(channelh, dtr);
3299171095Ssam	} while(xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code)
3300171095Ssam	    == XGE_HAL_OK);
3301173139Srwatson	xge_send_locked(ifnetp, qindex);
3302171095Ssam	ifnetp->if_drv_flags &= ~IFF_DRV_OACTIVE;
3303171095Ssam
3304173139Srwatson	mtx_unlock(&lldev->mtx_tx[qindex]);
3305173139Srwatson
3306171095Ssam	return XGE_HAL_OK;
3307171095Ssam}
3308171095Ssam
3309173139Srwatson/**
3310173139Srwatson * xge_tx_initial_replenish
3311173139Srwatson * Initially allocate buffers and set them into descriptors for later use
3312173139Srwatson *
3313173139Srwatson * @channelh Tx Channel Handle
3314173139Srwatson * @dtrh Descriptor Handle
3315173139Srwatson * @index
3316173139Srwatson * @userdata Per-adapter Data
3317173139Srwatson * @reopen Channel open/reopen option
3318173139Srwatson *
3319173139Srwatson * Returns XGE_HAL_OK or HAL error enums
3320173139Srwatson */
3321171095Ssamxge_hal_status_e
3322173139Srwatsonxge_tx_initial_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
3323171095Ssam	int index, void *userdata, xge_hal_channel_reopen_e reopen)
3324171095Ssam{
3325173139Srwatson	xge_tx_priv_t *txd_priv = NULL;
3326173139Srwatson	int            status   = XGE_HAL_OK;
3327171095Ssam
3328171095Ssam	/* Get the user data portion from channel handle */
3329173139Srwatson	xge_lldev_t *lldev = xge_hal_channel_userdata(channelh);
3330171095Ssam	if(lldev == NULL) {
3331173139Srwatson	    XGE_EXIT_ON_ERR("Failed to get user data from channel", txinit_out,
3332173139Srwatson	        XGE_HAL_FAIL);
3333171095Ssam	}
3334171095Ssam
3335171095Ssam	/* Get the private data */
3336173139Srwatson	txd_priv = (xge_tx_priv_t *) xge_hal_fifo_dtr_private(dtrh);
3337171095Ssam	if(txd_priv == NULL) {
3338173139Srwatson	    XGE_EXIT_ON_ERR("Failed to get descriptor private data", txinit_out,
3339173139Srwatson	        XGE_HAL_FAIL);
3340171095Ssam	}
3341171095Ssam
3342171095Ssam	/* Create DMA map for this descriptor */
3343171095Ssam	if(bus_dmamap_create(lldev->dma_tag_tx, BUS_DMA_NOWAIT,
3344171095Ssam	    &txd_priv->dma_map)) {
3345173139Srwatson	    XGE_EXIT_ON_ERR("DMA map creation for Tx descriptor failed",
3346173139Srwatson	        txinit_out, XGE_HAL_FAIL);
3347171095Ssam	}
3348171095Ssam
3349171095Ssamtxinit_out:
3350173139Srwatson	return status;
3351171095Ssam}
3352171095Ssam
3353173139Srwatson/**
3354173139Srwatson * xge_rx_initial_replenish
3355173139Srwatson * Initially allocate buffers and set them into descriptors for later use
3356173139Srwatson *
3357173139Srwatson * @channelh Tx Channel Handle
3358173139Srwatson * @dtrh Descriptor Handle
3359173139Srwatson * @index Ring Index
3360173139Srwatson * @userdata Per-adapter Data
3361173139Srwatson * @reopen Channel open/reopen option
3362173139Srwatson *
3363173139Srwatson * Returns XGE_HAL_OK or HAL error enums
3364173139Srwatson */
3365171095Ssamxge_hal_status_e
3366173139Srwatsonxge_rx_initial_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
3367171095Ssam	int index, void *userdata, xge_hal_channel_reopen_e reopen)
3368171095Ssam{
3369173139Srwatson	xge_rx_priv_t  *rxd_priv = NULL;
3370173139Srwatson	int             status   = XGE_HAL_OK;
3371173139Srwatson	int             index1 = 0, index2 = 0;
3372171095Ssam
3373171095Ssam	/* Get the user data portion from channel handle */
3374173139Srwatson	xge_lldev_t *lldev = xge_hal_channel_userdata(channelh);
3375171095Ssam	if(lldev == NULL) {
3376173139Srwatson	    XGE_EXIT_ON_ERR("Failed to get user data from channel", rxinit_out,
3377173139Srwatson	        XGE_HAL_FAIL);
3378171095Ssam	}
3379171095Ssam
3380171095Ssam	/* Get the private data */
3381173139Srwatson	rxd_priv = (xge_rx_priv_t *) xge_hal_ring_dtr_private(channelh, dtrh);
3382171095Ssam	if(rxd_priv == NULL) {
3383173139Srwatson	    XGE_EXIT_ON_ERR("Failed to get descriptor private data", rxinit_out,
3384173139Srwatson	        XGE_HAL_FAIL);
3385171095Ssam	}
3386171095Ssam
3387173139Srwatson	rxd_priv->bufferArray = xge_os_malloc(NULL,
3388173139Srwatson	        (sizeof(rxd_priv->bufferArray) * lldev->rxd_mbuf_cnt));
3389171095Ssam
3390171095Ssam	if(rxd_priv->bufferArray == NULL) {
3391173139Srwatson	    XGE_EXIT_ON_ERR("Failed to allocate Rxd private", rxinit_out,
3392173139Srwatson	        XGE_HAL_FAIL);
3393171095Ssam	}
3394171095Ssam
3395171095Ssam	if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
3396171095Ssam	    /* Create DMA map for these descriptors*/
3397171095Ssam	    if(bus_dmamap_create(lldev->dma_tag_rx , BUS_DMA_NOWAIT,
3398171095Ssam	        &rxd_priv->dmainfo[0].dma_map)) {
3399173139Srwatson	        XGE_EXIT_ON_ERR("DMA map creation for Rx descriptor failed",
3400173139Srwatson	            rxinit_err_out, XGE_HAL_FAIL);
3401171095Ssam	    }
3402171095Ssam	    /* Get a buffer, attach it to this descriptor */
3403173139Srwatson	    status = xge_get_buf(dtrh, rxd_priv, lldev, 0);
3404171095Ssam	}
3405171095Ssam	else {
3406171095Ssam	    for(index1 = 0; index1 < lldev->rxd_mbuf_cnt; index1++) {
3407171095Ssam	        /* Create DMA map for this descriptor */
3408171095Ssam	        if(bus_dmamap_create(lldev->dma_tag_rx , BUS_DMA_NOWAIT ,
3409171095Ssam	            &rxd_priv->dmainfo[index1].dma_map)) {
3410171095Ssam	            for(index2 = index1 - 1; index2 >= 0; index2--) {
3411171095Ssam	                bus_dmamap_destroy(lldev->dma_tag_rx,
3412171095Ssam	                    rxd_priv->dmainfo[index2].dma_map);
3413171095Ssam	            }
3414173139Srwatson	            XGE_EXIT_ON_ERR(
3415173139Srwatson	                "Jumbo DMA map creation for Rx descriptor failed",
3416173139Srwatson	                rxinit_err_out, XGE_HAL_FAIL);
3417171095Ssam	        }
3418171095Ssam	    }
3419173139Srwatson	    status = xge_get_buf_3b_5b(dtrh, rxd_priv, lldev);
3420171095Ssam	}
3421171095Ssam
3422173139Srwatson	if(status != XGE_HAL_OK) {
3423171095Ssam	    for(index1 = 0; index1 < lldev->rxd_mbuf_cnt; index1++) {
3424171095Ssam	        bus_dmamap_destroy(lldev->dma_tag_rx,
3425171095Ssam	            rxd_priv->dmainfo[index1].dma_map);
3426171095Ssam	    }
3427171095Ssam	    goto rxinit_err_out;
3428171095Ssam	}
3429171095Ssam	else {
3430171095Ssam	    goto rxinit_out;
3431171095Ssam	}
3432171095Ssam
3433171095Ssamrxinit_err_out:
3434173139Srwatson	xge_os_free(NULL, rxd_priv->bufferArray,
3435173139Srwatson	    (sizeof(rxd_priv->bufferArray) * lldev->rxd_mbuf_cnt));
3436171095Ssamrxinit_out:
3437173139Srwatson	return status;
3438171095Ssam}
3439171095Ssam
3440173139Srwatson/**
3441173139Srwatson * xge_rx_term
3442173139Srwatson * During unload terminate and free all descriptors
3443173139Srwatson *
3444173139Srwatson * @channelh Rx Channel Handle
3445173139Srwatson * @dtrh Rx Descriptor Handle
3446173139Srwatson * @state Descriptor State
3447173139Srwatson * @userdata Per-adapter Data
3448173139Srwatson * @reopen Channel open/reopen option
3449173139Srwatson */
3450171095Ssamvoid
3451173139Srwatsonxge_rx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
3452171095Ssam	xge_hal_dtr_state_e state, void *userdata,
3453171095Ssam	xge_hal_channel_reopen_e reopen)
3454171095Ssam{
3455173139Srwatson	xge_rx_priv_t *rxd_priv = NULL;
3456173139Srwatson	xge_lldev_t   *lldev    = NULL;
3457173139Srwatson	int            index = 0;
3458171095Ssam
3459171095Ssam	/* Descriptor state is not "Posted" */
3460173139Srwatson	if(state != XGE_HAL_DTR_STATE_POSTED) goto rxterm_out;
3461171095Ssam
3462171095Ssam	/* Get the user data portion */
3463171095Ssam	lldev = xge_hal_channel_userdata(channelh);
3464171095Ssam
3465171095Ssam	/* Get the private data */
3466173139Srwatson	rxd_priv = (xge_rx_priv_t *) xge_hal_ring_dtr_private(channelh, dtrh);
3467171095Ssam
3468173139Srwatson	for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
3469173139Srwatson	    if(rxd_priv->dmainfo[index].dma_map != NULL) {
3470171095Ssam	        bus_dmamap_sync(lldev->dma_tag_rx,
3471171095Ssam	            rxd_priv->dmainfo[index].dma_map, BUS_DMASYNC_POSTREAD);
3472171095Ssam	        bus_dmamap_unload(lldev->dma_tag_rx,
3473171095Ssam	            rxd_priv->dmainfo[index].dma_map);
3474173139Srwatson	        if(rxd_priv->bufferArray[index] != NULL)
3475173139Srwatson	            m_free(rxd_priv->bufferArray[index]);
3476171095Ssam	        bus_dmamap_destroy(lldev->dma_tag_rx,
3477171095Ssam	            rxd_priv->dmainfo[index].dma_map);
3478171095Ssam	    }
3479171095Ssam	}
3480173139Srwatson	xge_os_free(NULL, rxd_priv->bufferArray,
3481173139Srwatson	    (sizeof(rxd_priv->bufferArray) * lldev->rxd_mbuf_cnt));
3482171095Ssam
3483171095Ssam	/* Free the descriptor */
3484171095Ssam	xge_hal_ring_dtr_free(channelh, dtrh);
3485171095Ssam
3486171095Ssamrxterm_out:
3487171095Ssam	return;
3488171095Ssam}
3489171095Ssam
3490173139Srwatson/**
3491173139Srwatson * xge_tx_term
3492173139Srwatson * During unload terminate and free all descriptors
3493173139Srwatson *
3494173139Srwatson * @channelh Rx Channel Handle
3495173139Srwatson * @dtrh Rx Descriptor Handle
3496173139Srwatson * @state Descriptor State
3497173139Srwatson * @userdata Per-adapter Data
3498173139Srwatson * @reopen Channel open/reopen option
3499173139Srwatson */
3500171095Ssamvoid
3501173139Srwatsonxge_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtr,
3502171095Ssam	xge_hal_dtr_state_e state, void *userdata,
3503171095Ssam	xge_hal_channel_reopen_e reopen)
3504171095Ssam{
3505173139Srwatson	xge_tx_priv_t *ll_tx_priv = xge_hal_fifo_dtr_private(dtr);
3506173139Srwatson	xge_lldev_t   *lldev      = (xge_lldev_t *)userdata;
3507171095Ssam
3508171095Ssam	/* Destroy DMA map */
3509171095Ssam	bus_dmamap_destroy(lldev->dma_tag_tx, ll_tx_priv->dma_map);
3510171095Ssam}
3511171095Ssam
3512173139Srwatson/**
3513171095Ssam * xge_methods
3514171095Ssam *
3515171095Ssam * FreeBSD device interface entry points
3516173139Srwatson */
3517171095Ssamstatic device_method_t xge_methods[] = {
3518171095Ssam	DEVMETHOD(device_probe,     xge_probe),
3519171095Ssam	DEVMETHOD(device_attach,    xge_attach),
3520171095Ssam	DEVMETHOD(device_detach,    xge_detach),
3521171095Ssam	DEVMETHOD(device_shutdown,  xge_shutdown),
3522246128Ssbz
3523246128Ssbz	DEVMETHOD_END
3524171095Ssam};
3525171095Ssam
3526171095Ssamstatic driver_t xge_driver = {
3527171095Ssam	"nxge",
3528171095Ssam	xge_methods,
3529173139Srwatson	sizeof(xge_lldev_t),
3530171095Ssam};
3531171095Ssamstatic devclass_t xge_devclass;
3532171095SsamDRIVER_MODULE(nxge, pci, xge_driver, xge_devclass, 0, 0);
3533173139Srwatson
3534