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$
27171095Ssam */
28171095Ssam
29171095Ssam#ifdef XGE_DEBUG_FP
30171095Ssam#include <dev/nxge/include/xgehal-device.h>
31171095Ssam#endif
32171095Ssam
33171095Ssam#include <dev/nxge/include/xgehal-ring.h>
34171095Ssam#include <dev/nxge/include/xgehal-fifo.h>
35171095Ssam
36171095Ssam/**
37171095Ssam * xge_hal_device_bar0 - Get BAR0 mapped address.
38171095Ssam * @hldev: HAL device handle.
39171095Ssam *
40173139Srwatson * Returns: BAR0 address of the specified device.
41171095Ssam */
42173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE char *
43171095Ssamxge_hal_device_bar0(xge_hal_device_t *hldev)
44171095Ssam{
45171095Ssam	return hldev->bar0;
46171095Ssam}
47171095Ssam
48171095Ssam/**
49173139Srwatson * xge_hal_device_isrbar0 - Get BAR0 mapped address.
50171095Ssam * @hldev: HAL device handle.
51171095Ssam *
52173139Srwatson * Returns: BAR0 address of the specified device.
53171095Ssam */
54173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE char *
55173139Srwatsonxge_hal_device_isrbar0(xge_hal_device_t *hldev)
56171095Ssam{
57171095Ssam	return hldev->isrbar0;
58171095Ssam}
59171095Ssam
60171095Ssam/**
61171095Ssam * xge_hal_device_bar1 - Get BAR1 mapped address.
62171095Ssam * @hldev: HAL device handle.
63171095Ssam *
64173139Srwatson * Returns: BAR1 address of the specified device.
65171095Ssam */
66173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE char *
67171095Ssamxge_hal_device_bar1(xge_hal_device_t *hldev)
68171095Ssam{
69171095Ssam	return hldev->bar1;
70171095Ssam}
71171095Ssam
72171095Ssam/**
73171095Ssam * xge_hal_device_bar0_set - Set BAR0 mapped address.
74171095Ssam * @hldev: HAL device handle.
75171095Ssam * @bar0: BAR0 mapped address.
76173139Srwatson * * Set BAR0 address in the HAL device object.
77171095Ssam */
78173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
79171095Ssamxge_hal_device_bar0_set(xge_hal_device_t *hldev, char *bar0)
80171095Ssam{
81171095Ssam	xge_assert(bar0);
82173139Srwatson	hldev->bar0 = bar0;
83171095Ssam}
84171095Ssam
85171095Ssam/**
86173139Srwatson * xge_hal_device_isrbar0_set - Set BAR0 mapped address.
87171095Ssam * @hldev: HAL device handle.
88171095Ssam * @isrbar0: BAR0 mapped address.
89173139Srwatson * * Set BAR0 address in the HAL device object.
90171095Ssam */
91173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
92173139Srwatsonxge_hal_device_isrbar0_set(xge_hal_device_t *hldev, char *isrbar0)
93171095Ssam{
94171095Ssam	xge_assert(isrbar0);
95171095Ssam	hldev->isrbar0 = isrbar0;
96171095Ssam}
97171095Ssam
98171095Ssam/**
99171095Ssam * xge_hal_device_bar1_set - Set BAR1 mapped address.
100171095Ssam * @hldev: HAL device handle.
101171095Ssam * @channelh: Channel handle.
102171095Ssam * @bar1: BAR1 mapped address.
103171095Ssam *
104173139Srwatson * Set BAR1 address for the given channel.
105171095Ssam */
106173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
107171095Ssamxge_hal_device_bar1_set(xge_hal_device_t *hldev, xge_hal_channel_h channelh,
108173139Srwatson	           char *bar1)
109171095Ssam{
110171095Ssam	xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
111171095Ssam
112171095Ssam	xge_assert(bar1);
113171095Ssam	xge_assert(fifo);
114171095Ssam
115173139Srwatson	/* Initializing the BAR1 address as the start of
116173139Srwatson	 * the FIFO queue pointer and as a location of FIFO control
117171095Ssam	 * word. */
118171095Ssam	fifo->hw_pair =
119173139Srwatson	        (xge_hal_fifo_hw_pair_t *) (bar1 +
120173139Srwatson	            (fifo->channel.post_qid * XGE_HAL_FIFO_HW_PAIR_OFFSET));
121173139Srwatson	hldev->bar1 = bar1;
122171095Ssam}
123171095Ssam
124171095Ssam
125171095Ssam/**
126173139Srwatson * xge_hal_device_rev - Get Device revision number.
127171095Ssam * @hldev: HAL device handle.
128171095Ssam *
129173139Srwatson * Returns: Device revision number
130171095Ssam */
131173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE int
132173139Srwatsonxge_hal_device_rev(xge_hal_device_t *hldev)
133171095Ssam{
134173139Srwatson	    return hldev->revision;
135171095Ssam}
136171095Ssam
137171095Ssam
138171095Ssam/**
139173139Srwatson * xge_hal_device_begin_irq - Begin IRQ processing.
140171095Ssam * @hldev: HAL device handle.
141173139Srwatson * @reason: "Reason" for the interrupt, the value of Xframe's
142173139Srwatson *          general_int_status register.
143171095Ssam *
144173139Srwatson * The function performs two actions, It first checks whether (shared IRQ) the
145173139Srwatson * interrupt was raised by the device. Next, it masks the device interrupts.
146171095Ssam *
147171095Ssam * Note:
148171095Ssam * xge_hal_device_begin_irq() does not flush MMIO writes through the
149171095Ssam * bridge. Therefore, two back-to-back interrupts are potentially possible.
150173139Srwatson * It is the responsibility of the ULD to make sure that only one
151171095Ssam * xge_hal_device_continue_irq() runs at a time.
152171095Ssam *
153173139Srwatson * Returns: 0, if the interrupt is not "ours" (note that in this case the
154171095Ssam * device remain enabled).
155171095Ssam * Otherwise, xge_hal_device_begin_irq() returns 64bit general adapter
156171095Ssam * status.
157171095Ssam * See also: xge_hal_device_handle_irq()
158171095Ssam */
159173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
160171095Ssamxge_hal_device_begin_irq(xge_hal_device_t *hldev, u64 *reason)
161171095Ssam{
162173139Srwatson	u64 val64;
163173139Srwatson	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
164171095Ssam
165171095Ssam	hldev->stats.sw_dev_info_stats.total_intr_cnt++;
166171095Ssam
167173139Srwatson	val64 = xge_os_pio_mem_read64(hldev->pdev,
168173139Srwatson	              hldev->regh0, &isrbar0->general_int_status);
169171095Ssam	if (xge_os_unlikely(!val64)) {
170173139Srwatson	    /* not Xframe interrupt */
171173139Srwatson	    hldev->stats.sw_dev_info_stats.not_xge_intr_cnt++;
172173139Srwatson	    *reason = 0;
173173139Srwatson	        return XGE_HAL_ERR_WRONG_IRQ;
174171095Ssam	}
175171095Ssam
176171095Ssam	if (xge_os_unlikely(val64 == XGE_HAL_ALL_FOXES)) {
177173139Srwatson	            u64 adapter_status =
178173139Srwatson	                    xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
179173139Srwatson	                      &isrbar0->adapter_status);
180173139Srwatson	            if (adapter_status == XGE_HAL_ALL_FOXES)  {
181173139Srwatson	                (void) xge_queue_produce(hldev->queueh,
182173139Srwatson	                     XGE_HAL_EVENT_SLOT_FREEZE,
183173139Srwatson	                     hldev,
184173139Srwatson	                     1,  /* critical: slot freeze */
185173139Srwatson	                     sizeof(u64),
186173139Srwatson	                     (void*)&adapter_status);
187173139Srwatson	        *reason = 0;
188173139Srwatson	        return XGE_HAL_ERR_CRITICAL;
189173139Srwatson	    }
190171095Ssam	}
191171095Ssam
192173139Srwatson	*reason = val64;
193171095Ssam
194173139Srwatson	/* separate fast path, i.e. no errors */
195173139Srwatson	if (val64 & XGE_HAL_GEN_INTR_RXTRAFFIC) {
196173139Srwatson	    hldev->stats.sw_dev_info_stats.rx_traffic_intr_cnt++;
197173139Srwatson	    return XGE_HAL_OK;
198171095Ssam	}
199173139Srwatson	if (val64 & XGE_HAL_GEN_INTR_TXTRAFFIC) {
200173139Srwatson	    hldev->stats.sw_dev_info_stats.tx_traffic_intr_cnt++;
201173139Srwatson	    return XGE_HAL_OK;
202171095Ssam	}
203171095Ssam
204171095Ssam	hldev->stats.sw_dev_info_stats.not_traffic_intr_cnt++;
205173139Srwatson	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_TXPIC)) {
206173139Srwatson	    xge_hal_status_e status;
207173139Srwatson	    hldev->stats.sw_dev_info_stats.txpic_intr_cnt++;
208173139Srwatson	    status = __hal_device_handle_txpic(hldev, val64);
209173139Srwatson	    if (status != XGE_HAL_OK) {
210173139Srwatson	        return status;
211173139Srwatson	    }
212171095Ssam	}
213171095Ssam
214173139Srwatson	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_TXDMA)) {
215173139Srwatson	    xge_hal_status_e status;
216173139Srwatson	    hldev->stats.sw_dev_info_stats.txdma_intr_cnt++;
217173139Srwatson	    status = __hal_device_handle_txdma(hldev, val64);
218173139Srwatson	    if (status != XGE_HAL_OK) {
219173139Srwatson	        return status;
220173139Srwatson	    }
221171095Ssam	}
222171095Ssam
223173139Srwatson	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_TXMAC)) {
224173139Srwatson	    xge_hal_status_e status;
225173139Srwatson	    hldev->stats.sw_dev_info_stats.txmac_intr_cnt++;
226173139Srwatson	    status = __hal_device_handle_txmac(hldev, val64);
227173139Srwatson	    if (status != XGE_HAL_OK) {
228173139Srwatson	        return status;
229173139Srwatson	    }
230171095Ssam	}
231171095Ssam
232173139Srwatson	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_TXXGXS)) {
233173139Srwatson	    xge_hal_status_e status;
234173139Srwatson	    hldev->stats.sw_dev_info_stats.txxgxs_intr_cnt++;
235173139Srwatson	    status = __hal_device_handle_txxgxs(hldev, val64);
236173139Srwatson	    if (status != XGE_HAL_OK) {
237173139Srwatson	        return status;
238173139Srwatson	    }
239171095Ssam	}
240171095Ssam
241173139Srwatson	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_RXPIC)) {
242173139Srwatson	    xge_hal_status_e status;
243173139Srwatson	    hldev->stats.sw_dev_info_stats.rxpic_intr_cnt++;
244173139Srwatson	    status = __hal_device_handle_rxpic(hldev, val64);
245173139Srwatson	    if (status != XGE_HAL_OK) {
246173139Srwatson	        return status;
247173139Srwatson	    }
248171095Ssam	}
249171095Ssam
250173139Srwatson	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_RXDMA)) {
251173139Srwatson	    xge_hal_status_e status;
252173139Srwatson	    hldev->stats.sw_dev_info_stats.rxdma_intr_cnt++;
253173139Srwatson	    status = __hal_device_handle_rxdma(hldev, val64);
254173139Srwatson	    if (status != XGE_HAL_OK) {
255173139Srwatson	        return status;
256173139Srwatson	    }
257171095Ssam	}
258171095Ssam
259173139Srwatson	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_RXMAC)) {
260173139Srwatson	    xge_hal_status_e status;
261173139Srwatson	    hldev->stats.sw_dev_info_stats.rxmac_intr_cnt++;
262173139Srwatson	    status = __hal_device_handle_rxmac(hldev, val64);
263173139Srwatson	    if (status != XGE_HAL_OK) {
264173139Srwatson	        return status;
265173139Srwatson	    }
266171095Ssam	}
267171095Ssam
268173139Srwatson	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_RXXGXS)) {
269173139Srwatson	    xge_hal_status_e status;
270173139Srwatson	    hldev->stats.sw_dev_info_stats.rxxgxs_intr_cnt++;
271173139Srwatson	    status = __hal_device_handle_rxxgxs(hldev, val64);
272173139Srwatson	    if (status != XGE_HAL_OK) {
273173139Srwatson	        return status;
274173139Srwatson	    }
275171095Ssam	}
276171095Ssam
277173139Srwatson	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_MC)) {
278173139Srwatson	    xge_hal_status_e status;
279173139Srwatson	    hldev->stats.sw_dev_info_stats.mc_intr_cnt++;
280173139Srwatson	    status = __hal_device_handle_mc(hldev, val64);
281173139Srwatson	    if (status != XGE_HAL_OK) {
282173139Srwatson	        return status;
283173139Srwatson	    }
284171095Ssam	}
285171095Ssam
286171095Ssam	return XGE_HAL_OK;
287171095Ssam}
288171095Ssam
289171095Ssam/**
290171095Ssam * xge_hal_device_clear_rx - Acknowledge (that is, clear) the
291173139Srwatson * condition that has caused the RX interrupt.
292171095Ssam * @hldev: HAL device handle.
293171095Ssam *
294173139Srwatson * Acknowledge (that is, clear) the condition that has caused
295171095Ssam * the Rx interrupt.
296171095Ssam * See also: xge_hal_device_begin_irq(), xge_hal_device_continue_irq(),
297171095Ssam * xge_hal_device_clear_tx(), xge_hal_device_mask_rx().
298171095Ssam */
299173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
300171095Ssamxge_hal_device_clear_rx(xge_hal_device_t *hldev)
301171095Ssam{
302173139Srwatson	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
303171095Ssam
304173139Srwatson	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
305173139Srwatson	             0xFFFFFFFFFFFFFFFFULL,
306173139Srwatson	             &isrbar0->rx_traffic_int);
307171095Ssam}
308171095Ssam
309171095Ssam/**
310171095Ssam * xge_hal_device_clear_tx - Acknowledge (that is, clear) the
311173139Srwatson * condition that has caused the TX interrupt.
312171095Ssam * @hldev: HAL device handle.
313171095Ssam *
314173139Srwatson * Acknowledge (that is, clear) the condition that has caused
315171095Ssam * the Tx interrupt.
316171095Ssam * See also: xge_hal_device_begin_irq(), xge_hal_device_continue_irq(),
317171095Ssam * xge_hal_device_clear_rx(), xge_hal_device_mask_tx().
318171095Ssam */
319173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
320171095Ssamxge_hal_device_clear_tx(xge_hal_device_t *hldev)
321171095Ssam{
322173139Srwatson	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
323171095Ssam
324173139Srwatson	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
325173139Srwatson	             0xFFFFFFFFFFFFFFFFULL,
326173139Srwatson	             &isrbar0->tx_traffic_int);
327171095Ssam}
328171095Ssam
329171095Ssam/**
330173139Srwatson * xge_hal_device_poll_rx_channel - Poll Rx channel for completed
331171095Ssam * descriptors and process the same.
332171095Ssam * @channel: HAL channel.
333171095Ssam * @got_rx: Buffer to return the flag set if receive interrupt is occured
334171095Ssam *
335173139Srwatson * The function polls the Rx channel for the completed  descriptors and calls
336173139Srwatson * the upper-layer driver (ULD) via supplied completion callback.
337171095Ssam *
338173139Srwatson * Returns: XGE_HAL_OK, if the polling is completed successful.
339173139Srwatson * XGE_HAL_COMPLETIONS_REMAIN: There are still more completed
340171095Ssam * descriptors available which are yet to be processed.
341171095Ssam *
342171095Ssam * See also: xge_hal_device_poll_tx_channel()
343171095Ssam */
344173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
345171095Ssamxge_hal_device_poll_rx_channel(xge_hal_channel_t *channel, int *got_rx)
346171095Ssam{
347171095Ssam	xge_hal_status_e ret = XGE_HAL_OK;
348171095Ssam	xge_hal_dtr_h first_dtrh;
349171095Ssam	xge_hal_device_t *hldev = (xge_hal_device_t *)channel->devh;
350171095Ssam	u8 t_code;
351171095Ssam	int got_bytes;
352171095Ssam
353171095Ssam	/* for each opened rx channel */
354171095Ssam	got_bytes = *got_rx = 0;
355171095Ssam	((xge_hal_ring_t *)channel)->cmpl_cnt = 0;
356171095Ssam	channel->poll_bytes = 0;
357171095Ssam	if ((ret = xge_hal_ring_dtr_next_completed (channel, &first_dtrh,
358173139Srwatson	    &t_code)) == XGE_HAL_OK) {
359173139Srwatson	    if (channel->callback(channel, first_dtrh,
360173139Srwatson	        t_code, channel->userdata) != XGE_HAL_OK) {
361173139Srwatson	        (*got_rx) += ((xge_hal_ring_t *)channel)->cmpl_cnt + 1;
362173139Srwatson	        got_bytes += channel->poll_bytes + 1;
363173139Srwatson	        ret = XGE_HAL_COMPLETIONS_REMAIN;
364173139Srwatson	    } else {
365173139Srwatson	        (*got_rx) += ((xge_hal_ring_t *)channel)->cmpl_cnt + 1;
366173139Srwatson	        got_bytes += channel->poll_bytes + 1;
367173139Srwatson	    }
368171095Ssam	}
369171095Ssam
370171095Ssam	if (*got_rx) {
371173139Srwatson	    hldev->irq_workload_rxd[channel->post_qid] += *got_rx;
372173139Srwatson	    hldev->irq_workload_rxcnt[channel->post_qid] ++;
373171095Ssam	}
374171095Ssam	hldev->irq_workload_rxlen[channel->post_qid] += got_bytes;
375171095Ssam
376171095Ssam	return ret;
377171095Ssam}
378171095Ssam
379171095Ssam/**
380173139Srwatson * xge_hal_device_poll_tx_channel - Poll Tx channel for completed
381171095Ssam * descriptors and process the same.
382171095Ssam * @channel: HAL channel.
383171095Ssam * @got_tx: Buffer to return the flag set if transmit interrupt is occured
384171095Ssam *
385173139Srwatson * The function polls the Tx channel for the completed  descriptors and calls
386173139Srwatson * the upper-layer driver (ULD) via supplied completion callback.
387171095Ssam *
388173139Srwatson * Returns: XGE_HAL_OK, if the polling is completed successful.
389173139Srwatson * XGE_HAL_COMPLETIONS_REMAIN: There are still more completed
390171095Ssam * descriptors available which are yet to be processed.
391171095Ssam *
392171095Ssam * See also: xge_hal_device_poll_rx_channel().
393171095Ssam */
394173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
395171095Ssamxge_hal_device_poll_tx_channel(xge_hal_channel_t *channel, int *got_tx)
396171095Ssam{
397171095Ssam	xge_hal_dtr_h first_dtrh;
398171095Ssam	xge_hal_device_t *hldev = (xge_hal_device_t *)channel->devh;
399171095Ssam	u8 t_code;
400171095Ssam	int got_bytes;
401171095Ssam
402171095Ssam	/* for each opened tx channel */
403171095Ssam	got_bytes = *got_tx = 0;
404171095Ssam	channel->poll_bytes = 0;
405171095Ssam	if (xge_hal_fifo_dtr_next_completed (channel, &first_dtrh,
406173139Srwatson	    &t_code) == XGE_HAL_OK) {
407173139Srwatson	    if (channel->callback(channel, first_dtrh,
408173139Srwatson	        t_code, channel->userdata) != XGE_HAL_OK) {
409173139Srwatson	        (*got_tx)++;
410173139Srwatson	        got_bytes += channel->poll_bytes + 1;
411173139Srwatson	        return XGE_HAL_COMPLETIONS_REMAIN;
412173139Srwatson	    }
413173139Srwatson	    (*got_tx)++;
414173139Srwatson	    got_bytes += channel->poll_bytes + 1;
415171095Ssam	}
416171095Ssam
417171095Ssam	if (*got_tx) {
418173139Srwatson	    hldev->irq_workload_txd[channel->post_qid] += *got_tx;
419173139Srwatson	    hldev->irq_workload_txcnt[channel->post_qid] ++;
420171095Ssam	}
421171095Ssam	hldev->irq_workload_txlen[channel->post_qid] += got_bytes;
422171095Ssam
423171095Ssam	return XGE_HAL_OK;
424171095Ssam}
425171095Ssam
426171095Ssam/**
427171095Ssam * xge_hal_device_poll_rx_channels - Poll Rx channels for completed
428171095Ssam * descriptors and process the same.
429171095Ssam * @hldev: HAL device handle.
430171095Ssam * @got_rx: Buffer to return flag set if receive is ready
431171095Ssam *
432173139Srwatson * The function polls the Rx channels for the completed descriptors and calls
433173139Srwatson * the upper-layer driver (ULD) via supplied completion callback.
434171095Ssam *
435173139Srwatson * Returns: XGE_HAL_OK, if the polling is completed successful.
436173139Srwatson * XGE_HAL_COMPLETIONS_REMAIN: There are still more completed
437171095Ssam * descriptors available which are yet to be processed.
438171095Ssam *
439173139Srwatson * See also: xge_hal_device_poll_tx_channels(), xge_hal_device_continue_irq().
440171095Ssam */
441173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
442171095Ssamxge_hal_device_poll_rx_channels(xge_hal_device_t *hldev, int *got_rx)
443171095Ssam{
444171095Ssam	xge_list_t *item;
445171095Ssam	xge_hal_channel_t *channel;
446171095Ssam
447171095Ssam	/* for each opened rx channel */
448173139Srwatson	xge_list_for_each(item, &hldev->ring_channels) {
449173139Srwatson	    if (hldev->terminating)
450173139Srwatson	        return XGE_HAL_OK;
451173139Srwatson	    channel = xge_container_of(item, xge_hal_channel_t, item);
452173139Srwatson	    (void) xge_hal_device_poll_rx_channel(channel, got_rx);
453171095Ssam	}
454171095Ssam
455171095Ssam	return XGE_HAL_OK;
456171095Ssam}
457171095Ssam
458171095Ssam/**
459171095Ssam * xge_hal_device_poll_tx_channels - Poll Tx channels for completed
460171095Ssam * descriptors and process the same.
461171095Ssam * @hldev: HAL device handle.
462171095Ssam * @got_tx: Buffer to return flag set if transmit is ready
463171095Ssam *
464173139Srwatson * The function polls the Tx channels for the completed descriptors and calls
465173139Srwatson * the upper-layer driver (ULD) via supplied completion callback.
466171095Ssam *
467173139Srwatson * Returns: XGE_HAL_OK, if the polling is completed successful.
468173139Srwatson * XGE_HAL_COMPLETIONS_REMAIN: There are still more completed
469171095Ssam * descriptors available which are yet to be processed.
470171095Ssam *
471173139Srwatson * See also: xge_hal_device_poll_rx_channels(), xge_hal_device_continue_irq().
472171095Ssam */
473173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
474171095Ssamxge_hal_device_poll_tx_channels(xge_hal_device_t *hldev, int *got_tx)
475171095Ssam{
476171095Ssam	xge_list_t *item;
477171095Ssam	xge_hal_channel_t *channel;
478171095Ssam
479171095Ssam	/* for each opened tx channel */
480173139Srwatson	xge_list_for_each(item, &hldev->fifo_channels) {
481173139Srwatson	    if (hldev->terminating)
482173139Srwatson	        return XGE_HAL_OK;
483173139Srwatson	    channel = xge_container_of(item, xge_hal_channel_t, item);
484173139Srwatson	    (void) xge_hal_device_poll_tx_channel(channel, got_tx);
485171095Ssam	}
486171095Ssam
487171095Ssam	return XGE_HAL_OK;
488171095Ssam}
489171095Ssam
490171095Ssam/**
491173139Srwatson * xge_hal_device_mask_tx - Mask Tx interrupts.
492171095Ssam * @hldev: HAL device handle.
493171095Ssam *
494173139Srwatson * Mask Tx device interrupts.
495171095Ssam *
496171095Ssam * See also: xge_hal_device_unmask_tx(), xge_hal_device_mask_rx(),
497171095Ssam * xge_hal_device_clear_tx().
498171095Ssam */
499173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
500173139Srwatsonxge_hal_device_mask_tx(xge_hal_device_t *hldev)
501171095Ssam{
502173139Srwatson	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
503171095Ssam
504173139Srwatson	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
505173139Srwatson	               0xFFFFFFFFFFFFFFFFULL,
506173139Srwatson	               &isrbar0->tx_traffic_mask);
507171095Ssam}
508171095Ssam
509171095Ssam/**
510173139Srwatson * xge_hal_device_mask_rx - Mask Rx interrupts.
511171095Ssam * @hldev: HAL device handle.
512171095Ssam *
513173139Srwatson * Mask Rx device interrupts.
514171095Ssam *
515171095Ssam * See also: xge_hal_device_unmask_rx(), xge_hal_device_mask_tx(),
516171095Ssam * xge_hal_device_clear_rx().
517171095Ssam */
518173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
519173139Srwatsonxge_hal_device_mask_rx(xge_hal_device_t *hldev)
520171095Ssam{
521173139Srwatson	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
522171095Ssam
523173139Srwatson	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
524173139Srwatson	               0xFFFFFFFFFFFFFFFFULL,
525173139Srwatson	               &isrbar0->rx_traffic_mask);
526171095Ssam}
527171095Ssam
528171095Ssam/**
529171095Ssam * xge_hal_device_mask_all - Mask all device interrupts.
530171095Ssam * @hldev: HAL device handle.
531171095Ssam *
532173139Srwatson * Mask all device interrupts.
533171095Ssam *
534171095Ssam * See also: xge_hal_device_unmask_all()
535171095Ssam */
536173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
537171095Ssamxge_hal_device_mask_all(xge_hal_device_t *hldev)
538171095Ssam{
539173139Srwatson	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
540171095Ssam
541173139Srwatson	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
542173139Srwatson	               0xFFFFFFFFFFFFFFFFULL,
543173139Srwatson	               &isrbar0->general_int_mask);
544171095Ssam}
545171095Ssam
546171095Ssam/**
547173139Srwatson * xge_hal_device_unmask_tx - Unmask Tx interrupts.
548171095Ssam * @hldev: HAL device handle.
549171095Ssam *
550173139Srwatson * Unmask Tx device interrupts.
551171095Ssam *
552171095Ssam * See also: xge_hal_device_mask_tx(), xge_hal_device_clear_tx().
553171095Ssam */
554173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
555171095Ssamxge_hal_device_unmask_tx(xge_hal_device_t *hldev)
556171095Ssam{
557173139Srwatson	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
558171095Ssam
559173139Srwatson	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
560173139Srwatson	               0x0ULL,
561173139Srwatson	               &isrbar0->tx_traffic_mask);
562171095Ssam}
563171095Ssam
564171095Ssam/**
565173139Srwatson * xge_hal_device_unmask_rx - Unmask Rx interrupts.
566171095Ssam * @hldev: HAL device handle.
567171095Ssam *
568173139Srwatson * Unmask Rx device interrupts.
569171095Ssam *
570171095Ssam * See also: xge_hal_device_mask_rx(), xge_hal_device_clear_rx().
571171095Ssam */
572173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
573171095Ssamxge_hal_device_unmask_rx(xge_hal_device_t *hldev)
574171095Ssam{
575173139Srwatson	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
576171095Ssam
577173139Srwatson	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
578173139Srwatson	               0x0ULL,
579173139Srwatson	               &isrbar0->rx_traffic_mask);
580171095Ssam}
581171095Ssam
582171095Ssam/**
583171095Ssam * xge_hal_device_unmask_all - Unmask all device interrupts.
584171095Ssam * @hldev: HAL device handle.
585171095Ssam *
586171095Ssam * Unmask all device interrupts.
587171095Ssam *
588171095Ssam * See also: xge_hal_device_mask_all()
589171095Ssam */
590173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
591171095Ssamxge_hal_device_unmask_all(xge_hal_device_t *hldev)
592171095Ssam{
593173139Srwatson	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
594171095Ssam
595173139Srwatson	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
596173139Srwatson	               0x0ULL,
597173139Srwatson	               &isrbar0->general_int_mask);
598171095Ssam}
599171095Ssam
600171095Ssam
601171095Ssam/**
602173139Srwatson * xge_hal_device_continue_irq - Continue handling IRQ: process all
603171095Ssam * completed descriptors.
604171095Ssam * @hldev: HAL device handle.
605171095Ssam *
606173139Srwatson * Process completed descriptors and unmask the device interrupts.
607171095Ssam *
608173139Srwatson * The xge_hal_device_continue_irq() walks all open channels
609173139Srwatson * and calls upper-layer driver (ULD) via supplied completion
610173139Srwatson * callback. Note that the completion callback is specified at channel open
611171095Ssam * time, see xge_hal_channel_open().
612171095Ssam *
613173139Srwatson * Note that the xge_hal_device_continue_irq is part of the _fast_ path.
614173139Srwatson * To optimize the processing, the function does _not_ check for
615171095Ssam * errors and alarms.
616171095Ssam *
617173139Srwatson * The latter is done in a polling fashion, via xge_hal_device_poll().
618171095Ssam *
619173139Srwatson * Returns: XGE_HAL_OK.
620171095Ssam *
621171095Ssam * See also: xge_hal_device_handle_irq(), xge_hal_device_poll(),
622171095Ssam * xge_hal_ring_dtr_next_completed(),
623171095Ssam * xge_hal_fifo_dtr_next_completed(), xge_hal_channel_callback_f{}.
624171095Ssam */
625173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
626171095Ssamxge_hal_device_continue_irq(xge_hal_device_t *hldev)
627171095Ssam{
628173139Srwatson	int got_rx = 1, got_tx = 1;
629173139Srwatson	int isr_polling_cnt = hldev->config.isr_polling_cnt;
630173139Srwatson	int count = 0;
631171095Ssam
632171095Ssam	do
633171095Ssam	{
634173139Srwatson	    if (got_rx)
635173139Srwatson	        (void) xge_hal_device_poll_rx_channels(hldev, &got_rx);
636173139Srwatson	    if (got_tx && hldev->tti_enabled)
637173139Srwatson	        (void) xge_hal_device_poll_tx_channels(hldev, &got_tx);
638171095Ssam
639173139Srwatson	    if (!got_rx && !got_tx)
640173139Srwatson	        break;
641171095Ssam
642173139Srwatson	    count += (got_rx + got_tx);
643171095Ssam	}while (isr_polling_cnt--);
644171095Ssam
645171095Ssam	if (!count)
646173139Srwatson	    hldev->stats.sw_dev_info_stats.not_traffic_intr_cnt++;
647171095Ssam
648171095Ssam	return XGE_HAL_OK;
649171095Ssam}
650171095Ssam
651171095Ssam/**
652171095Ssam * xge_hal_device_handle_irq - Handle device IRQ.
653171095Ssam * @hldev: HAL device handle.
654171095Ssam *
655173139Srwatson * Perform the complete handling of the line interrupt. The function
656173139Srwatson * performs two calls.
657173139Srwatson * First it uses xge_hal_device_begin_irq() to  check the reason for
658171095Ssam * the interrupt and mask the device interrupts.
659173139Srwatson * Second, it calls xge_hal_device_continue_irq() to process all
660171095Ssam * completed descriptors and re-enable the interrupts.
661171095Ssam *
662173139Srwatson * Returns: XGE_HAL_OK - success;
663173139Srwatson * XGE_HAL_ERR_WRONG_IRQ - (shared) IRQ produced by other device.
664171095Ssam *
665171095Ssam * See also: xge_hal_device_begin_irq(), xge_hal_device_continue_irq().
666171095Ssam */
667173139Srwatson__HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
668171095Ssamxge_hal_device_handle_irq(xge_hal_device_t *hldev)
669171095Ssam{
670173139Srwatson	u64 reason;
671171095Ssam	xge_hal_status_e status;
672171095Ssam
673171095Ssam	xge_hal_device_mask_all(hldev);
674171095Ssam
675171095Ssam	status = xge_hal_device_begin_irq(hldev, &reason);
676171095Ssam	if (status != XGE_HAL_OK) {
677173139Srwatson	    xge_hal_device_unmask_all(hldev);
678173139Srwatson	    return status;
679171095Ssam	}
680171095Ssam
681171095Ssam	if (reason & XGE_HAL_GEN_INTR_RXTRAFFIC) {
682173139Srwatson	    xge_hal_device_clear_rx(hldev);
683171095Ssam	}
684171095Ssam
685171095Ssam	status = xge_hal_device_continue_irq(hldev);
686171095Ssam
687171095Ssam	xge_hal_device_clear_tx(hldev);
688171095Ssam
689171095Ssam	xge_hal_device_unmask_all(hldev);
690171095Ssam
691171095Ssam	return status;
692171095Ssam}
693171095Ssam
694173139Srwatson#if defined(XGE_HAL_CONFIG_LRO)
695171095Ssam
696171095Ssam
697171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
698173139Srwatson__hal_lro_check_for_session_match(lro_t *lro, tcplro_t *tcp, iplro_t *ip)
699171095Ssam{
700171095Ssam
701173139Srwatson	/* Match Source address field */
702173139Srwatson	if ((lro->ip_hdr->saddr != ip->saddr))
703173139Srwatson	    return XGE_HAL_FAIL;
704171095Ssam
705171095Ssam	/* Match Destination address field */
706173139Srwatson	if ((lro->ip_hdr->daddr != ip->daddr))
707173139Srwatson	    return XGE_HAL_FAIL;
708171095Ssam
709173139Srwatson	/* Match Source Port field */
710171095Ssam	if ((lro->tcp_hdr->source != tcp->source))
711173139Srwatson	    return XGE_HAL_FAIL;
712171095Ssam
713173139Srwatson	/* Match Destination Port field */
714173139Srwatson	if ((lro->tcp_hdr->dest != tcp->dest))
715173139Srwatson	    return XGE_HAL_FAIL;
716173139Srwatson
717171095Ssam	return XGE_HAL_OK;
718171095Ssam}
719171095Ssam
720171095Ssam/*
721171095Ssam * __hal_tcp_seg_len: Find the tcp seg len.
722173139Srwatson * @ip: ip header.
723171095Ssam * @tcp: tcp header.
724173139Srwatson * returns: Tcp seg length.
725171095Ssam */
726171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL u16
727173139Srwatson__hal_tcp_seg_len(iplro_t *ip, tcplro_t *tcp)
728171095Ssam{
729173139Srwatson	u16 ret;
730171095Ssam
731173139Srwatson	ret =  (xge_os_ntohs(ip->tot_len) -
732173139Srwatson	       ((ip->version_ihl & 0x0F)<<2) -
733173139Srwatson	       ((tcp->doff_res)>>2));
734171095Ssam	return (ret);
735171095Ssam}
736171095Ssam
737171095Ssam/*
738171095Ssam * __hal_ip_lro_capable: Finds whether ip is lro capable.
739173139Srwatson * @ip: ip header.
740171095Ssam * @ext_info:  descriptor info.
741171095Ssam */
742171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
743171095Ssam__hal_ip_lro_capable(iplro_t *ip,
744173139Srwatson	         xge_hal_dtr_info_t *ext_info)
745171095Ssam{
746171095Ssam
747171095Ssam#ifdef XGE_LL_DEBUG_DUMP_PKT
748173139Srwatson	    {
749173139Srwatson	        u16 i;
750173139Srwatson	        u8 ch, *iph = (u8 *)ip;
751171095Ssam
752173139Srwatson	        xge_debug_ring(XGE_TRACE, "Dump Ip:" );
753173139Srwatson	        for (i =0; i < 40; i++) {
754173139Srwatson	            ch = ntohs(*((u8 *)(iph + i)) );
755173139Srwatson	            printf("i:%d %02x, ",i,ch);
756173139Srwatson	        }
757173139Srwatson	    }
758171095Ssam#endif
759171095Ssam
760173139Srwatson	if (ip->version_ihl != IP_FAST_PATH_HDR_MASK) {
761173139Srwatson	    xge_debug_ring(XGE_ERR, "iphdr !=45 :%d",ip->version_ihl);
762173139Srwatson	    return XGE_HAL_FAIL;
763171095Ssam	}
764171095Ssam
765173139Srwatson	if (ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED) {
766173139Srwatson	    xge_debug_ring(XGE_ERR, "IP fragmented");
767173139Srwatson	    return XGE_HAL_FAIL;
768171095Ssam	}
769171095Ssam
770171095Ssam	return XGE_HAL_OK;
771171095Ssam}
772171095Ssam
773171095Ssam/*
774173139Srwatson * __hal_tcp_lro_capable: Finds whether tcp is lro capable.
775173139Srwatson * @ip: ip header.
776171095Ssam * @tcp: tcp header.
777171095Ssam */
778171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
779173139Srwatson__hal_tcp_lro_capable(iplro_t *ip, tcplro_t *tcp, lro_t *lro, int *ts_off)
780171095Ssam{
781171095Ssam#ifdef XGE_LL_DEBUG_DUMP_PKT
782173139Srwatson	    {
783173139Srwatson	        u8 ch;
784173139Srwatson	        u16 i;
785171095Ssam
786173139Srwatson	        xge_debug_ring(XGE_TRACE, "Dump Tcp:" );
787173139Srwatson	        for (i =0; i < 20; i++) {
788173139Srwatson	            ch = ntohs(*((u8 *)((u8 *)tcp + i)) );
789173139Srwatson	            xge_os_printf("i:%d %02x, ",i,ch);
790173139Srwatson	        }
791173139Srwatson	    }
792171095Ssam#endif
793173139Srwatson	if ((TCP_FAST_PATH_HDR_MASK2 != tcp->ctrl) &&
794173139Srwatson	    (TCP_FAST_PATH_HDR_MASK3 != tcp->ctrl))
795173139Srwatson	    goto _exit_fail;
796171095Ssam
797173139Srwatson	*ts_off = -1;
798173139Srwatson	if (TCP_FAST_PATH_HDR_MASK1 != tcp->doff_res) {
799173139Srwatson	    u16 tcp_hdr_len = tcp->doff_res >> 2; /* TCP header len */
800173139Srwatson	    u16 off = 20; /* Start of tcp options */
801173139Srwatson	    int i, diff;
802171095Ssam
803173139Srwatson	    /* Does Packet can contain time stamp */
804173139Srwatson	    if (tcp_hdr_len < 32) {
805173139Srwatson	        /*
806173139Srwatson	         * If the session is not opened, we can consider
807173139Srwatson	         * this packet for LRO
808173139Srwatson	         */
809173139Srwatson	        if (lro == NULL)
810173139Srwatson	            return XGE_HAL_OK;
811171095Ssam
812173139Srwatson	        goto _exit_fail;
813173139Srwatson	    }
814171095Ssam
815173139Srwatson	    /* Ignore No-operation 0x1 */
816173139Srwatson	    while (((u8 *)tcp)[off] == 0x1)
817173139Srwatson	        off++;
818171095Ssam
819173139Srwatson	    /* Next option == Timestamp */
820173139Srwatson	    if (((u8 *)tcp)[off] != 0x8) {
821173139Srwatson	        /*
822173139Srwatson	         * If the session ie not opened, we can consider
823173139Srwatson	         * this packet for LRO
824173139Srwatson	         */
825173139Srwatson	        if (lro == NULL)
826173139Srwatson	            return XGE_HAL_OK;
827171095Ssam
828173139Srwatson	        goto _exit_fail;
829173139Srwatson	    }
830171095Ssam
831173139Srwatson	    *ts_off = off;
832173139Srwatson	    if (lro == NULL)
833173139Srwatson	        return XGE_HAL_OK;
834171095Ssam
835173139Srwatson	    /*
836173139Srwatson	     * Now the session is opened. If the LRO frame doesn't
837173139Srwatson	     * have time stamp, we cannot consider current packet for
838173139Srwatson	     * LRO.
839173139Srwatson	     */
840173139Srwatson	    if (lro->ts_off == -1) {
841173139Srwatson	        xge_debug_ring(XGE_ERR, "Pkt received with time stamp after session opened with no time stamp : %02x %02x", tcp->doff_res, tcp->ctrl);
842173139Srwatson	        return XGE_HAL_FAIL;
843173139Srwatson	    }
844171095Ssam
845173139Srwatson	    /*
846173139Srwatson	     * If the difference is greater than three, then there are
847173139Srwatson	     * more options possible.
848173139Srwatson	     * else, there are two cases:
849173139Srwatson	     * case 1: remaining are padding bytes.
850173139Srwatson	     * case 2: remaining can contain options or padding
851173139Srwatson	     */
852173139Srwatson	    off += ((u8 *)tcp)[off+1];
853173139Srwatson	    diff = tcp_hdr_len - off;
854173139Srwatson	    if (diff > 3) {
855173139Srwatson	        /*
856173139Srwatson	         * Probably contains more options.
857173139Srwatson	         */
858173139Srwatson	        xge_debug_ring(XGE_ERR, "tcphdr not fastpth : pkt received with tcp options in addition to time stamp after the session is opened %02x %02x ", tcp->doff_res,   tcp->ctrl);
859173139Srwatson	        return XGE_HAL_FAIL;
860173139Srwatson	    }
861171095Ssam
862173139Srwatson	    for (i = 0; i < diff; i++) {
863173139Srwatson	        u8 byte = ((u8 *)tcp)[off+i];
864171095Ssam
865173139Srwatson	        /* Ignore No-operation 0x1 */
866173139Srwatson	        if ((byte == 0x0) || (byte == 0x1))
867173139Srwatson	            continue;
868173139Srwatson	        xge_debug_ring(XGE_ERR, "tcphdr not fastpth : pkt received with tcp options in addition to time stamp after the session is opened %02x %02x ", tcp->doff_res,   tcp->ctrl);
869173139Srwatson	        return XGE_HAL_FAIL;
870173139Srwatson	    }
871171095Ssam
872173139Srwatson	    /*
873173139Srwatson	     * Update the time stamp of LRO frame.
874173139Srwatson	     */
875173139Srwatson	    xge_os_memcpy(((char *)lro->tcp_hdr + lro->ts_off + 2),
876173139Srwatson	            (char *)((char *)tcp + (*ts_off) + 2), 8);
877171095Ssam	}
878171095Ssam
879171095Ssam	return XGE_HAL_OK;
880171095Ssam
881171095Ssam_exit_fail:
882173139Srwatson	xge_debug_ring(XGE_TRACE,   "tcphdr not fastpth %02x %02x", tcp->doff_res, tcp->ctrl);
883171095Ssam	return XGE_HAL_FAIL;
884171095Ssam
885171095Ssam}
886171095Ssam
887171095Ssam/*
888173139Srwatson * __hal_lro_capable: Finds whether frame is lro capable.
889173139Srwatson * @buffer: Ethernet frame.
890173139Srwatson * @ip: ip frame.
891171095Ssam * @tcp: tcp frame.
892171095Ssam * @ext_info: Descriptor info.
893171095Ssam */
894171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
895171095Ssam__hal_lro_capable( u8 *buffer,
896173139Srwatson	       iplro_t **ip,
897173139Srwatson	       tcplro_t **tcp,
898173139Srwatson	   xge_hal_dtr_info_t *ext_info)
899171095Ssam{
900171095Ssam	u8 ip_off, ip_length;
901171095Ssam
902173139Srwatson	if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_TCP)) {
903173139Srwatson	    xge_debug_ring(XGE_ERR, "Cant do lro %d", ext_info->proto);
904173139Srwatson	    return XGE_HAL_FAIL;
905171095Ssam	}
906171095Ssam
907171095Ssam  if ( !*ip )
908171095Ssam  {
909171095Ssam#ifdef XGE_LL_DEBUG_DUMP_PKT
910173139Srwatson	    {
911173139Srwatson	        u8 ch;
912173139Srwatson	        u16 i;
913171095Ssam
914173139Srwatson	        xge_os_printf("Dump Eth:" );
915173139Srwatson	        for (i =0; i < 60; i++) {
916173139Srwatson	            ch = ntohs(*((u8 *)(buffer + i)) );
917173139Srwatson	            xge_os_printf("i:%d %02x, ",i,ch);
918173139Srwatson	        }
919173139Srwatson	    }
920171095Ssam#endif
921171095Ssam
922173139Srwatson	switch (ext_info->frame) {
923173139Srwatson	case XGE_HAL_FRAME_TYPE_DIX:
924173139Srwatson	  ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE;
925173139Srwatson	  break;
926173139Srwatson	case XGE_HAL_FRAME_TYPE_LLC:
927173139Srwatson	  ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE   +
928173139Srwatson	            XGE_HAL_HEADER_802_2_SIZE);
929173139Srwatson	  break;
930173139Srwatson	case XGE_HAL_FRAME_TYPE_SNAP:
931173139Srwatson	  ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE   +
932173139Srwatson	            XGE_HAL_HEADER_SNAP_SIZE);
933173139Srwatson	  break;
934173139Srwatson	default: // XGE_HAL_FRAME_TYPE_IPX, etc.
935173139Srwatson	  return XGE_HAL_FAIL;
936173139Srwatson	}
937171095Ssam
938171095Ssam
939173139Srwatson	if (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED) {
940173139Srwatson	  ip_off += XGE_HAL_HEADER_VLAN_SIZE;
941173139Srwatson	}
942171095Ssam
943173139Srwatson	/* Grab ip, tcp headers */
944173139Srwatson	*ip = (iplro_t *)((char*)buffer + ip_off);
945171095Ssam  } /* !*ip */
946171095Ssam
947173139Srwatson	ip_length = (u8)((*ip)->version_ihl & 0x0F);
948173139Srwatson	ip_length = ip_length <<2;
949171095Ssam	*tcp = (tcplro_t *)((char *)*ip + ip_length);
950171095Ssam
951173139Srwatson	xge_debug_ring(XGE_TRACE, "ip_length:%d ip:"XGE_OS_LLXFMT
952173139Srwatson	       " tcp:"XGE_OS_LLXFMT"", (int)ip_length,
953173139Srwatson	    (unsigned long long)(ulong_t)*ip, (unsigned long long)(ulong_t)*tcp);
954171095Ssam
955171095Ssam	return XGE_HAL_OK;
956171095Ssam
957171095Ssam}
958171095Ssam
959171095Ssam
960171095Ssam/*
961173139Srwatson * __hal_open_lro_session: Open a new LRO session.
962173139Srwatson * @buffer: Ethernet frame.
963173139Srwatson * @ip: ip header.
964171095Ssam * @tcp: tcp header.
965171095Ssam * @lro: lro pointer
966171095Ssam * @ext_info: Descriptor info.
967171095Ssam * @hldev: Hal context.
968171095Ssam * @ring_lro: LRO descriptor per rx ring.
969171095Ssam * @slot: Bucket no.
970173139Srwatson * @tcp_seg_len: Length of tcp segment.
971173139Srwatson * @ts_off: time stamp offset in the packet.
972171095Ssam */
973171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
974173139Srwatson__hal_open_lro_session (u8 *buffer, iplro_t *ip, tcplro_t *tcp, lro_t **lro,
975173139Srwatson	        xge_hal_device_t *hldev, xge_hal_lro_desc_t *ring_lro, int slot,
976173139Srwatson	  u32 tcp_seg_len, int  ts_off)
977171095Ssam{
978171095Ssam
979171095Ssam	lro_t *lro_new = &ring_lro->lro_pool[slot];
980171095Ssam
981173139Srwatson	lro_new->in_use         =   1;
982173139Srwatson	lro_new->ll_hdr         =   buffer;
983173139Srwatson	lro_new->ip_hdr         =   ip;
984173139Srwatson	lro_new->tcp_hdr        =   tcp;
985173139Srwatson	lro_new->tcp_next_seq_num   =   tcp_seg_len + xge_os_ntohl(
986173139Srwatson	                            tcp->seq);
987173139Srwatson	lro_new->tcp_seq_num        =   tcp->seq;
988173139Srwatson	lro_new->tcp_ack_num        =   tcp->ack_seq;
989173139Srwatson	lro_new->sg_num         =   1;
990173139Srwatson	lro_new->total_length       =   xge_os_ntohs(ip->tot_len);
991173139Srwatson	lro_new->frags_len      =   0;
992173139Srwatson	lro_new->ts_off         =   ts_off;
993171095Ssam
994171095Ssam	hldev->stats.sw_dev_info_stats.tot_frms_lroised++;
995171095Ssam	hldev->stats.sw_dev_info_stats.tot_lro_sessions++;
996171095Ssam
997171095Ssam	*lro = ring_lro->lro_recent = lro_new;
998171095Ssam	return;
999171095Ssam}
1000171095Ssam/*
1001173139Srwatson * __hal_lro_get_free_slot: Get a free LRO bucket.
1002171095Ssam * @ring_lro: LRO descriptor per ring.
1003171095Ssam */
1004171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
1005173139Srwatson__hal_lro_get_free_slot (xge_hal_lro_desc_t *ring_lro)
1006171095Ssam{
1007173139Srwatson	int i;
1008171095Ssam
1009173139Srwatson	for (i = 0; i < XGE_HAL_LRO_MAX_BUCKETS; i++) {
1010173139Srwatson	    lro_t *lro_temp = &ring_lro->lro_pool[i];
1011171095Ssam
1012173139Srwatson	    if (!lro_temp->in_use)
1013173139Srwatson	        return i;
1014171095Ssam	}
1015173139Srwatson	return -1;
1016171095Ssam}
1017171095Ssam
1018171095Ssam/*
1019173139Srwatson * __hal_get_lro_session: Gets matching LRO session or creates one.
1020173139Srwatson * @eth_hdr:    Ethernet header.
1021173139Srwatson * @ip: ip header.
1022171095Ssam * @tcp: tcp header.
1023171095Ssam * @lro: lro pointer
1024171095Ssam * @ext_info: Descriptor info.
1025171095Ssam * @hldev: Hal context.
1026171095Ssam * @ring_lro: LRO descriptor per rx ring
1027171095Ssam */
1028171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1029171095Ssam__hal_get_lro_session (u8 *eth_hdr,
1030173139Srwatson	           iplro_t *ip,
1031173139Srwatson	           tcplro_t *tcp,
1032173139Srwatson	           lro_t **lro,
1033173139Srwatson	           xge_hal_dtr_info_t *ext_info,
1034173139Srwatson	           xge_hal_device_t *hldev,
1035173139Srwatson	           xge_hal_lro_desc_t   *ring_lro,
1036173139Srwatson	           lro_t **lro_end3 /* Valid only when ret=END_3 */)
1037171095Ssam{
1038171095Ssam	lro_t *lro_match;
1039173139Srwatson	int i, free_slot = -1;
1040173139Srwatson	u32 tcp_seg_len;
1041173139Srwatson	int ts_off = -1;
1042171095Ssam
1043171095Ssam	*lro = lro_match = NULL;
1044171095Ssam	/*
1045173139Srwatson	 * Compare the incoming frame with the lro session left from the
1046173139Srwatson	 * previous call.  There is a good chance that this incoming frame
1047171095Ssam	 * matches the lro session.
1048171095Ssam	 */
1049173139Srwatson	if (ring_lro->lro_recent && ring_lro->lro_recent->in_use)   {
1050173139Srwatson	    if (__hal_lro_check_for_session_match(ring_lro->lro_recent,
1051173139Srwatson	                          tcp, ip)
1052173139Srwatson	                        == XGE_HAL_OK)
1053173139Srwatson	        lro_match = ring_lro->lro_recent;
1054171095Ssam	}
1055171095Ssam
1056173139Srwatson	if (!lro_match) {
1057173139Srwatson	    /*
1058173139Srwatson	     * Search in the pool of LROs for the session that matches
1059173139Srwatson	     * the incoming frame.
1060173139Srwatson	     */
1061173139Srwatson	    for (i = 0; i < XGE_HAL_LRO_MAX_BUCKETS; i++) {
1062173139Srwatson	        lro_t *lro_temp = &ring_lro->lro_pool[i];
1063171095Ssam
1064173139Srwatson	        if (!lro_temp->in_use) {
1065173139Srwatson	            if (free_slot == -1)
1066173139Srwatson	                free_slot = i;
1067173139Srwatson	            continue;
1068173139Srwatson	        }
1069171095Ssam
1070173139Srwatson	        if (__hal_lro_check_for_session_match(lro_temp, tcp,
1071173139Srwatson	                          ip) == XGE_HAL_OK) {
1072173139Srwatson	            lro_match = lro_temp;
1073173139Srwatson	            break;
1074173139Srwatson	        }
1075173139Srwatson	    }
1076171095Ssam	}
1077171095Ssam
1078171095Ssam
1079171095Ssam	if (lro_match) {
1080173139Srwatson	    /*
1081173139Srwatson	     * Matching LRO Session found
1082173139Srwatson	     */
1083173139Srwatson	    *lro = lro_match;
1084171095Ssam
1085173139Srwatson	    if (lro_match->tcp_next_seq_num != xge_os_ntohl(tcp->seq)) {
1086173139Srwatson	 xge_debug_ring(XGE_ERR,    "**retransmit  **"
1087173139Srwatson	                    "found***");
1088173139Srwatson	        hldev->stats.sw_dev_info_stats.lro_out_of_seq_pkt_cnt++;
1089173139Srwatson	        return XGE_HAL_INF_LRO_END_2;
1090173139Srwatson	    }
1091171095Ssam
1092173139Srwatson	    if (XGE_HAL_OK != __hal_ip_lro_capable(ip, ext_info))
1093173139Srwatson	{
1094173139Srwatson	        return XGE_HAL_INF_LRO_END_2;
1095173139Srwatson	}
1096171095Ssam
1097173139Srwatson	    if (XGE_HAL_OK != __hal_tcp_lro_capable(ip, tcp, lro_match,
1098173139Srwatson	                        &ts_off)) {
1099173139Srwatson	        /*
1100173139Srwatson	         * Close the current session and open a new
1101173139Srwatson	         * LRO session with this packet,
1102173139Srwatson	         * provided it has tcp payload
1103173139Srwatson	         */
1104173139Srwatson	        tcp_seg_len = __hal_tcp_seg_len(ip, tcp);
1105173139Srwatson	        if (tcp_seg_len == 0)
1106173139Srwatson	  {
1107173139Srwatson	            return XGE_HAL_INF_LRO_END_2;
1108173139Srwatson	  }
1109171095Ssam
1110173139Srwatson	        /* Get a free bucket  */
1111173139Srwatson	        free_slot = __hal_lro_get_free_slot(ring_lro);
1112173139Srwatson	        if (free_slot == -1)
1113173139Srwatson	  {
1114173139Srwatson	            return XGE_HAL_INF_LRO_END_2;
1115173139Srwatson	  }
1116171095Ssam
1117173139Srwatson	        /*
1118173139Srwatson	         * Open a new LRO session
1119173139Srwatson	         */
1120173139Srwatson	        __hal_open_lro_session (eth_hdr,    ip, tcp, lro_end3,
1121173139Srwatson	                    hldev, ring_lro, free_slot, tcp_seg_len,
1122173139Srwatson	                    ts_off);
1123171095Ssam
1124173139Srwatson	        return XGE_HAL_INF_LRO_END_3;
1125173139Srwatson	    }
1126171095Ssam
1127173139Srwatson	            /*
1128173139Srwatson	     * The frame is good, in-sequence, can be LRO-ed;
1129173139Srwatson	     * take its (latest) ACK - unless it is a dupack.
1130173139Srwatson	     * Note: to be exact need to check window size as well..
1131173139Srwatson	    */
1132173139Srwatson	    if (lro_match->tcp_ack_num == tcp->ack_seq &&
1133173139Srwatson	        lro_match->tcp_seq_num == tcp->seq) {
1134173139Srwatson	        hldev->stats.sw_dev_info_stats.lro_dup_pkt_cnt++;
1135173139Srwatson	        return XGE_HAL_INF_LRO_END_2;
1136173139Srwatson	    }
1137171095Ssam
1138173139Srwatson	    lro_match->tcp_seq_num = tcp->seq;
1139173139Srwatson	    lro_match->tcp_ack_num = tcp->ack_seq;
1140173139Srwatson	    lro_match->frags_len += __hal_tcp_seg_len(ip, tcp);
1141171095Ssam
1142173139Srwatson	    ring_lro->lro_recent =  lro_match;
1143171095Ssam
1144173139Srwatson	    return XGE_HAL_INF_LRO_CONT;
1145171095Ssam	}
1146171095Ssam
1147171095Ssam	/* ********** New Session ***************/
1148171095Ssam	if (free_slot == -1)
1149173139Srwatson	    return XGE_HAL_INF_LRO_UNCAPABLE;
1150171095Ssam
1151173139Srwatson	if (XGE_HAL_FAIL == __hal_ip_lro_capable(ip, ext_info))
1152173139Srwatson	    return XGE_HAL_INF_LRO_UNCAPABLE;
1153171095Ssam
1154173139Srwatson	if (XGE_HAL_FAIL == __hal_tcp_lro_capable(ip, tcp, NULL, &ts_off))
1155173139Srwatson	    return XGE_HAL_INF_LRO_UNCAPABLE;
1156173139Srwatson
1157173139Srwatson	xge_debug_ring(XGE_TRACE, "Creating lro session.");
1158171095Ssam
1159171095Ssam	/*
1160173139Srwatson	 * Open a LRO session, provided the packet contains payload.
1161171095Ssam	 */
1162173139Srwatson	tcp_seg_len = __hal_tcp_seg_len(ip, tcp);
1163173139Srwatson	if (tcp_seg_len == 0)
1164173139Srwatson	    return XGE_HAL_INF_LRO_UNCAPABLE;
1165171095Ssam
1166173139Srwatson	__hal_open_lro_session (eth_hdr,    ip, tcp, lro, hldev, ring_lro, free_slot,
1167173139Srwatson	            tcp_seg_len, ts_off);
1168171095Ssam
1169171095Ssam	return XGE_HAL_INF_LRO_BEGIN;
1170171095Ssam}
1171171095Ssam
1172171095Ssam/*
1173171095Ssam * __hal_lro_under_optimal_thresh: Finds whether combined session is optimal.
1174173139Srwatson * @ip: ip header.
1175171095Ssam * @tcp: tcp header.
1176171095Ssam * @lro: lro pointer
1177171095Ssam * @hldev: Hal context.
1178171095Ssam */
1179171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1180173139Srwatson__hal_lro_under_optimal_thresh (iplro_t *ip,
1181173139Srwatson	                tcplro_t *tcp,
1182173139Srwatson	            lro_t *lro,
1183173139Srwatson	            xge_hal_device_t *hldev)
1184171095Ssam{
1185171095Ssam	if (!lro) return XGE_HAL_FAIL;
1186171095Ssam
1187173139Srwatson	if ((lro->total_length + __hal_tcp_seg_len(ip, tcp) ) >
1188173139Srwatson	                    hldev->config.lro_frm_len) {
1189173139Srwatson	    xge_debug_ring(XGE_TRACE, "Max LRO frame len exceeded:"
1190173139Srwatson	     "max length %d ", hldev->config.lro_frm_len);
1191173139Srwatson	    hldev->stats.sw_dev_info_stats.lro_frm_len_exceed_cnt++;
1192173139Srwatson	    return XGE_HAL_FAIL;
1193171095Ssam	}
1194171095Ssam
1195173139Srwatson	if (lro->sg_num == hldev->config.lro_sg_size) {
1196173139Srwatson	    xge_debug_ring(XGE_TRACE, "Max sg count exceeded:"
1197173139Srwatson	             "max sg %d ", hldev->config.lro_sg_size);
1198173139Srwatson	    hldev->stats.sw_dev_info_stats.lro_sg_exceed_cnt++;
1199173139Srwatson	    return XGE_HAL_FAIL;
1200171095Ssam	}
1201171095Ssam
1202171095Ssam	return XGE_HAL_OK;
1203171095Ssam}
1204171095Ssam
1205171095Ssam/*
1206173139Srwatson * __hal_collapse_ip_hdr: Collapses ip header.
1207173139Srwatson * @ip: ip header.
1208171095Ssam * @tcp: tcp header.
1209171095Ssam * @lro: lro pointer
1210171095Ssam * @hldev: Hal context.
1211171095Ssam */
1212171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1213173139Srwatson__hal_collapse_ip_hdr ( iplro_t *ip,
1214173139Srwatson	        tcplro_t *tcp,
1215173139Srwatson	        lro_t *lro,
1216173139Srwatson	        xge_hal_device_t *hldev)
1217171095Ssam{
1218171095Ssam
1219171095Ssam	lro->total_length += __hal_tcp_seg_len(ip, tcp);
1220171095Ssam
1221173139Srwatson	/* May be we have to handle time stamps or more options */
1222171095Ssam
1223171095Ssam	return XGE_HAL_OK;
1224171095Ssam
1225171095Ssam}
1226171095Ssam
1227171095Ssam/*
1228171095Ssam * __hal_collapse_tcp_hdr: Collapses tcp header.
1229173139Srwatson * @ip: ip header.
1230171095Ssam * @tcp: tcp header.
1231171095Ssam * @lro: lro pointer
1232171095Ssam * @hldev: Hal context.
1233171095Ssam */
1234171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1235171095Ssam__hal_collapse_tcp_hdr ( iplro_t *ip,
1236173139Srwatson	         tcplro_t *tcp,
1237173139Srwatson	         lro_t *lro,
1238173139Srwatson	         xge_hal_device_t *hldev)
1239171095Ssam{
1240171095Ssam	lro->tcp_next_seq_num += __hal_tcp_seg_len(ip, tcp);
1241171095Ssam	return XGE_HAL_OK;
1242171095Ssam
1243171095Ssam}
1244171095Ssam
1245171095Ssam/*
1246171095Ssam * __hal_append_lro: Appends new frame to existing LRO session.
1247173139Srwatson * @ip: ip header.
1248173139Srwatson * @tcp: IN tcp header, OUT tcp payload.
1249171095Ssam * @seg_len: tcp payload length.
1250171095Ssam * @lro: lro pointer
1251171095Ssam * @hldev: Hal context.
1252171095Ssam */
1253171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1254171095Ssam__hal_append_lro(iplro_t *ip,
1255173139Srwatson	     tcplro_t **tcp,
1256173139Srwatson	     u32 *seg_len,
1257173139Srwatson	     lro_t *lro,
1258173139Srwatson	     xge_hal_device_t *hldev)
1259171095Ssam{
1260173139Srwatson	(void) __hal_collapse_ip_hdr(ip, *tcp,  lro, hldev);
1261171095Ssam	(void) __hal_collapse_tcp_hdr(ip, *tcp, lro, hldev);
1262173139Srwatson	// Update mbuf chain will be done in ll driver.
1263171095Ssam	// xge_hal_accumulate_large_rx on success of appending new frame to
1264173139Srwatson	// lro will return to ll driver tcpdata pointer, and tcp payload length.
1265173139Srwatson	// along with return code lro frame appended.
1266171095Ssam
1267171095Ssam	lro->sg_num++;
1268171095Ssam	*seg_len = __hal_tcp_seg_len(ip, *tcp);
1269173139Srwatson	*tcp = (tcplro_t *)((char *)*tcp    + (((*tcp)->doff_res)>>2));
1270171095Ssam
1271171095Ssam	return XGE_HAL_OK;
1272171095Ssam
1273171095Ssam}
1274171095Ssam
1275171095Ssam/**
1276173139Srwatson * __xge_hal_accumulate_large_rx:   LRO a given frame
1277171095Ssam * frames
1278171095Ssam * @ring: rx ring number
1279171095Ssam * @eth_hdr: ethernet header.
1280171095Ssam * @ip_hdr: ip header (optional)
1281171095Ssam * @tcp: tcp header.
1282173139Srwatson * @seglen: packet length.
1283171095Ssam * @p_lro: lro pointer.
1284171095Ssam * @ext_info: descriptor info, see xge_hal_dtr_info_t{}.
1285171095Ssam * @hldev: HAL device.
1286171095Ssam * @lro_end3: for lro_end3 output
1287171095Ssam *
1288173139Srwatson * LRO the newly received frame, i.e. attach it (if possible) to the
1289171095Ssam * already accumulated (i.e., already LRO-ed) received frames (if any),
1290173139Srwatson * to form one super-sized frame for the subsequent processing
1291171095Ssam * by the stack.
1292171095Ssam */
1293171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1294171095Ssamxge_hal_lro_process_rx(int ring, u8 *eth_hdr, u8 *ip_hdr, tcplro_t **tcp,
1295173139Srwatson	                   u32 *seglen, lro_t **p_lro,
1296173139Srwatson	                   xge_hal_dtr_info_t *ext_info, xge_hal_device_t *hldev,
1297173139Srwatson	                   lro_t **lro_end3)
1298171095Ssam{
1299173139Srwatson	iplro_t *ip = (iplro_t *)ip_hdr;
1300171095Ssam	xge_hal_status_e ret;
1301171095Ssam	lro_t *lro;
1302171095Ssam
1303171095Ssam	xge_debug_ring(XGE_TRACE, "Entered accumu lro. ");
1304171095Ssam	if (XGE_HAL_OK != __hal_lro_capable(eth_hdr, &ip, (tcplro_t **)tcp,
1305173139Srwatson	                                  ext_info))
1306173139Srwatson	    return XGE_HAL_INF_LRO_UNCAPABLE;
1307171095Ssam
1308171095Ssam	/*
1309173139Srwatson	 * This function shall get matching LRO or else
1310171095Ssam	 * create one and return it
1311171095Ssam	 */
1312171095Ssam	ret = __hal_get_lro_session(eth_hdr, ip, (tcplro_t *)*tcp,
1313173139Srwatson	                          p_lro, ext_info, hldev,   &hldev->lro_desc[ring],
1314173139Srwatson	                          lro_end3);
1315171095Ssam	xge_debug_ring(XGE_TRACE, "ret from get_lro:%d ",ret);
1316171095Ssam	lro = *p_lro;
1317171095Ssam	if (XGE_HAL_INF_LRO_CONT == ret) {
1318173139Srwatson	    if (XGE_HAL_OK == __hal_lro_under_optimal_thresh(ip,
1319173139Srwatson	                    (tcplro_t *)*tcp, lro, hldev)) {
1320173139Srwatson	        (void) __hal_append_lro(ip,(tcplro_t **) tcp, seglen,
1321173139Srwatson	                         lro, hldev);
1322173139Srwatson	        hldev->stats.sw_dev_info_stats.tot_frms_lroised++;
1323171095Ssam
1324173139Srwatson	        if (lro->sg_num >= hldev->config.lro_sg_size) {
1325173139Srwatson	            hldev->stats.sw_dev_info_stats.lro_sg_exceed_cnt++;
1326173139Srwatson	            ret = XGE_HAL_INF_LRO_END_1;
1327173139Srwatson	        }
1328171095Ssam
1329173139Srwatson	    } else ret = XGE_HAL_INF_LRO_END_2;
1330171095Ssam	}
1331171095Ssam
1332171095Ssam	/*
1333171095Ssam	 * Since its time to flush,
1334173139Srwatson	 * update ip header so that it can be sent up
1335171095Ssam	 */
1336171095Ssam	if ((ret == XGE_HAL_INF_LRO_END_1) ||
1337173139Srwatson	    (ret == XGE_HAL_INF_LRO_END_2) ||
1338173139Srwatson	    (ret == XGE_HAL_INF_LRO_END_3)) {
1339173139Srwatson	    lro->ip_hdr->tot_len = xge_os_htons((*p_lro)->total_length);
1340173139Srwatson	    lro->ip_hdr->check = xge_os_htons(0);
1341173139Srwatson	    lro->ip_hdr->check = XGE_LL_IP_FAST_CSUM(((u8 *)(lro->ip_hdr)),
1342173139Srwatson	                (lro->ip_hdr->version_ihl & 0x0F));
1343173139Srwatson	    lro->tcp_hdr->ack_seq = lro->tcp_ack_num;
1344171095Ssam	}
1345171095Ssam
1346171095Ssam	return (ret);
1347171095Ssam}
1348171095Ssam
1349171095Ssam/**
1350173139Srwatson * xge_hal_accumulate_large_rx: LRO a given frame
1351171095Ssam * frames
1352173139Srwatson * @buffer: Ethernet frame.
1353171095Ssam * @tcp: tcp header.
1354173139Srwatson * @seglen: packet length.
1355171095Ssam * @p_lro: lro pointer.
1356171095Ssam * @ext_info: descriptor info, see xge_hal_dtr_info_t{}.
1357171095Ssam * @hldev: HAL device.
1358171095Ssam * @lro_end3: for lro_end3 output
1359171095Ssam *
1360173139Srwatson * LRO the newly received frame, i.e. attach it (if possible) to the
1361171095Ssam * already accumulated (i.e., already LRO-ed) received frames (if any),
1362173139Srwatson * to form one super-sized frame for the subsequent processing
1363171095Ssam * by the stack.
1364171095Ssam */
1365171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1366171095Ssamxge_hal_accumulate_large_rx(u8 *buffer, tcplro_t **tcp, u32 *seglen,
1367171095Ssamlro_t **p_lro, xge_hal_dtr_info_t *ext_info, xge_hal_device_t *hldev,
1368171095Ssamlro_t **lro_end3)
1369171095Ssam{
1370171095Ssam  int ring = 0;
1371171095Ssam  return xge_hal_lro_process_rx(ring, buffer, NULL, tcp, seglen, p_lro,
1372173139Srwatson	                            ext_info, hldev, lro_end3);
1373171095Ssam}
1374171095Ssam
1375171095Ssam/**
1376171095Ssam * xge_hal_lro_close_session: Close LRO session
1377171095Ssam * @lro: LRO Session.
1378171095Ssam * @hldev: HAL Context.
1379171095Ssam */
1380171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
1381171095Ssamxge_hal_lro_close_session (lro_t *lro)
1382171095Ssam{
1383171095Ssam	lro->in_use = 0;
1384171095Ssam}
1385171095Ssam
1386171095Ssam/**
1387171095Ssam * xge_hal_lro_next_session: Returns next LRO session in the list or NULL
1388173139Srwatson *                  if none exists.
1389171095Ssam * @hldev: HAL Context.
1390171095Ssam * @ring: rx ring number.
1391171095Ssam */
1392173139Srwatson__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL lro_t *
1393171095Ssamxge_hal_lro_next_session (xge_hal_device_t *hldev, int ring)
1394171095Ssam{
1395171095Ssamxge_hal_lro_desc_t *ring_lro = &hldev->lro_desc[ring];
1396173139Srwatson	int i;
1397173139Srwatson	int start_idx = ring_lro->lro_next_idx;
1398171095Ssam
1399173139Srwatson	for(i = start_idx; i < XGE_HAL_LRO_MAX_BUCKETS; i++) {
1400173139Srwatson	    lro_t *lro = &ring_lro->lro_pool[i];
1401171095Ssam
1402173139Srwatson	    if (!lro->in_use)
1403173139Srwatson	        continue;
1404171095Ssam
1405173139Srwatson	    lro->ip_hdr->tot_len = xge_os_htons(lro->total_length);
1406173139Srwatson	    lro->ip_hdr->check = xge_os_htons(0);
1407173139Srwatson	    lro->ip_hdr->check = XGE_LL_IP_FAST_CSUM(((u8 *)(lro->ip_hdr)),
1408173139Srwatson	                            (lro->ip_hdr->version_ihl & 0x0F));
1409173139Srwatson	    ring_lro->lro_next_idx  = i + 1;
1410173139Srwatson	    return lro;
1411171095Ssam	}
1412171095Ssam
1413173139Srwatson	ring_lro->lro_next_idx  = 0;
1414171095Ssam	return NULL;
1415171095Ssam
1416171095Ssam}
1417171095Ssam
1418171095Ssam__HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL lro_t *
1419171095Ssamxge_hal_lro_get_next_session(xge_hal_device_t *hldev)
1420171095Ssam{
1421171095Ssam  int ring = 0; /* assume default ring=0 */
1422171095Ssam  return xge_hal_lro_next_session(hldev, ring);
1423171095Ssam}
1424171095Ssam#endif
1425