xref: /onnv-gate/usr/src/uts/common/io/xge/hal/xgehal/xgehal-device-fp.c (revision 8275:7c223a798022)
11256Syl150051 /*
21256Syl150051  * CDDL HEADER START
31256Syl150051  *
41256Syl150051  * The contents of this file are subject to the terms of the
51256Syl150051  * Common Development and Distribution License (the "License").
61256Syl150051  * You may not use this file except in compliance with the License.
71256Syl150051  *
81256Syl150051  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91256Syl150051  * or http://www.opensolaris.org/os/licensing.
101256Syl150051  * See the License for the specific language governing permissions
111256Syl150051  * and limitations under the License.
121256Syl150051  *
131256Syl150051  * When distributing Covered Code, include this CDDL HEADER in each
141256Syl150051  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151256Syl150051  * If applicable, add the following below this CDDL HEADER, with the
161256Syl150051  * fields enclosed by brackets "[]" replaced with your own identifying
171256Syl150051  * information: Portions Copyright [yyyy] [name of copyright owner]
181256Syl150051  *
191256Syl150051  * CDDL HEADER END
201256Syl150051  *
213115Syl150051  * Copyright (c) 2002-2006 Neterion, Inc.
221256Syl150051  */
231256Syl150051 
24*8275SEric Cheng /*
25*8275SEric Cheng  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
26*8275SEric Cheng  * Use is subject to license terms.
27*8275SEric Cheng  */
28*8275SEric Cheng 
291256Syl150051 #ifdef XGE_DEBUG_FP
301256Syl150051 #include "xgehal-device.h"
311256Syl150051 #endif
321256Syl150051 
331256Syl150051 #include "xgehal-ring.h"
341256Syl150051 #include "xgehal-fifo.h"
351256Syl150051 
361256Syl150051 /**
371256Syl150051  * xge_hal_device_bar0 - Get BAR0 mapped address.
381256Syl150051  * @hldev: HAL device handle.
391256Syl150051  *
403115Syl150051  * Returns:	BAR0 address of	the	specified device.
411256Syl150051  */
423115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	char *
xge_hal_device_bar0(xge_hal_device_t * hldev)431256Syl150051 xge_hal_device_bar0(xge_hal_device_t *hldev)
441256Syl150051 {
451256Syl150051 	return hldev->bar0;
461256Syl150051 }
471256Syl150051 
481256Syl150051 /**
493115Syl150051  * xge_hal_device_isrbar0 -	Get	BAR0 mapped	address.
501256Syl150051  * @hldev: HAL device handle.
511256Syl150051  *
523115Syl150051  * Returns:	BAR0 address of	the	specified device.
531256Syl150051  */
543115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	char *
xge_hal_device_isrbar0(xge_hal_device_t * hldev)553115Syl150051 xge_hal_device_isrbar0(xge_hal_device_t	*hldev)
561256Syl150051 {
571256Syl150051 	return hldev->isrbar0;
581256Syl150051 }
591256Syl150051 
601256Syl150051 /**
611256Syl150051  * xge_hal_device_bar1 - Get BAR1 mapped address.
621256Syl150051  * @hldev: HAL device handle.
631256Syl150051  *
643115Syl150051  * Returns:	BAR1 address of	the	specified device.
651256Syl150051  */
663115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	char *
xge_hal_device_bar1(xge_hal_device_t * hldev)671256Syl150051 xge_hal_device_bar1(xge_hal_device_t *hldev)
681256Syl150051 {
691256Syl150051 	return hldev->bar1;
701256Syl150051 }
711256Syl150051 
721256Syl150051 /**
731256Syl150051  * xge_hal_device_bar0_set - Set BAR0 mapped address.
741256Syl150051  * @hldev: HAL device handle.
751256Syl150051  * @bar0: BAR0 mapped address.
763115Syl150051  * * Set BAR0 address in the HAL device	object.
771256Syl150051  */
783115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_bar0_set(xge_hal_device_t * hldev,char * bar0)791256Syl150051 xge_hal_device_bar0_set(xge_hal_device_t *hldev, char *bar0)
801256Syl150051 {
811256Syl150051 	xge_assert(bar0);
823115Syl150051 	hldev->bar0	= bar0;
831256Syl150051 }
841256Syl150051 
851256Syl150051 /**
863115Syl150051  * xge_hal_device_isrbar0_set -	Set	BAR0 mapped	address.
871256Syl150051  * @hldev: HAL device handle.
881256Syl150051  * @isrbar0: BAR0 mapped address.
893115Syl150051  * * Set BAR0 address in the HAL device	object.
901256Syl150051  */
913115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_isrbar0_set(xge_hal_device_t * hldev,char * isrbar0)923115Syl150051 xge_hal_device_isrbar0_set(xge_hal_device_t	*hldev,	char *isrbar0)
931256Syl150051 {
941256Syl150051 	xge_assert(isrbar0);
951256Syl150051 	hldev->isrbar0 = isrbar0;
961256Syl150051 }
971256Syl150051 
981256Syl150051 /**
991256Syl150051  * xge_hal_device_bar1_set - Set BAR1 mapped address.
1001256Syl150051  * @hldev: HAL device handle.
1011256Syl150051  * @channelh: Channel handle.
1021256Syl150051  * @bar1: BAR1 mapped address.
1031256Syl150051  *
1043115Syl150051  * Set BAR1	address	for	the	given channel.
1051256Syl150051  */
1063115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_bar1_set(xge_hal_device_t * hldev,xge_hal_channel_h channelh,char * bar1)1071256Syl150051 xge_hal_device_bar1_set(xge_hal_device_t *hldev, xge_hal_channel_h channelh,
1083115Syl150051 			   char	*bar1)
1091256Syl150051 {
1101256Syl150051 	xge_hal_fifo_t *fifo = (xge_hal_fifo_t *)channelh;
1111256Syl150051 
1121256Syl150051 	xge_assert(bar1);
1131256Syl150051 	xge_assert(fifo);
1141256Syl150051 
1153115Syl150051 	/* Initializing	the	BAR1 address as	the	start of
1163115Syl150051 	 * the FIFO	queue pointer and as a location	of FIFO	control
1171256Syl150051 	 * word. */
1181256Syl150051 	fifo->hw_pair =
1193115Syl150051 			(xge_hal_fifo_hw_pair_t	*) (bar1 +
1203115Syl150051 				(fifo->channel.post_qid	* XGE_HAL_FIFO_HW_PAIR_OFFSET));
1213115Syl150051 	hldev->bar1	= bar1;
1221256Syl150051 }
1231256Syl150051 
1241256Syl150051 
1251256Syl150051 /**
1263115Syl150051  * xge_hal_device_rev -	Get	Device revision	number.
1271256Syl150051  * @hldev: HAL device handle.
1281256Syl150051  *
1293115Syl150051  * Returns:	Device revision	number
1301256Syl150051  */
1313115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	int
xge_hal_device_rev(xge_hal_device_t * hldev)1323115Syl150051 xge_hal_device_rev(xge_hal_device_t	*hldev)
1331256Syl150051 {
1343115Syl150051 		return hldev->revision;
1351256Syl150051 }
1361256Syl150051 
1371256Syl150051 
1381256Syl150051 /**
1393115Syl150051  * xge_hal_device_begin_irq	- Begin	IRQ	processing.
1401256Syl150051  * @hldev: HAL device handle.
1413115Syl150051  * @reason:	"Reason" for the interrupt,	the	value of Xframe's
1423115Syl150051  *			general_int_status register.
1431256Syl150051  *
1443115Syl150051  * The function	performs two actions, It first checks whether (shared IRQ) the
1453115Syl150051  * interrupt was raised	by the device. Next, it	masks the device interrupts.
1461256Syl150051  *
1471256Syl150051  * Note:
1481256Syl150051  * xge_hal_device_begin_irq() does not flush MMIO writes through the
1491256Syl150051  * bridge. Therefore, two back-to-back interrupts are potentially possible.
1503115Syl150051  * It is the responsibility	of the ULD to make sure	that only one
1511256Syl150051  * xge_hal_device_continue_irq() runs at a time.
1521256Syl150051  *
1533115Syl150051  * Returns:	0, if the interrupt	is not "ours" (note	that in	this case the
1541256Syl150051  * device remain enabled).
1551256Syl150051  * Otherwise, xge_hal_device_begin_irq() returns 64bit general adapter
1561256Syl150051  * status.
1571256Syl150051  * See also: xge_hal_device_handle_irq()
1581256Syl150051  */
1593115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	xge_hal_status_e
xge_hal_device_begin_irq(xge_hal_device_t * hldev,u64 * reason)1601256Syl150051 xge_hal_device_begin_irq(xge_hal_device_t *hldev, u64 *reason)
1611256Syl150051 {
1623115Syl150051 	u64	val64;
1633115Syl150051 	xge_hal_pci_bar0_t *isrbar0	= (xge_hal_pci_bar0_t *)hldev->isrbar0;
1641256Syl150051 
1651256Syl150051 	hldev->stats.sw_dev_info_stats.total_intr_cnt++;
1661256Syl150051 
1673115Syl150051 	val64 =	xge_os_pio_mem_read64(hldev->pdev,
1683115Syl150051 				  hldev->regh0,	&isrbar0->general_int_status);
1691256Syl150051 	if (xge_os_unlikely(!val64)) {
1703115Syl150051 		/* not Xframe interrupt	*/
1716937Sxw161283 		hldev->stats.sw_dev_info_stats.not_xge_intr_cnt++;
1723115Syl150051 		*reason	= 0;
1733115Syl150051 			return XGE_HAL_ERR_WRONG_IRQ;
1741256Syl150051 	}
1751256Syl150051 
1761256Syl150051 	if (xge_os_unlikely(val64 == XGE_HAL_ALL_FOXES)) {
1773115Syl150051 				u64	adapter_status =
1783115Syl150051 						xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
1793115Syl150051 						  &isrbar0->adapter_status);
1803115Syl150051 				if (adapter_status == XGE_HAL_ALL_FOXES)  {
1813115Syl150051 					(void) xge_queue_produce(hldev->queueh,
1821256Syl150051 						 XGE_HAL_EVENT_SLOT_FREEZE,
1831256Syl150051 						 hldev,
1843115Syl150051 						 1,	 /*	critical: slot freeze */
1851256Syl150051 						 sizeof(u64),
1861256Syl150051 						 (void*)&adapter_status);
1873115Syl150051 			*reason	= 0;
1881256Syl150051 			return XGE_HAL_ERR_CRITICAL;
1891256Syl150051 		}
1901256Syl150051 	}
1911256Syl150051 
1923115Syl150051 	*reason	= val64;
1931256Syl150051 
1943115Syl150051 	/* separate	fast path, i.e.	no errors */
1953115Syl150051 	if (val64 &	XGE_HAL_GEN_INTR_RXTRAFFIC)	{
1961256Syl150051 		hldev->stats.sw_dev_info_stats.rx_traffic_intr_cnt++;
1971256Syl150051 		return XGE_HAL_OK;
1981256Syl150051 	}
1993115Syl150051 	if (val64 &	XGE_HAL_GEN_INTR_TXTRAFFIC)	{
2001256Syl150051 		hldev->stats.sw_dev_info_stats.tx_traffic_intr_cnt++;
2011256Syl150051 		return XGE_HAL_OK;
2021256Syl150051 	}
2031256Syl150051 
2043115Syl150051 	hldev->stats.sw_dev_info_stats.not_traffic_intr_cnt++;
2053115Syl150051 	if (xge_os_unlikely(val64 &	XGE_HAL_GEN_INTR_TXPIC)) {
2061256Syl150051 		xge_hal_status_e status;
2073115Syl150051 		hldev->stats.sw_dev_info_stats.txpic_intr_cnt++;
2081256Syl150051 		status = __hal_device_handle_txpic(hldev, val64);
2091256Syl150051 		if (status != XGE_HAL_OK) {
2101256Syl150051 			return status;
2111256Syl150051 		}
2121256Syl150051 	}
2131256Syl150051 
2143115Syl150051 	if (xge_os_unlikely(val64 &	XGE_HAL_GEN_INTR_TXDMA)) {
2151256Syl150051 		xge_hal_status_e status;
2163115Syl150051 		hldev->stats.sw_dev_info_stats.txdma_intr_cnt++;
2171256Syl150051 		status = __hal_device_handle_txdma(hldev, val64);
2181256Syl150051 		if (status != XGE_HAL_OK) {
2191256Syl150051 			return status;
2201256Syl150051 		}
2211256Syl150051 	}
2221256Syl150051 
2233115Syl150051 	if (xge_os_unlikely(val64 &	XGE_HAL_GEN_INTR_TXMAC)) {
2241256Syl150051 		xge_hal_status_e status;
2253115Syl150051 		hldev->stats.sw_dev_info_stats.txmac_intr_cnt++;
2261256Syl150051 		status = __hal_device_handle_txmac(hldev, val64);
2271256Syl150051 		if (status != XGE_HAL_OK) {
2281256Syl150051 			return status;
2291256Syl150051 		}
2301256Syl150051 	}
2311256Syl150051 
2323115Syl150051 	if (xge_os_unlikely(val64 &	XGE_HAL_GEN_INTR_TXXGXS)) {
2331256Syl150051 		xge_hal_status_e status;
2343115Syl150051 		hldev->stats.sw_dev_info_stats.txxgxs_intr_cnt++;
2351256Syl150051 		status = __hal_device_handle_txxgxs(hldev, val64);
2361256Syl150051 		if (status != XGE_HAL_OK) {
2371256Syl150051 			return status;
2381256Syl150051 		}
2391256Syl150051 	}
2401256Syl150051 
2413115Syl150051 	if (xge_os_unlikely(val64 &	XGE_HAL_GEN_INTR_RXPIC)) {
2421256Syl150051 		xge_hal_status_e status;
2433115Syl150051 		hldev->stats.sw_dev_info_stats.rxpic_intr_cnt++;
2441256Syl150051 		status = __hal_device_handle_rxpic(hldev, val64);
2451256Syl150051 		if (status != XGE_HAL_OK) {
2461256Syl150051 			return status;
2471256Syl150051 		}
2481256Syl150051 	}
2491256Syl150051 
2503115Syl150051 	if (xge_os_unlikely(val64 &	XGE_HAL_GEN_INTR_RXDMA)) {
2511256Syl150051 		xge_hal_status_e status;
2523115Syl150051 		hldev->stats.sw_dev_info_stats.rxdma_intr_cnt++;
2531256Syl150051 		status = __hal_device_handle_rxdma(hldev, val64);
2541256Syl150051 		if (status != XGE_HAL_OK) {
2551256Syl150051 			return status;
2561256Syl150051 		}
2571256Syl150051 	}
2581256Syl150051 
2593115Syl150051 	if (xge_os_unlikely(val64 &	XGE_HAL_GEN_INTR_RXMAC)) {
2601256Syl150051 		xge_hal_status_e status;
2613115Syl150051 		hldev->stats.sw_dev_info_stats.rxmac_intr_cnt++;
2621256Syl150051 		status = __hal_device_handle_rxmac(hldev, val64);
2631256Syl150051 		if (status != XGE_HAL_OK) {
2641256Syl150051 			return status;
2651256Syl150051 		}
2661256Syl150051 	}
2671256Syl150051 
2683115Syl150051 	if (xge_os_unlikely(val64 &	XGE_HAL_GEN_INTR_RXXGXS)) {
2691256Syl150051 		xge_hal_status_e status;
2703115Syl150051 		hldev->stats.sw_dev_info_stats.rxxgxs_intr_cnt++;
2711256Syl150051 		status = __hal_device_handle_rxxgxs(hldev, val64);
2721256Syl150051 		if (status != XGE_HAL_OK) {
2731256Syl150051 			return status;
2741256Syl150051 		}
2751256Syl150051 	}
2761256Syl150051 
2773115Syl150051 	if (xge_os_unlikely(val64 &	XGE_HAL_GEN_INTR_MC)) {
2781256Syl150051 		xge_hal_status_e status;
2793115Syl150051 		hldev->stats.sw_dev_info_stats.mc_intr_cnt++;
2801256Syl150051 		status = __hal_device_handle_mc(hldev, val64);
2811256Syl150051 		if (status != XGE_HAL_OK) {
2821256Syl150051 			return status;
2831256Syl150051 		}
2841256Syl150051 	}
2851256Syl150051 
2861256Syl150051 	return XGE_HAL_OK;
2871256Syl150051 }
2881256Syl150051 
2891256Syl150051 /**
2901256Syl150051  * xge_hal_device_clear_rx - Acknowledge (that is, clear) the
2913115Syl150051  * condition that has caused the RX	interrupt.
2921256Syl150051  * @hldev: HAL device handle.
2931256Syl150051  *
2943115Syl150051  * Acknowledge (that is, clear)	the	condition that has caused
2951256Syl150051  * the Rx interrupt.
2961256Syl150051  * See also: xge_hal_device_begin_irq(), xge_hal_device_continue_irq(),
2971256Syl150051  * xge_hal_device_clear_tx(), xge_hal_device_mask_rx().
2981256Syl150051  */
2993115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_clear_rx(xge_hal_device_t * hldev)3001256Syl150051 xge_hal_device_clear_rx(xge_hal_device_t *hldev)
3011256Syl150051 {
3023115Syl150051 	xge_hal_pci_bar0_t *isrbar0	= (xge_hal_pci_bar0_t *)hldev->isrbar0;
3031256Syl150051 
3043115Syl150051 	xge_os_pio_mem_write64(hldev->pdev,	hldev->regh0,
3053115Syl150051 				 0xFFFFFFFFFFFFFFFFULL,
3063115Syl150051 				 &isrbar0->rx_traffic_int);
3071256Syl150051 }
3081256Syl150051 
3091256Syl150051 /**
3101256Syl150051  * xge_hal_device_clear_tx - Acknowledge (that is, clear) the
3113115Syl150051  * condition that has caused the TX	interrupt.
3121256Syl150051  * @hldev: HAL device handle.
3131256Syl150051  *
3143115Syl150051  * Acknowledge (that is, clear)	the	condition that has caused
3151256Syl150051  * the Tx interrupt.
3161256Syl150051  * See also: xge_hal_device_begin_irq(), xge_hal_device_continue_irq(),
3171256Syl150051  * xge_hal_device_clear_rx(), xge_hal_device_mask_tx().
3181256Syl150051  */
3193115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_clear_tx(xge_hal_device_t * hldev)3201256Syl150051 xge_hal_device_clear_tx(xge_hal_device_t *hldev)
3211256Syl150051 {
3223115Syl150051 	xge_hal_pci_bar0_t *isrbar0	= (xge_hal_pci_bar0_t *)hldev->isrbar0;
3233115Syl150051 
3243115Syl150051 	xge_os_pio_mem_write64(hldev->pdev,	hldev->regh0,
3253115Syl150051 				 0xFFFFFFFFFFFFFFFFULL,
3263115Syl150051 				 &isrbar0->tx_traffic_int);
3273115Syl150051 }
3283115Syl150051 
3293115Syl150051 /**
3303115Syl150051  * xge_hal_device_poll_rx_channel -	Poll Rx	channel	for	completed
3313115Syl150051  * descriptors and process the same.
3323115Syl150051  * @channel: HAL channel.
3336937Sxw161283  * @got_rx: Buffer to return the flag set if receive interrupt is occured
3343115Syl150051  *
3353115Syl150051  * The function	polls the Rx channel for the completed	descriptors	and	calls
3363115Syl150051  * the upper-layer driver (ULD)	via	supplied completion	callback.
3373115Syl150051  *
3383115Syl150051  * Returns:	XGE_HAL_OK,	if the polling is completed	successful.
3393115Syl150051  * XGE_HAL_COMPLETIONS_REMAIN: There are still more	completed
3403115Syl150051  * descriptors available which are yet to be processed.
3413115Syl150051  *
3423115Syl150051  * See also: xge_hal_device_poll_tx_channel()
3433115Syl150051  */
3443115Syl150051 __HAL_STATIC_DEVICE __HAL_INLINE_DEVICE	xge_hal_status_e
xge_hal_device_poll_rx_channel(xge_hal_channel_t * channel,int * got_rx)3453115Syl150051 xge_hal_device_poll_rx_channel(xge_hal_channel_t *channel, int *got_rx)
3463115Syl150051 {
3473115Syl150051 	xge_hal_status_e ret = XGE_HAL_OK;
3483115Syl150051 	xge_hal_dtr_h first_dtrh;
3493115Syl150051 	xge_hal_device_t *hldev = (xge_hal_device_t *)channel->devh;
3503115Syl150051 	u8 t_code;
3513115Syl150051 	int got_bytes;
3523115Syl150051 
3533115Syl150051 	/* for each opened rx channel */
3543115Syl150051 	got_bytes = *got_rx = 0;
3553115Syl150051 	((xge_hal_ring_t *)channel)->cmpl_cnt = 0;
3563115Syl150051 	channel->poll_bytes = 0;
3573115Syl150051 	if ((ret = xge_hal_ring_dtr_next_completed (channel, &first_dtrh,
3583115Syl150051 		&t_code)) == XGE_HAL_OK) {
3593115Syl150051 		if (channel->callback(channel, first_dtrh,
3603115Syl150051 			t_code,	channel->userdata) != XGE_HAL_OK) {
3613115Syl150051 			(*got_rx) += ((xge_hal_ring_t *)channel)->cmpl_cnt + 1;
3623115Syl150051 			got_bytes += channel->poll_bytes + 1;
3633115Syl150051 			ret = XGE_HAL_COMPLETIONS_REMAIN;
3643115Syl150051 		} else {
3653115Syl150051 			(*got_rx) += ((xge_hal_ring_t *)channel)->cmpl_cnt + 1;
3663115Syl150051 			got_bytes += channel->poll_bytes + 1;
3673115Syl150051 		}
3683115Syl150051 	}
3691256Syl150051 
3703115Syl150051 	if (*got_rx) {
3713115Syl150051 		hldev->irq_workload_rxd[channel->post_qid] += *got_rx;
3723115Syl150051 		hldev->irq_workload_rxcnt[channel->post_qid] ++;
3733115Syl150051 	}
3743115Syl150051 	hldev->irq_workload_rxlen[channel->post_qid] += got_bytes;
3753115Syl150051 
3763115Syl150051 	return ret;
3773115Syl150051 }
3783115Syl150051 
3793115Syl150051 /**
3803115Syl150051  * xge_hal_device_poll_tx_channel -	Poll Tx	channel	for	completed
3813115Syl150051  * descriptors and process the same.
3826937Sxw161283  * @channel: HAL channel.
3836937Sxw161283  * @got_tx: Buffer to return the flag set if transmit interrupt is occured
3843115Syl150051  *
3853115Syl150051  * The function	polls the Tx channel for the completed	descriptors	and	calls
3863115Syl150051  * the upper-layer driver (ULD)	via	supplied completion	callback.
3873115Syl150051  *
3883115Syl150051  * Returns:	XGE_HAL_OK,	if the polling is completed	successful.
3893115Syl150051  * XGE_HAL_COMPLETIONS_REMAIN: There are still more	completed
3903115Syl150051  * descriptors available which are yet to be processed.
3913115Syl150051  *
3923115Syl150051  * See also: xge_hal_device_poll_rx_channel().
3933115Syl150051  */
3943115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE xge_hal_status_e
xge_hal_device_poll_tx_channel(xge_hal_channel_t * channel,int * got_tx)3953115Syl150051 xge_hal_device_poll_tx_channel(xge_hal_channel_t *channel, int *got_tx)
3963115Syl150051 {
3973115Syl150051 	xge_hal_dtr_h first_dtrh;
3983115Syl150051 	xge_hal_device_t *hldev = (xge_hal_device_t *)channel->devh;
3993115Syl150051 	u8 t_code;
4003115Syl150051 	int got_bytes;
4013115Syl150051 
4023115Syl150051 	/* for each opened tx channel */
4033115Syl150051 	got_bytes = *got_tx = 0;
4043115Syl150051 	channel->poll_bytes = 0;
4053115Syl150051 	if (xge_hal_fifo_dtr_next_completed (channel, &first_dtrh,
4063115Syl150051 		&t_code) ==	XGE_HAL_OK)	{
4073115Syl150051 		if (channel->callback(channel, first_dtrh,
4083115Syl150051 			t_code,	channel->userdata) != XGE_HAL_OK) {
4093115Syl150051 			(*got_tx)++;
4103115Syl150051 			got_bytes += channel->poll_bytes + 1;
4113115Syl150051 			return XGE_HAL_COMPLETIONS_REMAIN;
4123115Syl150051 		}
4133115Syl150051 		(*got_tx)++;
4143115Syl150051 		got_bytes += channel->poll_bytes + 1;
4153115Syl150051 	}
4163115Syl150051 
4173115Syl150051 	if (*got_tx) {
4183115Syl150051 		hldev->irq_workload_txd[channel->post_qid] += *got_tx;
4193115Syl150051 		hldev->irq_workload_txcnt[channel->post_qid] ++;
4203115Syl150051 	}
4213115Syl150051 	hldev->irq_workload_txlen[channel->post_qid] += got_bytes;
4223115Syl150051 
4233115Syl150051 	return XGE_HAL_OK;
4241256Syl150051 }
4251256Syl150051 
4261256Syl150051 /**
4271256Syl150051  * xge_hal_device_poll_rx_channels - Poll Rx channels for completed
4281256Syl150051  * descriptors and process the same.
4291256Syl150051  * @hldev: HAL device handle.
4306937Sxw161283  * @got_rx: Buffer to return flag set if receive is ready
4311256Syl150051  *
4323115Syl150051  * The function	polls the Rx channels for the completed	descriptors	and	calls
4333115Syl150051  * the upper-layer driver (ULD)	via	supplied completion	callback.
4341256Syl150051  *
4353115Syl150051  * Returns:	XGE_HAL_OK,	if the polling is completed	successful.
4363115Syl150051  * XGE_HAL_COMPLETIONS_REMAIN: There are still more	completed
4371256Syl150051  * descriptors available which are yet to be processed.
4381256Syl150051  *
4393115Syl150051  * See also: xge_hal_device_poll_tx_channels(),	xge_hal_device_continue_irq().
4401256Syl150051  */
4413115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	xge_hal_status_e
xge_hal_device_poll_rx_channels(xge_hal_device_t * hldev,int * got_rx)4423115Syl150051 xge_hal_device_poll_rx_channels(xge_hal_device_t *hldev, int *got_rx)
4431256Syl150051 {
4441256Syl150051 	xge_list_t *item;
4451256Syl150051 	xge_hal_channel_t *channel;
4461256Syl150051 
4471256Syl150051 	/* for each opened rx channel */
4483115Syl150051 	xge_list_for_each(item,	&hldev->ring_channels) {
4493115Syl150051 		if (hldev->terminating)
4503115Syl150051 			return XGE_HAL_OK;
4513115Syl150051 		channel	= xge_container_of(item, xge_hal_channel_t,	item);
452*8275SEric Cheng 		if (!(channel->flags & XGE_HAL_CHANNEL_FLAG_USE_RX_POLLING)) {
453*8275SEric Cheng 			(void) xge_hal_device_poll_rx_channel(channel, got_rx);
454*8275SEric Cheng 		}
4551256Syl150051 	}
4561256Syl150051 
4571256Syl150051 	return XGE_HAL_OK;
4581256Syl150051 }
4591256Syl150051 
4601256Syl150051 /**
4611256Syl150051  * xge_hal_device_poll_tx_channels - Poll Tx channels for completed
4621256Syl150051  * descriptors and process the same.
4631256Syl150051  * @hldev: HAL device handle.
4646937Sxw161283  * @got_tx: Buffer to return flag set if transmit is ready
4651256Syl150051  *
4663115Syl150051  * The function	polls the Tx channels for the completed	descriptors	and	calls
4673115Syl150051  * the upper-layer driver (ULD)	via	supplied completion	callback.
4681256Syl150051  *
4693115Syl150051  * Returns:	XGE_HAL_OK,	if the polling is completed	successful.
4703115Syl150051  * XGE_HAL_COMPLETIONS_REMAIN: There are still more	completed
4711256Syl150051  * descriptors available which are yet to be processed.
4721256Syl150051  *
4733115Syl150051  * See also: xge_hal_device_poll_rx_channels(),	xge_hal_device_continue_irq().
4741256Syl150051  */
4753115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	xge_hal_status_e
xge_hal_device_poll_tx_channels(xge_hal_device_t * hldev,int * got_tx)4763115Syl150051 xge_hal_device_poll_tx_channels(xge_hal_device_t *hldev, int *got_tx)
4771256Syl150051 {
4781256Syl150051 	xge_list_t *item;
4791256Syl150051 	xge_hal_channel_t *channel;
4801256Syl150051 
4811256Syl150051 	/* for each opened tx channel */
4823115Syl150051 	xge_list_for_each(item,	&hldev->fifo_channels) {
4833115Syl150051 		if (hldev->terminating)
4843115Syl150051 			return XGE_HAL_OK;
4853115Syl150051 		channel	= xge_container_of(item, xge_hal_channel_t, item);
4863115Syl150051 		(void) xge_hal_device_poll_tx_channel(channel, got_tx);
4871256Syl150051 	}
4881256Syl150051 
4891256Syl150051 	return XGE_HAL_OK;
4901256Syl150051 }
4911256Syl150051 
4921256Syl150051 /**
493*8275SEric Cheng  *
494*8275SEric Cheng  */
495*8275SEric Cheng __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_rx_channel_enable_polling(xge_hal_channel_t * channel)496*8275SEric Cheng xge_hal_device_rx_channel_enable_polling(xge_hal_channel_t *channel)
497*8275SEric Cheng {
498*8275SEric Cheng 	channel->flags |= XGE_HAL_CHANNEL_FLAG_USE_RX_POLLING;
499*8275SEric Cheng }
500*8275SEric Cheng 
501*8275SEric Cheng __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_rx_channel_disable_polling(xge_hal_channel_t * channel)502*8275SEric Cheng xge_hal_device_rx_channel_disable_polling(xge_hal_channel_t *channel)
503*8275SEric Cheng {
504*8275SEric Cheng 	channel->flags &= ~XGE_HAL_CHANNEL_FLAG_USE_RX_POLLING;
505*8275SEric Cheng }
506*8275SEric Cheng 
507*8275SEric Cheng /**
5083115Syl150051  * xge_hal_device_mask_tx -	Mask Tx	interrupts.
5091256Syl150051  * @hldev: HAL device handle.
5101256Syl150051  *
5113115Syl150051  * Mask	Tx device interrupts.
5121256Syl150051  *
5131256Syl150051  * See also: xge_hal_device_unmask_tx(), xge_hal_device_mask_rx(),
5141256Syl150051  * xge_hal_device_clear_tx().
5151256Syl150051  */
5163115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_mask_tx(xge_hal_device_t * hldev)5173115Syl150051 xge_hal_device_mask_tx(xge_hal_device_t	*hldev)
5181256Syl150051 {
5193115Syl150051 	xge_hal_pci_bar0_t *isrbar0	= (xge_hal_pci_bar0_t *)hldev->isrbar0;
5201256Syl150051 
5213115Syl150051 	xge_os_pio_mem_write64(hldev->pdev,	hldev->regh0,
5223115Syl150051 				   0xFFFFFFFFFFFFFFFFULL,
5233115Syl150051 				   &isrbar0->tx_traffic_mask);
5241256Syl150051 }
5251256Syl150051 
5261256Syl150051 /**
5273115Syl150051  * xge_hal_device_mask_rx -	Mask Rx	interrupts.
5281256Syl150051  * @hldev: HAL device handle.
5291256Syl150051  *
5303115Syl150051  * Mask	Rx device interrupts.
5311256Syl150051  *
5321256Syl150051  * See also: xge_hal_device_unmask_rx(), xge_hal_device_mask_tx(),
5331256Syl150051  * xge_hal_device_clear_rx().
5341256Syl150051  */
5353115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_mask_rx(xge_hal_device_t * hldev)5363115Syl150051 xge_hal_device_mask_rx(xge_hal_device_t	*hldev)
5371256Syl150051 {
5383115Syl150051 	xge_hal_pci_bar0_t *isrbar0	= (xge_hal_pci_bar0_t *)hldev->isrbar0;
5391256Syl150051 
5403115Syl150051 	xge_os_pio_mem_write64(hldev->pdev,	hldev->regh0,
5413115Syl150051 				   0xFFFFFFFFFFFFFFFFULL,
5423115Syl150051 				   &isrbar0->rx_traffic_mask);
5431256Syl150051 }
5441256Syl150051 
5451256Syl150051 /**
5461256Syl150051  * xge_hal_device_mask_all - Mask all device interrupts.
5471256Syl150051  * @hldev: HAL device handle.
5481256Syl150051  *
5493115Syl150051  * Mask	all	device interrupts.
5501256Syl150051  *
5511256Syl150051  * See also: xge_hal_device_unmask_all()
5521256Syl150051  */
5533115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_mask_all(xge_hal_device_t * hldev)5541256Syl150051 xge_hal_device_mask_all(xge_hal_device_t *hldev)
5551256Syl150051 {
5563115Syl150051 	xge_hal_pci_bar0_t *isrbar0	= (xge_hal_pci_bar0_t *)hldev->isrbar0;
5571256Syl150051 
5583115Syl150051 	xge_os_pio_mem_write64(hldev->pdev,	hldev->regh0,
5593115Syl150051 				   0xFFFFFFFFFFFFFFFFULL,
5603115Syl150051 				   &isrbar0->general_int_mask);
5611256Syl150051 }
5621256Syl150051 
5631256Syl150051 /**
5643115Syl150051  * xge_hal_device_unmask_tx	- Unmask Tx	interrupts.
5651256Syl150051  * @hldev: HAL device handle.
5661256Syl150051  *
5673115Syl150051  * Unmask Tx device	interrupts.
5681256Syl150051  *
5691256Syl150051  * See also: xge_hal_device_mask_tx(), xge_hal_device_clear_tx().
5701256Syl150051  */
5713115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_unmask_tx(xge_hal_device_t * hldev)5721256Syl150051 xge_hal_device_unmask_tx(xge_hal_device_t *hldev)
5731256Syl150051 {
5743115Syl150051 	xge_hal_pci_bar0_t *isrbar0	= (xge_hal_pci_bar0_t *)hldev->isrbar0;
5751256Syl150051 
5763115Syl150051 	xge_os_pio_mem_write64(hldev->pdev,	hldev->regh0,
5773115Syl150051 				   0x0ULL,
5783115Syl150051 				   &isrbar0->tx_traffic_mask);
5791256Syl150051 }
5801256Syl150051 
5811256Syl150051 /**
5823115Syl150051  * xge_hal_device_unmask_rx	- Unmask Rx	interrupts.
5831256Syl150051  * @hldev: HAL device handle.
5841256Syl150051  *
5853115Syl150051  * Unmask Rx device	interrupts.
5861256Syl150051  *
5871256Syl150051  * See also: xge_hal_device_mask_rx(), xge_hal_device_clear_rx().
5881256Syl150051  */
5893115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_unmask_rx(xge_hal_device_t * hldev)5901256Syl150051 xge_hal_device_unmask_rx(xge_hal_device_t *hldev)
5911256Syl150051 {
5923115Syl150051 	xge_hal_pci_bar0_t *isrbar0	= (xge_hal_pci_bar0_t *)hldev->isrbar0;
5931256Syl150051 
5943115Syl150051 	xge_os_pio_mem_write64(hldev->pdev,	hldev->regh0,
5953115Syl150051 				   0x0ULL,
5963115Syl150051 				   &isrbar0->rx_traffic_mask);
5971256Syl150051 }
5981256Syl150051 
5991256Syl150051 /**
6001256Syl150051  * xge_hal_device_unmask_all - Unmask all device interrupts.
6011256Syl150051  * @hldev: HAL device handle.
6021256Syl150051  *
6031256Syl150051  * Unmask all device interrupts.
6041256Syl150051  *
6051256Syl150051  * See also: xge_hal_device_mask_all()
6061256Syl150051  */
6073115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	void
xge_hal_device_unmask_all(xge_hal_device_t * hldev)6081256Syl150051 xge_hal_device_unmask_all(xge_hal_device_t *hldev)
6091256Syl150051 {
6103115Syl150051 	xge_hal_pci_bar0_t *isrbar0	= (xge_hal_pci_bar0_t *)hldev->isrbar0;
6111256Syl150051 
6123115Syl150051 	xge_os_pio_mem_write64(hldev->pdev,	hldev->regh0,
6133115Syl150051 				   0x0ULL,
6143115Syl150051 				   &isrbar0->general_int_mask);
6151256Syl150051 }
6161256Syl150051 
6171256Syl150051 
6181256Syl150051 /**
6193115Syl150051  * xge_hal_device_continue_irq - Continue handling IRQ:	process	all
6201256Syl150051  * completed descriptors.
6211256Syl150051  * @hldev: HAL device handle.
6221256Syl150051  *
6233115Syl150051  * Process completed descriptors and unmask	the	device interrupts.
6241256Syl150051  *
6253115Syl150051  * The xge_hal_device_continue_irq() walks all open	channels
6263115Syl150051  * and calls upper-layer driver	(ULD) via supplied completion
6273115Syl150051  * callback. Note that the completion callback is specified	at channel open
6281256Syl150051  * time, see xge_hal_channel_open().
6291256Syl150051  *
6303115Syl150051  * Note	that the xge_hal_device_continue_irq is	part of	the	_fast_ path.
6313115Syl150051  * To optimize the processing, the function	does _not_ check for
6321256Syl150051  * errors and alarms.
6331256Syl150051  *
6343115Syl150051  * The latter is done in a polling fashion,	via	xge_hal_device_poll().
6351256Syl150051  *
6363115Syl150051  * Returns:	XGE_HAL_OK.
6371256Syl150051  *
6381256Syl150051  * See also: xge_hal_device_handle_irq(), xge_hal_device_poll(),
6391256Syl150051  * xge_hal_ring_dtr_next_completed(),
6401256Syl150051  * xge_hal_fifo_dtr_next_completed(), xge_hal_channel_callback_f{}.
6411256Syl150051  */
6423115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	xge_hal_status_e
xge_hal_device_continue_irq(xge_hal_device_t * hldev)6431256Syl150051 xge_hal_device_continue_irq(xge_hal_device_t *hldev)
6441256Syl150051 {
6453115Syl150051 	int	got_rx = 1,	got_tx = 1;
6463115Syl150051 	int	isr_polling_cnt	= hldev->config.isr_polling_cnt;
6473115Syl150051 	int	count =	0;
6481256Syl150051 
6493115Syl150051 	do
6503115Syl150051 	{
6513115Syl150051 		if (got_rx)
6523115Syl150051 			(void) xge_hal_device_poll_rx_channels(hldev, &got_rx);
6533115Syl150051 		if (got_tx && hldev->tti_enabled)
6543115Syl150051 			(void) xge_hal_device_poll_tx_channels(hldev, &got_tx);
6551256Syl150051 
6563115Syl150051 		if (!got_rx && !got_tx)
6573115Syl150051 			break;
6581256Syl150051 
6593115Syl150051 		count += (got_rx + got_tx);
6603115Syl150051 	}while (isr_polling_cnt--);
6613115Syl150051 
6623115Syl150051 	if (!count)
6631256Syl150051 		hldev->stats.sw_dev_info_stats.not_traffic_intr_cnt++;
6641256Syl150051 
6651256Syl150051 	return XGE_HAL_OK;
6661256Syl150051 }
6671256Syl150051 
6681256Syl150051 /**
6691256Syl150051  * xge_hal_device_handle_irq - Handle device IRQ.
6701256Syl150051  * @hldev: HAL device handle.
6711256Syl150051  *
6723115Syl150051  * Perform the complete	handling of	the	line interrupt.	The	function
6733115Syl150051  * performs	two	calls.
6743115Syl150051  * First it	uses xge_hal_device_begin_irq()	to	check the reason for
6751256Syl150051  * the interrupt and mask the device interrupts.
6763115Syl150051  * Second, it calls	xge_hal_device_continue_irq() to process all
6771256Syl150051  * completed descriptors and re-enable the interrupts.
6781256Syl150051  *
6793115Syl150051  * Returns:	XGE_HAL_OK - success;
6803115Syl150051  * XGE_HAL_ERR_WRONG_IRQ - (shared)	IRQ	produced by	other device.
6811256Syl150051  *
6821256Syl150051  * See also: xge_hal_device_begin_irq(), xge_hal_device_continue_irq().
6831256Syl150051  */
6843115Syl150051 __HAL_STATIC_DEVICE	__HAL_INLINE_DEVICE	xge_hal_status_e
xge_hal_device_handle_irq(xge_hal_device_t * hldev)6851256Syl150051 xge_hal_device_handle_irq(xge_hal_device_t *hldev)
6861256Syl150051 {
6873115Syl150051 	u64	reason;
6881256Syl150051 	xge_hal_status_e status;
6891256Syl150051 
6901256Syl150051 	xge_hal_device_mask_all(hldev);
6911256Syl150051 
6923115Syl150051 	status = xge_hal_device_begin_irq(hldev, &reason);
6933115Syl150051 	if (status != XGE_HAL_OK) {
6941256Syl150051 		xge_hal_device_unmask_all(hldev);
6953115Syl150051 		return status;
6961256Syl150051 	}
6971256Syl150051 
6981256Syl150051 	if (reason & XGE_HAL_GEN_INTR_RXTRAFFIC) {
6991256Syl150051 		xge_hal_device_clear_rx(hldev);
7001256Syl150051 	}
7011256Syl150051 
7023115Syl150051 	status = xge_hal_device_continue_irq(hldev);
7031256Syl150051 
7041256Syl150051 	xge_hal_device_clear_tx(hldev);
7051256Syl150051 
7061256Syl150051 	xge_hal_device_unmask_all(hldev);
7071256Syl150051 
7081256Syl150051 	return status;
7091256Syl150051 }
7101256Syl150051 
7113115Syl150051 #if	defined(XGE_HAL_CONFIG_LRO)
7123115Syl150051 
7133115Syl150051 
7143115Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
__hal_lro_check_for_session_match(lro_t * lro,tcplro_t * tcp,iplro_t * ip)7153115Syl150051 __hal_lro_check_for_session_match(lro_t	*lro, tcplro_t *tcp, iplro_t *ip)
7163115Syl150051 {
7173115Syl150051 
7183115Syl150051 	/* Match Source	address	field */
7193115Syl150051 	if ((lro->ip_hdr->saddr	!= ip->saddr))
7203115Syl150051 		return XGE_HAL_FAIL;
7213115Syl150051 
7223115Syl150051 	/* Match Destination address field */
7233115Syl150051 	if ((lro->ip_hdr->daddr	!= ip->daddr))
7243115Syl150051 		return XGE_HAL_FAIL;
7253115Syl150051 
7263115Syl150051 	/* Match Source	Port field */
7273115Syl150051 	if ((lro->tcp_hdr->source != tcp->source))
7283115Syl150051 		return XGE_HAL_FAIL;
7293115Syl150051 
7303115Syl150051 	/* Match Destination Port field	*/
7313115Syl150051 	if ((lro->tcp_hdr->dest	!= tcp->dest))
7323115Syl150051 		return XGE_HAL_FAIL;
7333115Syl150051 
7343115Syl150051 	return XGE_HAL_OK;
7353115Syl150051 }
7361256Syl150051 
7371256Syl150051 /*
7381256Syl150051  * __hal_tcp_seg_len: Find the tcp seg len.
7393115Syl150051  * @ip:	ip header.
7401256Syl150051  * @tcp: tcp header.
7413115Syl150051  * returns:	Tcp	seg	length.
7421256Syl150051  */
7431256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL u16
__hal_tcp_seg_len(iplro_t * ip,tcplro_t * tcp)7443115Syl150051 __hal_tcp_seg_len(iplro_t *ip, tcplro_t	*tcp)
7451256Syl150051 {
7463115Syl150051 	u16	ret;
7471256Syl150051 
7483115Syl150051 	ret	=  (xge_os_ntohs(ip->tot_len) -
7493115Syl150051 		   ((ip->version_ihl & 0x0F)<<2) -
7503115Syl150051 		   ((tcp->doff_res)>>2));
7511256Syl150051 	return (ret);
7521256Syl150051 }
7531256Syl150051 
7541256Syl150051 /*
7551256Syl150051  * __hal_ip_lro_capable: Finds whether ip is lro capable.
7563115Syl150051  * @ip:	ip header.
7571256Syl150051  * @ext_info:  descriptor info.
7581256Syl150051  */
7591256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_ip_lro_capable(iplro_t * ip,xge_hal_dtr_info_t * ext_info)7601256Syl150051 __hal_ip_lro_capable(iplro_t *ip,
7613115Syl150051 			 xge_hal_dtr_info_t	*ext_info)
7621256Syl150051 {
7631256Syl150051 
7641256Syl150051 #ifdef XGE_LL_DEBUG_DUMP_PKT
7651256Syl150051 		{
7663115Syl150051 			u16	i;
7673115Syl150051 			u8 ch, *iph	= (u8 *)ip;
7681256Syl150051 
7693115Syl150051 			xge_debug_ring(XGE_TRACE, "Dump	Ip:" );
7703115Syl150051 			for	(i =0; i < 40; i++)	{
7713115Syl150051 				ch = ntohs(*((u8 *)(iph	+ i)) );
7721256Syl150051 				printf("i:%d %02x, ",i,ch);
7731256Syl150051 			}
7741256Syl150051 		}
7751256Syl150051 #endif
7761256Syl150051 
7773115Syl150051 	if (ip->version_ihl	!= IP_FAST_PATH_HDR_MASK) {
7783115Syl150051 		xge_debug_ring(XGE_ERR,	"iphdr !=45	:%d",ip->version_ihl);
7791256Syl150051 		return XGE_HAL_FAIL;
7801256Syl150051 	}
7811256Syl150051 
7823115Syl150051 	if (ext_info->proto	& XGE_HAL_FRAME_PROTO_IP_FRAGMENTED) {
7833115Syl150051 		xge_debug_ring(XGE_ERR,	"IP	fragmented");
7841256Syl150051 		return XGE_HAL_FAIL;
7851256Syl150051 	}
7861256Syl150051 
7871256Syl150051 	return XGE_HAL_OK;
7881256Syl150051 }
7891256Syl150051 
7901256Syl150051 /*
7913115Syl150051  * __hal_tcp_lro_capable: Finds	whether	tcp	is lro capable.
7923115Syl150051  * @ip:	ip header.
7931256Syl150051  * @tcp: tcp header.
7941256Syl150051  */
7951256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_tcp_lro_capable(iplro_t * ip,tcplro_t * tcp,lro_t * lro,int * ts_off)7963115Syl150051 __hal_tcp_lro_capable(iplro_t *ip, tcplro_t	*tcp, lro_t	*lro, int *ts_off)
7971256Syl150051 {
7981256Syl150051 #ifdef XGE_LL_DEBUG_DUMP_PKT
7991256Syl150051 		{
8001256Syl150051 			u8 ch;
8013115Syl150051 			u16	i;
8021256Syl150051 
8033115Syl150051 			xge_debug_ring(XGE_TRACE, "Dump	Tcp:" );
8043115Syl150051 			for	(i =0; i < 20; i++)	{
8053115Syl150051 				ch = ntohs(*((u8 *)((u8	*)tcp +	i))	);
8063115Syl150051 				xge_os_printf("i:%d	%02x, ",i,ch);
8071256Syl150051 			}
8081256Syl150051 		}
8091256Syl150051 #endif
8103115Syl150051 	if ((TCP_FAST_PATH_HDR_MASK2 !=	tcp->ctrl) &&
8113115Syl150051 		(TCP_FAST_PATH_HDR_MASK3 !=	tcp->ctrl))
8123115Syl150051 		goto _exit_fail;
8133115Syl150051 
8143115Syl150051 	*ts_off	= -1;
8153115Syl150051 	if (TCP_FAST_PATH_HDR_MASK1	!= tcp->doff_res) {
8163115Syl150051 		u16	tcp_hdr_len	= tcp->doff_res	>> 2; /* TCP header	len	*/
8173115Syl150051 		u16	off	= 20; /* Start of tcp options */
8183115Syl150051 		int	i, diff;
8193115Syl150051 
8203115Syl150051 		/* Does	Packet can contain time	stamp */
8213115Syl150051 		if (tcp_hdr_len	< 32) {
8223115Syl150051 			/*
8233115Syl150051 			 * If the session is not opened, we	can	consider
8243115Syl150051 			 * this	packet for LRO
8253115Syl150051 			 */
8263115Syl150051 			if (lro	== NULL)
8273115Syl150051 				return XGE_HAL_OK;
8283115Syl150051 
8293115Syl150051 			goto _exit_fail;
8303115Syl150051 		}
8313115Syl150051 
8323115Syl150051 		/* Ignore No-operation 0x1 */
8333115Syl150051 		while (((u8	*)tcp)[off]	== 0x1)
8343115Syl150051 			off++;
8353115Syl150051 
8363115Syl150051 		/* Next	option == Timestamp	*/
8373115Syl150051 		if (((u8 *)tcp)[off] !=	0x8) {
8383115Syl150051 			/*
8393115Syl150051 			 * If the session ie not opened, we	can	consider
8403115Syl150051 			 * this	packet for LRO
8413115Syl150051 			 */
8423115Syl150051 			if (lro	== NULL)
8433115Syl150051 				return XGE_HAL_OK;
8443115Syl150051 
8453115Syl150051 			goto _exit_fail;
8463115Syl150051 		}
8473115Syl150051 
8483115Syl150051 		*ts_off	= off;
8493115Syl150051 		if (lro	== NULL)
8503115Syl150051 			return XGE_HAL_OK;
8513115Syl150051 
8523115Syl150051 		/*
8533115Syl150051 		 * Now the session is opened. If the LRO frame doesn't
8543115Syl150051 		 * have	time stamp,	we cannot consider current packet for
8553115Syl150051 		 * LRO.
8563115Syl150051 		 */
8573115Syl150051 		if (lro->ts_off	== -1) {
8586937Sxw161283 			xge_debug_ring(XGE_ERR,	"Pkt received with time	stamp after	session	opened with	no time	stamp :	%02x %02x", tcp->doff_res, tcp->ctrl);
8593115Syl150051 			return XGE_HAL_FAIL;
8603115Syl150051 		}
8613115Syl150051 
8623115Syl150051 		/*
8633115Syl150051 		 * If the difference is	greater	than three,	then there are
8643115Syl150051 		 * more	options	possible.
8653115Syl150051 		 * else, there are two cases:
8663115Syl150051 		 * case	1: remaining are padding bytes.
8673115Syl150051 		 * case	2: remaining can contain options or	padding
8683115Syl150051 		 */
8693115Syl150051 		off	+= ((u8	*)tcp)[off+1];
8703115Syl150051 		diff = tcp_hdr_len - off;
8713115Syl150051 		if (diff > 3) {
8723115Syl150051 			/*
8733115Syl150051 			 * Probably	contains more options.
8743115Syl150051 			 */
8756937Sxw161283 			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);
8763115Syl150051 			return XGE_HAL_FAIL;
8773115Syl150051 		}
8783115Syl150051 
8793115Syl150051 		for	(i = 0;	i <	diff; i++) {
8803115Syl150051 			u8 byte	= ((u8 *)tcp)[off+i];
8813115Syl150051 
8823115Syl150051 			/* Ignore No-operation 0x1 */
8833115Syl150051 			if ((byte == 0x0) || (byte == 0x1))
8843115Syl150051 				continue;
8856937Sxw161283 			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);
8863115Syl150051 			return XGE_HAL_FAIL;
8873115Syl150051 		}
8883115Syl150051 
8893115Syl150051 		/*
8903115Syl150051 		 * Update the time stamp of	LRO	frame.
8913115Syl150051 		 */
8923115Syl150051 		xge_os_memcpy(((char *)lro->tcp_hdr	+ lro->ts_off +	2),
8933115Syl150051 				(char *)((char *)tcp + (*ts_off) + 2), 8);
8941256Syl150051 	}
8951256Syl150051 
8961256Syl150051 	return XGE_HAL_OK;
8973115Syl150051 
8983115Syl150051 _exit_fail:
8996937Sxw161283 	xge_debug_ring(XGE_TRACE,	"tcphdr	not	fastpth	%02x %02x", tcp->doff_res, tcp->ctrl);
9003115Syl150051 	return XGE_HAL_FAIL;
9013115Syl150051 
9021256Syl150051 }
9031256Syl150051 
9041256Syl150051 /*
9053115Syl150051  * __hal_lro_capable: Finds	whether	frame is lro capable.
9063115Syl150051  * @buffer:	Ethernet frame.
9073115Syl150051  * @ip:	ip frame.
9081256Syl150051  * @tcp: tcp frame.
9091256Syl150051  * @ext_info: Descriptor info.
9101256Syl150051  */
9111256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_lro_capable(u8 * buffer,iplro_t ** ip,tcplro_t ** tcp,xge_hal_dtr_info_t * ext_info)9121256Syl150051 __hal_lro_capable( u8 *buffer,
9131256Syl150051 		   iplro_t **ip,
9143115Syl150051 		   tcplro_t	**tcp,
9156937Sxw161283        xge_hal_dtr_info_t *ext_info)
9161256Syl150051 {
9171256Syl150051 	u8 ip_off, ip_length;
9181256Syl150051 
9193115Syl150051 	if (!(ext_info->proto &	XGE_HAL_FRAME_PROTO_TCP)) {
9203115Syl150051 		xge_debug_ring(XGE_ERR,	"Cant do lro %d", ext_info->proto);
9211256Syl150051 		return XGE_HAL_FAIL;
9221256Syl150051 	}
9236937Sxw161283 
9246937Sxw161283   if ( !*ip )
9256937Sxw161283   {
9261256Syl150051 #ifdef XGE_LL_DEBUG_DUMP_PKT
9271256Syl150051 		{
9281256Syl150051 			u8 ch;
9293115Syl150051 			u16	i;
9301256Syl150051 
9313115Syl150051 			xge_os_printf("Dump	Eth:" );
9323115Syl150051 			for	(i =0; i < 60; i++)	{
9331256Syl150051 				ch = ntohs(*((u8 *)(buffer + i)) );
9343115Syl150051 				xge_os_printf("i:%d	%02x, ",i,ch);
9351256Syl150051 			}
9361256Syl150051 		}
9371256Syl150051 #endif
9381256Syl150051 
9396937Sxw161283     switch (ext_info->frame) {
9406937Sxw161283     case XGE_HAL_FRAME_TYPE_DIX:
9416937Sxw161283       ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE;
9426937Sxw161283       break;
9436937Sxw161283     case XGE_HAL_FRAME_TYPE_LLC:
9446937Sxw161283       ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE	+
9456937Sxw161283                 XGE_HAL_HEADER_802_2_SIZE);
9466937Sxw161283       break;
9476937Sxw161283     case XGE_HAL_FRAME_TYPE_SNAP:
9486937Sxw161283       ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE	+
9496937Sxw161283                 XGE_HAL_HEADER_SNAP_SIZE);
9506937Sxw161283       break;
9516937Sxw161283     default: //	XGE_HAL_FRAME_TYPE_IPX,	etc.
9526937Sxw161283       return XGE_HAL_FAIL;
9536937Sxw161283     }
9541256Syl150051 
9551256Syl150051 
9566937Sxw161283     if (ext_info->proto	& XGE_HAL_FRAME_PROTO_VLAN_TAGGED) {
9576937Sxw161283       ip_off += XGE_HAL_HEADER_VLAN_SIZE;
9586937Sxw161283     }
9591256Syl150051 
9606937Sxw161283     /* Grab	ip,	tcp	headers	*/
9616937Sxw161283     *ip	= (iplro_t *)((char*)buffer	+ ip_off);
9626937Sxw161283   } /* !*ip */
9631256Syl150051 
9643115Syl150051 	ip_length =	(u8)((*ip)->version_ihl	& 0x0F);
9653115Syl150051 	ip_length =	ip_length <<2;
9666937Sxw161283 	*tcp = (tcplro_t *)((char *)*ip + ip_length);
9671256Syl150051 
9683115Syl150051 	xge_debug_ring(XGE_TRACE, "ip_length:%d	ip:"XGE_OS_LLXFMT
9693115Syl150051 		   " tcp:"XGE_OS_LLXFMT"", (int)ip_length,
9706937Sxw161283 		(unsigned long long)(ulong_t)*ip, (unsigned long long)(ulong_t)*tcp);
9711256Syl150051 
9721256Syl150051 	return XGE_HAL_OK;
9731256Syl150051 
9741256Syl150051 }
9751256Syl150051 
9761256Syl150051 
9771256Syl150051 /*
9783115Syl150051  * __hal_open_lro_session: Open	a new LRO session.
9793115Syl150051  * @buffer:	Ethernet frame.
9803115Syl150051  * @ip:	ip header.
9811256Syl150051  * @tcp: tcp header.
9821256Syl150051  * @lro: lro pointer
9831256Syl150051  * @ext_info: Descriptor info.
9841256Syl150051  * @hldev: Hal context.
9856937Sxw161283  * @ring_lro: LRO descriptor per rx ring.
9863115Syl150051  * @slot: Bucket no.
9873115Syl150051  * @tcp_seg_len: Length	of tcp segment.
9883115Syl150051  * @ts_off:	time stamp offset in the packet.
9893115Syl150051  */
9903115Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
__hal_open_lro_session(u8 * buffer,iplro_t * ip,tcplro_t * tcp,lro_t ** lro,xge_hal_device_t * hldev,xge_hal_lro_desc_t * ring_lro,int slot,u32 tcp_seg_len,int ts_off)9913115Syl150051 __hal_open_lro_session (u8 *buffer,	iplro_t	*ip, tcplro_t *tcp,	lro_t **lro,
9926937Sxw161283 			xge_hal_device_t *hldev, xge_hal_lro_desc_t	*ring_lro, int slot,
9936937Sxw161283       u32 tcp_seg_len, int	ts_off)
9943115Syl150051 {
9953115Syl150051 
9966937Sxw161283 	lro_t *lro_new = &ring_lro->lro_pool[slot];
9973115Syl150051 
9983115Syl150051 	lro_new->in_use			=	1;
9993115Syl150051 	lro_new->ll_hdr			=	buffer;
10003115Syl150051 	lro_new->ip_hdr			=	ip;
10013115Syl150051 	lro_new->tcp_hdr		=	tcp;
10023115Syl150051 	lro_new->tcp_next_seq_num	=	tcp_seg_len	+ xge_os_ntohl(
10033115Syl150051 								tcp->seq);
10043115Syl150051 	lro_new->tcp_seq_num		=	tcp->seq;
10053115Syl150051 	lro_new->tcp_ack_num		=	tcp->ack_seq;
10063115Syl150051 	lro_new->sg_num			=	1;
10073115Syl150051 	lro_new->total_length		=	xge_os_ntohs(ip->tot_len);
10083115Syl150051 	lro_new->frags_len		=	0;
10093115Syl150051 	lro_new->ts_off			=	ts_off;
10103115Syl150051 
10113115Syl150051 	hldev->stats.sw_dev_info_stats.tot_frms_lroised++;
10123115Syl150051 	hldev->stats.sw_dev_info_stats.tot_lro_sessions++;
10133115Syl150051 
10146937Sxw161283 	*lro = ring_lro->lro_recent = lro_new;
10153115Syl150051 	return;
10163115Syl150051 }
10173115Syl150051 /*
10183115Syl150051  * __hal_lro_get_free_slot:	Get	a free LRO bucket.
10196937Sxw161283  * @ring_lro: LRO descriptor per ring.
10203115Syl150051  */
10213115Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL int
__hal_lro_get_free_slot(xge_hal_lro_desc_t * ring_lro)10226937Sxw161283 __hal_lro_get_free_slot	(xge_hal_lro_desc_t	*ring_lro)
10233115Syl150051 {
10243115Syl150051 	int	i;
10253115Syl150051 
10263115Syl150051 	for	(i = 0;	i <	XGE_HAL_LRO_MAX_BUCKETS; i++) {
10276937Sxw161283 		lro_t *lro_temp	= &ring_lro->lro_pool[i];
10283115Syl150051 
10293115Syl150051 		if (!lro_temp->in_use)
10303115Syl150051 			return i;
10313115Syl150051 	}
10323115Syl150051 	return -1;
10333115Syl150051 }
10343115Syl150051 
10353115Syl150051 /*
10363115Syl150051  * __hal_get_lro_session: Gets matching	LRO	session	or creates one.
10376937Sxw161283  * @eth_hdr:	Ethernet header.
10383115Syl150051  * @ip:	ip header.
10393115Syl150051  * @tcp: tcp header.
10403115Syl150051  * @lro: lro pointer
10413115Syl150051  * @ext_info: Descriptor info.
10423115Syl150051  * @hldev: Hal context.
10436937Sxw161283  * @ring_lro: LRO descriptor per rx ring
10441256Syl150051  */
10451256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_get_lro_session(u8 * eth_hdr,iplro_t * ip,tcplro_t * tcp,lro_t ** lro,xge_hal_dtr_info_t * ext_info,xge_hal_device_t * hldev,xge_hal_lro_desc_t * ring_lro,lro_t ** lro_end3)10466937Sxw161283 __hal_get_lro_session (u8 *eth_hdr,
10473115Syl150051 			   iplro_t *ip,
10483115Syl150051 			   tcplro_t	*tcp,
10493115Syl150051 			   lro_t **lro,
10503115Syl150051 			   xge_hal_dtr_info_t *ext_info,
10513115Syl150051 			   xge_hal_device_t	*hldev,
10526937Sxw161283 			   xge_hal_lro_desc_t	*ring_lro,
10533115Syl150051 			   lro_t **lro_end3	/* Valid only when ret=END_3 */)
10541256Syl150051 {
10553115Syl150051 	lro_t *lro_match;
10563115Syl150051 	int	i, free_slot = -1;
10573115Syl150051 	u32	tcp_seg_len;
10583115Syl150051 	int	ts_off = -1;
10591256Syl150051 
10603115Syl150051 	*lro = lro_match = NULL;
10613115Syl150051 	/*
10623115Syl150051 	 * Compare the incoming	frame with the lro session left	from the
10633115Syl150051 	 * previous	call.  There is	a good chance that this	incoming frame
10643115Syl150051 	 * matches the lro session.
10653115Syl150051 	 */
10666937Sxw161283 	if (ring_lro->lro_recent && ring_lro->lro_recent->in_use)	{
10676937Sxw161283 		if (__hal_lro_check_for_session_match(ring_lro->lro_recent,
10683115Syl150051 							  tcp, ip)
10693115Syl150051 							== XGE_HAL_OK)
10706937Sxw161283 			lro_match =	ring_lro->lro_recent;
10713115Syl150051 	}
10723115Syl150051 
10733115Syl150051 	if (!lro_match)	{
10743115Syl150051 		/*
10753115Syl150051 		 * Search in the pool of LROs for the session that matches
10763115Syl150051 		 * the incoming	frame.
10773115Syl150051 		 */
10783115Syl150051 		for	(i = 0;	i <	XGE_HAL_LRO_MAX_BUCKETS; i++) {
10796937Sxw161283 			lro_t *lro_temp	= &ring_lro->lro_pool[i];
10801256Syl150051 
10813115Syl150051 			if (!lro_temp->in_use) {
10823115Syl150051 				if (free_slot == -1)
10833115Syl150051 					free_slot =	i;
10843115Syl150051 				continue;
10853115Syl150051 			}
10863115Syl150051 
10873115Syl150051 			if (__hal_lro_check_for_session_match(lro_temp,	tcp,
10883115Syl150051 							  ip) == XGE_HAL_OK) {
10893115Syl150051 				lro_match =	lro_temp;
10903115Syl150051 				break;
10913115Syl150051 			}
10923115Syl150051 		}
10933115Syl150051 	}
10943115Syl150051 
10951256Syl150051 
10963115Syl150051 	if (lro_match) {
10973115Syl150051 		/*
10983115Syl150051 		 * Matching	LRO	Session	found
10993115Syl150051 		 */
11003115Syl150051 		*lro = lro_match;
11011256Syl150051 
11023115Syl150051 		if (lro_match->tcp_next_seq_num	!= xge_os_ntohl(tcp->seq)) {
11036937Sxw161283      xge_debug_ring(XGE_ERR,	"**retransmit  **"
11041256Syl150051 						"found***");
11053115Syl150051 			hldev->stats.sw_dev_info_stats.lro_out_of_seq_pkt_cnt++;
11061256Syl150051 			return XGE_HAL_INF_LRO_END_2;
11071256Syl150051 		}
11081256Syl150051 
11091256Syl150051 		if (XGE_HAL_OK != __hal_ip_lro_capable(ip, ext_info))
11106937Sxw161283     {
11111256Syl150051 			return XGE_HAL_INF_LRO_END_2;
11126937Sxw161283     }
11131256Syl150051 
11143115Syl150051 		if (XGE_HAL_OK != __hal_tcp_lro_capable(ip,	tcp, lro_match,
11153115Syl150051 							&ts_off)) {
11163115Syl150051 			/*
11173115Syl150051 			 * Close the current session and open a	new
11183115Syl150051 			 * LRO session with	this packet,
11193115Syl150051 			 * provided	it has tcp payload
11203115Syl150051 			 */
11213115Syl150051 			tcp_seg_len	= __hal_tcp_seg_len(ip,	tcp);
11223115Syl150051 			if (tcp_seg_len	== 0)
11236937Sxw161283       {
11243115Syl150051 				return XGE_HAL_INF_LRO_END_2;
11256937Sxw161283       }
11263115Syl150051 
11273115Syl150051 			/* Get a free bucket  */
11286937Sxw161283 			free_slot =	__hal_lro_get_free_slot(ring_lro);
11293115Syl150051 			if (free_slot == -1)
11306937Sxw161283       {
11313115Syl150051 				return XGE_HAL_INF_LRO_END_2;
11326937Sxw161283       }
11331256Syl150051 
11343115Syl150051 			/*
11353115Syl150051 			 * Open	a new LRO session
11363115Syl150051 			 */
11376937Sxw161283 			__hal_open_lro_session (eth_hdr,	ip,	tcp, lro_end3,
11386937Sxw161283 						hldev, ring_lro, free_slot, tcp_seg_len,
11393115Syl150051 						ts_off);
11403115Syl150051 
11413115Syl150051 			return XGE_HAL_INF_LRO_END_3;
11423115Syl150051 		}
11433115Syl150051 
11443115Syl150051 				/*
11453115Syl150051 		 * The frame is	good, in-sequence, can be LRO-ed;
11463115Syl150051 		 * take	its	(latest) ACK - unless it is	a dupack.
11473115Syl150051 		 * Note: to	be exact need to check window size as well..
11483115Syl150051 		*/
11493115Syl150051 		if (lro_match->tcp_ack_num == tcp->ack_seq &&
11503115Syl150051 			lro_match->tcp_seq_num == tcp->seq)	{
11513115Syl150051 			hldev->stats.sw_dev_info_stats.lro_dup_pkt_cnt++;
11521256Syl150051 			return XGE_HAL_INF_LRO_END_2;
11533115Syl150051 		}
11541256Syl150051 
11553115Syl150051 		lro_match->tcp_seq_num = tcp->seq;
11563115Syl150051 		lro_match->tcp_ack_num = tcp->ack_seq;
11573115Syl150051 		lro_match->frags_len +=	__hal_tcp_seg_len(ip, tcp);
11581256Syl150051 
11596937Sxw161283 		ring_lro->lro_recent =	lro_match;
11603115Syl150051 
11611256Syl150051 		return XGE_HAL_INF_LRO_CONT;
11621256Syl150051 	}
11631256Syl150051 
11643115Syl150051 	/* ********** New Session ***************/
11651256Syl150051 	if (free_slot == -1)
11661256Syl150051 		return XGE_HAL_INF_LRO_UNCAPABLE;
11671256Syl150051 
11683115Syl150051 	if (XGE_HAL_FAIL ==	__hal_ip_lro_capable(ip, ext_info))
11691256Syl150051 		return XGE_HAL_INF_LRO_UNCAPABLE;
11701256Syl150051 
11713115Syl150051 	if (XGE_HAL_FAIL ==	__hal_tcp_lro_capable(ip, tcp, NULL, &ts_off))
11721256Syl150051 		return XGE_HAL_INF_LRO_UNCAPABLE;
11731256Syl150051 
11743115Syl150051 	xge_debug_ring(XGE_TRACE, "Creating	lro	session.");
11751256Syl150051 
11763115Syl150051 	/*
11773115Syl150051 	 * Open	a LRO session, provided	the	packet contains	payload.
11783115Syl150051 	 */
11793115Syl150051 	tcp_seg_len	= __hal_tcp_seg_len(ip,	tcp);
11803115Syl150051 	if (tcp_seg_len	== 0)
11813115Syl150051 		return XGE_HAL_INF_LRO_UNCAPABLE;
11823115Syl150051 
11836937Sxw161283 	__hal_open_lro_session (eth_hdr,	ip,	tcp, lro, hldev, ring_lro, free_slot,
11843115Syl150051 				tcp_seg_len, ts_off);
11851256Syl150051 
11861256Syl150051 	return XGE_HAL_INF_LRO_BEGIN;
11871256Syl150051 }
11881256Syl150051 
11891256Syl150051 /*
11901256Syl150051  * __hal_lro_under_optimal_thresh: Finds whether combined session is optimal.
11913115Syl150051  * @ip:	ip header.
11921256Syl150051  * @tcp: tcp header.
11931256Syl150051  * @lro: lro pointer
11941256Syl150051  * @hldev: Hal context.
11951256Syl150051  */
11961256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_lro_under_optimal_thresh(iplro_t * ip,tcplro_t * tcp,lro_t * lro,xge_hal_device_t * hldev)11973115Syl150051 __hal_lro_under_optimal_thresh (iplro_t	*ip,
11983115Syl150051 					tcplro_t *tcp,
11991256Syl150051 				lro_t *lro,
12001256Syl150051 				xge_hal_device_t *hldev)
12011256Syl150051 {
12021256Syl150051 	if (!lro) return XGE_HAL_FAIL;
12031256Syl150051 
12043115Syl150051 	if ((lro->total_length + __hal_tcp_seg_len(ip, tcp)	) >
12053115Syl150051 						hldev->config.lro_frm_len) {
12063115Syl150051 		xge_debug_ring(XGE_TRACE, "Max LRO frame len exceeded:"
12076937Sxw161283 		 "max length %d	", hldev->config.lro_frm_len);
12083115Syl150051 		hldev->stats.sw_dev_info_stats.lro_frm_len_exceed_cnt++;
12091256Syl150051 		return XGE_HAL_FAIL;
12101256Syl150051 	}
12111256Syl150051 
12123115Syl150051 	if (lro->sg_num	== hldev->config.lro_sg_size) {
12133115Syl150051 		xge_debug_ring(XGE_TRACE, "Max sg count	exceeded:"
12146937Sxw161283 				 "max sg %d	", hldev->config.lro_sg_size);
12153115Syl150051 		hldev->stats.sw_dev_info_stats.lro_sg_exceed_cnt++;
12161256Syl150051 		return XGE_HAL_FAIL;
12171256Syl150051 	}
12181256Syl150051 
12191256Syl150051 	return XGE_HAL_OK;
12201256Syl150051 }
12211256Syl150051 
12221256Syl150051 /*
12233115Syl150051  * __hal_collapse_ip_hdr: Collapses	ip header.
12243115Syl150051  * @ip:	ip header.
12251256Syl150051  * @tcp: tcp header.
12261256Syl150051  * @lro: lro pointer
12271256Syl150051  * @hldev: Hal context.
12281256Syl150051  */
12291256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_collapse_ip_hdr(iplro_t * ip,tcplro_t * tcp,lro_t * lro,xge_hal_device_t * hldev)12303115Syl150051 __hal_collapse_ip_hdr (	iplro_t	*ip,
12311256Syl150051 			tcplro_t *tcp,
12321256Syl150051 			lro_t *lro,
12331256Syl150051 			xge_hal_device_t *hldev)
12341256Syl150051 {
12351256Syl150051 
12361256Syl150051 	lro->total_length += __hal_tcp_seg_len(ip, tcp);
12371256Syl150051 
12383115Syl150051 	/* May be we have to handle	time stamps	or more	options	*/
12391256Syl150051 
12401256Syl150051 	return XGE_HAL_OK;
12411256Syl150051 
12421256Syl150051 }
12431256Syl150051 
12441256Syl150051 /*
12451256Syl150051  * __hal_collapse_tcp_hdr: Collapses tcp header.
12463115Syl150051  * @ip:	ip header.
12471256Syl150051  * @tcp: tcp header.
12481256Syl150051  * @lro: lro pointer
12491256Syl150051  * @hldev: Hal context.
12501256Syl150051  */
12511256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_collapse_tcp_hdr(iplro_t * ip,tcplro_t * tcp,lro_t * lro,xge_hal_device_t * hldev)12521256Syl150051 __hal_collapse_tcp_hdr ( iplro_t *ip,
12531256Syl150051 			 tcplro_t *tcp,
12541256Syl150051 			 lro_t *lro,
12551256Syl150051 			 xge_hal_device_t *hldev)
12561256Syl150051 {
12571256Syl150051 	lro->tcp_next_seq_num += __hal_tcp_seg_len(ip, tcp);
12581256Syl150051 	return XGE_HAL_OK;
12591256Syl150051 
12601256Syl150051 }
12611256Syl150051 
12621256Syl150051 /*
12631256Syl150051  * __hal_append_lro: Appends new frame to existing LRO session.
12643115Syl150051  * @ip:	ip header.
12653115Syl150051  * @tcp: IN	tcp	header,	OUT	tcp	payload.
12661256Syl150051  * @seg_len: tcp payload length.
12671256Syl150051  * @lro: lro pointer
12681256Syl150051  * @hldev: Hal context.
12691256Syl150051  */
12701256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
__hal_append_lro(iplro_t * ip,tcplro_t ** tcp,u32 * seg_len,lro_t * lro,xge_hal_device_t * hldev)12711256Syl150051 __hal_append_lro(iplro_t *ip,
12721256Syl150051 		 tcplro_t **tcp,
12731256Syl150051 		 u32 *seg_len,
12741256Syl150051 		 lro_t *lro,
12751256Syl150051 		 xge_hal_device_t *hldev)
12761256Syl150051 {
12773115Syl150051 	(void) __hal_collapse_ip_hdr(ip, *tcp,	lro, hldev);
12783115Syl150051 	(void) __hal_collapse_tcp_hdr(ip, *tcp, lro, hldev);
12793115Syl150051 	// Update mbuf chain will be done in ll	driver.
12801256Syl150051 	// xge_hal_accumulate_large_rx on success of appending new frame to
12813115Syl150051 	// lro will	return to ll driver	tcpdata	pointer, and tcp payload length.
12823115Syl150051 	// along with return code lro frame	appended.
12831256Syl150051 
12841256Syl150051 	lro->sg_num++;
12851256Syl150051 	*seg_len = __hal_tcp_seg_len(ip, *tcp);
12866937Sxw161283 	*tcp = (tcplro_t *)((char *)*tcp	+ (((*tcp)->doff_res)>>2));
12871256Syl150051 
12881256Syl150051 	return XGE_HAL_OK;
12891256Syl150051 
12901256Syl150051 }
12911256Syl150051 
12921256Syl150051 /**
12936937Sxw161283  * __xge_hal_accumulate_large_rx:	LRO	a given	frame
12941256Syl150051  * frames
12956937Sxw161283  * @ring: rx ring number
12966937Sxw161283  * @eth_hdr: ethernet header.
12976937Sxw161283  * @ip_hdr: ip header (optional)
12981256Syl150051  * @tcp: tcp header.
12993115Syl150051  * @seglen:	packet length.
13001256Syl150051  * @p_lro: lro pointer.
13011256Syl150051  * @ext_info: descriptor info, see xge_hal_dtr_info_t{}.
13021256Syl150051  * @hldev: HAL device.
13036937Sxw161283  * @lro_end3: for lro_end3 output
13041256Syl150051  *
13053115Syl150051  * LRO the newly received frame, i.e. attach it	(if	possible) to the
13061256Syl150051  * already accumulated (i.e., already LRO-ed) received frames (if any),
13073115Syl150051  * to form one super-sized frame for the subsequent	processing
13081256Syl150051  * by the stack.
13091256Syl150051  */
13101256Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
xge_hal_lro_process_rx(int ring,u8 * eth_hdr,u8 * ip_hdr,tcplro_t ** tcp,u32 * seglen,lro_t ** p_lro,xge_hal_dtr_info_t * ext_info,xge_hal_device_t * hldev,lro_t ** lro_end3)13116937Sxw161283 xge_hal_lro_process_rx(int ring, u8 *eth_hdr, u8 *ip_hdr, tcplro_t **tcp,
13126937Sxw161283                        u32 *seglen, lro_t **p_lro,
13136937Sxw161283                        xge_hal_dtr_info_t *ext_info, xge_hal_device_t *hldev,
13146937Sxw161283                        lro_t **lro_end3)
13151256Syl150051 {
13166937Sxw161283 	iplro_t	*ip = (iplro_t *)ip_hdr;
13171256Syl150051 	xge_hal_status_e ret;
13181256Syl150051 	lro_t *lro;
13191256Syl150051 
13201256Syl150051 	xge_debug_ring(XGE_TRACE, "Entered accumu lro. ");
13216937Sxw161283 	if (XGE_HAL_OK != __hal_lro_capable(eth_hdr, &ip, (tcplro_t **)tcp,
13226937Sxw161283                                       ext_info))
13231256Syl150051 		return XGE_HAL_INF_LRO_UNCAPABLE;
13241256Syl150051 
13251256Syl150051 	/*
13266937Sxw161283 	 * This	function shall get matching LRO or else
13271256Syl150051 	 * create one and return it
13281256Syl150051 	 */
13296937Sxw161283 	ret = __hal_get_lro_session(eth_hdr, ip, (tcplro_t *)*tcp,
13306937Sxw161283                               p_lro, ext_info, hldev,	&hldev->lro_desc[ring],
13316937Sxw161283                               lro_end3);
13321256Syl150051 	xge_debug_ring(XGE_TRACE, "ret from get_lro:%d ",ret);
13331256Syl150051 	lro = *p_lro;
13341256Syl150051 	if (XGE_HAL_INF_LRO_CONT == ret) {
13351256Syl150051 		if (XGE_HAL_OK == __hal_lro_under_optimal_thresh(ip,
13363115Syl150051 						(tcplro_t *)*tcp, lro, hldev)) {
13373115Syl150051 			(void) __hal_append_lro(ip,(tcplro_t **) tcp, seglen,
13386937Sxw161283 							 lro, hldev);
13391256Syl150051 			hldev->stats.sw_dev_info_stats.tot_frms_lroised++;
13401256Syl150051 
13413115Syl150051 			if (lro->sg_num	>= hldev->config.lro_sg_size) {
13423115Syl150051 				hldev->stats.sw_dev_info_stats.lro_sg_exceed_cnt++;
13436937Sxw161283 				ret = XGE_HAL_INF_LRO_END_1;
13443115Syl150051 			}
13451256Syl150051 
13461256Syl150051 		} else ret = XGE_HAL_INF_LRO_END_2;
13471256Syl150051 	}
13481256Syl150051 
13491256Syl150051 	/*
13501256Syl150051 	 * Since its time to flush,
13513115Syl150051 	 * update ip header	so that	it can be sent up
13521256Syl150051 	 */
13531256Syl150051 	if ((ret == XGE_HAL_INF_LRO_END_1) ||
13543115Syl150051 		(ret ==	XGE_HAL_INF_LRO_END_2) ||
13553115Syl150051 		(ret ==	XGE_HAL_INF_LRO_END_3))	{
13561256Syl150051 		lro->ip_hdr->tot_len = xge_os_htons((*p_lro)->total_length);
13571256Syl150051 		lro->ip_hdr->check = xge_os_htons(0);
13583115Syl150051 		lro->ip_hdr->check = XGE_LL_IP_FAST_CSUM(((u8 *)(lro->ip_hdr)),
13593115Syl150051 					(lro->ip_hdr->version_ihl & 0x0F));
13603115Syl150051 		lro->tcp_hdr->ack_seq =	lro->tcp_ack_num;
13611256Syl150051 	}
13621256Syl150051 
13631256Syl150051 	return (ret);
13641256Syl150051 }
13651256Syl150051 
13661256Syl150051 /**
13676937Sxw161283  * xge_hal_accumulate_large_rx:	LRO	a given	frame
13686937Sxw161283  * frames
13696937Sxw161283  * @buffer:	Ethernet frame.
13706937Sxw161283  * @tcp: tcp header.
13716937Sxw161283  * @seglen:	packet length.
13726937Sxw161283  * @p_lro: lro pointer.
13736937Sxw161283  * @ext_info: descriptor info, see xge_hal_dtr_info_t{}.
13746937Sxw161283  * @hldev: HAL device.
13756937Sxw161283  * @lro_end3: for lro_end3 output
13766937Sxw161283  *
13776937Sxw161283  * LRO the newly received frame, i.e. attach it	(if	possible) to the
13786937Sxw161283  * already accumulated (i.e., already LRO-ed) received frames (if any),
13796937Sxw161283  * to form one super-sized frame for the subsequent	processing
13806937Sxw161283  * by the stack.
13816937Sxw161283  */
13826937Sxw161283 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL xge_hal_status_e
xge_hal_accumulate_large_rx(u8 * buffer,tcplro_t ** tcp,u32 * seglen,lro_t ** p_lro,xge_hal_dtr_info_t * ext_info,xge_hal_device_t * hldev,lro_t ** lro_end3)13836937Sxw161283 xge_hal_accumulate_large_rx(u8 *buffer, tcplro_t **tcp, u32 *seglen,
13846937Sxw161283 lro_t **p_lro, xge_hal_dtr_info_t *ext_info, xge_hal_device_t *hldev,
13856937Sxw161283 lro_t **lro_end3)
13866937Sxw161283 {
13876937Sxw161283   int ring = 0;
13886937Sxw161283   return xge_hal_lro_process_rx(ring, buffer, NULL, tcp, seglen, p_lro,
13896937Sxw161283                                 ext_info, hldev, lro_end3);
13906937Sxw161283 }
13916937Sxw161283 
13926937Sxw161283 /**
13933115Syl150051  * xge_hal_lro_close_session: Close LRO session
13943115Syl150051  * @lro: LRO Session.
13953115Syl150051  * @hldev: HAL Context.
13963115Syl150051  */
13973115Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL void
xge_hal_lro_close_session(lro_t * lro)13983115Syl150051 xge_hal_lro_close_session (lro_t *lro)
13993115Syl150051 {
14003115Syl150051 	lro->in_use = 0;
14013115Syl150051 }
14023115Syl150051 
14033115Syl150051 /**
14046937Sxw161283  * xge_hal_lro_next_session: Returns next LRO session in the list or NULL
14053115Syl150051  *					if none	exists.
14066937Sxw161283  * @hldev: HAL Context.
14076937Sxw161283  * @ring: rx ring number.
14081256Syl150051  */
14093115Syl150051 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL lro_t	*
xge_hal_lro_next_session(xge_hal_device_t * hldev,int ring)14106937Sxw161283 xge_hal_lro_next_session (xge_hal_device_t *hldev, int ring)
14111256Syl150051 {
14126937Sxw161283 xge_hal_lro_desc_t *ring_lro = &hldev->lro_desc[ring];
14133115Syl150051 	int	i;
14146937Sxw161283 	int	start_idx =	ring_lro->lro_next_idx;
14151256Syl150051 
14163115Syl150051 	for(i =	start_idx; i < XGE_HAL_LRO_MAX_BUCKETS;	i++) {
14176937Sxw161283 		lro_t *lro = &ring_lro->lro_pool[i];
14183115Syl150051 
14193115Syl150051 		if (!lro->in_use)
14203115Syl150051 			continue;
14213115Syl150051 
14221256Syl150051 		lro->ip_hdr->tot_len = xge_os_htons(lro->total_length);
14231256Syl150051 		lro->ip_hdr->check = xge_os_htons(0);
14241256Syl150051 		lro->ip_hdr->check = XGE_LL_IP_FAST_CSUM(((u8 *)(lro->ip_hdr)),
14253115Syl150051 								(lro->ip_hdr->version_ihl &	0x0F));
14266937Sxw161283 		ring_lro->lro_next_idx	= i	+ 1;
14273115Syl150051 		return lro;
14281256Syl150051 	}
14291256Syl150051 
14306937Sxw161283 	ring_lro->lro_next_idx	= 0;
14311256Syl150051 	return NULL;
14323115Syl150051 
14331256Syl150051 }
14346937Sxw161283 
14356937Sxw161283 __HAL_STATIC_CHANNEL __HAL_INLINE_CHANNEL lro_t *
xge_hal_lro_get_next_session(xge_hal_device_t * hldev)14366937Sxw161283 xge_hal_lro_get_next_session(xge_hal_device_t *hldev)
14376937Sxw161283 {
14386937Sxw161283   int ring = 0; /* assume default ring=0 */
14396937Sxw161283   return xge_hal_lro_next_session(hldev, ring);
14406937Sxw161283 }
14411256Syl150051 #endif
1442