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