xref: /illumos-gate/usr/src/uts/common/io/xge/hal/xgehal/xgehal-device-fp.c (revision a23fd118e437af0a7877dd313db8fdaa3537c675)
1*a23fd118Syl150051 /*
2*a23fd118Syl150051  * CDDL HEADER START
3*a23fd118Syl150051  *
4*a23fd118Syl150051  * The contents of this file are subject to the terms of the
5*a23fd118Syl150051  * Common Development and Distribution License (the "License").
6*a23fd118Syl150051  * You may not use this file except in compliance with the License.
7*a23fd118Syl150051  *
8*a23fd118Syl150051  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*a23fd118Syl150051  * or http://www.opensolaris.org/os/licensing.
10*a23fd118Syl150051  * See the License for the specific language governing permissions
11*a23fd118Syl150051  * and limitations under the License.
12*a23fd118Syl150051  *
13*a23fd118Syl150051  * When distributing Covered Code, include this CDDL HEADER in each
14*a23fd118Syl150051  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*a23fd118Syl150051  * If applicable, add the following below this CDDL HEADER, with the
16*a23fd118Syl150051  * fields enclosed by brackets "[]" replaced with your own identifying
17*a23fd118Syl150051  * information: Portions Copyright [yyyy] [name of copyright owner]
18*a23fd118Syl150051  *
19*a23fd118Syl150051  * CDDL HEADER END
20*a23fd118Syl150051  */
21*a23fd118Syl150051 
22*a23fd118Syl150051 /*
23*a23fd118Syl150051  *  Copyright (c) 2002-2005 Neterion, Inc.
24*a23fd118Syl150051  *  All right Reserved.
25*a23fd118Syl150051  *
26*a23fd118Syl150051  *  FileName :    xgehal-device-fp.c
27*a23fd118Syl150051  *
28*a23fd118Syl150051  *  Description:  HAL device object functionality (fast path)
29*a23fd118Syl150051  *
30*a23fd118Syl150051  *  Created:      10 June 2004
31*a23fd118Syl150051  */
32*a23fd118Syl150051 
33*a23fd118Syl150051 #ifdef XGE_DEBUG_FP
34*a23fd118Syl150051 #include "xgehal-device.h"
35*a23fd118Syl150051 #endif
36*a23fd118Syl150051 
37*a23fd118Syl150051 #include "xgehal-ring.h"
38*a23fd118Syl150051 #include "xgehal-fifo.h"
39*a23fd118Syl150051 
40*a23fd118Syl150051 /**
41*a23fd118Syl150051  * xge_hal_device_bar0 - Get BAR0 mapped address.
42*a23fd118Syl150051  * @hldev: HAL device handle.
43*a23fd118Syl150051  *
44*a23fd118Syl150051  * Returns: BAR0 address of the specified device.
45*a23fd118Syl150051  */
46*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE char *
47*a23fd118Syl150051 xge_hal_device_bar0(xge_hal_device_t *hldev)
48*a23fd118Syl150051 {
49*a23fd118Syl150051 	return hldev->bar0;
50*a23fd118Syl150051 }
51*a23fd118Syl150051 
52*a23fd118Syl150051 /**
53*a23fd118Syl150051  * xge_hal_device_isrbar0 - Get BAR0 mapped address.
54*a23fd118Syl150051  * @hldev: HAL device handle.
55*a23fd118Syl150051  *
56*a23fd118Syl150051  * Returns: BAR0 address of the specified device.
57*a23fd118Syl150051  */
58*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE char *
59*a23fd118Syl150051 xge_hal_device_isrbar0(xge_hal_device_t *hldev)
60*a23fd118Syl150051 {
61*a23fd118Syl150051 	return hldev->isrbar0;
62*a23fd118Syl150051 }
63*a23fd118Syl150051 
64*a23fd118Syl150051 /**
65*a23fd118Syl150051  * xge_hal_device_bar1 - Get BAR1 mapped address.
66*a23fd118Syl150051  * @hldev: HAL device handle.
67*a23fd118Syl150051  *
68*a23fd118Syl150051  * Returns: BAR1 address of the specified device.
69*a23fd118Syl150051  */
70*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE char *
71*a23fd118Syl150051 xge_hal_device_bar1(xge_hal_device_t *hldev)
72*a23fd118Syl150051 {
73*a23fd118Syl150051 	return hldev->bar1;
74*a23fd118Syl150051 }
75*a23fd118Syl150051 
76*a23fd118Syl150051 /**
77*a23fd118Syl150051  * xge_hal_device_bar0_set - Set BAR0 mapped address.
78*a23fd118Syl150051  * @hldev: HAL device handle.
79*a23fd118Syl150051  * @bar0: BAR0 mapped address.
80*a23fd118Syl150051  * * Set BAR0 address in the HAL device object.
81*a23fd118Syl150051  */
82*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
83*a23fd118Syl150051 xge_hal_device_bar0_set(xge_hal_device_t *hldev, char *bar0)
84*a23fd118Syl150051 {
85*a23fd118Syl150051 	xge_assert(bar0);
86*a23fd118Syl150051 	hldev->bar0 = bar0;
87*a23fd118Syl150051 }
88*a23fd118Syl150051 
89*a23fd118Syl150051 /**
90*a23fd118Syl150051  * xge_hal_device_isrbar0_set - Set BAR0 mapped address.
91*a23fd118Syl150051  * @hldev: HAL device handle.
92*a23fd118Syl150051  * @isrbar0: BAR0 mapped address.
93*a23fd118Syl150051  * * Set BAR0 address in the HAL device object.
94*a23fd118Syl150051  */
95*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
96*a23fd118Syl150051 xge_hal_device_isrbar0_set(xge_hal_device_t *hldev, char *isrbar0)
97*a23fd118Syl150051 {
98*a23fd118Syl150051 	xge_assert(isrbar0);
99*a23fd118Syl150051 	hldev->isrbar0 = isrbar0;
100*a23fd118Syl150051 }
101*a23fd118Syl150051 
102*a23fd118Syl150051 /**
103*a23fd118Syl150051  * xge_hal_device_bar1_set - Set BAR1 mapped address.
104*a23fd118Syl150051  * @hldev: HAL device handle.
105*a23fd118Syl150051  * @channelh: Channel handle.
106*a23fd118Syl150051  * @bar1: BAR1 mapped address.
107*a23fd118Syl150051  *
108*a23fd118Syl150051  * Set BAR1 address for the given channel.
109*a23fd118Syl150051  */
110*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
111*a23fd118Syl150051 xge_hal_device_bar1_set(xge_hal_device_t *hldev, xge_hal_channel_h channelh,
112*a23fd118Syl150051 		       char *bar1)
113*a23fd118Syl150051 {
114*a23fd118Syl150051 	xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
115*a23fd118Syl150051 
116*a23fd118Syl150051 	xge_assert(bar1);
117*a23fd118Syl150051 	xge_assert(fifo);
118*a23fd118Syl150051 
119*a23fd118Syl150051 	/* Initializing the BAR1 address as the start of
120*a23fd118Syl150051 	 * the FIFO queue pointer and as a location of FIFO control
121*a23fd118Syl150051 	 * word. */
122*a23fd118Syl150051 	fifo->hw_pair =
123*a23fd118Syl150051 	        (xge_hal_fifo_hw_pair_t *) (bar1 +
124*a23fd118Syl150051 		        (fifo->channel.post_qid * XGE_HAL_FIFO_HW_PAIR_OFFSET));
125*a23fd118Syl150051 	hldev->bar1 = bar1;
126*a23fd118Syl150051 }
127*a23fd118Syl150051 
128*a23fd118Syl150051 
129*a23fd118Syl150051 /**
130*a23fd118Syl150051  * xge_hal_device_rev - Get Device revision number.
131*a23fd118Syl150051  * @hldev: HAL device handle.
132*a23fd118Syl150051  *
133*a23fd118Syl150051  * Returns: Device revision number
134*a23fd118Syl150051  */
135*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE int
136*a23fd118Syl150051 xge_hal_device_rev(xge_hal_device_t *hldev)
137*a23fd118Syl150051 {
138*a23fd118Syl150051         return hldev->revision;
139*a23fd118Syl150051 }
140*a23fd118Syl150051 
141*a23fd118Syl150051 
142*a23fd118Syl150051 /**
143*a23fd118Syl150051  * xge_hal_device_begin_irq - Begin IRQ processing.
144*a23fd118Syl150051  * @hldev: HAL device handle.
145*a23fd118Syl150051  * @reason: "Reason" for the interrupt, the value of Xframe's
146*a23fd118Syl150051  *          general_int_status register.
147*a23fd118Syl150051  *
148*a23fd118Syl150051  * The function performs two actions, It first checks whether (shared IRQ) the
149*a23fd118Syl150051  * interrupt was raised by the device. Next, it masks the device interrupts.
150*a23fd118Syl150051  *
151*a23fd118Syl150051  * Note:
152*a23fd118Syl150051  * xge_hal_device_begin_irq() does not flush MMIO writes through the
153*a23fd118Syl150051  * bridge. Therefore, two back-to-back interrupts are potentially possible.
154*a23fd118Syl150051  * It is the responsibility of the ULD to make sure that only one
155*a23fd118Syl150051  * xge_hal_device_continue_irq() runs at a time.
156*a23fd118Syl150051  *
157*a23fd118Syl150051  * Returns: 0, if the interrupt is not "ours" (note that in this case the
158*a23fd118Syl150051  * device remain enabled).
159*a23fd118Syl150051  * Otherwise, xge_hal_device_begin_irq() returns 64bit general adapter
160*a23fd118Syl150051  * status.
161*a23fd118Syl150051  * See also: xge_hal_device_handle_irq()
162*a23fd118Syl150051  */
163*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
164*a23fd118Syl150051 xge_hal_device_begin_irq(xge_hal_device_t *hldev, u64 *reason)
165*a23fd118Syl150051 {
166*a23fd118Syl150051 	u64 val64;
167*a23fd118Syl150051 	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
168*a23fd118Syl150051 
169*a23fd118Syl150051 	hldev->stats.sw_dev_info_stats.total_intr_cnt++;
170*a23fd118Syl150051 
171*a23fd118Syl150051 	val64 = xge_os_pio_mem_read64(hldev->pdev,
172*a23fd118Syl150051 			      hldev->regh0, &isrbar0->general_int_status);
173*a23fd118Syl150051 	if (xge_os_unlikely(!val64)) {
174*a23fd118Syl150051 		/* not Xframe interrupt */
175*a23fd118Syl150051 		hldev->stats.sw_dev_info_stats.not_traffic_intr_cnt++;
176*a23fd118Syl150051 		*reason = 0;
177*a23fd118Syl150051 	        return XGE_HAL_ERR_WRONG_IRQ;
178*a23fd118Syl150051 	}
179*a23fd118Syl150051 
180*a23fd118Syl150051 	if (xge_os_unlikely(val64 == XGE_HAL_ALL_FOXES)) {
181*a23fd118Syl150051                 u64 adapter_status =
182*a23fd118Syl150051                         xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
183*a23fd118Syl150051 					      &isrbar0->adapter_status);
184*a23fd118Syl150051                 if (adapter_status == XGE_HAL_ALL_FOXES)  {
185*a23fd118Syl150051 	                (void) xge_queue_produce(hldev->queueh,
186*a23fd118Syl150051 						 XGE_HAL_EVENT_SLOT_FREEZE,
187*a23fd118Syl150051 						 hldev,
188*a23fd118Syl150051 						 1,  /* critical: slot freeze */
189*a23fd118Syl150051 						 sizeof(u64),
190*a23fd118Syl150051 						 (void*)&adapter_status);
191*a23fd118Syl150051 			*reason = 0;
192*a23fd118Syl150051 			return XGE_HAL_ERR_CRITICAL;
193*a23fd118Syl150051 		}
194*a23fd118Syl150051 	}
195*a23fd118Syl150051 
196*a23fd118Syl150051 	*reason = val64;
197*a23fd118Syl150051 
198*a23fd118Syl150051 	/* separate fast path, i.e. no errors */
199*a23fd118Syl150051 	if (val64 & XGE_HAL_GEN_INTR_RXTRAFFIC) {
200*a23fd118Syl150051 		hldev->stats.sw_dev_info_stats.rx_traffic_intr_cnt++;
201*a23fd118Syl150051 		return XGE_HAL_OK;
202*a23fd118Syl150051 	}
203*a23fd118Syl150051 	if (val64 & XGE_HAL_GEN_INTR_TXTRAFFIC) {
204*a23fd118Syl150051 		hldev->stats.sw_dev_info_stats.tx_traffic_intr_cnt++;
205*a23fd118Syl150051 		return XGE_HAL_OK;
206*a23fd118Syl150051 	}
207*a23fd118Syl150051 
208*a23fd118Syl150051 	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_TXPIC)) {
209*a23fd118Syl150051 		xge_hal_status_e status;
210*a23fd118Syl150051 		status = __hal_device_handle_txpic(hldev, val64);
211*a23fd118Syl150051 		if (status != XGE_HAL_OK) {
212*a23fd118Syl150051 			return status;
213*a23fd118Syl150051 		}
214*a23fd118Syl150051 	}
215*a23fd118Syl150051 
216*a23fd118Syl150051 	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_TXDMA)) {
217*a23fd118Syl150051 		xge_hal_status_e status;
218*a23fd118Syl150051 		status = __hal_device_handle_txdma(hldev, val64);
219*a23fd118Syl150051 		if (status != XGE_HAL_OK) {
220*a23fd118Syl150051 			return status;
221*a23fd118Syl150051 		}
222*a23fd118Syl150051 	}
223*a23fd118Syl150051 
224*a23fd118Syl150051 	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_TXMAC)) {
225*a23fd118Syl150051 		xge_hal_status_e status;
226*a23fd118Syl150051 		status = __hal_device_handle_txmac(hldev, val64);
227*a23fd118Syl150051 		if (status != XGE_HAL_OK) {
228*a23fd118Syl150051 			return status;
229*a23fd118Syl150051 		}
230*a23fd118Syl150051 	}
231*a23fd118Syl150051 
232*a23fd118Syl150051 	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_TXXGXS)) {
233*a23fd118Syl150051 		xge_hal_status_e status;
234*a23fd118Syl150051 		status = __hal_device_handle_txxgxs(hldev, val64);
235*a23fd118Syl150051 		if (status != XGE_HAL_OK) {
236*a23fd118Syl150051 			return status;
237*a23fd118Syl150051 		}
238*a23fd118Syl150051 	}
239*a23fd118Syl150051 
240*a23fd118Syl150051 	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_RXPIC)) {
241*a23fd118Syl150051 		xge_hal_status_e status;
242*a23fd118Syl150051 		status = __hal_device_handle_rxpic(hldev, val64);
243*a23fd118Syl150051 		if (status != XGE_HAL_OK) {
244*a23fd118Syl150051 			return status;
245*a23fd118Syl150051 		}
246*a23fd118Syl150051 	}
247*a23fd118Syl150051 
248*a23fd118Syl150051 	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_RXDMA)) {
249*a23fd118Syl150051 		xge_hal_status_e status;
250*a23fd118Syl150051 		status = __hal_device_handle_rxdma(hldev, val64);
251*a23fd118Syl150051 		if (status != XGE_HAL_OK) {
252*a23fd118Syl150051 			return status;
253*a23fd118Syl150051 		}
254*a23fd118Syl150051 	}
255*a23fd118Syl150051 
256*a23fd118Syl150051 	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_RXMAC)) {
257*a23fd118Syl150051 		xge_hal_status_e status;
258*a23fd118Syl150051 		status = __hal_device_handle_rxmac(hldev, val64);
259*a23fd118Syl150051 		if (status != XGE_HAL_OK) {
260*a23fd118Syl150051 			return status;
261*a23fd118Syl150051 		}
262*a23fd118Syl150051 	}
263*a23fd118Syl150051 
264*a23fd118Syl150051 	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_RXXGXS)) {
265*a23fd118Syl150051 		xge_hal_status_e status;
266*a23fd118Syl150051 		status = __hal_device_handle_rxxgxs(hldev, val64);
267*a23fd118Syl150051 		if (status != XGE_HAL_OK) {
268*a23fd118Syl150051 			return status;
269*a23fd118Syl150051 		}
270*a23fd118Syl150051 	}
271*a23fd118Syl150051 
272*a23fd118Syl150051 	if (xge_os_unlikely(val64 & XGE_HAL_GEN_INTR_MC)) {
273*a23fd118Syl150051 		xge_hal_status_e status;
274*a23fd118Syl150051 		status = __hal_device_handle_mc(hldev, val64);
275*a23fd118Syl150051 		if (status != XGE_HAL_OK) {
276*a23fd118Syl150051 			return status;
277*a23fd118Syl150051 		}
278*a23fd118Syl150051 	}
279*a23fd118Syl150051 
280*a23fd118Syl150051 	return XGE_HAL_OK;
281*a23fd118Syl150051 }
282*a23fd118Syl150051 
283*a23fd118Syl150051 /**
284*a23fd118Syl150051  * xge_hal_device_clear_rx - Acknowledge (that is, clear) the
285*a23fd118Syl150051  * condition that has caused the RX interrupt.
286*a23fd118Syl150051  * @hldev: HAL device handle.
287*a23fd118Syl150051  *
288*a23fd118Syl150051  * Acknowledge (that is, clear) the condition that has caused
289*a23fd118Syl150051  * the Rx interrupt.
290*a23fd118Syl150051  * See also: xge_hal_device_begin_irq(), xge_hal_device_continue_irq(),
291*a23fd118Syl150051  * xge_hal_device_clear_tx(), xge_hal_device_mask_rx().
292*a23fd118Syl150051  */
293*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
294*a23fd118Syl150051 xge_hal_device_clear_rx(xge_hal_device_t *hldev)
295*a23fd118Syl150051 {
296*a23fd118Syl150051 	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
297*a23fd118Syl150051 
298*a23fd118Syl150051 	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
299*a23fd118Syl150051 			     0xFFFFFFFFFFFFFFFFULL,
300*a23fd118Syl150051 			     &isrbar0->rx_traffic_int);
301*a23fd118Syl150051 }
302*a23fd118Syl150051 
303*a23fd118Syl150051 /**
304*a23fd118Syl150051  * xge_hal_device_clear_tx - Acknowledge (that is, clear) the
305*a23fd118Syl150051  * condition that has caused the TX interrupt.
306*a23fd118Syl150051  * @hldev: HAL device handle.
307*a23fd118Syl150051  *
308*a23fd118Syl150051  * Acknowledge (that is, clear) the condition that has caused
309*a23fd118Syl150051  * the Tx interrupt.
310*a23fd118Syl150051  * See also: xge_hal_device_begin_irq(), xge_hal_device_continue_irq(),
311*a23fd118Syl150051  * xge_hal_device_clear_rx(), xge_hal_device_mask_tx().
312*a23fd118Syl150051  */
313*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
314*a23fd118Syl150051 xge_hal_device_clear_tx(xge_hal_device_t *hldev)
315*a23fd118Syl150051 {
316*a23fd118Syl150051 	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
317*a23fd118Syl150051 
318*a23fd118Syl150051 	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
319*a23fd118Syl150051 			     0xFFFFFFFFFFFFFFFFULL,
320*a23fd118Syl150051 			     &isrbar0->tx_traffic_int);
321*a23fd118Syl150051 }
322*a23fd118Syl150051 
323*a23fd118Syl150051 /**
324*a23fd118Syl150051  * xge_hal_device_poll_rx_channels - Poll Rx channels for completed
325*a23fd118Syl150051  * descriptors and process the same.
326*a23fd118Syl150051  * @hldev: HAL device handle.
327*a23fd118Syl150051  *
328*a23fd118Syl150051  * The function polls the Rx channels for the completed descriptors and calls
329*a23fd118Syl150051  * the upper-layer driver (ULD) via supplied completion callback.
330*a23fd118Syl150051  *
331*a23fd118Syl150051  * Returns: XGE_HAL_OK, if the polling is completed successful.
332*a23fd118Syl150051  * XGE_HAL_COMPLETIONS_REMAIN: There are still more completed
333*a23fd118Syl150051  * descriptors available which are yet to be processed.
334*a23fd118Syl150051  *
335*a23fd118Syl150051  * See also: xge_hal_device_poll_tx_channels(), xge_hal_device_continue_irq().
336*a23fd118Syl150051  */
337*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
338*a23fd118Syl150051 xge_hal_device_poll_rx_channels(xge_hal_device_t *hldev)
339*a23fd118Syl150051 {
340*a23fd118Syl150051 	xge_list_t *item;
341*a23fd118Syl150051 	xge_hal_channel_t *channel;
342*a23fd118Syl150051 	xge_hal_dtr_h first_dtrh;
343*a23fd118Syl150051 	u8 t_code;
344*a23fd118Syl150051 
345*a23fd118Syl150051 	/* for each opened rx channel */
346*a23fd118Syl150051 	xge_list_for_each(item, &hldev->ring_channels) {
347*a23fd118Syl150051 		channel = xge_container_of(item,
348*a23fd118Syl150051 				xge_hal_channel_t, item);
349*a23fd118Syl150051 
350*a23fd118Syl150051 		((xge_hal_ring_t*)channel)->cmpl_cnt = 0;
351*a23fd118Syl150051 		if (xge_hal_ring_dtr_next_completed (channel, &first_dtrh,
352*a23fd118Syl150051 					&t_code) == XGE_HAL_OK) {
353*a23fd118Syl150051 			if (channel->callback(channel, first_dtrh,
354*a23fd118Syl150051 				t_code, channel->userdata) != XGE_HAL_OK) {
355*a23fd118Syl150051 				return XGE_HAL_COMPLETIONS_REMAIN;
356*a23fd118Syl150051 			}
357*a23fd118Syl150051 		}
358*a23fd118Syl150051 	}
359*a23fd118Syl150051 
360*a23fd118Syl150051 	return XGE_HAL_OK;
361*a23fd118Syl150051 }
362*a23fd118Syl150051 
363*a23fd118Syl150051 /**
364*a23fd118Syl150051  * xge_hal_device_poll_tx_channels - Poll Tx channels for completed
365*a23fd118Syl150051  * descriptors and process the same.
366*a23fd118Syl150051  * @hldev: HAL device handle.
367*a23fd118Syl150051  *
368*a23fd118Syl150051  * The function polls the Tx channels for the completed descriptors and calls
369*a23fd118Syl150051  * the upper-layer driver (ULD) via supplied completion callback.
370*a23fd118Syl150051  *
371*a23fd118Syl150051  * Returns: XGE_HAL_OK, if the polling is completed successful.
372*a23fd118Syl150051  * XGE_HAL_COMPLETIONS_REMAIN: There are still more completed
373*a23fd118Syl150051  * descriptors available which are yet to be processed.
374*a23fd118Syl150051  *
375*a23fd118Syl150051  * See also: xge_hal_device_poll_rx_channels(), xge_hal_device_continue_irq().
376*a23fd118Syl150051  */
377*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
378*a23fd118Syl150051 xge_hal_device_poll_tx_channels(xge_hal_device_t *hldev)
379*a23fd118Syl150051 {
380*a23fd118Syl150051 	xge_list_t *item;
381*a23fd118Syl150051 	xge_hal_channel_t *channel;
382*a23fd118Syl150051 	xge_hal_dtr_h first_dtrh;
383*a23fd118Syl150051 	u8 t_code;
384*a23fd118Syl150051 
385*a23fd118Syl150051 	/* for each opened tx channel */
386*a23fd118Syl150051 	xge_list_for_each(item, &hldev->fifo_channels) {
387*a23fd118Syl150051 		channel = xge_container_of(item,
388*a23fd118Syl150051 				xge_hal_channel_t, item);
389*a23fd118Syl150051 
390*a23fd118Syl150051 		if (xge_hal_fifo_dtr_next_completed (channel, &first_dtrh,
391*a23fd118Syl150051 					&t_code) == XGE_HAL_OK) {
392*a23fd118Syl150051 			if (channel->callback(channel, first_dtrh,
393*a23fd118Syl150051 				t_code, channel->userdata) != XGE_HAL_OK) {
394*a23fd118Syl150051 				return XGE_HAL_COMPLETIONS_REMAIN;
395*a23fd118Syl150051 			}
396*a23fd118Syl150051 		}
397*a23fd118Syl150051 	}
398*a23fd118Syl150051 
399*a23fd118Syl150051 	return XGE_HAL_OK;
400*a23fd118Syl150051 }
401*a23fd118Syl150051 
402*a23fd118Syl150051 /**
403*a23fd118Syl150051  * xge_hal_device_mask_tx - Mask Tx interrupts.
404*a23fd118Syl150051  * @hldev: HAL device handle.
405*a23fd118Syl150051  *
406*a23fd118Syl150051  * Mask Tx device interrupts.
407*a23fd118Syl150051  *
408*a23fd118Syl150051  * See also: xge_hal_device_unmask_tx(), xge_hal_device_mask_rx(),
409*a23fd118Syl150051  * xge_hal_device_clear_tx().
410*a23fd118Syl150051  */
411*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
412*a23fd118Syl150051 xge_hal_device_mask_tx(xge_hal_device_t *hldev)
413*a23fd118Syl150051 {
414*a23fd118Syl150051 	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
415*a23fd118Syl150051 
416*a23fd118Syl150051 	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
417*a23fd118Syl150051 			       0xFFFFFFFFFFFFFFFFULL,
418*a23fd118Syl150051 			       &isrbar0->tx_traffic_mask);
419*a23fd118Syl150051 }
420*a23fd118Syl150051 
421*a23fd118Syl150051 /**
422*a23fd118Syl150051  * xge_hal_device_mask_rx - Mask Rx interrupts.
423*a23fd118Syl150051  * @hldev: HAL device handle.
424*a23fd118Syl150051  *
425*a23fd118Syl150051  * Mask Rx device interrupts.
426*a23fd118Syl150051  *
427*a23fd118Syl150051  * See also: xge_hal_device_unmask_rx(), xge_hal_device_mask_tx(),
428*a23fd118Syl150051  * xge_hal_device_clear_rx().
429*a23fd118Syl150051  */
430*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
431*a23fd118Syl150051 xge_hal_device_mask_rx(xge_hal_device_t *hldev)
432*a23fd118Syl150051 {
433*a23fd118Syl150051 	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
434*a23fd118Syl150051 
435*a23fd118Syl150051 	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
436*a23fd118Syl150051 			       0xFFFFFFFFFFFFFFFFULL,
437*a23fd118Syl150051 			       &isrbar0->rx_traffic_mask);
438*a23fd118Syl150051 }
439*a23fd118Syl150051 
440*a23fd118Syl150051 /**
441*a23fd118Syl150051  * xge_hal_device_mask_all - Mask all device interrupts.
442*a23fd118Syl150051  * @hldev: HAL device handle.
443*a23fd118Syl150051  *
444*a23fd118Syl150051  * Mask all device interrupts.
445*a23fd118Syl150051  *
446*a23fd118Syl150051  * See also: xge_hal_device_unmask_all()
447*a23fd118Syl150051  */
448*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
449*a23fd118Syl150051 xge_hal_device_mask_all(xge_hal_device_t *hldev)
450*a23fd118Syl150051 {
451*a23fd118Syl150051 	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
452*a23fd118Syl150051 
453*a23fd118Syl150051 	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
454*a23fd118Syl150051 			       0xFFFFFFFFFFFFFFFFULL,
455*a23fd118Syl150051 			       &isrbar0->general_int_mask);
456*a23fd118Syl150051 }
457*a23fd118Syl150051 
458*a23fd118Syl150051 /**
459*a23fd118Syl150051  * xge_hal_device_unmask_tx - Unmask Tx interrupts.
460*a23fd118Syl150051  * @hldev: HAL device handle.
461*a23fd118Syl150051  *
462*a23fd118Syl150051  * Unmask Tx device interrupts.
463*a23fd118Syl150051  *
464*a23fd118Syl150051  * See also: xge_hal_device_mask_tx(), xge_hal_device_clear_tx().
465*a23fd118Syl150051  */
466*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
467*a23fd118Syl150051 xge_hal_device_unmask_tx(xge_hal_device_t *hldev)
468*a23fd118Syl150051 {
469*a23fd118Syl150051 	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
470*a23fd118Syl150051 
471*a23fd118Syl150051 	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
472*a23fd118Syl150051 			       0x0ULL,
473*a23fd118Syl150051 			       &isrbar0->tx_traffic_mask);
474*a23fd118Syl150051 }
475*a23fd118Syl150051 
476*a23fd118Syl150051 /**
477*a23fd118Syl150051  * xge_hal_device_unmask_rx - Unmask Rx interrupts.
478*a23fd118Syl150051  * @hldev: HAL device handle.
479*a23fd118Syl150051  *
480*a23fd118Syl150051  * Unmask Rx device interrupts.
481*a23fd118Syl150051  *
482*a23fd118Syl150051  * See also: xge_hal_device_mask_rx(), xge_hal_device_clear_rx().
483*a23fd118Syl150051  */
484*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
485*a23fd118Syl150051 xge_hal_device_unmask_rx(xge_hal_device_t *hldev)
486*a23fd118Syl150051 {
487*a23fd118Syl150051 	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
488*a23fd118Syl150051 
489*a23fd118Syl150051 	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
490*a23fd118Syl150051 			       0x0ULL,
491*a23fd118Syl150051 			       &isrbar0->rx_traffic_mask);
492*a23fd118Syl150051 }
493*a23fd118Syl150051 
494*a23fd118Syl150051 /**
495*a23fd118Syl150051  * xge_hal_device_unmask_all - Unmask all device interrupts.
496*a23fd118Syl150051  * @hldev: HAL device handle.
497*a23fd118Syl150051  *
498*a23fd118Syl150051  * Unmask all device interrupts.
499*a23fd118Syl150051  *
500*a23fd118Syl150051  * See also: xge_hal_device_mask_all()
501*a23fd118Syl150051  */
502*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE void
503*a23fd118Syl150051 xge_hal_device_unmask_all(xge_hal_device_t *hldev)
504*a23fd118Syl150051 {
505*a23fd118Syl150051 	xge_hal_pci_bar0_t *isrbar0 = (xge_hal_pci_bar0_t *)hldev->isrbar0;
506*a23fd118Syl150051 
507*a23fd118Syl150051 	xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
508*a23fd118Syl150051 			       0x0ULL,
509*a23fd118Syl150051 			       &isrbar0->general_int_mask);
510*a23fd118Syl150051 }
511*a23fd118Syl150051 
512*a23fd118Syl150051 
513*a23fd118Syl150051 /**
514*a23fd118Syl150051  * xge_hal_device_continue_irq - Continue handling IRQ: process all
515*a23fd118Syl150051  * completed descriptors.
516*a23fd118Syl150051  * @hldev: HAL device handle.
517*a23fd118Syl150051  *
518*a23fd118Syl150051  * Process completed descriptors and unmask the device interrupts.
519*a23fd118Syl150051  *
520*a23fd118Syl150051  * The xge_hal_device_continue_irq() walks all open channels
521*a23fd118Syl150051  * and calls upper-layer driver (ULD) via supplied completion
522*a23fd118Syl150051  * callback. Note that the completion callback is specified at channel open
523*a23fd118Syl150051  * time, see xge_hal_channel_open().
524*a23fd118Syl150051  *
525*a23fd118Syl150051  * Note that the xge_hal_device_continue_irq is part of the _fast_ path.
526*a23fd118Syl150051  * To optimize the processing, the function does _not_ check for
527*a23fd118Syl150051  * errors and alarms.
528*a23fd118Syl150051  *
529*a23fd118Syl150051  * The latter is done in a polling fashion, via xge_hal_device_poll().
530*a23fd118Syl150051  *
531*a23fd118Syl150051  * Returns: XGE_HAL_OK.
532*a23fd118Syl150051  *
533*a23fd118Syl150051  * See also: xge_hal_device_handle_irq(), xge_hal_device_poll(),
534*a23fd118Syl150051  * xge_hal_ring_dtr_next_completed(),
535*a23fd118Syl150051  * xge_hal_fifo_dtr_next_completed(), xge_hal_channel_callback_f{}.
536*a23fd118Syl150051  */
537*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
538*a23fd118Syl150051 xge_hal_device_continue_irq(xge_hal_device_t *hldev)
539*a23fd118Syl150051 {
540*a23fd118Syl150051 	xge_list_t *item;
541*a23fd118Syl150051 	xge_hal_channel_t *channel;
542*a23fd118Syl150051 	xge_hal_dtr_h first_dtrh;
543*a23fd118Syl150051 	int got_rx = 0, got_tx = 0;
544*a23fd118Syl150051 	unsigned int isr_polling_cnt = (unsigned int) hldev->config.isr_polling_cnt;
545*a23fd118Syl150051 	u8 t_code;
546*a23fd118Syl150051 
547*a23fd118Syl150051 _try_again:
548*a23fd118Syl150051 
549*a23fd118Syl150051 	/* for each opened rx channel */
550*a23fd118Syl150051 	xge_list_for_each(item, &hldev->ring_channels) {
551*a23fd118Syl150051 		channel = xge_container_of(item,
552*a23fd118Syl150051 				xge_hal_channel_t, item);
553*a23fd118Syl150051 
554*a23fd118Syl150051 		((xge_hal_ring_t*)channel)->cmpl_cnt = 0;
555*a23fd118Syl150051 		if (xge_hal_ring_dtr_next_completed (channel, &first_dtrh,
556*a23fd118Syl150051 					&t_code) == XGE_HAL_OK) {
557*a23fd118Syl150051 			channel->callback(channel, first_dtrh,
558*a23fd118Syl150051 						t_code, channel->userdata);
559*a23fd118Syl150051 			got_rx++;
560*a23fd118Syl150051 		}
561*a23fd118Syl150051 
562*a23fd118Syl150051 		if (hldev->terminating)
563*a23fd118Syl150051 			return XGE_HAL_OK;
564*a23fd118Syl150051 
565*a23fd118Syl150051 	}
566*a23fd118Syl150051 
567*a23fd118Syl150051 	/* Note.
568*a23fd118Syl150051 	 * All interrupts are masked by general_int_status at this point,
569*a23fd118Syl150051 	 * i.e. no new interrupts going to be produced by the adapter.
570*a23fd118Syl150051 	 * We intentionally do not mask rx/tx interrupts right after
571*a23fd118Syl150051 	 * walking to continue processing new descriptors on next
572*a23fd118Syl150051 	 * interation if configured. */
573*a23fd118Syl150051 
574*a23fd118Syl150051 	/* for each opened tx channel */
575*a23fd118Syl150051 	xge_list_for_each(item, &hldev->fifo_channels) {
576*a23fd118Syl150051 		channel = xge_container_of(item,
577*a23fd118Syl150051 				xge_hal_channel_t, item);
578*a23fd118Syl150051 
579*a23fd118Syl150051 		if (xge_hal_fifo_dtr_next_completed (channel, &first_dtrh,
580*a23fd118Syl150051 					&t_code) == XGE_HAL_OK) {
581*a23fd118Syl150051 			channel->callback(channel, first_dtrh,
582*a23fd118Syl150051 					t_code, channel->userdata);
583*a23fd118Syl150051 			got_tx++;
584*a23fd118Syl150051 		}
585*a23fd118Syl150051 
586*a23fd118Syl150051 		if (hldev->terminating)
587*a23fd118Syl150051 			return XGE_HAL_OK;
588*a23fd118Syl150051 
589*a23fd118Syl150051 	}
590*a23fd118Syl150051 
591*a23fd118Syl150051 	if (got_rx || got_tx) {
592*a23fd118Syl150051 		xge_hal_pci_bar0_t *isrbar0 =
593*a23fd118Syl150051 			(xge_hal_pci_bar0_t *)hldev->isrbar0;
594*a23fd118Syl150051 		got_tx = got_rx = 0;
595*a23fd118Syl150051 		if (isr_polling_cnt--)
596*a23fd118Syl150051 			goto _try_again;
597*a23fd118Syl150051 		/* to avoid interrupt loss, we force bridge to flush cached
598*a23fd118Syl150051 		 * writes, in simple case OSDEP needs to just readl(), some
599*a23fd118Syl150051 		 * OSes (e.g. M$ Windows) has special bridge flush API */
600*a23fd118Syl150051 		(void) xge_os_flush_bridge(hldev->pdev, hldev->regh0,
601*a23fd118Syl150051 				    &isrbar0->general_int_status);
602*a23fd118Syl150051 	} else if (isr_polling_cnt == hldev->config.isr_polling_cnt) {
603*a23fd118Syl150051 		hldev->stats.sw_dev_info_stats.not_traffic_intr_cnt++;
604*a23fd118Syl150051 	}
605*a23fd118Syl150051 
606*a23fd118Syl150051 	return XGE_HAL_OK;
607*a23fd118Syl150051 }
608*a23fd118Syl150051 
609*a23fd118Syl150051 /**
610*a23fd118Syl150051  * xge_hal_device_handle_irq - Handle device IRQ.
611*a23fd118Syl150051  * @hldev: HAL device handle.
612*a23fd118Syl150051  *
613*a23fd118Syl150051  * Perform the complete handling of the line interrupt. The function
614*a23fd118Syl150051  * performs two calls.
615*a23fd118Syl150051  * First it uses xge_hal_device_begin_irq() to  check the reason for
616*a23fd118Syl150051  * the interrupt and mask the device interrupts.
617*a23fd118Syl150051  * Second, it calls xge_hal_device_continue_irq() to process all
618*a23fd118Syl150051  * completed descriptors and re-enable the interrupts.
619*a23fd118Syl150051  *
620*a23fd118Syl150051  * Returns: XGE_HAL_OK - success;
621*a23fd118Syl150051  * XGE_HAL_ERR_WRONG_IRQ - (shared) IRQ produced by other device.
622*a23fd118Syl150051  *
623*a23fd118Syl150051  * See also: xge_hal_device_begin_irq(), xge_hal_device_continue_irq().
624*a23fd118Syl150051  */
625*a23fd118Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE xge_hal_status_e
626*a23fd118Syl150051 xge_hal_device_handle_irq(xge_hal_device_t *hldev)
627*a23fd118Syl150051 {
628*a23fd118Syl150051 	u64 reason;
629*a23fd118Syl150051 	xge_hal_status_e status;
630*a23fd118Syl150051 
631*a23fd118Syl150051 	xge_hal_device_mask_all(hldev);
632*a23fd118Syl150051 
633*a23fd118Syl150051         status = xge_hal_device_begin_irq(hldev, &reason);
634*a23fd118Syl150051         if (status != XGE_HAL_OK) {
635*a23fd118Syl150051 		xge_hal_device_unmask_all(hldev);
636*a23fd118Syl150051 	        return status;
637*a23fd118Syl150051 	}
638*a23fd118Syl150051 
639*a23fd118Syl150051 	if (reason & XGE_HAL_GEN_INTR_RXTRAFFIC) {
640*a23fd118Syl150051 		xge_hal_device_clear_rx(hldev);
641*a23fd118Syl150051 	}
642*a23fd118Syl150051 
643*a23fd118Syl150051         status = xge_hal_device_continue_irq(hldev);
644*a23fd118Syl150051 
645*a23fd118Syl150051 	xge_hal_device_clear_tx(hldev);
646*a23fd118Syl150051 
647*a23fd118Syl150051 	xge_hal_device_unmask_all(hldev);
648*a23fd118Syl150051 
649*a23fd118Syl150051 	return status;
650*a23fd118Syl150051 }
651*a23fd118Syl150051 
652*a23fd118Syl150051 #if defined(XGE_HAL_CONFIG_LRO)
653*a23fd118Syl150051 
654*a23fd118Syl150051 /*
655*a23fd118Syl150051  * __hal_tcp_seg_len: Find the tcp seg len.
656*a23fd118Syl150051  * @ip: ip header.
657*a23fd118Syl150051  * @tcp: tcp header.
658*a23fd118Syl150051  * returns: Tcp seg length.
659*a23fd118Syl150051  */
660*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL u16
661*a23fd118Syl150051 __hal_tcp_seg_len(iplro_t *ip, tcplro_t *tcp)
662*a23fd118Syl150051 {
663*a23fd118Syl150051 	u16 ret;
664*a23fd118Syl150051 
665*a23fd118Syl150051 	ret =  (xge_os_ntohs(ip->tot_len) -
666*a23fd118Syl150051 	       ((ip->version_ihl & 0x0F)<<2) -
667*a23fd118Syl150051 	       ((tcp->doff_res)>>2));
668*a23fd118Syl150051 	return (ret);
669*a23fd118Syl150051 }
670*a23fd118Syl150051 
671*a23fd118Syl150051 /*
672*a23fd118Syl150051  * __hal_ip_lro_capable: Finds whether ip is lro capable.
673*a23fd118Syl150051  * @ip: ip header.
674*a23fd118Syl150051  * @ext_info:  descriptor info.
675*a23fd118Syl150051  */
676*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
677*a23fd118Syl150051 __hal_ip_lro_capable(iplro_t *ip,
678*a23fd118Syl150051 		     xge_hal_dtr_info_t *ext_info)
679*a23fd118Syl150051 {
680*a23fd118Syl150051 
681*a23fd118Syl150051 #ifdef XGE_LL_DEBUG_DUMP_PKT
682*a23fd118Syl150051 		{
683*a23fd118Syl150051 			u16 i;
684*a23fd118Syl150051 			u8 ch, *iph = (u8 *)ip;
685*a23fd118Syl150051 
686*a23fd118Syl150051 			xge_debug_ring(XGE_TRACE, "Dump Ip:" );
687*a23fd118Syl150051 			for (i =0; i < 40; i++) {
688*a23fd118Syl150051 				ch = ntohs(*((u8 *)(iph + i)) );
689*a23fd118Syl150051 				printf("i:%d %02x, ",i,ch);
690*a23fd118Syl150051 			}
691*a23fd118Syl150051 		}
692*a23fd118Syl150051 #endif
693*a23fd118Syl150051 
694*a23fd118Syl150051 	if (ip->version_ihl != IP_FAST_PATH_HDR_MASK) {
695*a23fd118Syl150051 		xge_debug_ring(XGE_ERR, "iphdr !=45 :%d",ip->version_ihl);
696*a23fd118Syl150051 		return XGE_HAL_FAIL;
697*a23fd118Syl150051 	}
698*a23fd118Syl150051 
699*a23fd118Syl150051 	if (ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED) {
700*a23fd118Syl150051 		xge_debug_ring(XGE_ERR, "IP fragmented");
701*a23fd118Syl150051 		return XGE_HAL_FAIL;
702*a23fd118Syl150051 	}
703*a23fd118Syl150051 
704*a23fd118Syl150051 	return XGE_HAL_OK;
705*a23fd118Syl150051 }
706*a23fd118Syl150051 
707*a23fd118Syl150051 /*
708*a23fd118Syl150051  * __hal_tcp_lro_capable: Finds whether tcp is lro capable.
709*a23fd118Syl150051  * @ip: ip header.
710*a23fd118Syl150051  * @tcp: tcp header.
711*a23fd118Syl150051  */
712*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
713*a23fd118Syl150051 __hal_tcp_lro_capable(iplro_t *ip, tcplro_t *tcp)
714*a23fd118Syl150051 {
715*a23fd118Syl150051 #ifdef XGE_LL_DEBUG_DUMP_PKT
716*a23fd118Syl150051 		{
717*a23fd118Syl150051 			u8 ch;
718*a23fd118Syl150051 			u16 i;
719*a23fd118Syl150051 
720*a23fd118Syl150051 			xge_debug_ring(XGE_TRACE, "Dump Tcp:" );
721*a23fd118Syl150051 			for (i =0; i < 20; i++) {
722*a23fd118Syl150051 				ch = ntohs(*((u8 *)((u8 *)tcp + i)) );
723*a23fd118Syl150051 				xge_os_printf("i:%d %02x, ",i,ch);
724*a23fd118Syl150051 			}
725*a23fd118Syl150051 		}
726*a23fd118Syl150051 #endif
727*a23fd118Syl150051 	if ((TCP_FAST_PATH_HDR_MASK1 != tcp->doff_res) ||
728*a23fd118Syl150051 	    ((TCP_FAST_PATH_HDR_MASK2 != tcp->ctrl) &&
729*a23fd118Syl150051 	     (TCP_FAST_PATH_HDR_MASK3 != tcp->ctrl))) {
730*a23fd118Syl150051 		xge_debug_ring(XGE_ERR, "tcphdr not fastpth %02x %02x \n", tcp->doff_res, tcp->ctrl);
731*a23fd118Syl150051 		return XGE_HAL_FAIL;
732*a23fd118Syl150051 	}
733*a23fd118Syl150051 
734*a23fd118Syl150051 	return XGE_HAL_OK;
735*a23fd118Syl150051 }
736*a23fd118Syl150051 
737*a23fd118Syl150051 /*
738*a23fd118Syl150051  * __hal_lro_capable: Finds whether frame is lro capable.
739*a23fd118Syl150051  * @buffer: Ethernet frame.
740*a23fd118Syl150051  * @ip: ip frame.
741*a23fd118Syl150051  * @tcp: tcp frame.
742*a23fd118Syl150051  * @ext_info: Descriptor info.
743*a23fd118Syl150051  * @hldev: Hal context.
744*a23fd118Syl150051  */
745*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
746*a23fd118Syl150051 __hal_lro_capable( u8 *buffer,
747*a23fd118Syl150051 		   iplro_t **ip,
748*a23fd118Syl150051 		   tcplro_t **tcp,
749*a23fd118Syl150051 		   xge_hal_dtr_info_t *ext_info,
750*a23fd118Syl150051 		   xge_hal_device_t *hldev)
751*a23fd118Syl150051 {
752*a23fd118Syl150051 	u8 ip_off, ip_length;
753*a23fd118Syl150051 
754*a23fd118Syl150051 	if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_TCP)) {
755*a23fd118Syl150051 		xge_debug_ring(XGE_ERR, "Cant do lro %d", ext_info->proto);
756*a23fd118Syl150051 		return XGE_HAL_FAIL;
757*a23fd118Syl150051 	}
758*a23fd118Syl150051 #ifdef XGE_LL_DEBUG_DUMP_PKT
759*a23fd118Syl150051 		{
760*a23fd118Syl150051 			u8 ch;
761*a23fd118Syl150051 			u16 i;
762*a23fd118Syl150051 
763*a23fd118Syl150051 			xge_os_printf("Dump Eth:" );
764*a23fd118Syl150051 			for (i =0; i < 60; i++) {
765*a23fd118Syl150051 				ch = ntohs(*((u8 *)(buffer + i)) );
766*a23fd118Syl150051 				xge_os_printf("i:%d %02x, ",i,ch);
767*a23fd118Syl150051 			}
768*a23fd118Syl150051 		}
769*a23fd118Syl150051 #endif
770*a23fd118Syl150051 
771*a23fd118Syl150051 	switch (ext_info->frame) {
772*a23fd118Syl150051 	case XGE_HAL_FRAME_TYPE_DIX:
773*a23fd118Syl150051 		ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE;
774*a23fd118Syl150051 		break;
775*a23fd118Syl150051 	case XGE_HAL_FRAME_TYPE_LLC:
776*a23fd118Syl150051 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
777*a23fd118Syl150051 			  XGE_HAL_HEADER_802_2_SIZE);
778*a23fd118Syl150051 		break;
779*a23fd118Syl150051 	case XGE_HAL_FRAME_TYPE_SNAP:
780*a23fd118Syl150051 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
781*a23fd118Syl150051 			  XGE_HAL_HEADER_SNAP_SIZE);
782*a23fd118Syl150051 		break;
783*a23fd118Syl150051 	default: // XGE_HAL_FRAME_TYPE_IPX, etc.
784*a23fd118Syl150051 		return XGE_HAL_FAIL;
785*a23fd118Syl150051 	}
786*a23fd118Syl150051 
787*a23fd118Syl150051 
788*a23fd118Syl150051 	if (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED) {
789*a23fd118Syl150051 		ip_off += XGE_HAL_HEADER_VLAN_SIZE;
790*a23fd118Syl150051 	}
791*a23fd118Syl150051 
792*a23fd118Syl150051 	/* Grab ip, tcp headers */
793*a23fd118Syl150051 	*ip = (iplro_t *)((char*)buffer + ip_off);
794*a23fd118Syl150051 
795*a23fd118Syl150051 	ip_length = (u8)((*ip)->version_ihl & 0x0F);
796*a23fd118Syl150051 	ip_length = ip_length <<2;
797*a23fd118Syl150051 	*tcp = (tcplro_t *)((unsigned long)*ip + ip_length);
798*a23fd118Syl150051 
799*a23fd118Syl150051 	xge_debug_ring(XGE_TRACE, "ip_length:%d ip:%llx tcp:%llx", (int)ip_length,
800*a23fd118Syl150051 	(u64)(unsigned long)*ip, (u64)(unsigned long)*tcp);
801*a23fd118Syl150051 
802*a23fd118Syl150051 	return XGE_HAL_OK;
803*a23fd118Syl150051 
804*a23fd118Syl150051 }
805*a23fd118Syl150051 
806*a23fd118Syl150051 /**
807*a23fd118Syl150051  * xge_hal_lro_free - Used to recycle lro memory.
808*a23fd118Syl150051  * @lro: LRO memory.
809*a23fd118Syl150051  * @hldev: Hal device structure.
810*a23fd118Syl150051  *
811*a23fd118Syl150051  */
812*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
813*a23fd118Syl150051 xge_hal_lro_free(lro_t *lro, xge_hal_device_t *hldev)
814*a23fd118Syl150051 {
815*a23fd118Syl150051 	lro->in_use = 0;
816*a23fd118Syl150051 #if 1 // For debug.
817*a23fd118Syl150051 	xge_os_memzero(lro, sizeof(lro_t));
818*a23fd118Syl150051 #endif
819*a23fd118Syl150051 }
820*a23fd118Syl150051 
821*a23fd118Syl150051 /*
822*a23fd118Syl150051  * __hal_lro_malloc - Gets LRO from free memory pool.
823*a23fd118Syl150051  * @hldev: Hal device structure.
824*a23fd118Syl150051  */
825*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL lro_t *
826*a23fd118Syl150051 __hal_lro_malloc(xge_hal_device_t *hldev)
827*a23fd118Syl150051 {
828*a23fd118Syl150051 	hldev->g_lro_pool->in_use = 1;
829*a23fd118Syl150051 	return (hldev->g_lro_pool);
830*a23fd118Syl150051 }
831*a23fd118Syl150051 
832*a23fd118Syl150051 
833*a23fd118Syl150051 /*
834*a23fd118Syl150051  * __hal_get_lro_session: Gets matching LRO session or creates one.
835*a23fd118Syl150051  * @buffer: Ethernet frame.
836*a23fd118Syl150051  * @ip: ip header.
837*a23fd118Syl150051  * @tcp: tcp header.
838*a23fd118Syl150051  * @lro: lro pointer
839*a23fd118Syl150051  * @ext_info: Descriptor info.
840*a23fd118Syl150051  * @hldev: Hal context.
841*a23fd118Syl150051  * Note: Current implementation will contain only one LRO session.
842*a23fd118Syl150051  *       Global lro will not exist once more LRO sessions are permitted.
843*a23fd118Syl150051  */
844*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
845*a23fd118Syl150051 __hal_get_lro_session (u8 *buffer,
846*a23fd118Syl150051 		       iplro_t *ip,
847*a23fd118Syl150051 		       tcplro_t *tcp,
848*a23fd118Syl150051 		       lro_t **lro,
849*a23fd118Syl150051 		       xge_hal_dtr_info_t *ext_info,
850*a23fd118Syl150051 		       xge_hal_device_t *hldev)
851*a23fd118Syl150051 {
852*a23fd118Syl150051 	xge_hal_status_e ret;
853*a23fd118Syl150051 	lro_t *g_lro;
854*a23fd118Syl150051 	int i, free_slot = -1;
855*a23fd118Syl150051 
856*a23fd118Syl150051 	/***********************************************************
857*a23fd118Syl150051 	Search in the pool of LROs for the session that matches the incoming
858*a23fd118Syl150051 	frame.
859*a23fd118Syl150051 	************************************************************/
860*a23fd118Syl150051 	*lro = g_lro = NULL;
861*a23fd118Syl150051 	for (i = 0; i < XGE_HAL_MAX_LRO_SESSIONS; i++) {
862*a23fd118Syl150051 		g_lro = &hldev->g_lro_pool[i];
863*a23fd118Syl150051 
864*a23fd118Syl150051 		if (!g_lro->in_use) {
865*a23fd118Syl150051 			if (free_slot == -1)
866*a23fd118Syl150051 				free_slot = i;
867*a23fd118Syl150051 			continue;
868*a23fd118Syl150051 		}
869*a23fd118Syl150051 
870*a23fd118Syl150051 		/* Match Source address field */
871*a23fd118Syl150051 		if ((g_lro->ip_hdr->saddr != ip->saddr))
872*a23fd118Syl150051 			continue;
873*a23fd118Syl150051 
874*a23fd118Syl150051 		/* Match Destination address field */
875*a23fd118Syl150051 		if ((g_lro->ip_hdr->daddr != ip->daddr))
876*a23fd118Syl150051 			continue;
877*a23fd118Syl150051 
878*a23fd118Syl150051 
879*a23fd118Syl150051 		/* Match Source Port field */
880*a23fd118Syl150051 		if ((g_lro->tcp_hdr->source != tcp->source))
881*a23fd118Syl150051 			continue;
882*a23fd118Syl150051 
883*a23fd118Syl150051 
884*a23fd118Syl150051 		/* Match Destination Port field */
885*a23fd118Syl150051 		if ((g_lro->tcp_hdr->dest != tcp->dest))
886*a23fd118Syl150051 			continue;
887*a23fd118Syl150051 
888*a23fd118Syl150051 		*lro = g_lro;
889*a23fd118Syl150051 
890*a23fd118Syl150051 		if (g_lro->tcp_next_seq_num != xge_os_ntohl(tcp->seq)) {
891*a23fd118Syl150051 			xge_debug_ring(XGE_ERR, "**retransmit  **"
892*a23fd118Syl150051 						"found***");
893*a23fd118Syl150051 			return XGE_HAL_INF_LRO_END_2;
894*a23fd118Syl150051 		}
895*a23fd118Syl150051 
896*a23fd118Syl150051 		if (XGE_HAL_OK != __hal_ip_lro_capable(ip, ext_info))
897*a23fd118Syl150051 			return XGE_HAL_INF_LRO_END_2;
898*a23fd118Syl150051 
899*a23fd118Syl150051 		if (XGE_HAL_OK != __hal_tcp_lro_capable(ip, tcp))
900*a23fd118Syl150051 			return XGE_HAL_INF_LRO_END_2;
901*a23fd118Syl150051 
902*a23fd118Syl150051                	/*
903*a23fd118Syl150051 		 * The frame is good, in-sequence, can be LRO-ed;
904*a23fd118Syl150051 		 * take its (latest) ACK - unless it is a dupack.
905*a23fd118Syl150051 		 * Note: to be exact need to check window size as well..
906*a23fd118Syl150051 	 	*/
907*a23fd118Syl150051 		if (g_lro->tcp_ack_num == tcp->ack_seq &&
908*a23fd118Syl150051 		    g_lro->tcp_seq_num == tcp->seq)
909*a23fd118Syl150051 			return XGE_HAL_INF_LRO_END_2;
910*a23fd118Syl150051 
911*a23fd118Syl150051 		g_lro->tcp_seq_num = tcp->seq;
912*a23fd118Syl150051 		g_lro->tcp_ack_num = tcp->ack_seq;
913*a23fd118Syl150051 		g_lro->frags_len += __hal_tcp_seg_len(ip, tcp);
914*a23fd118Syl150051 
915*a23fd118Syl150051 		return XGE_HAL_INF_LRO_CONT;
916*a23fd118Syl150051 	}
917*a23fd118Syl150051 
918*a23fd118Syl150051 	if (free_slot == -1)
919*a23fd118Syl150051 		return XGE_HAL_INF_LRO_UNCAPABLE;
920*a23fd118Syl150051 
921*a23fd118Syl150051 	g_lro = &hldev->g_lro_pool[free_slot];
922*a23fd118Syl150051 	if (XGE_HAL_FAIL == __hal_ip_lro_capable(ip, ext_info))
923*a23fd118Syl150051 		return XGE_HAL_INF_LRO_UNCAPABLE;
924*a23fd118Syl150051 
925*a23fd118Syl150051 	if (XGE_HAL_FAIL == __hal_tcp_lro_capable(ip, tcp))
926*a23fd118Syl150051 		return XGE_HAL_INF_LRO_UNCAPABLE;
927*a23fd118Syl150051 
928*a23fd118Syl150051 	*lro = g_lro;
929*a23fd118Syl150051 	xge_debug_ring(XGE_TRACE, "Creating lro session.");
930*a23fd118Syl150051 
931*a23fd118Syl150051 	g_lro->in_use		=	1;
932*a23fd118Syl150051 	g_lro->ll_hdr		=	buffer;
933*a23fd118Syl150051 	g_lro->ip_hdr		=	ip;
934*a23fd118Syl150051 	g_lro->tcp_hdr		=	tcp;
935*a23fd118Syl150051 	g_lro->tcp_next_seq_num =	__hal_tcp_seg_len(ip, tcp) +
936*a23fd118Syl150051 					xge_os_ntohl(tcp->seq);
937*a23fd118Syl150051 	g_lro->tcp_seq_num	=	tcp->seq;
938*a23fd118Syl150051 	g_lro->tcp_ack_num	=	tcp->ack_seq;
939*a23fd118Syl150051 	g_lro->sg_num		=	1;
940*a23fd118Syl150051 	g_lro->total_length	=	xge_os_ntohs(ip->tot_len);
941*a23fd118Syl150051 	g_lro->frags_len	=	0;
942*a23fd118Syl150051 	hldev->stats.sw_dev_info_stats.tot_frms_lroised++;
943*a23fd118Syl150051 		hldev->stats.sw_dev_info_stats.tot_lro_sessions++;
944*a23fd118Syl150051 
945*a23fd118Syl150051 	return XGE_HAL_INF_LRO_BEGIN;
946*a23fd118Syl150051 }
947*a23fd118Syl150051 
948*a23fd118Syl150051 /*
949*a23fd118Syl150051  * __hal_lro_under_optimal_thresh: Finds whether combined session is optimal.
950*a23fd118Syl150051  * @ip: ip header.
951*a23fd118Syl150051  * @tcp: tcp header.
952*a23fd118Syl150051  * @lro: lro pointer
953*a23fd118Syl150051  * @hldev: Hal context.
954*a23fd118Syl150051  */
955*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
956*a23fd118Syl150051 __hal_lro_under_optimal_thresh (iplro_t *ip,
957*a23fd118Syl150051 			        tcplro_t *tcp,
958*a23fd118Syl150051 				lro_t *lro,
959*a23fd118Syl150051 				xge_hal_device_t *hldev)
960*a23fd118Syl150051 {
961*a23fd118Syl150051 	if (!lro) return XGE_HAL_FAIL;
962*a23fd118Syl150051 
963*a23fd118Syl150051 	if ((lro->total_length + __hal_tcp_seg_len(ip, tcp) ) >
964*a23fd118Syl150051 	     CONFIG_LRO_MAX_ACCUM_LENGTH) {
965*a23fd118Syl150051 		xge_debug_ring(XGE_TRACE, "Max accumulation length exceeded:  max length %d \n", CONFIG_LRO_MAX_ACCUM_LENGTH);
966*a23fd118Syl150051 		return XGE_HAL_FAIL;
967*a23fd118Syl150051 	}
968*a23fd118Syl150051 
969*a23fd118Syl150051 	if (lro->sg_num == CONFIG_LRO_MAX_SG_NUM) {
970*a23fd118Syl150051 		xge_debug_ring(XGE_TRACE, "Max sg count exceeded:  max sg %d \n", CONFIG_LRO_MAX_SG_NUM);
971*a23fd118Syl150051 		return XGE_HAL_FAIL;
972*a23fd118Syl150051 	}
973*a23fd118Syl150051 
974*a23fd118Syl150051 	return XGE_HAL_OK;
975*a23fd118Syl150051 }
976*a23fd118Syl150051 
977*a23fd118Syl150051 /*
978*a23fd118Syl150051  * __hal_collapse_ip_hdr: Collapses ip header.
979*a23fd118Syl150051  * @ip: ip header.
980*a23fd118Syl150051  * @tcp: tcp header.
981*a23fd118Syl150051  * @lro: lro pointer
982*a23fd118Syl150051  * @hldev: Hal context.
983*a23fd118Syl150051  */
984*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
985*a23fd118Syl150051 __hal_collapse_ip_hdr ( iplro_t *ip,
986*a23fd118Syl150051 			tcplro_t *tcp,
987*a23fd118Syl150051 			lro_t *lro,
988*a23fd118Syl150051 			xge_hal_device_t *hldev)
989*a23fd118Syl150051 {
990*a23fd118Syl150051 
991*a23fd118Syl150051 	lro->total_length += __hal_tcp_seg_len(ip, tcp);
992*a23fd118Syl150051 
993*a23fd118Syl150051 	/* May be we have to handle time stamps or more options */
994*a23fd118Syl150051 
995*a23fd118Syl150051 	return XGE_HAL_OK;
996*a23fd118Syl150051 
997*a23fd118Syl150051 }
998*a23fd118Syl150051 
999*a23fd118Syl150051 /*
1000*a23fd118Syl150051  * __hal_collapse_tcp_hdr: Collapses tcp header.
1001*a23fd118Syl150051  * @ip: ip header.
1002*a23fd118Syl150051  * @tcp: tcp header.
1003*a23fd118Syl150051  * @lro: lro pointer
1004*a23fd118Syl150051  * @hldev: Hal context.
1005*a23fd118Syl150051  */
1006*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1007*a23fd118Syl150051 __hal_collapse_tcp_hdr ( iplro_t *ip,
1008*a23fd118Syl150051 			 tcplro_t *tcp,
1009*a23fd118Syl150051 			 lro_t *lro,
1010*a23fd118Syl150051 			 xge_hal_device_t *hldev)
1011*a23fd118Syl150051 {
1012*a23fd118Syl150051 
1013*a23fd118Syl150051 	lro->tcp_next_seq_num += __hal_tcp_seg_len(ip, tcp);
1014*a23fd118Syl150051 	return XGE_HAL_OK;
1015*a23fd118Syl150051 
1016*a23fd118Syl150051 }
1017*a23fd118Syl150051 
1018*a23fd118Syl150051 /*
1019*a23fd118Syl150051  * __hal_append_lro: Appends new frame to existing LRO session.
1020*a23fd118Syl150051  * @ip: ip header.
1021*a23fd118Syl150051  * @tcp: tcp header.
1022*a23fd118Syl150051  * @seg_len: tcp payload length.
1023*a23fd118Syl150051  * @lro: lro pointer
1024*a23fd118Syl150051  * @hldev: Hal context.
1025*a23fd118Syl150051  */
1026*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1027*a23fd118Syl150051 __hal_append_lro(iplro_t *ip,
1028*a23fd118Syl150051 		 tcplro_t **tcp,
1029*a23fd118Syl150051 		 u32 *seg_len,
1030*a23fd118Syl150051 		 lro_t *lro,
1031*a23fd118Syl150051 		 xge_hal_device_t *hldev)
1032*a23fd118Syl150051 {
1033*a23fd118Syl150051 	__hal_collapse_ip_hdr(ip, *tcp, lro, hldev);
1034*a23fd118Syl150051 	__hal_collapse_tcp_hdr(ip, *tcp, lro, hldev);
1035*a23fd118Syl150051 	// Update mbuf chain will be done in ll driver.
1036*a23fd118Syl150051 	// xge_hal_accumulate_large_rx on success of appending new frame to
1037*a23fd118Syl150051 	// lro will return to ll driver tcpdata pointer, and tcp payload length.
1038*a23fd118Syl150051 	// along with return code lro frame appended.
1039*a23fd118Syl150051 
1040*a23fd118Syl150051 	lro->sg_num++;
1041*a23fd118Syl150051 	*seg_len = __hal_tcp_seg_len(ip, *tcp);
1042*a23fd118Syl150051 	*tcp = (tcplro_t *)((unsigned long)*tcp + (((*tcp)->doff_res)>>2));
1043*a23fd118Syl150051 
1044*a23fd118Syl150051 	return XGE_HAL_OK;
1045*a23fd118Syl150051 
1046*a23fd118Syl150051 }
1047*a23fd118Syl150051 
1048*a23fd118Syl150051 /**
1049*a23fd118Syl150051  * xge_hal_accumulate_large_rx: LRO a given frame
1050*a23fd118Syl150051  * frames
1051*a23fd118Syl150051  * @buffer: Ethernet frame.
1052*a23fd118Syl150051  * @tcp: tcp header.
1053*a23fd118Syl150051  * @seglen: packet length.
1054*a23fd118Syl150051  * @p_lro: lro pointer.
1055*a23fd118Syl150051  * @ext_info: descriptor info, see xge_hal_dtr_info_t{}.
1056*a23fd118Syl150051  * @hldev: HAL device.
1057*a23fd118Syl150051  *
1058*a23fd118Syl150051  * LRO the newly received frame, i.e. attach it (if possible) to the
1059*a23fd118Syl150051  * already accumulated (i.e., already LRO-ed) received frames (if any),
1060*a23fd118Syl150051  * to form one super-sized frame for the subsequent processing
1061*a23fd118Syl150051  * by the stack.
1062*a23fd118Syl150051  */
1063*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
1064*a23fd118Syl150051 xge_hal_accumulate_large_rx(u8 *buffer,
1065*a23fd118Syl150051 			    u8 **tcp,
1066*a23fd118Syl150051 			    u32 *seglen,
1067*a23fd118Syl150051 			    lro_t **p_lro,
1068*a23fd118Syl150051 			    xge_hal_dtr_info_t *ext_info,
1069*a23fd118Syl150051 			    xge_hal_device_t *hldev)
1070*a23fd118Syl150051 {
1071*a23fd118Syl150051 	iplro_t *ip;
1072*a23fd118Syl150051 	xge_hal_status_e ret;
1073*a23fd118Syl150051 	lro_t *lro;
1074*a23fd118Syl150051 
1075*a23fd118Syl150051 	xge_debug_ring(XGE_TRACE, "Entered accumu lro. ");
1076*a23fd118Syl150051 	if (XGE_HAL_OK != __hal_lro_capable(buffer, &ip, (tcplro_t **)tcp,
1077*a23fd118Syl150051 					    ext_info, hldev))
1078*a23fd118Syl150051 		return XGE_HAL_INF_LRO_UNCAPABLE;
1079*a23fd118Syl150051 
1080*a23fd118Syl150051 	/*
1081*a23fd118Syl150051 	 * This function shall get matching LRO or else
1082*a23fd118Syl150051 	 * create one and return it
1083*a23fd118Syl150051 	 */
1084*a23fd118Syl150051         ret = __hal_get_lro_session(buffer, ip,
1085*a23fd118Syl150051                                     (tcplro_t *)*tcp,
1086*a23fd118Syl150051                                     p_lro, ext_info, hldev);
1087*a23fd118Syl150051 	xge_debug_ring(XGE_TRACE, "ret from get_lro:%d ",ret);
1088*a23fd118Syl150051 	lro = *p_lro;
1089*a23fd118Syl150051 	if (XGE_HAL_INF_LRO_CONT == ret) {
1090*a23fd118Syl150051 		if (XGE_HAL_OK == __hal_lro_under_optimal_thresh(ip,
1091*a23fd118Syl150051 				        (tcplro_t *)*tcp, lro, hldev)) {
1092*a23fd118Syl150051 			__hal_append_lro(ip,(tcplro_t **) tcp, seglen,
1093*a23fd118Syl150051 			                 lro,
1094*a23fd118Syl150051 					 hldev);
1095*a23fd118Syl150051 			hldev->stats.sw_dev_info_stats.tot_frms_lroised++;
1096*a23fd118Syl150051 
1097*a23fd118Syl150051 			if (lro->sg_num >= CONFIG_LRO_MAX_SG_NUM)
1098*a23fd118Syl150051 				ret = XGE_HAL_INF_LRO_END_1;
1099*a23fd118Syl150051 
1100*a23fd118Syl150051 		} else ret = XGE_HAL_INF_LRO_END_2;
1101*a23fd118Syl150051 	}
1102*a23fd118Syl150051 
1103*a23fd118Syl150051 	/*
1104*a23fd118Syl150051 	 * Since its time to flush,
1105*a23fd118Syl150051 	 * update ip header so that it can be sent up
1106*a23fd118Syl150051 	 */
1107*a23fd118Syl150051 	if ((ret == XGE_HAL_INF_LRO_END_1) ||
1108*a23fd118Syl150051 	    (ret == XGE_HAL_INF_LRO_END_2)) {
1109*a23fd118Syl150051 		lro->ip_hdr->tot_len = xge_os_htons((*p_lro)->total_length);
1110*a23fd118Syl150051 		lro->ip_hdr->check = xge_os_htons(0);
1111*a23fd118Syl150051 		lro->ip_hdr->check =
1112*a23fd118Syl150051 		        XGE_LL_IP_FAST_CSUM(((u8 *)(lro->ip_hdr)),
1113*a23fd118Syl150051 		                (lro->ip_hdr->version_ihl & 0x0F));
1114*a23fd118Syl150051 		lro->tcp_hdr->ack_seq = lro->tcp_ack_num;
1115*a23fd118Syl150051 	}
1116*a23fd118Syl150051 
1117*a23fd118Syl150051 	return (ret);
1118*a23fd118Syl150051 }
1119*a23fd118Syl150051 
1120*a23fd118Syl150051 /**
1121*a23fd118Syl150051  * xge_hal_lro_exist: Returns LRO list head if any.
1122*a23fd118Syl150051  * @hldev: Hal context.
1123*a23fd118Syl150051  */
1124*a23fd118Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL lro_t *
1125*a23fd118Syl150051 xge_hal_lro_exist (xge_hal_device_t *hldev)
1126*a23fd118Syl150051 {
1127*a23fd118Syl150051 
1128*a23fd118Syl150051 	if (hldev->g_lro_pool->in_use) {
1129*a23fd118Syl150051 	/* Since its time to flush, Update ip header so that it can be sent up*/
1130*a23fd118Syl150051 		lro_t *lro;
1131*a23fd118Syl150051 		lro = hldev->g_lro_pool;
1132*a23fd118Syl150051 		lro->ip_hdr->tot_len = xge_os_htons(lro->total_length);
1133*a23fd118Syl150051 		lro->ip_hdr->check = xge_os_htons(0);
1134*a23fd118Syl150051 		lro->ip_hdr->check = XGE_LL_IP_FAST_CSUM(((u8 *)(lro->ip_hdr)),
1135*a23fd118Syl150051 		                        (lro->ip_hdr->version_ihl & 0x0F));
1136*a23fd118Syl150051 		return (hldev->g_lro_pool);
1137*a23fd118Syl150051 	}
1138*a23fd118Syl150051 
1139*a23fd118Syl150051 	return NULL;
1140*a23fd118Syl150051 }
1141*a23fd118Syl150051 #endif
1142