6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
47693af92e50a1ad81825eb01b7157a211269613mx * CDDL HEADER START
47693af92e50a1ad81825eb01b7157a211269613mx *
47693af92e50a1ad81825eb01b7157a211269613mx * The contents of this file are subject to the terms of the
47693af92e50a1ad81825eb01b7157a211269613mx * Common Development and Distribution License (the "License").
47693af92e50a1ad81825eb01b7157a211269613mx * You may not use this file except in compliance with the License.
47693af92e50a1ad81825eb01b7157a211269613mx *
47693af92e50a1ad81825eb01b7157a211269613mx * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
47693af92e50a1ad81825eb01b7157a211269613mx * or http://www.opensolaris.org/os/licensing.
47693af92e50a1ad81825eb01b7157a211269613mx * See the License for the specific language governing permissions
47693af92e50a1ad81825eb01b7157a211269613mx * and limitations under the License.
47693af92e50a1ad81825eb01b7157a211269613mx *
47693af92e50a1ad81825eb01b7157a211269613mx * When distributing Covered Code, include this CDDL HEADER in each
47693af92e50a1ad81825eb01b7157a211269613mx * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
47693af92e50a1ad81825eb01b7157a211269613mx * If applicable, add the following below this CDDL HEADER, with the
47693af92e50a1ad81825eb01b7157a211269613mx * fields enclosed by brackets "[]" replaced with your own identifying
47693af92e50a1ad81825eb01b7157a211269613mx * information: Portions Copyright [yyyy] [name of copyright owner]
47693af92e50a1ad81825eb01b7157a211269613mx *
47693af92e50a1ad81825eb01b7157a211269613mx * CDDL HEADER END
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
47693af92e50a1ad81825eb01b7157a211269613mx * Use is subject to license terms.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#include "nge.h"
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#undef NGE_DBG
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define NGE_DBG NGE_DBG_RECV
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_END 0x20000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_ERR 0x40000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_OWN 0x80000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_CSUM_MSK 0x1C000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_BCNT_MSK 0x00003FFF
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_CK8G_NO_HSUM 0x0
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_CK8G_TCP_SUM_ERR 0x04000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_CK8G_UDP_SUM_ERR 0x08000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_CK8G_IP_HSUM_ERR 0x0C000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_CK8G_IP_HSUM 0x10000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_CK8G_TCP_SUM 0x14000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_CK8G_UDP_SUM 0x18000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RXD_CK8G_RESV 0x1C000000
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxextern ddi_device_acc_attr_t nge_data_accattr;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
75675fb724f5909db6f601f4c342437208ca4178vb * Callback code invoked from STREAMs when the recv data buffer is free for
75675fb724f5909db6f601f4c342437208ca4178vb * recycling.
75675fb724f5909db6f601f4c342437208ca4178vb *
75675fb724f5909db6f601f4c342437208ca4178vb * The following table describes function behaviour:
75675fb724f5909db6f601f4c342437208ca4178vb *
75675fb724f5909db6f601f4c342437208ca4178vb * | mac stopped | mac running
75675fb724f5909db6f601f4c342437208ca4178vb * ---------------------------------------------------
75675fb724f5909db6f601f4c342437208ca4178vb * buffer delivered | free buffer | recycle buffer
75675fb724f5909db6f601f4c342437208ca4178vb * buffer not delivered | do nothing | recycle buffer (*)
75675fb724f5909db6f601f4c342437208ca4178vb *
75675fb724f5909db6f601f4c342437208ca4178vb * Note (*):
75675fb724f5909db6f601f4c342437208ca4178vb * Recycle buffer only if mac state did not change during execution of
75675fb724f5909db6f601f4c342437208ca4178vb * function. Otherwise if mac state changed, set buffer delivered & re-enter
75675fb724f5909db6f601f4c342437208ca4178vb * function by calling freemsg().
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxvoid
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_recv_recycle(caddr_t arg)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t val;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx boolean_t valid;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_t *ngep;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx dma_area_t *bufp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx buff_ring_t *brp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_sw_statistics_t *sw_stp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx bufp = (dma_area_t *)arg;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep = (nge_t *)bufp->private;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx brp = ngep->buff;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp = &ngep->statistics.sw_statistics;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Free the buffer directly if the buffer was allocated
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * previously or mac was stopped.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (bufp->signature != brp->buf_sign) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (bufp->rx_delivered == B_TRUE) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_free_dma_mem(bufp);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx kmem_free(bufp, sizeof (dma_area_t));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx val = nge_atomic_decrease(&brp->rx_hold, 1);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ASSERT(val == B_TRUE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * recycle the data buffer again and fill them in free ring
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx bufp->rx_recycle.free_func = nge_recv_recycle;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx bufp->rx_recycle.free_arg = (caddr_t)bufp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx bufp->mp = desballoc(DMA_VPTR(*bufp),
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->buf_size + NGE_HEADROOM, 0, &bufp->rx_recycle);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (bufp->mp == NULL) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp->mp_alloc_err++;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp->recy_free++;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_free_dma_mem(bufp);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx kmem_free(bufp, sizeof (dma_area_t));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx val = nge_atomic_decrease(&brp->rx_hold, 1);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ASSERT(val == B_TRUE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mutex_enter(brp->recycle_lock);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (bufp->signature != brp->buf_sign)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx valid = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx else
6f3e57ac9d0b054c3169579f3422080b8ba10105mx valid = B_FALSE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx bufp->rx_delivered = valid;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (bufp->rx_delivered == B_FALSE) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx bufp->next = brp->recycle_list;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx brp->recycle_list = bufp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mutex_exit(brp->recycle_lock);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (valid == B_TRUE)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /* call nge_rx_recycle again to free it */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx freemsg(bufp->mp);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx else {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx val = nge_atomic_decrease(&brp->rx_hold, 1);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ASSERT(val == B_TRUE);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Checking the rx's BDs (one or more) to receive
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * one complete packet.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * start_index: the start indexer of BDs for one packet.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * end_index: the end indexer of BDs for one packet.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic mblk_t *nge_recv_packet(nge_t *ngep, uint32_t start_index, size_t len);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#pragma inline(nge_recv_packet)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic mblk_t *
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_recv_packet(nge_t *ngep, uint32_t start_index, size_t len)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint8_t *rptr;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint32_t minsize;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint32_t maxsize;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mblk_t *mp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx buff_ring_t *brp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_rx_sbd_t *srbdp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx dma_area_t *bufp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_sw_statistics_t *sw_stp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx void *hw_bd_p;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx brp = ngep->buff;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx minsize = ETHERMIN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx maxsize = ngep->max_sdu;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp = &ngep->statistics.sw_statistics;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp = NULL;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp = &brp->sw_rbds[start_index];
6f3e57ac9d0b054c3169579f3422080b8ba10105mx DMA_SYNC(*srbdp->bufp, DDI_DMA_SYNC_FORKERNEL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p = DMA_VPTR(srbdp->desc);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * First check the free_list, if it is NULL,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * make the recycle_list be free_list.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (brp->free_list == NULL) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mutex_enter(brp->recycle_lock);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx brp->free_list = brp->recycle_list;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx brp->recycle_list = NULL;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mutex_exit(brp->recycle_lock);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx bufp = brp->free_list;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /* If it's not a qualified packet, delete it */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (len > maxsize || len < minsize) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->desc_attr.rxd_fill(hw_bd_p, &srbdp->bufp->cookie,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->bufp->alength);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->flags = CONTROLER_OWN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (NULL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * If receive packet size is smaller than RX bcopy threshold,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * or there is no available buffer in free_list or recycle list,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * we use bcopy directly.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (len <= ngep->param_rxbcopy_threshold || bufp == NULL)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx brp->rx_bcopy = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx else
6f3e57ac9d0b054c3169579f3422080b8ba10105mx brp->rx_bcopy = B_FALSE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (brp->rx_bcopy) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp = allocb(len + NGE_HEADROOM, 0);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (mp == NULL) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp->mp_alloc_err++;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->desc_attr.rxd_fill(hw_bd_p, &srbdp->bufp->cookie,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->bufp->alength);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->flags = CONTROLER_OWN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (NULL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx rptr = DMA_VPTR(*srbdp->bufp);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp->b_rptr = mp->b_rptr + NGE_HEADROOM;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx bcopy(rptr + NGE_HEADROOM, mp->b_rptr, len);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp->b_wptr = mp->b_rptr + len;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp = srbdp->bufp->mp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Make sure the packet *contents* 4-byte aligned
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp->b_rptr += NGE_HEADROOM;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp->b_wptr = mp->b_rptr + len;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp->b_next = mp->b_cont = NULL;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->bufp->rx_delivered = B_TRUE;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->bufp = NULL;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_atomic_increase(&brp->rx_hold, 1);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /* Fill the buffer from free_list */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->bufp = bufp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx brp->free_list = bufp->next;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx bufp->next = NULL;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /* replenish the buffer for hardware descriptor */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->desc_attr.rxd_fill(hw_bd_p, &srbdp->bufp->cookie,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->bufp->alength);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->flags = CONTROLER_OWN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp->rbytes += len;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp->recv_count++;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (mp);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RX_HW_ERR 0x01
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RX_SUM_NO 0x02
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#define RX_SUM_ERR 0x04
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx/*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Statistic the rx's error
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * and generate a log msg for these.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Note:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * RXE, Parity Error, Symbo error, CRC error
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * have been recored by nvidia's hardware
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * statistics part (nge_statistics). So it is uncessary to record them by
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * driver in this place.
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic uint32_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_rxsta_handle(nge_t *ngep, uint32_t stflag, uint32_t *pflags);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx#pragma inline(nge_rxsta_handle)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic uint32_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_rxsta_handle(nge_t *ngep, uint32_t stflag, uint32_t *pflags)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint32_t errors;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint32_t err_flag;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_sw_statistics_t *sw_stp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx err_flag = 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp = &ngep->statistics.sw_statistics;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if ((RXD_END & stflag) == 0)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (RX_HW_ERR);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx errors = stflag & RXD_CSUM_MSK;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx switch (errors) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx default:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case RXD_CK8G_TCP_SUM:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case RXD_CK8G_UDP_SUM:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *pflags |= HCK_IPV4_HDRCKSUM_OK;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx *pflags |= HCK_FULLCKSUM_OK;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case RXD_CK8G_TCP_SUM_ERR:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case RXD_CK8G_UDP_SUM_ERR:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp->tcp_hwsum_err++;
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *pflags |= HCK_IPV4_HDRCKSUM_OK;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case RXD_CK8G_IP_HSUM:
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer *pflags |= HCK_IPV4_HDRCKSUM_OK;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case RXD_CK8G_NO_HSUM:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx err_flag |= RX_SUM_NO;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx case RXD_CK8G_IP_HSUM_ERR:
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_stp->ip_hwsum_err++;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx err_flag |= RX_SUM_ERR;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if ((stflag & RXD_ERR) != 0) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx err_flag |= RX_HW_ERR;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx NGE_DEBUG(("Receive desc error, status: 0x%x", stflag));
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (err_flag);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxstatic mblk_t *
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_recv_ring(nge_t *ngep)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint32_t stflag;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint32_t flag_err;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint32_t sum_flags;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx size_t len;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint64_t end_index;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint64_t sync_start;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mblk_t *mp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mblk_t **tail;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mblk_t *head;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx recv_ring_t *rrp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx buff_ring_t *brp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sw_rx_sbd_t *srbdp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx void * hw_bd_p;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_mode_cntl mode_cntl;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp = NULL;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx head = NULL;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx tail = &head;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx rrp = ngep->recv;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx brp = ngep->buff;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx end_index = sync_start = rrp->prod_index;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /* Sync the descriptor for kernel */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (sync_start + ngep->param_recv_max_packet <= ngep->rx_desc) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (void) ddi_dma_sync(rrp->desc.dma_hdl,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sync_start * ngep->desc_attr.rxd_size,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->param_recv_max_packet * ngep->desc_attr.rxd_size,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx DDI_DMA_SYNC_FORKERNEL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (void) ddi_dma_sync(rrp->desc.dma_hdl,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sync_start * ngep->desc_attr.rxd_size,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx 0,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx DDI_DMA_SYNC_FORKERNEL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (void) ddi_dma_sync(rrp->desc.dma_hdl,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx 0,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (ngep->param_recv_max_packet + sync_start - ngep->rx_desc) *
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->desc_attr.rxd_size,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx DDI_DMA_SYNC_FORKERNEL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * Looking through the rx's ring to find the good packets
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * and try to receive more and more packets in rx's ring
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx for (;;) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sum_flags = 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx flag_err = 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx end_index = rrp->prod_index;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp = &brp->sw_rbds[end_index];
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p = DMA_VPTR(srbdp->desc);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx stflag = ngep->desc_attr.rxd_check(hw_bd_p, &len);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /*
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * If there is no packet in receving ring
6f3e57ac9d0b054c3169579f3422080b8ba10105mx * break the loop
6f3e57ac9d0b054c3169579f3422080b8ba10105mx */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if ((stflag & RXD_OWN) != 0 || HOST_OWN == srbdp->flags)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->recv_count++;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx flag_err = nge_rxsta_handle(ngep, stflag, &sum_flags);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if ((flag_err & RX_HW_ERR) == 0) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->flags = NGE_END_PACKET;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp = nge_recv_packet(ngep, end_index, len);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /* Hardware error, re-use the buffer */
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->desc_attr.rxd_fill(hw_bd_p, &srbdp->bufp->cookie,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->bufp->alength);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx srbdp->flags = CONTROLER_OWN;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (mp != NULL) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (!(flag_err & (RX_SUM_NO | RX_SUM_ERR))) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mac_hcksum_set(mp, 0, 0, 0, 0, sum_flags);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx *tail = mp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx tail = &mp->b_next;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp = NULL;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx rrp->prod_index = NEXT(end_index, rrp->desc.nslots);
6ad2424573dc54dfdafb513b5b710b59337b0869Winson Wang - Sun Microsystems - Beijing China if (ngep->recv_count >= ngep->param_recv_max_packet)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx break;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx /* Sync the descriptors for device */
02d51d0d625c185ad277d9ad1ddf34b06f78b9b4jj if (sync_start + ngep->recv_count <= ngep->rx_desc) {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (void) ddi_dma_sync(rrp->desc.dma_hdl,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sync_start * ngep->desc_attr.rxd_size,
02d51d0d625c185ad277d9ad1ddf34b06f78b9b4jj ngep->recv_count * ngep->desc_attr.rxd_size,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx DDI_DMA_SYNC_FORDEV);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx } else {
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (void) ddi_dma_sync(rrp->desc.dma_hdl,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sync_start * ngep->desc_attr.rxd_size,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx 0,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx DDI_DMA_SYNC_FORDEV);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx (void) ddi_dma_sync(rrp->desc.dma_hdl,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx 0,
02d51d0d625c185ad277d9ad1ddf34b06f78b9b4jj (ngep->recv_count + sync_start - ngep->rx_desc) *
6f3e57ac9d0b054c3169579f3422080b8ba10105mx ngep->desc_attr.rxd_size,
6f3e57ac9d0b054c3169579f3422080b8ba10105mx DDI_DMA_SYNC_FORDEV);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx }
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mode_cntl.mode_val = nge_reg_get32(ngep, NGE_MODE_CNTL);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mode_cntl.mode_bits.rxdm = NGE_SET;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mode_cntl.mode_bits.tx_rcom_en = NGE_SET;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx nge_reg_put32(ngep, NGE_MODE_CNTL, mode_cntl.mode_val);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (head);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxvoid
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_receive(nge_t *ngep)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mblk_t *mp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx recv_ring_t *rrp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx rrp = ngep->recv;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mp = nge_recv_ring(ngep);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mutex_exit(ngep->genlock);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx if (mp != NULL)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mac_rx(ngep->mh, rrp->handle, mp);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx mutex_enter(ngep->genlock);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxvoid
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_hot_rxd_fill(void *hwd, const ddi_dma_cookie_t *cookie, size_t len)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint64_t dmac_addr;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hot_rx_bd * hw_bd_p;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p = (hot_rx_bd *)hwd;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx dmac_addr = cookie->dmac_laddress + NGE_HEADROOM;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p->cntl_status.cntl_val = 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p->host_buf_addr_hi = dmac_addr >> 32;
a55f711916b9f7718fabc2d1822bf5719aa6140fMiles Xu, Sun Microsystems hw_bd_p->host_buf_addr_lo = (uint32_t)dmac_addr;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p->cntl_status.control_bits.bcnt = len - 1;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx membar_producer();
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p->cntl_status.control_bits.own = NGE_SET;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxvoid
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_sum_rxd_fill(void *hwd, const ddi_dma_cookie_t *cookie, size_t len)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx sum_rx_bd * hw_bd_p;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p = hwd;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p->cntl_status.cntl_val = 0;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
a55f711916b9f7718fabc2d1822bf5719aa6140fMiles Xu, Sun Microsystems hw_bd_p->host_buf_addr =
a55f711916b9f7718fabc2d1822bf5719aa6140fMiles Xu, Sun Microsystems (uint32_t)(cookie->dmac_address + NGE_HEADROOM);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p->cntl_status.control_bits.bcnt = len - 1;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx membar_producer();
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hw_bd_p->cntl_status.control_bits.own = NGE_SET;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxuint32_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_hot_rxd_check(const void *hwd, size_t *len)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint32_t err_flag;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx const hot_rx_bd * hrbdp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hrbdp = hwd;
9fa05d92f6b225eb418fb782225c991b887ea8b7Winson Wang - Sun Microsystems - Beijing China err_flag = hrbdp->cntl_status.cntl_val;
9fa05d92f6b225eb418fb782225c991b887ea8b7Winson Wang - Sun Microsystems - Beijing China *len = err_flag & RXD_BCNT_MSK;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (err_flag);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mxuint32_t
6f3e57ac9d0b054c3169579f3422080b8ba10105mxnge_sum_rxd_check(const void *hwd, size_t *len)
6f3e57ac9d0b054c3169579f3422080b8ba10105mx{
6f3e57ac9d0b054c3169579f3422080b8ba10105mx uint32_t err_flag;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx const sum_rx_bd * hrbdp;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
6f3e57ac9d0b054c3169579f3422080b8ba10105mx hrbdp = hwd;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx
9fa05d92f6b225eb418fb782225c991b887ea8b7Winson Wang - Sun Microsystems - Beijing China err_flag = hrbdp->cntl_status.cntl_val;
9fa05d92f6b225eb418fb782225c991b887ea8b7Winson Wang - Sun Microsystems - Beijing China *len = err_flag & RXD_BCNT_MSK;
6f3e57ac9d0b054c3169579f3422080b8ba10105mx return (err_flag);
6f3e57ac9d0b054c3169579f3422080b8ba10105mx}