c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * CDDL HEADER START
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * The contents of this file are subject to the terms of the
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb * Common Development and Distribution License (the "License").
ba2e4443695ee6a6f420a35cd4fc3d3346d22932seb * You may not use this file except in compliance with the License.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * or http://www.opensolaris.org/os/licensing.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * See the License for the specific language governing permissions
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * and limitations under the License.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * When distributing Covered Code, include this CDDL HEADER in each
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * If applicable, add the following below this CDDL HEADER, with the
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * fields enclosed by brackets "[]" replaced with your own identifying
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * information: Portions Copyright [yyyy] [name of copyright owner]
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * CDDL HEADER END
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
7b114c4b72aa312e481641f6d76a0f0194877786Winson Wang - Sun Microsystems - Beijing China * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Use is subject to license terms.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#include "rge.h"
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define U32TOPTR(x) ((void *)(uintptr_t)(uint32_t)(x))
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define PTRTOU32(x) ((uint32_t)(uintptr_t)(void *)(x))
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ========== RX side routines ==========
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define RGE_DBG RGE_DBG_RECV /* debug flag for this code */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic uint32_t rge_atomic_reserve(uint32_t *count_p, uint32_t n);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_atomic_reserve)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic uint32_t
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_atomic_reserve(uint32_t *count_p, uint32_t n)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t oldval;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t newval;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /* ATOMICALLY */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs do {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs oldval = *count_p;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs newval = oldval - n;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (oldval <= n)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0); /* no resources left */
75d94465dbafa487b716482dc36d5150a4ec9853Josef 'Jeff' Sipek } while (atomic_cas_32(count_p, oldval, newval) != oldval);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (newval);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Atomically increment a counter
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void rge_atomic_renounce(uint32_t *count_p, uint32_t n);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_atomic_renounce)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_atomic_renounce(uint32_t *count_p, uint32_t n)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t oldval;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t newval;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /* ATOMICALLY */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs do {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs oldval = *count_p;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs newval = oldval + n;
75d94465dbafa487b716482dc36d5150a4ec9853Josef 'Jeff' Sipek } while (atomic_cas_32(count_p, oldval, newval) != oldval);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Callback code invoked from STREAMs when the recv data buffer is free
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * for recycling.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsvoid
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_rx_recycle(caddr_t arg)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_t *rgep;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs dma_buf_t *rx_buf;
aa81749390e332985277568edab1ee6132326b42gs sw_rbd_t *free_srbdp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t slot_recy;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rx_buf = (dma_buf_t *)arg;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep = (rge_t *)rx_buf->private;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
aa81749390e332985277568edab1ee6132326b42gs * In rge_unattach() and rge_attach(), this callback function will
aa81749390e332985277568edab1ee6132326b42gs * also be called to free mp in rge_fini_rings() and rge_init_rings().
aa81749390e332985277568edab1ee6132326b42gs * In such situation, we shouldn't do below desballoc(), otherwise,
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * there'll be memory leak.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
aa81749390e332985277568edab1ee6132326b42gs if (rgep->rge_mac_state == RGE_MAC_UNATTACH ||
aa81749390e332985277568edab1ee6132326b42gs rgep->rge_mac_state == RGE_MAC_ATTACH)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Recycle the data buffer again
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * and fill them in free ring
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf),
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->rxbuf_size, 0, &rx_buf->rx_recycle);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (rx_buf->mp == NULL) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_problem(rgep, "rge_rx_recycle: desballoc() failed");
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_enter(rgep->rc_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs slot_recy = rgep->rc_next;
aa81749390e332985277568edab1ee6132326b42gs free_srbdp = &rgep->free_srbds[slot_recy];
aa81749390e332985277568edab1ee6132326b42gs
aa81749390e332985277568edab1ee6132326b42gs ASSERT(free_srbdp->rx_buf == NULL);
aa81749390e332985277568edab1ee6132326b42gs free_srbdp->rx_buf = rx_buf;
aa81749390e332985277568edab1ee6132326b42gs rgep->rc_next = NEXT(slot_recy, RGE_BUF_SLOTS);
aa81749390e332985277568edab1ee6132326b42gs rge_atomic_renounce(&rgep->rx_free, 1);
aa81749390e332985277568edab1ee6132326b42gs if (rgep->rx_bcopy && rgep->rx_free == RGE_BUF_SLOTS)
aa81749390e332985277568edab1ee6132326b42gs rgep->rx_bcopy = B_FALSE;
aa81749390e332985277568edab1ee6132326b42gs ASSERT(rgep->rx_free <= RGE_BUF_SLOTS);
aa81749390e332985277568edab1ee6132326b42gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_exit(rgep->rc_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic int rge_rx_refill(rge_t *rgep, uint32_t slot);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_rx_refill)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic int
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_rx_refill(rge_t *rgep, uint32_t slot)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs dma_buf_t *free_buf;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_bd_t *hw_rbd_p;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs sw_rbd_t *srbdp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t free_slot;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs srbdp = &rgep->sw_rbds[slot];
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_rbd_p = &rgep->rx_ring[slot];
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs free_slot = rgep->rf_next;
aa81749390e332985277568edab1ee6132326b42gs free_buf = rgep->free_srbds[free_slot].rx_buf;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (free_buf != NULL) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs srbdp->rx_buf = free_buf;
aa81749390e332985277568edab1ee6132326b42gs rgep->free_srbds[free_slot].rx_buf = NULL;
aa81749390e332985277568edab1ee6132326b42gs hw_rbd_p->host_buf_addr = RGE_BSWAP_32(rgep->head_room +
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs + free_buf->pbuf.cookie.dmac_laddress);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_rbd_p->host_buf_addr_hi =
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_BSWAP_32(free_buf->pbuf.cookie.dmac_laddress >> 32);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->rf_next = NEXT(free_slot, RGE_BUF_SLOTS);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (1);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs } else {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * This situation shouldn't happen
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_problem(rgep, "rge_rx_refill: free buffer %d is NULL",
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs free_slot);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->rx_bcopy = B_TRUE;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic mblk_t *rge_receive_packet(rge_t *rgep, uint32_t slot);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_receive_packet)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic mblk_t *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_receive_packet(rge_t *rgep, uint32_t slot)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_bd_t *hw_rbd_p;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs sw_rbd_t *srbdp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uchar_t *dp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mblk_t *mp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint8_t *rx_ptr;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t rx_status;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint_t packet_len;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint_t minsize;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint_t maxsize;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t proto;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t pflags;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs struct ether_vlan_header *ehp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint16_t vtag = 0;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_rbd_p = &rgep->rx_ring[slot];
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs srbdp = &rgep->sw_rbds[slot];
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Read receive status
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rx_status = RGE_BSWAP_32(hw_rbd_p->flags_len) & RBD_FLAGS_MASK;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Handle error packet
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (!(rx_status & BD_FLAG_PKT_END)) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_DEBUG(("rge_receive_packet: not a complete packat"));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (rx_status & RBD_FLAG_ERROR) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (rx_status & RBD_FLAG_CRC_ERR)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->stats.crc_err++;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (rx_status & RBD_FLAG_RUNT)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->stats.in_short++;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Set chip_error flag to reset chip:
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * (suggested in Realtek programming guide.)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_DEBUG(("rge_receive_packet: error packet, status = %x",
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rx_status));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_enter(rgep->genlock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->rge_chip_state = RGE_CHIP_ERROR;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_exit(rgep->genlock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Handle size error packet
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
aa81749390e332985277568edab1ee6132326b42gs packet_len = RGE_BSWAP_32(hw_rbd_p->flags_len) & RBD_LEN_MASK;
aa81749390e332985277568edab1ee6132326b42gs packet_len -= ETHERFCSL;
aa81749390e332985277568edab1ee6132326b42gs minsize = ETHERMIN;
aa81749390e332985277568edab1ee6132326b42gs pflags = RGE_BSWAP_32(hw_rbd_p->vlan_tag);
aa81749390e332985277568edab1ee6132326b42gs if (pflags & RBD_VLAN_PKT)
aa81749390e332985277568edab1ee6132326b42gs minsize -= VLAN_TAGSZ;
aa81749390e332985277568edab1ee6132326b42gs maxsize = rgep->ethmax_size;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (packet_len < minsize || packet_len > maxsize) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_DEBUG(("rge_receive_packet: len err = %d", packet_len));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs DMA_SYNC(srbdp->rx_buf->pbuf, DDI_DMA_SYNC_FORKERNEL);
aa81749390e332985277568edab1ee6132326b42gs if (rgep->rx_bcopy || packet_len <= RGE_RECV_COPY_SIZE ||
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs !rge_atomic_reserve(&rgep->rx_free, 1)) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate buffer to receive this good packet
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mp = allocb(packet_len + RGE_HEADROOM, 0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (mp == NULL) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_DEBUG(("rge_receive_packet: allocate buffer fail"));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->stats.no_rcvbuf++;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Copy the data found into the new cluster
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rx_ptr = DMA_VPTR(srbdp->rx_buf->pbuf);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mp->b_rptr = dp = mp->b_rptr + RGE_HEADROOM;
aa81749390e332985277568edab1ee6132326b42gs bcopy(rx_ptr + rgep->head_room, dp, packet_len);
aa81749390e332985277568edab1ee6132326b42gs mp->b_wptr = dp + packet_len;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs } else {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mp = srbdp->rx_buf->mp;
aa81749390e332985277568edab1ee6132326b42gs mp->b_rptr += rgep->head_room;
aa81749390e332985277568edab1ee6132326b42gs mp->b_wptr = mp->b_rptr + packet_len;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mp->b_next = mp->b_cont = NULL;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Refill the current receive bd buffer
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * if fails, will just keep the mp.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (!rge_rx_refill(rgep, slot))
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->stats.rbytes += packet_len;
22dc213396fdd861beeb93f8cb17eaaeb9960cf4mx rgep->stats.rpackets ++;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * VLAN packet ?
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (pflags & RBD_VLAN_PKT)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs vtag = pflags & RBD_VLAN_TAG;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (vtag) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs vtag = TCI_CHIP2OS(vtag);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * As h/w strips the VLAN tag from incoming packet, we need
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * insert VLAN tag into this packet before send up here.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs (void) memmove(mp->b_rptr - VLAN_TAGSZ, mp->b_rptr,
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs 2 * ETHERADDRL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mp->b_rptr -= VLAN_TAGSZ;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ehp = (struct ether_vlan_header *)mp->b_rptr;
605445d5657096e69d948ccb554c9ff024fa34dfdg ehp->ether_tpid = htons(ETHERTYPE_VLAN);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ehp->ether_tci = htons(vtag);
aa81749390e332985277568edab1ee6132326b42gs rgep->stats.rbytes += VLAN_TAGSZ;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Check h/w checksum offload status
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs pflags = 0;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs proto = rx_status & RBD_FLAG_PROTOCOL;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if ((proto == RBD_FLAG_TCP && !(rx_status & RBD_TCP_CKSUM_ERR)) ||
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs (proto == RBD_FLAG_UDP && !(rx_status & RBD_UDP_CKSUM_ERR)))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer pflags |= HCK_FULLCKSUM_OK;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (proto != RBD_FLAG_NONE_IP && !(rx_status & RBD_IP_CKSUM_ERR))
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer pflags |= HCK_IPV4_HDRCKSUM_OK;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (pflags != 0) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mac_hcksum_set(mp, 0, 0, 0, 0, pflags);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (mp);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Accept the packets received in rx ring.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Returns a chain of mblks containing the received data, to be
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * passed up to mac_rx().
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * The routine returns only when a complete scan has been performed
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * without finding any packets to receive.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * This function must SET the OWN bit of BD to indicate the packets
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * it has accepted from the ring.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic mblk_t *rge_receive_ring(rge_t *rgep);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_receive_ring)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic mblk_t *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_receive_ring(rge_t *rgep)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_bd_t *hw_rbd_p;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mblk_t *head;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mblk_t **tail;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mblk_t *mp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t slot;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ASSERT(mutex_owned(rgep->rx_lock));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Sync (all) the receive ring descriptors
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * before accepting the packets they describe
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORKERNEL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs slot = rgep->rx_next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_rbd_p = &rgep->rx_ring[slot];
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs head = NULL;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs tail = &head;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs while (!(hw_rbd_p->flags_len & RGE_BSWAP_32(BD_FLAG_HW_OWN))) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if ((mp = rge_receive_packet(rgep, slot)) != NULL) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs *tail = mp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs tail = &mp->b_next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Clear RBD flags
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_rbd_p->flags_len =
aa81749390e332985277568edab1ee6132326b42gs RGE_BSWAP_32(rgep->rxbuf_size - rgep->head_room);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs HW_RBD_INIT(hw_rbd_p, slot);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs slot = NEXT(slot, RGE_RECV_SLOTS);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_rbd_p = &rgep->rx_ring[slot];
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->rx_next = slot;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (head);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Receive all ready packets.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsvoid rge_receive(rge_t *rgep);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma no_inline(rge_receive)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsvoid
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_receive(rge_t *rgep)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mblk_t *mp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_enter(rgep->rx_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mp = rge_receive_ring(rgep);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_exit(rgep->rx_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (mp != NULL)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_rx(rgep->mh, NULL, mp);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#undef RGE_DBG
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define RGE_DBG RGE_DBG_SEND /* debug flag for this code */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ========== Send-side recycle routines ==========
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic uint32_t rge_send_claim(rge_t *rgep);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_send_claim)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic uint32_t
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_send_claim(rge_t *rgep)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t slot;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_enter(rgep->tx_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs slot = rgep->tx_next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs next = NEXT(slot, RGE_SEND_SLOTS);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->tx_next = next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->tx_flow++;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_exit(rgep->tx_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * We check that our invariants still hold:
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * + the slot and next indexes are in range
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * + the slot must not be the last one (i.e. the *next*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * index must not match the next-recycle index), 'cos
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * there must always be at least one free slot in a ring
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ASSERT(slot < RGE_SEND_SLOTS);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ASSERT(next < RGE_SEND_SLOTS);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ASSERT(next != rgep->tc_next);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (slot);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * We don't want to call this function every time after a successful
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * h/w transmit done in ISR. Instead, we call this function in the
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_send() when there're few or no free tx BDs remained.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
9e1a9180bec2232328687ae8e96007921a6ed05dLi-Zhen Youvoid rge_send_recycle(rge_t *rgep);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_send_recycle)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
9e1a9180bec2232328687ae8e96007921a6ed05dLi-Zhen Youvoid
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_send_recycle(rge_t *rgep)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_bd_t *hw_sbd_p;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t tc_tail;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t tc_head;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t n;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_enter(rgep->tc_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs tc_head = rgep->tc_next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs tc_tail = rgep->tc_tail;
aa81749390e332985277568edab1ee6132326b42gs if (tc_head == tc_tail)
aa81749390e332985277568edab1ee6132326b42gs goto resched;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs do {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs tc_tail = LAST(tc_tail, RGE_SEND_SLOTS);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_sbd_p = &rgep->tx_ring[tc_tail];
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (tc_tail == tc_head) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (hw_sbd_p->flags_len &
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_BSWAP_32(BD_FLAG_HW_OWN)) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
aa81749390e332985277568edab1ee6132326b42gs * Recyled nothing: bump the watchdog counter,
aa81749390e332985277568edab1ee6132326b42gs * thus guaranteeing that it's nonzero
aa81749390e332985277568edab1ee6132326b42gs * (watchdog activated).
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
9e1a9180bec2232328687ae8e96007921a6ed05dLi-Zhen You if (rgep->watchdog == 0)
9e1a9180bec2232328687ae8e96007921a6ed05dLi-Zhen You rgep->watchdog = 1;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_exit(rgep->tc_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs break;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs } while (hw_sbd_p->flags_len & RGE_BSWAP_32(BD_FLAG_HW_OWN));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
aa81749390e332985277568edab1ee6132326b42gs /*
aa81749390e332985277568edab1ee6132326b42gs * Recyled something :-)
aa81749390e332985277568edab1ee6132326b42gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->tc_next = NEXT(tc_tail, RGE_SEND_SLOTS);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs n = rgep->tc_next - tc_head;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (rgep->tc_next < tc_head)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs n += RGE_SEND_SLOTS;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_atomic_renounce(&rgep->tx_free, n);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->watchdog = 0;
aa81749390e332985277568edab1ee6132326b42gs ASSERT(rgep->tx_free <= RGE_SEND_SLOTS);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
aa81749390e332985277568edab1ee6132326b42gsresched:
aa81749390e332985277568edab1ee6132326b42gs mutex_exit(rgep->tc_lock);
aa81749390e332985277568edab1ee6132326b42gs if (rgep->resched_needed &&
aa81749390e332985277568edab1ee6132326b42gs rgep->rge_mac_state == RGE_MAC_STARTED) {
aa81749390e332985277568edab1ee6132326b42gs rgep->resched_needed = B_FALSE;
aa81749390e332985277568edab1ee6132326b42gs mac_tx_update(rgep->mh);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Send a message by copying it into a preallocated (and premapped) buffer
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
aa81749390e332985277568edab1ee6132326b42gsstatic void rge_send_copy(rge_t *rgep, mblk_t *mp, uint16_t tci);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_send_copy)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
aa81749390e332985277568edab1ee6132326b42gsrge_send_copy(rge_t *rgep, mblk_t *mp, uint16_t tci)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_bd_t *hw_sbd_p;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs sw_sbd_t *ssbdp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mblk_t *bp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs char *txb;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t slot;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs size_t totlen;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs size_t mblen;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs uint32_t pflags;
aa81749390e332985277568edab1ee6132326b42gs struct ether_header *ethhdr;
aa81749390e332985277568edab1ee6132326b42gs struct ip *ip_hdr;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * IMPORTANT:
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Up to the point where it claims a place, a send_msg()
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * routine can indicate failure by returning B_FALSE. Once it's
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * claimed a place, it mustn't fail.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * In this version, there's no setup to be done here, and there's
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * nothing that can fail, so we can go straight to claiming our
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * already-reserved place on the train.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * This is the point of no return!
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs slot = rge_send_claim(rgep);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ssbdp = &rgep->sw_sbds[slot];
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Copy the data into a pre-mapped buffer, which avoids the
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * overhead (and complication) of mapping/unmapping STREAMS
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * buffers and keeping hold of them until the DMA has completed.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Because all buffers are the same size, and larger than the
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * longest single valid message, we don't have to bother about
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * splitting the message across multiple buffers either.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs txb = DMA_VPTR(ssbdp->pbuf);
aa81749390e332985277568edab1ee6132326b42gs totlen = 0;
aa81749390e332985277568edab1ee6132326b42gs bp = mp;
aa81749390e332985277568edab1ee6132326b42gs if (tci != 0) {
aa81749390e332985277568edab1ee6132326b42gs /*
aa81749390e332985277568edab1ee6132326b42gs * Do not copy the vlan tag
aa81749390e332985277568edab1ee6132326b42gs */
aa81749390e332985277568edab1ee6132326b42gs bcopy(bp->b_rptr, txb, 2 * ETHERADDRL);
aa81749390e332985277568edab1ee6132326b42gs txb += 2 * ETHERADDRL;
aa81749390e332985277568edab1ee6132326b42gs totlen += 2 * ETHERADDRL;
22eb7cb54d8a6bcf6fe2674cb4b1f0cf2d85cfb6gd mblen = MBLKL(bp);
aa81749390e332985277568edab1ee6132326b42gs ASSERT(mblen >= 2 * ETHERADDRL + VLAN_TAGSZ);
aa81749390e332985277568edab1ee6132326b42gs mblen -= 2 * ETHERADDRL + VLAN_TAGSZ;
aa81749390e332985277568edab1ee6132326b42gs if ((totlen += mblen) <= rgep->ethmax_size) {
aa81749390e332985277568edab1ee6132326b42gs bcopy(bp->b_rptr + 2 * ETHERADDRL + VLAN_TAGSZ,
aa81749390e332985277568edab1ee6132326b42gs txb, mblen);
aa81749390e332985277568edab1ee6132326b42gs txb += mblen;
aa81749390e332985277568edab1ee6132326b42gs }
aa81749390e332985277568edab1ee6132326b42gs bp = bp->b_cont;
aa81749390e332985277568edab1ee6132326b42gs rgep->stats.obytes += VLAN_TAGSZ;
aa81749390e332985277568edab1ee6132326b42gs }
aa81749390e332985277568edab1ee6132326b42gs for (; bp != NULL; bp = bp->b_cont) {
22eb7cb54d8a6bcf6fe2674cb4b1f0cf2d85cfb6gd mblen = MBLKL(bp);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if ((totlen += mblen) <= rgep->ethmax_size) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs bcopy(bp->b_rptr, txb, mblen);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs txb += mblen;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
aa81749390e332985277568edab1ee6132326b42gs rgep->stats.obytes += totlen;
22dc213396fdd861beeb93f8cb17eaaeb9960cf4mx rgep->stats.tx_pre_ismax = rgep->stats.tx_cur_ismax;
22dc213396fdd861beeb93f8cb17eaaeb9960cf4mx if (totlen == rgep->ethmax_size)
22dc213396fdd861beeb93f8cb17eaaeb9960cf4mx rgep->stats.tx_cur_ismax = B_TRUE;
22dc213396fdd861beeb93f8cb17eaaeb9960cf4mx else
22dc213396fdd861beeb93f8cb17eaaeb9960cf4mx rgep->stats.tx_cur_ismax = B_FALSE;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * We'e reached the end of the chain; and we should have
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * collected no more than ETHERMAX bytes into our buffer.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ASSERT(bp == NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ASSERT(totlen <= rgep->ethmax_size);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs DMA_SYNC(ssbdp->pbuf, DDI_DMA_SYNC_FORDEV);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
aa81749390e332985277568edab1ee6132326b42gs * Update the hardware send buffer descriptor flags
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_sbd_p = &rgep->tx_ring[slot];
aa81749390e332985277568edab1ee6132326b42gs ASSERT(hw_sbd_p == ssbdp->desc.mem_va);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_sbd_p->flags_len = RGE_BSWAP_32(totlen & SBD_LEN_MASK);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (tci != 0) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs tci = TCI_OS2CHIP(tci);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_sbd_p->vlan_tag = RGE_BSWAP_32(tci);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_sbd_p->vlan_tag |= RGE_BSWAP_32(SBD_VLAN_PKT);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs } else {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_sbd_p->vlan_tag = 0;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
aa81749390e332985277568edab1ee6132326b42gs /*
aa81749390e332985277568edab1ee6132326b42gs * h/w checksum offload flags
aa81749390e332985277568edab1ee6132326b42gs */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &pflags);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (pflags & HCK_FULLCKSUM) {
aa81749390e332985277568edab1ee6132326b42gs ASSERT(totlen >= sizeof (struct ether_header) +
aa81749390e332985277568edab1ee6132326b42gs sizeof (struct ip));
aa81749390e332985277568edab1ee6132326b42gs ethhdr = (struct ether_header *)(DMA_VPTR(ssbdp->pbuf));
aa81749390e332985277568edab1ee6132326b42gs /*
aa81749390e332985277568edab1ee6132326b42gs * Is the packet an IP(v4) packet?
aa81749390e332985277568edab1ee6132326b42gs */
aa81749390e332985277568edab1ee6132326b42gs if (ntohs(ethhdr->ether_type) == ETHERTYPE_IP) {
aa81749390e332985277568edab1ee6132326b42gs ip_hdr = (struct ip *)
aa81749390e332985277568edab1ee6132326b42gs ((uint8_t *)DMA_VPTR(ssbdp->pbuf) +
aa81749390e332985277568edab1ee6132326b42gs sizeof (struct ether_header));
aa81749390e332985277568edab1ee6132326b42gs if (ip_hdr->ip_p == IPPROTO_TCP)
aa81749390e332985277568edab1ee6132326b42gs hw_sbd_p->flags_len |=
aa81749390e332985277568edab1ee6132326b42gs RGE_BSWAP_32(SBD_FLAG_TCP_CKSUM);
aa81749390e332985277568edab1ee6132326b42gs else if (ip_hdr->ip_p == IPPROTO_UDP)
aa81749390e332985277568edab1ee6132326b42gs hw_sbd_p->flags_len |=
aa81749390e332985277568edab1ee6132326b42gs RGE_BSWAP_32(SBD_FLAG_UDP_CKSUM);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
aa81749390e332985277568edab1ee6132326b42gs if (pflags & HCK_IPV4_HDRCKSUM)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_sbd_p->flags_len |= RGE_BSWAP_32(SBD_FLAG_IP_CKSUM);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs HW_SBD_SET(hw_sbd_p, slot);
aa81749390e332985277568edab1ee6132326b42gs
aa81749390e332985277568edab1ee6132326b42gs /*
aa81749390e332985277568edab1ee6132326b42gs * We're done.
aa81749390e332985277568edab1ee6132326b42gs * The message can be freed right away, as we've already
aa81749390e332985277568edab1ee6132326b42gs * copied the contents ...
aa81749390e332985277568edab1ee6132326b42gs */
aa81749390e332985277568edab1ee6132326b42gs freemsg(mp);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic boolean_t
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_send(rge_t *rgep, mblk_t *mp)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs struct ether_vlan_header *ehp;
aa81749390e332985277568edab1ee6132326b42gs uint16_t tci;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ASSERT(mp->b_next == NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Try to reserve a place in the transmit ring.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (!rge_atomic_reserve(&rgep->tx_free, 1)) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_DEBUG(("rge_send: no free slots"));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->stats.defer++;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->resched_needed = B_TRUE;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (B_FALSE);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
aa81749390e332985277568edab1ee6132326b42gs /*
aa81749390e332985277568edab1ee6132326b42gs * Determine if the packet is VLAN tagged.
aa81749390e332985277568edab1ee6132326b42gs */
aa81749390e332985277568edab1ee6132326b42gs ASSERT(MBLKL(mp) >= sizeof (struct ether_header));
aa81749390e332985277568edab1ee6132326b42gs tci = 0;
aa81749390e332985277568edab1ee6132326b42gs ehp = (struct ether_vlan_header *)mp->b_rptr;
605445d5657096e69d948ccb554c9ff024fa34dfdg if (ehp->ether_tpid == htons(ETHERTYPE_VLAN))
aa81749390e332985277568edab1ee6132326b42gs tci = ntohs(ehp->ether_tci);
aa81749390e332985277568edab1ee6132326b42gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * We've reserved a place :-)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * These ASSERTions check that our invariants still hold:
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * there must still be at least one free place
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * there must be at least one place NOT free (ours!)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ASSERT(rgep->tx_free < RGE_SEND_SLOTS);
aa81749390e332985277568edab1ee6132326b42gs rge_send_copy(rgep, mp, tci);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Trigger chip h/w transmit ...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_enter(rgep->tx_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (--rgep->tx_flow == 0) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rgep->tc_tail = rgep->tx_next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China rgep->stats.opackets++;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mutex_exit(rgep->tx_lock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (B_TRUE);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsuint_t
aa81749390e332985277568edab1ee6132326b42gsrge_reschedule(caddr_t arg1, caddr_t arg2)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_t *rgep;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
aa81749390e332985277568edab1ee6132326b42gs rgep = (rge_t *)arg1;
aa81749390e332985277568edab1ee6132326b42gs _NOTE(ARGUNUSED(arg2))
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
aa81749390e332985277568edab1ee6132326b42gs rge_send_recycle(rgep);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China if (rgep->chipid.is_pcie && rgep->tx_free != RGE_SEND_SLOTS) {
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China /*
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China * It's observed that in current Realtek PCI-E chips, tx
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China * request of the second fragment for upper layer packets
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China * will be ignored if the hardware transmission is in
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China * progress and will not be processed when the tx engine
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China * is idle. So one solution is to re-issue the requests
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China * if there are untransmitted packets after tx interrupts
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China * occur.
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China */
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China rge_tx_trigger(rgep);
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China }
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China
aa81749390e332985277568edab1ee6132326b42gs return (DDI_INTR_CLAIMED);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs/*
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_m_tx() - send a chain of packets
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsmblk_t *
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsrge_m_tx(void *arg, mblk_t *mp)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs{
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_t *rgep = arg; /* private device info */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mblk_t *next;
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China mblk_t *mp_org = mp;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs ASSERT(mp != NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
343c26163d86b7f3b861ae03b20226fecee1ab99mx rw_enter(rgep->errlock, RW_READER);
343c26163d86b7f3b861ae03b20226fecee1ab99mx if ((rgep->rge_mac_state != RGE_MAC_STARTED) ||
7b114c4b72aa312e481641f6d76a0f0194877786Winson Wang - Sun Microsystems - Beijing China (rgep->rge_chip_state != RGE_CHIP_RUNNING) ||
7b114c4b72aa312e481641f6d76a0f0194877786Winson Wang - Sun Microsystems - Beijing China (rgep->param_link_up != LINK_STATE_UP)) {
343c26163d86b7f3b861ae03b20226fecee1ab99mx rw_exit(rgep->errlock);
7b114c4b72aa312e481641f6d76a0f0194877786Winson Wang - Sun Microsystems - Beijing China RGE_DEBUG(("rge_m_tx: tx doesn't work"));
7b114c4b72aa312e481641f6d76a0f0194877786Winson Wang - Sun Microsystems - Beijing China freemsgchain(mp);
7b114c4b72aa312e481641f6d76a0f0194877786Winson Wang - Sun Microsystems - Beijing China return (NULL);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs while (mp != NULL) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs next = mp->b_next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mp->b_next = NULL;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (!rge_send(rgep, mp)) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mp->b_next = next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs break;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs mp = next;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs }
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China if (mp != mp_org) {
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China rge_tx_trigger(rgep);
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China }
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rw_exit(rgep->errlock);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (mp);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs}