c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * CDDL HEADER START
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 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * See the License for the specific language governing permissions
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * and limitations under the License.
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 * CDDL HEADER END
7b114c4b72aa312e481641f6d76a0f0194877786Winson Wang - Sun Microsystems - Beijing China * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Use is subject to license terms.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ========== RX side routines ==========
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define RGE_DBG RGE_DBG_RECV /* debug flag for this code */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic uint32_t rge_atomic_reserve(uint32_t *count_p, uint32_t n);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_atomic_reserve)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /* ATOMICALLY */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0); /* no resources left */
75d94465dbafa487b716482dc36d5150a4ec9853Josef 'Jeff' Sipek } while (atomic_cas_32(count_p, oldval, newval) != oldval);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Atomically increment a counter
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void rge_atomic_renounce(uint32_t *count_p, uint32_t n);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_atomic_renounce)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs /* ATOMICALLY */
75d94465dbafa487b716482dc36d5150a4ec9853Josef 'Jeff' Sipek } while (atomic_cas_32(count_p, oldval, newval) != oldval);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Callback code invoked from STREAMs when the recv data buffer is free
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * for recycling.
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 * Recycle the data buffer again
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * and fill them in free ring
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_rx_refill)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (1);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * This situation shouldn't happen
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rge_problem(rgep, "rge_rx_refill: free buffer %d is NULL",
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (0);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic mblk_t *rge_receive_packet(rge_t *rgep, uint32_t slot);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_receive_packet)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Read receive status
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs rx_status = RGE_BSWAP_32(hw_rbd_p->flags_len) & RBD_FLAGS_MASK;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Handle error packet
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_DEBUG(("rge_receive_packet: not a complete packat"));
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Set chip_error flag to reset chip:
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * (suggested in Realtek programming guide.)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_DEBUG(("rge_receive_packet: error packet, status = %x",
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Handle size error packet
aa81749390e332985277568edab1ee6132326b42gs packet_len = RGE_BSWAP_32(hw_rbd_p->flags_len) & RBD_LEN_MASK;
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs RGE_DEBUG(("rge_receive_packet: len err = %d", packet_len));
aa81749390e332985277568edab1ee6132326b42gs if (rgep->rx_bcopy || packet_len <= RGE_RECV_COPY_SIZE ||
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Allocate buffer to receive this good packet
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Copy the data found into the new cluster
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Refill the current receive bd buffer
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * if fails, will just keep the mp.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * VLAN packet ?
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 * Check h/w checksum offload status
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if ((proto == RBD_FLAG_TCP && !(rx_status & RBD_TCP_CKSUM_ERR)) ||
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs (proto == RBD_FLAG_UDP && !(rx_status & RBD_UDP_CKSUM_ERR)))
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (proto != RBD_FLAG_NONE_IP && !(rx_status & RBD_IP_CKSUM_ERR))
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (pflags != 0) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (mp);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Accept the packets received in rx ring.
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#pragma inline(rge_receive_ring)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Sync (all) the receive ring descriptors
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * before accepting the packets they describe
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs while (!(hw_rbd_p->flags_len & RGE_BSWAP_32(BD_FLAG_HW_OWN))) {
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Clear RBD flags
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Receive all ready packets.
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#define RGE_DBG RGE_DBG_SEND /* debug flag for this code */
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * ========== Send-side recycle routines ==========
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_send_claim)
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 * 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#pragma inline(rge_send_recycle)
aa81749390e332985277568edab1ee6132326b42gs * Recyled nothing: bump the watchdog counter,
aa81749390e332985277568edab1ee6132326b42gs * thus guaranteeing that it's nonzero
aa81749390e332985277568edab1ee6132326b42gs * (watchdog activated).
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs } while (hw_sbd_p->flags_len & RGE_BSWAP_32(BD_FLAG_HW_OWN));
aa81749390e332985277568edab1ee6132326b42gs * Recyled something :-)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Send a message by copying it into a preallocated (and premapped) buffer
aa81749390e332985277568edab1ee6132326b42gsstatic void rge_send_copy(rge_t *rgep, mblk_t *mp, uint16_t tci);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs#pragma inline(rge_send_copy)
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gsstatic void
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 * 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 * This is the point of no return!
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 * 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.
aa81749390e332985277568edab1ee6132326b42gs if (tci != 0) {
aa81749390e332985277568edab1ee6132326b42gs * Do not copy the vlan tag
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * We'e reached the end of the chain; and we should have
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * collected no more than ETHERMAX bytes into our buffer.
aa81749390e332985277568edab1ee6132326b42gs * Update the hardware send buffer descriptor flags
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs hw_sbd_p->flags_len = RGE_BSWAP_32(totlen & SBD_LEN_MASK);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs if (tci != 0) {
aa81749390e332985277568edab1ee6132326b42gs * h/w checksum offload flags
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &pflags);
aa81749390e332985277568edab1ee6132326b42gs sizeof (struct ip));
aa81749390e332985277568edab1ee6132326b42gs * Is the packet an IP(v4) packet?
aa81749390e332985277568edab1ee6132326b42gs sizeof (struct ether_header));
aa81749390e332985277568edab1ee6132326b42gs * We're done.
aa81749390e332985277568edab1ee6132326b42gs * The message can be freed right away, as we've already
aa81749390e332985277568edab1ee6132326b42gs * copied the contents ...
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * Try to reserve a place in the transmit ring.
aa81749390e332985277568edab1ee6132326b42gs * Determine if the packet is VLAN tagged.
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 * Trigger chip h/w transmit ...
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China rgep->stats.opackets++;
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China if (rgep->chipid.is_pcie && rgep->tx_free != RGE_SEND_SLOTS) {
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 rge_tx_trigger(rgep);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs * rge_m_tx() - send a chain of packets
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China mblk_t *mp_org = mp;
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)) {
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);
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China if (mp != mp_org) {
3a84c50f71e0942a55e90913f6b44878d5062621Winson Wang - Sun Microsystems - Beijing China rge_tx_trigger(rgep);
c7fd2ed091e4e4beb47e1da3a6197a2c38f29c02gs return (mp);