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