f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * sfe_util.c: general ethernet mac driver framework version 2.6
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * Copyright (c) 2002-2008 Masayuki Murayama. All rights reserved.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Redistribution and use in source and binary forms, with or without
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * modification, are permitted provided that the following conditions are met:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * 1. Redistributions of source code must retain the above copyright notice,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * this list of conditions and the following disclaimer.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * 2. Redistributions in binary form must reproduce the above copyright notice,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * this list of conditions and the following disclaimer in the documentation
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * and/or other materials provided with the distribution.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * 3. Neither the name of the author nor the names of its contributors may be
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * used to endorse or promote products derived from this software without
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * specific prior written permission.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * DAMAGE.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Use is subject to license terms.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * System Header files.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/types.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/conf.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/debug.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/kmem.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/vtrace.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/ethernet.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/modctl.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/errno.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/ddi.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/sunddi.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/stream.h> /* required for MBLK* */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/strsun.h> /* required for mionack() */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/byteorder.h>
5c5f137104b2d56181283389fa902220f2023809Richard Lowe#include <sys/sysmacros.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/pci.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <inet/common.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <inet/led.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <inet/mi.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <inet/nd.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/crc32.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include <sys/note.h>
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include "sfe_mii.h"
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#include "sfe_util.h"
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffextern char ident[];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* Debugging support */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_debug = GEM_DEBUG_LEVEL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define DPRINTF(n, args) if (gem_debug > (n)) cmn_err args
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#else
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define DPRINTF(n, args)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#undef ASSERT
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define ASSERT(x)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define IOC_LINESIZE 0x40 /* Is it right for amd64? */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Useful macros and typedefs
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define ROUNDUP(x, a) (((x) + (a) - 1) & ~((a) - 1))
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define GET_NET16(p) ((((uint8_t *)(p))[0] << 8)| ((uint8_t *)(p))[1])
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define GET_ETHERTYPE(p) GET_NET16(((uint8_t *)(p)) + ETHERADDRL*2)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define GET_IPTYPEv4(p) (((uint8_t *)(p))[sizeof (struct ether_header) + 9])
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define GET_IPTYPEv6(p) (((uint8_t *)(p))[sizeof (struct ether_header) + 6])
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifndef INT32_MAX
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define INT32_MAX 0x7fffffff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define VTAG_OFF (ETHERADDRL*2)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifndef VTAG_SIZE
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define VTAG_SIZE 4
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifndef VTAG_TPID
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define VTAG_TPID 0x8100U
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define GET_TXBUF(dp, sn) \
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &(dp)->tx_buf[SLOT((dp)->tx_slots_base + (sn), (dp)->gc.gc_tx_buf_size)]
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define TXFLAG_VTAG(flag) \
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (((flag) & GEM_TXFLAG_VTAG) >> GEM_TXFLAG_VTAG_SHIFT)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define MAXPKTBUF(dp) \
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ((dp)->mtu + sizeof (struct ether_header) + VTAG_SIZE + ETHERFCSL)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define WATCH_INTERVAL_FAST drv_usectohz(100*1000) /* 100mS */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#define BOOLEAN(x) ((x) != 0)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Macros to distinct chip generation.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Private functions
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_mii_start(struct gem_dev *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_mii_stop(struct gem_dev *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* local buffer management */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_nd_setup(struct gem_dev *dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_nd_cleanup(struct gem_dev *dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_alloc_memory(struct gem_dev *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_free_memory(struct gem_dev *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_init_rx_ring(struct gem_dev *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_init_tx_ring(struct gem_dev *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff__INLINE__ static void gem_append_rxbuf(struct gem_dev *, struct rxbuf *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_tx_timeout(struct gem_dev *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_mii_link_watcher(struct gem_dev *dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_mac_init(struct gem_dev *dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_mac_start(struct gem_dev *dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_mac_stop(struct gem_dev *dp, uint_t flags);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_mac_ioctl(struct gem_dev *dp, queue_t *wq, mblk_t *mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic struct ether_addr gem_etherbroadcastaddr = {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff};
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint gem_speed_value[] = {10, 100, 1000};
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Misc runtime routines
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Ether CRC calculation according to 21143 data sheet
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffuint32_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_ether_crc_le(const uint8_t *addr, int len)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint32_t crc;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff CRC32(crc, addr, ETHERADDRL, 0xffffffffU, crc32_table);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (crc);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffuint32_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_ether_crc_be(const uint8_t *addr, int len)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int idx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int bit;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t data;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint32_t crc;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define CRC32_POLY_BE 0x04c11db7
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff crc = 0xffffffff;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (idx = 0; idx < len; idx++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff crc = (crc << 1)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ^ ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (crc);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#undef CRC32_POLY_BE
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_prop_get_int(struct gem_dev *dp, char *prop_template, int def_val)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff char propname[32];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) sprintf(propname, prop_template, dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ddi_prop_get_int(DDI_DEV_T_ANY, dp->dip,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_PROP_DONTPASS, propname, def_val));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_population(uint32_t x)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int cnt;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cnt = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < 32; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (x & (1 << i)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cnt++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (cnt);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#ifdef GEM_DEBUG_LEVEL
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#ifdef GEM_DEBUG_VLAN
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
23d366e350386ec109bfa9b2cf91225729a1a26bduboffgem_dump_packet(struct gem_dev *dp, char *title, mblk_t *mp,
23d366e350386ec109bfa9b2cf91225729a1a26bduboff boolean_t check_cksum)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
23d366e350386ec109bfa9b2cf91225729a1a26bduboff char msg[180];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint8_t buf[18+20+20];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint8_t *p;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff size_t offset;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint_t ethertype;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint_t proto;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint_t ipproto = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint_t iplen;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint_t iphlen;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint_t tcplen;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint_t udplen;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint_t cksum;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff int rest;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff int len;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff char *bp;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff mblk_t *tp;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff extern uint_t ip_cksum(mblk_t *, int, uint32_t);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff msg[0] = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = msg;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff rest = sizeof (buf);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff offset = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff for (tp = mp; tp; tp = tp->b_cont) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff len = tp->b_wptr - tp->b_rptr;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff len = min(rest, len);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bcopy(tp->b_rptr, &buf[offset], len);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff rest -= len;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff offset += len;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (rest == 0) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff break;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff offset = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff p = &buf[offset];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* ethernet address */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp,
23d366e350386ec109bfa9b2cf91225729a1a26bduboff "ether: %02x:%02x:%02x:%02x:%02x:%02x"
23d366e350386ec109bfa9b2cf91225729a1a26bduboff " -> %02x:%02x:%02x:%02x:%02x:%02x",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff p[6], p[7], p[8], p[9], p[10], p[11],
23d366e350386ec109bfa9b2cf91225729a1a26bduboff p[0], p[1], p[2], p[3], p[4], p[5]);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = &msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* vlag tag and etherrtype */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff ethertype = GET_ETHERTYPE(p);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (ethertype == VTAG_TPID) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, " vtag:0x%04x", GET_NET16(&p[14]));
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = &msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff offset += VTAG_SIZE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff p = &buf[offset];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff ethertype = GET_ETHERTYPE(p);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, " type:%04x", ethertype);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = &msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* ethernet packet length */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, " mblklen:%d", msgdsize(mp));
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = &msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (mp->b_cont) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, "(");
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = &msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff for (tp = mp; tp; tp = tp->b_cont) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (tp == mp) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, "%d", tp->b_wptr - tp->b_rptr);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff } else {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, "+%d", tp->b_wptr - tp->b_rptr);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = &msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, ")");
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = &msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (ethertype != ETHERTYPE_IP) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff goto x;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* ip address */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff offset += sizeof (struct ether_header);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff p = &buf[offset];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff ipproto = p[9];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff iplen = GET_NET16(&p[2]);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, ", ip: %d.%d.%d.%d -> %d.%d.%d.%d proto:%d iplen:%d",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff p[12], p[13], p[14], p[15],
23d366e350386ec109bfa9b2cf91225729a1a26bduboff p[16], p[17], p[18], p[19],
23d366e350386ec109bfa9b2cf91225729a1a26bduboff ipproto, iplen);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = (void *)&msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff iphlen = (p[0] & 0xf) * 4;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* cksum for psuedo header */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cksum = *(uint16_t *)&p[12];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cksum += *(uint16_t *)&p[14];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cksum += *(uint16_t *)&p[16];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cksum += *(uint16_t *)&p[18];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cksum += BE_16(ipproto);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* tcp or udp protocol header */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff offset += iphlen;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff p = &buf[offset];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (ipproto == IPPROTO_TCP) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tcplen = iplen - iphlen;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, ", tcp: len:%d cksum:%x",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tcplen, GET_NET16(&p[16]));
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = (void *)&msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (check_cksum) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cksum += BE_16(tcplen);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cksum = (uint16_t)ip_cksum(mp, offset, cksum);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, " (%s)",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = (void *)&msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff } else if (ipproto == IPPROTO_UDP) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff udplen = GET_NET16(&p[4]);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, ", udp: len:%d cksum:%x",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff udplen, GET_NET16(&p[6]));
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = (void *)&msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (GET_NET16(&p[6]) && check_cksum) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cksum += *(uint16_t *)&p[4];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cksum = (uint16_t)ip_cksum(mp, offset, cksum);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff sprintf(bp, " (%s)",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = (void *)&msg[strlen(msg)];
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboffx:
23d366e350386ec109bfa9b2cf91225729a1a26bduboff cmn_err(CE_CONT, "!%s: %s: %s", dp->name, title, msg);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#endif /* GEM_DEBUG_VLAN */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#endif /* GEM_DEBUG_LEVEL */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * IO cache flush
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff__INLINE__ void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_rx_desc_dma_sync(struct gem_dev *dp, int head, int nslot, int how)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int n;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int m;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int rx_desc_unit_shift = dp->gc.gc_rx_desc_unit_shift;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* sync active descriptors */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (rx_desc_unit_shift < 0 || nslot == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* no rx descriptor ring */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff n = dp->gc.gc_rx_ring_size - head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((m = nslot - n) > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_sync(dp->desc_dma_handle,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (off_t)0,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (size_t)(m << rx_desc_unit_shift),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff how);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff nslot = n;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_sync(dp->desc_dma_handle,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (off_t)(head << rx_desc_unit_shift),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (size_t)(nslot << rx_desc_unit_shift),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff how);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff__INLINE__ void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_tx_desc_dma_sync(struct gem_dev *dp, int head, int nslot, int how)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int n;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int m;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int tx_desc_unit_shift = dp->gc.gc_tx_desc_unit_shift;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* sync active descriptors */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (tx_desc_unit_shift < 0 || nslot == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* no tx descriptor ring */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff n = dp->gc.gc_tx_ring_size - head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((m = nslot - n) > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_sync(dp->desc_dma_handle,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (off_t)(dp->tx_ring_dma - dp->rx_ring_dma),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (size_t)(m << tx_desc_unit_shift),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff how);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff nslot = n;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_sync(dp->desc_dma_handle,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (off_t)((head << tx_desc_unit_shift)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff + (dp->tx_ring_dma - dp->rx_ring_dma)),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (size_t)(nslot << tx_desc_unit_shift),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff how);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_rx_start_default(struct gem_dev *dp, int head, int nslot)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_rx_desc_dma_sync(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(head, dp->gc.gc_rx_ring_size), nslot,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_SYNC_FORDEV);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Buffer management
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_dump_txbuf(struct gem_dev *dp, int level, const char *title)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(level,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: tx_active: %d[%d] %d[%d] (+%d), "
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "tx_softq: %d[%d] %d[%d] (+%d), "
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "tx_free: %d[%d] %d[%d] (+%d), "
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "tx_desc: %d[%d] %d[%d] (+%d), "
23d366e350386ec109bfa9b2cf91225729a1a26bduboff "intr: %d[%d] (+%d), ",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, title,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_active_head, dp->gc.gc_tx_buf_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_tail,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_active_tail, dp->gc.gc_tx_buf_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_tail - dp->tx_active_head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_softq_head, dp->gc.gc_tx_buf_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_tail,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_softq_tail, dp->gc.gc_tx_buf_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_tail - dp->tx_softq_head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_free_head, dp->gc.gc_tx_buf_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_tail,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_free_tail, dp->gc.gc_tx_buf_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_tail - dp->tx_free_head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_desc_head, dp->gc.gc_tx_ring_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_tail,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_desc_tail, dp->gc.gc_tx_ring_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_tail - dp->tx_desc_head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_intr,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_desc_intr, dp->gc.gc_tx_ring_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_intr - dp->tx_desc_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_free_rxbuf(struct rxbuf *rbp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp = rbp->rxb_devp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp->rxb_next = dp->rx_buf_freelist;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_freelist = rbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_freecnt++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * gem_get_rxbuf: supply a receive buffer which have been mapped into
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * DMA space.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstruct rxbuf *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_get_rxbuf(struct gem_dev *dp, int cansleep)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct rxbuf *rbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t count = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(3, (CE_CONT, "!gem_get_rxbuf: called freecnt:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_freecnt));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Get rx buffer management structure
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp = dp->rx_buf_freelist;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (rbp) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* get one from the recycle list */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->rx_buf_freecnt > 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_freelist = rbp->rxb_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_freecnt--;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp->rxb_next = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (rbp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Allocate a rx buffer management structure
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp = kmem_zalloc(sizeof (*rbp), cansleep ? KM_SLEEP : KM_NOSLEEP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (rbp == NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* no memory */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Prepare a back pointer to the device structure which will be
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * refered on freeing the buffer later.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp->rxb_devp = dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* allocate a dma handle for rx data buffer */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((err = ddi_dma_alloc_handle(dp->dip,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &dp->gc.gc_dma_attr_rxbuf,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (cansleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff NULL, &rbp->rxb_dh)) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: ddi_dma_alloc_handle:1 failed, err=%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff kmem_free(rbp, sizeof (struct rxbuf));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* allocate a bounce buffer for rx */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((err = ddi_dma_mem_alloc(rbp->rxb_dh,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ROUNDUP(dp->rx_buf_len, IOC_LINESIZE),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &dp->gc.gc_buf_attr,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * if the nic requires a header at the top of receive buffers,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * it may access the rx buffer randomly.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->gc.gc_rx_header_len > 0)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ? DDI_DMA_CONSISTENT : DDI_DMA_STREAMING,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cansleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &rbp->rxb_buf, &rbp->rxb_buf_len,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &rbp->rxb_bah)) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: ddi_dma_mem_alloc: failed, err=%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&rbp->rxb_dh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff kmem_free(rbp, sizeof (struct rxbuf));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Mapin the bounce buffer into the DMA space */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((err = ddi_dma_addr_bind_handle(rbp->rxb_dh,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff NULL, rbp->rxb_buf, dp->rx_buf_len,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ((dp->gc.gc_rx_header_len > 0)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ?(DDI_DMA_RDWR | DDI_DMA_CONSISTENT)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff :(DDI_DMA_READ | DDI_DMA_STREAMING)),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cansleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp->rxb_dmacookie,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &count)) != DDI_DMA_MAPPED) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(err != DDI_DMA_INUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: ddi_dma_addr_bind_handle: failed, err=%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, err));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * we failed to allocate a dma resource
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * for the rx bounce buffer.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_mem_free(&rbp->rxb_bah);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&rbp->rxb_dh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff kmem_free(rbp, sizeof (struct rxbuf));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* correct the rest of the DMA mapping */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 1; i < count; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_nextcookie(rbp->rxb_dh, &rbp->rxb_dmacookie[i]);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp->rxb_nfrags = count;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Now we successfully prepared an rx buffer */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_allocated++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (rbp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * memory resource management
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_alloc_memory(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff caddr_t ring;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff caddr_t buf;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff size_t req_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff size_t ring_len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff size_t buf_len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_cookie_t ring_cookie;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_cookie_t buf_cookie;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t count;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct txbuf *tbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int tx_buf_len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_attr_t dma_attr_txbounce;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->desc_dma_handle = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff req_size = dp->rx_desc_size + dp->tx_desc_size + dp->gc.gc_io_area_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (req_size > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Alloc RX/TX descriptors and a io area.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((err = ddi_dma_alloc_handle(dp->dip,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &dp->gc.gc_dma_attr_desc,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_SLEEP, NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &dp->desc_dma_handle)) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: ddi_dma_alloc_handle failed: %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ENOMEM);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((err = ddi_dma_mem_alloc(dp->desc_dma_handle,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff req_size, &dp->gc.gc_desc_attr,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &ring, &ring_len,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &dp->desc_acc_handle)) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: ddi_dma_mem_alloc failed: "
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "ret %d, request size: %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, err, (int)req_size);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&dp->desc_dma_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ENOMEM);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((err = ddi_dma_addr_bind_handle(dp->desc_dma_handle,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff NULL, ring, ring_len,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_SLEEP, NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &ring_cookie, &count)) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(err != DDI_DMA_INUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: ddi_dma_addr_bind_handle failed: %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_mem_free(&dp->desc_acc_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&dp->desc_dma_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ENOMEM);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(count == 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* set base of rx descriptor ring */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_ring = ring;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_ring_dma = ring_cookie.dmac_laddress;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* set base of tx descriptor ring */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_ring = dp->rx_ring + dp->rx_desc_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_ring_dma = dp->rx_ring_dma + dp->rx_desc_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* set base of io area */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->io_area = dp->tx_ring + dp->tx_desc_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->io_area_dma = dp->tx_ring_dma + dp->tx_desc_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Prepare DMA resources for tx packets
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->gc.gc_tx_buf_size > 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Special dma attribute for tx bounce buffers */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dma_attr_txbounce = dp->gc.gc_dma_attr_txbuf;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dma_attr_txbounce.dma_attr_sgllen = 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dma_attr_txbounce.dma_attr_align =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff max(dma_attr_txbounce.dma_attr_align, IOC_LINESIZE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Size for tx bounce buffers must be max tx packet size. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_buf_len = MAXPKTBUF(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_buf_len = ROUNDUP(tx_buf_len, IOC_LINESIZE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(tx_buf_len >= ETHERMAX+ETHERFCSL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0, tbp = dp->tx_buf;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff i < dp->gc.gc_tx_buf_size; i++, tbp++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* setup bounce buffers for tx packets */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((err = ddi_dma_alloc_handle(dp->dip,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &dma_attr_txbounce,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_SLEEP, NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &tbp->txb_bdh)) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s ddi_dma_alloc_handle for bounce buffer failed:"
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff " err=%d, i=%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, err, i);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_alloc_dh;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((err = ddi_dma_mem_alloc(tbp->txb_bdh,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_buf_len,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &dp->gc.gc_buf_attr,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &buf, &buf_len,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &tbp->txb_bah)) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: ddi_dma_mem_alloc for bounce buffer failed"
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "ret %d, request size %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, err, tx_buf_len);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&tbp->txb_bdh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_alloc_dh;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((err = ddi_dma_addr_bind_handle(tbp->txb_bdh,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff NULL, buf, buf_len,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_WRITE | DDI_DMA_STREAMING,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_SLEEP, NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &buf_cookie, &count)) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(err != DDI_DMA_INUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: ddi_dma_addr_bind_handle for bounce buffer failed: %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_mem_free(&tbp->txb_bah);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&tbp->txb_bdh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_alloc_dh;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(count == 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_buf = buf;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_buf_dma = buf_cookie.dmac_laddress;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr_alloc_dh:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_tx_buf_size > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (i-- > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_unbind_handle(dp->tx_buf[i].txb_bdh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_mem_free(&dp->tx_buf[i].txb_bah);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&dp->tx_buf[i].txb_bdh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->desc_dma_handle) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_unbind_handle(dp->desc_dma_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_mem_free(&dp->desc_acc_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&dp->desc_dma_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->desc_dma_handle = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ENOMEM);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_free_memory(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct rxbuf *rbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct txbuf *tbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Free TX/RX descriptors and tx padding buffer */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->desc_dma_handle) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_unbind_handle(dp->desc_dma_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_mem_free(&dp->desc_acc_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&dp->desc_dma_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->desc_dma_handle = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Free dma handles for Tx */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = dp->gc.gc_tx_buf_size, tbp = dp->tx_buf; i--; tbp++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Free bounce buffer associated to each txbuf */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_unbind_handle(tbp->txb_bdh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_mem_free(&tbp->txb_bah);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&tbp->txb_bdh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Free rx buffer */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while ((rbp = dp->rx_buf_freelist) != NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->rx_buf_freecnt > 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_freelist = rbp->rxb_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_freecnt--;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* release DMA mapping */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(rbp->rxb_dh != NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* free dma handles for rx bbuf */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* it has dma mapping always */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(rbp->rxb_nfrags > 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_unbind_handle(rbp->rxb_dh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* free the associated bounce buffer and dma handle */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(rbp->rxb_bah != NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_mem_free(&rbp->rxb_bah);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* free the associated dma handle */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_free_handle(&rbp->rxb_dh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* free the base memory of rx buffer management */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff kmem_free(rbp, sizeof (struct rxbuf));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Rx/Tx descriptor slot management
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Initialize an empty rx ring.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_init_rx_ring(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int rx_ring_size = dp->gc.gc_rx_ring_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s ring_size:%d, buf_max:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rx_ring_size, dp->gc.gc_rx_buf_max));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* make a physical chain of rx descriptors */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < rx_ring_size; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_rx_desc_init)(dp, i);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_rx_desc_dma_sync(dp, 0, rx_ring_size, DDI_DMA_SYNC_FORDEV);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_active_head = (seqnum_t)0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_active_tail = (seqnum_t)0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->rx_buf_head == (struct rxbuf *)NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->rx_buf_tail == (struct rxbuf *)NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Prepare rx buffers and put them into the rx buffer/descriptor ring.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_prepare_rx_buf(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int nrbuf;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct rxbuf *rbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Now we have no active buffers in rx ring */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff nrbuf = min(dp->gc.gc_rx_ring_size, dp->gc.gc_rx_buf_max);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < nrbuf; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((rbp = gem_get_rxbuf(dp, B_TRUE)) == NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_append_rxbuf(dp, rbp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_rx_desc_dma_sync(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff 0, dp->gc.gc_rx_ring_size, DDI_DMA_SYNC_FORDEV);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Reclaim active rx buffers in rx buffer ring.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_clean_rx_buf(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct rxbuf *rbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int rx_ring_size = dp->gc.gc_rx_ring_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int total;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT, "!%s: %s: %d buffers are free",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, dp->rx_buf_freecnt));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * clean up HW descriptors
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < rx_ring_size; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_rx_desc_clean)(dp, i);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_rx_desc_dma_sync(dp, 0, rx_ring_size, DDI_DMA_SYNC_FORDEV);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff total = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Reclaim allocated rx buffers
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while ((rbp = dp->rx_buf_head) != NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff total++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* remove the first one from rx buffer list */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_head = rbp->rxb_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* recycle the rxbuf */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_free_rxbuf(rbp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_tail = (struct rxbuf *)NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: %d buffers freeed, total: %d free",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, total, dp->rx_buf_freecnt));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Initialize an empty transmit buffer/descriptor ring
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_init_tx_ring(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int tx_buf_size = dp->gc.gc_tx_buf_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int tx_ring_size = dp->gc.gc_tx_ring_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT, "!%s: %s: ring_size:%d, buf_size:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_tx_ring_size, dp->gc.gc_tx_buf_size));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(!dp->mac_active);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* initialize active list and free list */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_slots_base =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_slots_base + dp->tx_softq_head, tx_buf_size);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_tail -= dp->tx_softq_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_head = (seqnum_t)0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_head = dp->tx_softq_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_tail = dp->tx_softq_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_head = dp->tx_softq_tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_tail = dp->gc.gc_tx_buf_limit;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_head = (seqnum_t)0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_tail = (seqnum_t)0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_intr = (seqnum_t)0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < tx_ring_size; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_tx_desc_init)(dp, i);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_tx_desc_dma_sync(dp, 0, tx_ring_size, DDI_DMA_SYNC_FORDEV);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff__INLINE__
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_txbuf_free_dma_resources(struct txbuf *tbp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (tbp->txb_mp) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff freemsg(tbp->txb_mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_mp = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_nfrags = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tbp->txb_flag = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#pragma inline(gem_txbuf_free_dma_resources)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * reclaim active tx buffers and reset positions in tx rings.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_clean_tx_buf(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t sn;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct txbuf *tbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int tx_ring_size = dp->gc.gc_tx_ring_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(!dp->mac_active);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_busy == 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_softq_tail == dp->tx_free_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * clean up all HW descriptors
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < tx_ring_size; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_tx_desc_clean)(dp, i);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_tx_desc_dma_sync(dp, 0, tx_ring_size, DDI_DMA_SYNC_FORDEV);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* dequeue all active and loaded buffers */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff head = dp->tx_active_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tail = dp->tx_softq_tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_free_head - head >= 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = GET_TXBUF(dp, head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (sn = head; sn != tail; sn++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_txbuf_free_dma_resources(tbp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(tbp->txb_mp == NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.errxmt++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = tbp->txb_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* ensure no dma resources for tx are not in use now */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (sn != head + dp->gc.gc_tx_buf_size) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (tbp->txb_mp || tbp->txb_nfrags) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "%s: %s: sn:%d[%d] mp:%p nfrags:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff sn, SLOT(sn, dp->gc.gc_tx_buf_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_mp, tbp->txb_nfrags));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff sn++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = tbp->txb_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (err) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_dump_txbuf(dp, CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "gem_clean_tx_buf: tbp->txb_mp != NULL");
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* recycle buffers, now no active tx buffers in the ring */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_tail += tail - head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_free_tail == dp->tx_free_head + dp->gc.gc_tx_buf_limit);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* fix positions in tx buffer rings */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_head = dp->tx_free_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_tail = dp->tx_free_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_head = dp->tx_free_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_tail = dp->tx_free_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Reclaim transmitted buffers from tx buffer/descriptor ring.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff__INLINE__ int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_reclaim_txbuf(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct txbuf *tbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t txstat;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err = GEM_SUCCESS;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t sn;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t desc_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int tx_ring_size = dp->gc.gc_tx_ring_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t (*tx_desc_stat)(struct gem_dev *dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int slot, int ndesc) = dp->gc.gc_tx_desc_stat;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff clock_t now;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff now = ddi_get_lbolt();
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (now == (clock_t)0) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* make non-zero timestamp */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff now--;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff head = dp->tx_active_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tail = dp->tx_active_tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#if GEM_DEBUG_LEVEL > 2
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (head != tail) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: %s: "
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "testing active_head:%d[%d], active_tail:%d[%d]",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff head, SLOT(head, dp->gc.gc_tx_buf_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tail, SLOT(tail, dp->gc.gc_tx_buf_size));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef DEBUG
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->tx_reclaim_busy == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* check tx buffer management consistency */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_free_tail - dp->tx_active_head
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff == dp->gc.gc_tx_buf_limit);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* EMPTY */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_reclaim_busy++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* sync all active HW descriptors */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_tx_desc_dma_sync(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(dp->tx_desc_head, tx_ring_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_tail - dp->tx_desc_head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_SYNC_FORKERNEL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = GET_TXBUF(dp, head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff desc_head = dp->tx_desc_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (sn = head; sn != tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_head = (++sn), tbp = tbp->txb_next) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int ndescs;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(tbp->txb_desc == desc_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ndescs = tbp->txb_ndescs;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (ndescs == 0) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* skip errored descriptors */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff continue;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff txstat = (*tx_desc_stat)(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(tbp->txb_desc, tx_ring_size), ndescs);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (txstat == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* not transmitted yet */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (!dp->tx_blocked && (tbp->txb_flag & GEM_TXFLAG_INTR)) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_blocked = now;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(txstat & (GEM_TX_DONE | GEM_TX_ERR));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (txstat & GEM_TX_ERR) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = GEM_FAILURE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "!%s: tx error at desc %d[%d]",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, sn, SLOT(sn, tx_ring_size));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#if GEM_DEBUG_LEVEL > 4
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (now - tbp->txb_stime >= 50) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "!%s: tx delay while %d mS",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, (now - tbp->txb_stime)*10);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* free transmitted descriptors */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff desc_head += ndescs;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->tx_desc_head != desc_head) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* we have reclaimed one or more tx buffers */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_head = desc_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* If we passed the next interrupt position, update it */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (desc_head - dp->tx_desc_intr > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_intr = desc_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* free dma mapping resources associated with transmitted tx buffers */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = GET_TXBUF(dp, head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tail = sn;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#if GEM_DEBUG_LEVEL > 2
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (head != tail) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "%s: freeing head:%d[%d], tail:%d[%d]",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff head, SLOT(head, dp->gc.gc_tx_buf_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tail, SLOT(tail, dp->gc.gc_tx_buf_size));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (sn = head; sn != tail; sn++, tbp = tbp->txb_next) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_txbuf_free_dma_resources(tbp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* recycle the tx buffers */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (--dp->tx_reclaim_busy == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* we are the last thread who can update free tail */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#if GEM_DEBUG_LEVEL > 4
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* check all resouces have been deallocated */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff sn = dp->tx_free_tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = GET_TXBUF(dp, new_tail);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (sn != dp->tx_active_head + dp->gc.gc_tx_buf_limit) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (tbp->txb_nfrags) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* in use */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(tbp->txb_mp == NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = tbp->txb_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff sn++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_active_head + dp->gc.gc_tx_buf_limit == sn);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_tail =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_head + dp->gc.gc_tx_buf_limit;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mac_active) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* someone may be waiting for me. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cv_broadcast(&dp->tx_drain_cv);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#if GEM_DEBUG_LEVEL > 2
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: %s: called, "
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "free_head:%d free_tail:%d(+%d) added:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_head, dp->tx_free_tail,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_tail - dp->tx_free_head, tail - head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#pragma inline(gem_reclaim_txbuf)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Make tx descriptors in out-of-order manner
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_tx_load_descs_oo(struct gem_dev *dp,
23d366e350386ec109bfa9b2cf91225729a1a26bduboff seqnum_t start_slot, seqnum_t end_slot, uint64_t flags)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t sn;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct txbuf *tbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int tx_ring_size = dp->gc.gc_tx_ring_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int (*tx_desc_write)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (struct gem_dev *dp, int slot,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_dma_cookie_t *dmacookie,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int frags, uint64_t flag) = dp->gc.gc_tx_desc_write;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff clock_t now = ddi_get_lbolt();
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff sn = start_slot;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = GET_TXBUF(dp, sn);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff do {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#if GEM_DEBUG_LEVEL > 1
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->tx_cnt < 100) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_cnt++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff flags |= GEM_TXFLAG_INTR;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* write a tx descriptor */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_desc = sn;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_ndescs = (*tx_desc_write)(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(sn, tx_ring_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_nfrags, flags | tbp->txb_flag);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_stime = now;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(tbp->txb_ndescs == 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff flags = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff sn++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = tbp->txb_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } while (sn != end_slot);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff__INLINE__
23d366e350386ec109bfa9b2cf91225729a1a26bduboffstatic size_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_setup_txbuf_copy(struct gem_dev *dp, mblk_t *mp, struct txbuf *tbp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff size_t min_pkt;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff caddr_t bp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff size_t off;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mblk_t *tp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff size_t len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint64_t flag;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(tbp->txb_mp == NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* we use bounce buffer for the packet */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff min_pkt = ETHERMIN;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff bp = tbp->txb_buf;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff off = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tp = mp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff flag = tbp->txb_flag;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (flag & GEM_TXFLAG_SWVTAG) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* need to increase min packet size */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff min_pkt += VTAG_SIZE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT((flag & GEM_TXFLAG_VTAG) == 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* copy the rest */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (; tp; tp = tp->b_cont) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((len = (long)tp->b_wptr - (long)tp->b_rptr) > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff bcopy(tp->b_rptr, &bp[off], len);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff off += len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (off < min_pkt &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (min_pkt > ETHERMIN || !dp->gc.gc_tx_auto_pad)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * Extend the packet to minimum packet size explicitly.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * For software vlan packets, we shouldn't use tx autopad
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * function because nics may not be aware of vlan.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * we must keep 46 octet of payload even if we use vlan.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff bzero(&bp[off], min_pkt - off);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff off = min_pkt;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_sync(tbp->txb_bdh, (off_t)0, off, DDI_DMA_SYNC_FORDEV);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[0].dmac_laddress = tbp->txb_buf_dma;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[0].dmac_size = off;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: copy: addr:0x%llx len:0x%x, vtag:0x%04x, min_pkt:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[0].dmac_laddress,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[0].dmac_size,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (flag & GEM_TXFLAG_VTAG) >> GEM_TXFLAG_VTAG_SHIFT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff min_pkt));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* save misc info */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_mp = mp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_nfrags = 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef DEBUG_MULTIFRAGS
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_tx_max_frags >= 3 &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[0].dmac_size > 16*3) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[1].dmac_laddress =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[0].dmac_laddress + 16;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[2].dmac_laddress =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[1].dmac_laddress + 16;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[2].dmac_size =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[0].dmac_size - 16*2;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[1].dmac_size = 16;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_dmacookie[0].dmac_size = 16;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp->txb_nfrags = 3;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
23d366e350386ec109bfa9b2cf91225729a1a26bduboff return (off);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#pragma inline(gem_setup_txbuf_copy)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff__INLINE__
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_tx_start_unit(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct txbuf *tbp_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct txbuf *tbp_tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* update HW descriptors from soft queue */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->xmitlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_softq_head == dp->tx_active_tail);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff head = dp->tx_softq_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tail = dp->tx_softq_tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "%s: %s: called, softq %d %d[+%d], desc %d %d[+%d]",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, head, tail, tail - head,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_head, dp->tx_desc_tail,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_tail - dp->tx_desc_head));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(tail - head > 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_tail = tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp_head = GET_TXBUF(dp, head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp_tail = GET_TXBUF(dp, tail - 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(tbp_tail->txb_desc + tbp_tail->txb_ndescs == dp->tx_desc_tail);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_tx_start(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(tbp_head->txb_desc, dp->gc.gc_tx_ring_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp_tail->txb_desc + tbp_tail->txb_ndescs - tbp_head->txb_desc);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* advance softq head and active tail */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_head = dp->tx_active_tail = tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#pragma inline(gem_tx_start_unit)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_send_cnt[10];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#define PKT_MIN_SIZE (sizeof (struct ether_header) + 10 + VTAG_SIZE)
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#define EHLEN (sizeof (struct ether_header))
23d366e350386ec109bfa9b2cf91225729a1a26bduboff/*
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * check ether packet type and ip protocol
23d366e350386ec109bfa9b2cf91225729a1a26bduboff */
23d366e350386ec109bfa9b2cf91225729a1a26bduboffstatic uint64_t
23d366e350386ec109bfa9b2cf91225729a1a26bduboffgem_txbuf_options(struct gem_dev *dp, mblk_t *mp, uint8_t *bp)
23d366e350386ec109bfa9b2cf91225729a1a26bduboff{
23d366e350386ec109bfa9b2cf91225729a1a26bduboff mblk_t *tp;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff ssize_t len;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint_t vtag;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff int off;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint64_t flag;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff flag = 0ULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /*
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * prepare continuous header of the packet for protocol analysis
23d366e350386ec109bfa9b2cf91225729a1a26bduboff */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if ((long)mp->b_wptr - (long)mp->b_rptr < PKT_MIN_SIZE) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* we use work buffer to copy mblk */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff for (tp = mp, off = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tp && (off < PKT_MIN_SIZE);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tp = tp->b_cont, off += len) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff len = (long)tp->b_wptr - (long)tp->b_rptr;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff len = min(len, PKT_MIN_SIZE - off);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bcopy(tp->b_rptr, &bp[off], len);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff } else {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* we can use mblk without copy */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = mp->b_rptr;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* process vlan tag for GLD v3 */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (GET_NET16(&bp[VTAG_OFF]) == VTAG_TPID) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->misc_flag & GEM_VLAN_HARD) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff vtag = GET_NET16(&bp[VTAG_OFF + 2]);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff ASSERT(vtag);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff flag |= vtag << GEM_TXFLAG_VTAG_SHIFT;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff } else {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff flag |= GEM_TXFLAG_SWVTAG;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff return (flag);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff}
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#undef EHLEN
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#undef PKT_MIN_SIZE
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * gem_send_common is an exported function because hw depend routines may
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * use it for sending control frames like setup frames for 2114x chipset.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffmblk_t *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_send_common(struct gem_dev *dp, mblk_t *mp_head, uint32_t flags)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int nmblk;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int avail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mblk_t *tp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mblk_t *mp;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct txbuf *tbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint64_t load_flags;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint64_t len_total = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint32_t bcast = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint32_t mcast = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mp_head != NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp = mp_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff nmblk = 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while ((mp = mp->b_next) != NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff nmblk++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_send_cnt[0]++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_send_cnt[min(nmblk, 9)]++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Aquire resources
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp = mp_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (mp) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tp = mp->b_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff freemsg(mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp = tp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mac_active && (flags & GEM_SEND_CTRL) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* don't send data packets while mac isn't active */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* XXX - should we discard packets? */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (mp_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* allocate free slots */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff head = dp->tx_free_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff avail = dp->tx_free_tail - head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: called, free_head:%d free_tail:%d(+%d) req:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_head, dp->tx_free_tail, avail, nmblk));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff avail = min(avail, dp->tx_max_packets);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (nmblk > avail) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (avail == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* no resources; short cut */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT, "!%s: no resources", __func__));
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_max_packets = max(dp->tx_max_packets - 1, 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto done;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff nmblk = avail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_free_head = head + nmblk;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff load_flags = ((dp->tx_busy++) == 0) ? GEM_TXFLAG_HEAD : 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* update last interrupt position if tx buffers exhaust. */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (nmblk == avail) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tbp = GET_TXBUF(dp, head + avail - 1);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tbp->txb_flag = GEM_TXFLAG_INTR;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_desc_intr = head + avail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = GET_TXBUF(dp, head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff for (i = nmblk; i > 0; i--, tbp = tbp->txb_next) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint8_t *bp;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff uint64_t txflag;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* remove one from the mblk list */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mp_head != NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp = mp_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp_head = mp_head->b_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp->b_next = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* statistics for non-unicast packets */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bp = mp->b_rptr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((bp[0] & 1) && (flags & GEM_SEND_CTRL) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (bcmp(bp, gem_etherbroadcastaddr.ether_addr_octet,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ETHERADDRL) == 0) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff bcast++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff mcast++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* save misc info */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff txflag = tbp->txb_flag;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff txflag |= (flags & GEM_SEND_CTRL) << GEM_TXFLAG_PRIVATE_SHIFT;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff txflag |= gem_txbuf_options(dp, mp, (uint8_t *)tbp->txb_buf);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tbp->txb_flag = txflag;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff len_total += gem_setup_txbuf_copy(dp, mp, tbp);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff (void) gem_tx_load_descs_oo(dp, head, head + nmblk, load_flags);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Append the tbp at the tail of the active tx buffer list */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((--dp->tx_busy) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* extend the tail of softq, as new packets have been ready. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_tail = dp->tx_free_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mac_active && (flags & GEM_SEND_CTRL) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * The device status has changed while we are
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * preparing tx buf.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * As we are the last one that make tx non-busy.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * wake up someone who may wait for us.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cv_broadcast(&dp->tx_drain_cv);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_softq_tail - dp->tx_softq_head > 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_tx_start_unit(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.obytes += len_total;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->stats.opackets += nmblk;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->stats.obcast += bcast;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->stats.omcast += mcast;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffdone:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (mp_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ========================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * error detection and restart routines
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ========================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_restart_nic(struct gem_dev *dp, uint_t flags)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#ifdef GEM_DEBUG_LEVEL
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#if GEM_DEBUG_LEVEL > 1
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gem_dump_txbuf(dp, CE_CONT, "gem_restart_nic");
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#endif
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* should we return GEM_FAILURE ? */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * We should avoid calling any routines except xxx_chip_reset
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * when we are resuming the system.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_active) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (flags & GEM_RESTART_KEEP_BUF) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* stop rx gracefully */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode &= ~RXMODE_ENABLE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) (*dp->gc.gc_set_rx_filter)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_mac_stop(dp, flags);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* reset the chip. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_reset_chip)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "%s: %s: failed to reset chip",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_mac_init(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* setup media mode if the link have been up */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_state == MII_STATE_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((dp->gc.gc_set_media)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* setup mac address and enable rx filter */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode |= RXMODE_ENABLE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_set_rx_filter)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * XXX - a panic happened because of linkdown.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * We must check mii_state here, because the link can be down just
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * before the restart event happen. If the link is down now,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * gem_mac_start() will be called from gem_mii_link_check() when
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * the link become up later.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_state == MII_STATE_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* restart the nic */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(!dp->mac_active);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_mac_start(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_tx_timeout(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff clock_t now;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff boolean_t tx_sched;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct txbuf *tbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_sched = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff now = ddi_get_lbolt();
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mac_active || dp->mii_state != MII_STATE_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto schedule_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* reclaim transmitted buffers to check the trasmitter hangs or not. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_reclaim_txbuf(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* tx error happened, reset transmitter in the chip */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_restart_nic(dp, 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_sched = B_TRUE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_blocked = (clock_t)0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto schedule_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* check if the transmitter thread is stuck */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->tx_active_head == dp->tx_active_tail) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* no tx buffer is loaded to the nic */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->tx_blocked &&
23d366e350386ec109bfa9b2cf91225729a1a26bduboff now - dp->tx_blocked > dp->gc.gc_tx_timeout_interval) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gem_dump_txbuf(dp, CE_WARN,
23d366e350386ec109bfa9b2cf91225729a1a26bduboff "gem_tx_timeout: tx blocked");
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tx_sched = B_TRUE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_blocked = (clock_t)0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto schedule_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tbp = GET_TXBUF(dp, dp->tx_active_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (now - tbp->txb_stime < dp->gc.gc_tx_timeout) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto schedule_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gem_dump_txbuf(dp, CE_WARN, "gem_tx_timeout: tx timeout");
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* discard untransmitted packet and restart tx. */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff (void) gem_restart_nic(dp, GEM_RESTART_NOWAIT);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_sched = B_TRUE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_blocked = (clock_t)0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffschedule_next:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* restart the downstream if needed */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (tx_sched) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mac_tx_update(dp->mh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(4, (CE_CONT,
23d366e350386ec109bfa9b2cf91225729a1a26bduboff "!%s: blocked:%d active_head:%d active_tail:%d desc_intr:%d",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->name, BOOLEAN(dp->tx_blocked),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_head, dp->tx_active_tail, dp->tx_desc_intr));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->timeout_id =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff timeout((void (*)(void *))gem_tx_timeout,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void *)dp, dp->gc.gc_tx_timeout_interval);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ================================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Interrupt handler
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ================================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff__INLINE__
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_append_rxbuf(struct gem_dev *dp, struct rxbuf *rbp_head)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct rxbuf *rbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int rx_ring_size = dp->gc.gc_rx_ring_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(rbp_head != NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(3, (CE_CONT, "!%s: %s: slot_head:%d, slot_tail:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, dp->rx_active_head, dp->rx_active_tail));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Add new buffers into active rx buffer list
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->rx_buf_head == NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_head = rbp_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->rx_buf_tail == NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_tail->rxb_next = rbp_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tail = dp->rx_active_tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (rbp = rbp_head; rbp; rbp = rbp->rxb_next) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* need to notify the tail for the lower layer */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_tail = rbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_rx_desc_write(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(tail, rx_ring_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp->rxb_dmacookie,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp->rxb_nfrags);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_active_tail = tail = tail + 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#pragma inline(gem_append_rxbuf)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffmblk_t *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_get_packet_default(struct gem_dev *dp, struct rxbuf *rbp, size_t len)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int rx_header_len = dp->gc.gc_rx_header_len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint8_t *bp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mblk_t *mp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* allocate a new mblk */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (mp = allocb(len + VTAG_SIZE, BPRI_MED)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mp->b_next == NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mp->b_cont == NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp->b_rptr += VTAG_SIZE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff bp = mp->b_rptr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp->b_wptr = bp + len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /*
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * flush the range of the entire buffer to invalidate
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * all of corresponding dirty entries in iocache.
23d366e350386ec109bfa9b2cf91225729a1a26bduboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) ddi_dma_sync(rbp->rxb_dh, rx_header_len,
23d366e350386ec109bfa9b2cf91225729a1a26bduboff 0, DDI_DMA_SYNC_FORKERNEL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff bcopy(rbp->rxb_buf + rx_header_len, bp, len);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffuint_t gem_rx_pkts[17];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_receive(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint64_t len_total = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct rxbuf *rbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mblk_t *mp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int cnt = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint64_t rxstat;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct rxbuf *newbufs;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct rxbuf **newbufs_tailp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mblk_t *rx_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mblk_t **rx_tailp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int rx_ring_size = dp->gc.gc_rx_ring_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t active_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint64_t (*rx_desc_stat)(struct gem_dev *dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int slot, int ndesc);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int ethermin = ETHERMIN;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int ethermax = dp->mtu + sizeof (struct ether_header);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff int rx_header_len = dp->gc.gc_rx_header_len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(3, (CE_CONT, "!%s: gem_receive: rx_buf_head:%p",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, dp->rx_buf_head));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rx_desc_stat = dp->gc.gc_rx_desc_stat;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff newbufs_tailp = &newbufs;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rx_tailp = &rx_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (active_head = dp->rx_active_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (rbp = dp->rx_buf_head) != NULL; active_head++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (cnt == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cnt = max(dp->poll_pkt_delay*2, 10);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cnt = min(cnt,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_active_tail - active_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_rx_desc_dma_sync(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(active_head, rx_ring_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cnt,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DMA_SYNC_FORKERNEL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (rx_header_len > 0) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff (void) ddi_dma_sync(rbp->rxb_dh, 0,
23d366e350386ec109bfa9b2cf91225729a1a26bduboff rx_header_len, DDI_DMA_SYNC_FORKERNEL);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (((rxstat = (*rx_desc_stat)(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(active_head, rx_ring_size),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rbp->rxb_nfrags))
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff & (GEM_RX_DONE | GEM_RX_ERR)) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* not received yet */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Remove the head of the rx buffer list */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_head = rbp->rxb_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cnt--;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (rxstat & GEM_RX_ERR) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff len = rxstat & GEM_RX_LEN;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(3, (CE_CONT, "!%s: %s: rxstat:0x%llx, len:0x%x",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, rxstat, len));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Copy the packet
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((mp = dp->gc.gc_get_packet(dp, rbp, len)) == NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* no memory, discard the packet */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.norcvbuf++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Process VLAN tag
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ethermin = ETHERMIN;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ethermax = dp->mtu + sizeof (struct ether_header);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (GET_NET16(mp->b_rptr + VTAG_OFF) == VTAG_TPID) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ethermax += VTAG_SIZE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* check packet size */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (len < ethermin) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.errrcv++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.runt++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff freemsg(mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (len > ethermax) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.errrcv++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.frame_too_long++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff freemsg(mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff len_total += len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#ifdef GEM_DEBUG_VLAN
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (GET_ETHERTYPE(mp->b_rptr) == VTAG_TPID) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gem_dump_packet(dp, (char *)__func__, mp, B_TRUE);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* append received packet to temporaly rx buffer list */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *rx_tailp = mp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rx_tailp = &mp->b_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (mp->b_rptr[0] & 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (bcmp(mp->b_rptr,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_etherbroadcastaddr.ether_addr_octet,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ETHERADDRL) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.rbcast++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.rmcast++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffnext:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(rbp != NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* append new one to temporal new buffer list */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *newbufs_tailp = rbp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff newbufs_tailp = &rbp->rxb_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* advance rx_active_head */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((cnt = active_head - dp->rx_active_head) > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.rbytes += len_total;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.rpackets += cnt;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_active_head = active_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* terminate the working list */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *newbufs_tailp = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *rx_tailp = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->rx_buf_head == NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_tail = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(4, (CE_CONT, "%s: %s: cnt:%d, rx_head:%p",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, cnt, rx_head));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (newbufs) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * fillfull rx list with new buffers
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff seqnum_t head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* save current tail */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff head = dp->rx_active_tail;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_append_rxbuf(dp, newbufs);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* call hw depend start routine if we have. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_rx_start(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SLOT(head, rx_ring_size), dp->rx_active_tail - head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (rx_head) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * send up received packets
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_rx(dp->mh, NULL, rx_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_rx_pkts[min(cnt, sizeof (gem_rx_pkts)/sizeof (uint_t)-1)]++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (cnt);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffboolean_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_tx_done(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
23d366e350386ec109bfa9b2cf91225729a1a26bduboff boolean_t tx_sched = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_reclaim_txbuf(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_restart_nic(dp, GEM_RESTART_KEEP_BUF);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT, "!%s: gem_tx_done: tx_desc: %d %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, dp->tx_active_head, dp->tx_active_tail));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_sched = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto x;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* XXX - we must not have any packets in soft queue */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff ASSERT(dp->tx_softq_head == dp->tx_softq_tail);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * If we won't have chance to get more free tx buffers, and blocked,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * it is worth to reschedule the downstream i.e. tx side.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff ASSERT(dp->tx_desc_intr - dp->tx_desc_head >= 0);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->tx_blocked && dp->tx_desc_intr == dp->tx_desc_head) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * As no further tx-done interrupts are scheduled, this
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * is the last chance to kick tx side, which may be
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * blocked now, otherwise the tx side never works again.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_sched = B_TRUE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_blocked = (clock_t)0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_max_packets =
23d366e350386ec109bfa9b2cf91225729a1a26bduboff min(dp->tx_max_packets + 2, dp->gc.gc_tx_buf_limit);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff DPRINTF(3, (CE_CONT, "!%s: %s: ret: blocked:%d",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->name, __func__, BOOLEAN(dp->tx_blocked)));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffx:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (tx_sched);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic uint_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_intr(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t ret;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_INTR_UNCLAIMED);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->intr_busy = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ret = (*dp->gc.gc_interrupt)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ret == DDI_INTR_UNCLAIMED) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->intr_busy = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ret);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mac_active) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cv_broadcast(&dp->tx_drain_cv);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->stats.intr++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->intr_busy = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ret & INTR_RESTART_TX) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(4, (CE_CONT, "!%s: calling mac_tx_update", dp->name));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mac_tx_update(dp->mh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ret &= ~INTR_RESTART_TX;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ret);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_intr_watcher(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_intr(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* schedule next call of tu_intr_watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->intr_watcher_id =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff timeout((void (*)(void *))gem_intr_watcher, (void *)dp, 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ======================================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * MII support routines
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ======================================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_choose_forcedmode(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* choose media mode */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_1000fdx || dp->anadv_1000hdx) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_1000;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = dp->anadv_1000fdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (dp->anadv_100fdx || dp->anadv_100t4) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_100;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (dp->anadv_100hdx) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_100;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_10;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = dp->anadv_10fdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffuint16_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mii_read(struct gem_dev *dp, uint_t reg)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((dp->mii_status & MII_STATUS_MFPRMBLSUPR) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_mii_sync)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return ((*dp->gc.gc_mii_read)(dp, reg));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffvoid
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mii_write(struct gem_dev *dp, uint_t reg, uint16_t val)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((dp->mii_status & MII_STATUS_MFPRMBLSUPR) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_mii_sync)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_mii_write)(dp, reg, val);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define fc_cap_decode(x) \
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ((((x) & MII_ABILITY_PAUSE) ? 1 : 0) | \
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore (((x) & MII_ABILITY_ASMPAUSE) ? 2 : 0))
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mii_config_default(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t mii_stat;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff static uint16_t fc_cap_encode[4] = {
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore 0, /* none */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore MII_ABILITY_PAUSE, /* symmetric */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore MII_ABILITY_ASMPAUSE, /* tx */
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore MII_ABILITY_PAUSE | MII_ABILITY_ASMPAUSE, /* rx-symmetric */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff };
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Configure bits in advertisement register
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mii_stat = dp->mii_status;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: MII_STATUS reg:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, mii_stat, MII_STATUS_BITS));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((mii_stat & MII_STATUS_ABILITY_TECH) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* it's funny */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "!%s: wrong ability bits: mii_status:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, mii_stat, MII_STATUS_BITS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Do not change the rest of the ability bits in the advert reg */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gem_mii_read(dp, MII_AN_ADVERT) & ~MII_ABILITY_ALL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: 100T4:%d 100F:%d 100H:%d 10F:%d 10H:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100t4, dp->anadv_100fdx, dp->anadv_100hdx,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10fdx, dp->anadv_10hdx));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_100t4) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_ABILITY_100BASE_T4;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_100fdx) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_ABILITY_100BASE_TX_FD;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_100hdx) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_ABILITY_100BASE_TX;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_10fdx) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_ABILITY_10BASE_T_FD;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_10hdx) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_ABILITY_10BASE_T;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* set flow control capability */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= fc_cap_encode[dp->anadv_flow_control];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: setting MII_AN_ADVERT reg:%b, mii_mode:%d, fc:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, val, MII_ABILITY_BITS, dp->gc.gc_mii_mode,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_flow_control));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_AN_ADVERT, val);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (mii_stat & MII_STATUS_XSTATUS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * 1000Base-T GMII support
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->anadv_autoneg) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* enable manual configuration */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = MII_1000TC_CFG_EN;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_1000fdx) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_1000TC_ADV_FULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_1000hdx) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_1000TC_ADV_HALF;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: setting MII_1000TC reg:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, val, MII_1000TC_BITS));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_1000TC, val);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define GEM_LINKUP(dp) mac_link_update((dp)->mh, LINK_STATE_UP)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define GEM_LINKDOWN(dp) mac_link_update((dp)->mh, LINK_STATE_DOWN)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic uint8_t gem_fc_result[4 /* my cap */ ][4 /* lp cap */] = {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* none symm tx rx/symm */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* none */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff {FLOW_CONTROL_NONE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_NONE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_NONE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_NONE},
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* sym */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff {FLOW_CONTROL_NONE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_SYMMETRIC,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_NONE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_SYMMETRIC},
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* tx */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff {FLOW_CONTROL_NONE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_NONE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_NONE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_TX_PAUSE},
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* rx/symm */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff {FLOW_CONTROL_NONE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_SYMMETRIC,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_RX_PAUSE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff FLOW_CONTROL_SYMMETRIC},
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff};
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic char *gem_fc_type[] = {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "without",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "with symmetric",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "with tx",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "with rx",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff};
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffboolean_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mii_link_check(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t old_mii_state;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff boolean_t tx_sched = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t status;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t advert;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t lpable;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t exp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t ctl1000;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t stat1000;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff clock_t now;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff clock_t diff;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int linkdown_action;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff boolean_t fix_phy = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff now = ddi_get_lbolt();
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff old_mii_state = dp->mii_state;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(3, (CE_CONT, "!%s: %s: time:%d state:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, now, dp->mii_state));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff diff = now - dp->mii_last_check;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_last_check = now;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /*
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * For NWAM, don't show linkdown state right
23d366e350386ec109bfa9b2cf91225729a1a26bduboff * after the system boots
23d366e350386ec109bfa9b2cf91225729a1a26bduboff */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->linkup_delay > 0) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->linkup_delay > diff) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->linkup_delay -= diff;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff } else {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* link up timeout */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->linkup_delay = -1;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffnext_nowait:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (dp->mii_state) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_STATE_UNKNOWN:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* power-up, DP83840 requires 32 sync bits */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_mii_sync)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto reset_phy;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_STATE_RESETTING:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer -= diff;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_timer > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* don't read phy registers in resetting */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = WATCH_INTERVAL_FAST;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Timer expired, ensure reset bit is not set */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_status & MII_STATUS_MFPRMBLSUPR) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* some phys need sync bits after reset */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_mii_sync)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gem_mii_read(dp, MII_CONTROL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val & MII_CONTROL_RESET) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_NOTE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: time:%ld resetting phy not complete."
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff " mii_control:0x%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, ddi_get_lbolt(),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val, MII_CONTROL_BITS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* ensure neither isolated nor pwrdown nor auto-nego mode */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* XXX -- this operation is required for NS DP83840A. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_CONTROL, 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* As resetting PHY has completed, configure PHY registers */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_mii_config)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* we failed to configure PHY. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto reset_phy;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* mii_config may disable autonegatiation */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_choose_forcedmode(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_lpable = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_advert = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_exp = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_ctl1000 = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_stat1000 = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->flow_control = FLOW_CONTROL_NONE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->anadv_autoneg) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* skip auto-negotiation phase */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_MEDIA_SETUP;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next_nowait;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Issue auto-negotiation command */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto autonego;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_STATE_AUTONEGOTIATING:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Autonegotiation is in progress
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer -= diff;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_timer -
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->gc.gc_mii_an_timeout
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff - dp->gc.gc_mii_an_wait) > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * wait for a while, typically autonegotiation
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * completes in 2.3 - 2.5 sec.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = WATCH_INTERVAL_FAST;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* read PHY status */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status = gem_mii_read(dp, MII_STATUS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(4, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: called: mii_state:%d MII_STATUS reg:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, dp->mii_state,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status, MII_STATUS_BITS));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (status & MII_STATUS_REMFAULT) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * The link parnert told me something wrong happend.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * What do we do ?
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: auto-negotiation failed: remote fault",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto autonego;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((status & MII_STATUS_ANDONE) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_timer <= 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Auto-negotiation was timed out,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * try again w/o resetting phy.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mii_supress_msg) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: auto-negotiation failed: timeout",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_supress_msg = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto autonego;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Auto-negotiation is in progress. Wait.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = dp->gc.gc_mii_an_watch_interval;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Auto-negotiation have completed.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Assume linkdown and fall through.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_supress_msg = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_AN_DONE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: auto-negotiation completed, MII_STATUS:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, status, MII_STATUS_BITS));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_mii_an_delay > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer = dp->gc.gc_mii_an_delay;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = drv_usectohz(20*1000);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff diff = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next_nowait;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_STATE_AN_DONE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Auto-negotiation have done. Now we can set up media.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer -= diff;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_timer > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* wait for a while */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = WATCH_INTERVAL_FAST;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * set up the result of auto negotiation
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Read registers required to determin current
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * duplex mode and media speed.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_mii_an_delay > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * As the link watcher context has been suspended,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * 'status' is invalid. We must status register here
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status = gem_mii_read(dp, MII_STATUS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff advert = gem_mii_read(dp, MII_AN_ADVERT);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff lpable = gem_mii_read(dp, MII_AN_LPABLE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff exp = gem_mii_read(dp, MII_AN_EXPANSION);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (exp == 0xffff) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* some phys don't have exp register */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff exp = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ctl1000 = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff stat1000 = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_status & MII_STATUS_XSTATUS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ctl1000 = gem_mii_read(dp, MII_1000TC);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff stat1000 = gem_mii_read(dp, MII_1000TS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_lpable = lpable;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_advert = advert;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_exp = exp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_ctl1000 = ctl1000;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_stat1000 = stat1000;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: auto-negotiation done, advert:%b, lpable:%b, exp:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff advert, MII_ABILITY_BITS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff lpable, MII_ABILITY_BITS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff exp, MII_AN_EXP_BITS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_status & MII_STATUS_XSTATUS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "! MII_1000TC:%b, MII_1000TS:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ctl1000, MII_1000TC_BITS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff stat1000, MII_1000TS_BITS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_population(lpable) <= 1 &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (exp & MII_AN_EXP_LPCANAN) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((advert & MII_ABILITY_TECH) != lpable) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: but the link partnar doesn't seem"
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff " to have auto-negotiation capability."
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff " please check the link configuration.",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore * it should be result of parallel detection, which
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * cannot detect duplex mode.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (lpable & MII_ABILITY_100BASE_TX) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * we prefer full duplex mode for 100Mbps
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * connection, if we can.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff lpable |= advert & MII_ABILITY_100BASE_TX_FD;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((advert & lpable) == 0 &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff lpable & MII_ABILITY_10BASE_T) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff lpable |= advert & MII_ABILITY_10BASE_T_FD;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * as the link partnar isn't auto-negotiatable, use
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * fixed mode temporally.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff fix_phy = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (lpable == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "!%s: wrong lpable.", dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto reset_phy;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * configure current link mode according to AN priority.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = advert & lpable;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((ctl1000 & MII_1000TC_ADV_FULL) &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (stat1000 & MII_1000TS_LP_FULL)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* 1000BaseT & full duplex */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_1000;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if ((ctl1000 & MII_1000TC_ADV_HALF) &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (stat1000 & MII_1000TS_LP_HALF)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* 1000BaseT & half duplex */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_1000;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (val & MII_ABILITY_100BASE_TX_FD) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* 100BaseTx & full duplex */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_100;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (val & MII_ABILITY_100BASE_T4) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* 100BaseT4 & full duplex */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_100;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (val & MII_ABILITY_100BASE_TX) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* 100BaseTx & half duplex */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_100;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (val & MII_ABILITY_10BASE_T_FD) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* 10BaseT & full duplex */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_10;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (val & MII_ABILITY_10BASE_T) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* 10BaseT & half duplex */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_10;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * It seems that the link partnar doesn't have
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * auto-negotiation capability and our PHY
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * could not report the correct current mode.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * We guess current mode by mii_control register.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gem_mii_read(dp, MII_CONTROL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* select 100m full or 10m half */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = (val & MII_CONTROL_100MB) ?
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff GEM_SPD_100 : GEM_SPD_10;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = dp->speed != GEM_SPD_10;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff fix_phy = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_NOTE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: auto-negotiation done but "
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "common ability not found.\n"
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "PHY state: control:%b advert:%b lpable:%b\n"
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "guessing %d Mbps %s duplex mode",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val, MII_CONTROL_BITS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff advert, MII_ABILITY_BITS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff lpable, MII_ABILITY_BITS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_speed_value[dp->speed],
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex ? "full" : "half");
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->full_duplex) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->flow_control =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_fc_result[fc_cap_decode(advert)]
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff [fc_cap_decode(lpable)];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->flow_control = FLOW_CONTROL_NONE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_MEDIA_SETUP;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* FALLTHROUGH */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_STATE_MEDIA_SETUP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_LINKDOWN;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer = dp->gc.gc_mii_linkdown_timeout;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT, "!%s: setup midia mode done", dp->name));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_supress_msg = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* use short interval */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = WATCH_INTERVAL_FAST;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((!dp->anadv_autoneg) ||
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_mii_an_oneshot || fix_phy) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * write specified mode to phy.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gem_mii_read(dp, MII_CONTROL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val &= ~(MII_CONTROL_SPEED | MII_CONTROL_FDUPLEX |
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff MII_CONTROL_ANE | MII_CONTROL_RSAN);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->full_duplex) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_CONTROL_FDUPLEX;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (dp->speed) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case GEM_SPD_1000:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_CONTROL_1000MB;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case GEM_SPD_100:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val |= MII_CONTROL_100MB;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff default:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "%s: unknown speed:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, dp->speed);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* FALLTHROUGH */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case GEM_SPD_10:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* for GEM_SPD_10, do nothing */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_status & MII_STATUS_XSTATUS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff MII_1000TC, MII_1000TC_CFG_EN);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_CONTROL, val);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->nic_state >= NIC_STATE_INITIALIZED) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* notify the result of auto-negotiation to mac */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_set_media)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((void *)dp->gc.gc_mii_tune_phy) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* for built-in sis900 */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* XXX - this code should be removed. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_mii_tune_phy)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next_nowait;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_STATE_LINKDOWN:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status = gem_mii_read(dp, MII_STATUS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (status & MII_STATUS_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Link going up
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_LINKUP;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_supress_msg = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: link up detected: mii_stat:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, status, MII_STATUS_BITS));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * MII_CONTROL_100MB and MII_CONTROL_FDUPLEX are
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * ignored when MII_CONTROL_ANE is set.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: Link up: %d Mbps %s duplex %s flow control",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_speed_value[dp->speed],
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex ? "full" : "half",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_fc_type[dp->flow_control]);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = dp->gc.gc_mii_link_watch_interval;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* XXX - we need other timer to watch statictics */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_mii_hw_link_detection &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state == NIC_STATE_ONLINE) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->nic_state == NIC_STATE_ONLINE) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mac_active) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_mac_start(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_sched = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_supress_msg = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_autoneg) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer -= diff;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_timer <= 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * link down timer expired.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * need to restart auto-negotiation.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff linkdown_action =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_mii_linkdown_timeout_action;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto restart_autonego;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* don't change mii_state */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_STATE_LINKUP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status = gem_mii_read(dp, MII_STATUS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((status & MII_STATUS_LINKUP) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Link going down
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_NOTE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: link down detected: mii_stat:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, status, MII_STATUS_BITS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->nic_state == NIC_STATE_ONLINE &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mac_active &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_mii_stop_mac_on_linkdown) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_mac_stop(dp, 0);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->tx_blocked) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* drain tx */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff tx_sched = B_TRUE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->anadv_autoneg) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* need to restart auto-negotiation */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff linkdown_action = dp->gc.gc_mii_linkdown_action;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto restart_autonego;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_LINKDOWN;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer = dp->gc.gc_mii_linkdown_timeout;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((void *)dp->gc.gc_mii_tune_phy) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* for built-in sis900 */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_mii_tune_phy)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = dp->gc.gc_mii_link_watch_interval;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* don't change mii_state */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_mii_hw_link_detection &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state == NIC_STATE_ONLINE) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = dp->gc.gc_mii_link_watch_interval;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Actions on the end of state routine */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffrestart_autonego:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (linkdown_action) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_ACTION_RESET:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mii_supress_msg) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_supress_msg = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto reset_phy;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_ACTION_NONE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_supress_msg = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_mii_an_oneshot) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto autonego;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* PHY will restart autonego automatically */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_AUTONEGOTIATING;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer = dp->gc.gc_mii_an_timeout;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = dp->gc.gc_mii_an_watch_interval;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MII_ACTION_RSA:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mii_supress_msg) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: restarting auto-negotiation",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_supress_msg = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto autonego;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff default:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "!%s: unknowm linkdown action: %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, dp->gc.gc_mii_linkdown_action);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_supress_msg = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* NOTREACHED */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffreset_phy:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mii_supress_msg) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_RESETTING;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer = dp->gc.gc_mii_reset_timeout;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->gc.gc_mii_dont_reset) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_CONTROL, MII_CONTROL_RESET);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = WATCH_INTERVAL_FAST;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffautonego:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!dp->mii_supress_msg) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: auto-negotiation started", dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_AUTONEGOTIATING;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_timer = dp->gc.gc_mii_an_timeout;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* start/restart auto nego */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gem_mii_read(dp, MII_CONTROL) &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ~(MII_CONTROL_ISOLATE | MII_CONTROL_PWRDN | MII_CONTROL_RESET);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gem_mii_write(dp, MII_CONTROL,
23d366e350386ec109bfa9b2cf91225729a1a26bduboff val | MII_CONTROL_RSAN | MII_CONTROL_ANE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_interval = dp->gc.gc_mii_an_watch_interval;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffnext:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->link_watcher_id == 0 && dp->mii_interval) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* we must schedule next mii_watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->link_watcher_id =
23d366e350386ec109bfa9b2cf91225729a1a26bduboff timeout((void (*)(void *))&gem_mii_link_watcher,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void *)dp, dp->mii_interval);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (old_mii_state != dp->mii_state) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* notify new mii link state */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_state == MII_STATE_LINKUP) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->linkup_delay = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff GEM_LINKUP(dp);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff } else if (dp->linkup_delay <= 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff GEM_LINKDOWN(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff } else if (dp->linkup_delay < 0) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* first linkup timeout */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->linkup_delay = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff GEM_LINKDOWN(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (tx_sched);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mii_link_watcher(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff boolean_t tx_sched;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->link_watcher_id = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tx_sched = gem_mii_link_check(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#if GEM_DEBUG_LEVEL > 2
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->link_watcher_id == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "%s: link watcher stopped", dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (tx_sched) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* kick potentially stopped downstream */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mac_tx_update(dp->mh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mii_probe_default(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int8_t phy;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t status;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t adv;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint16_t adv_org;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Scan PHY
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* ensure to send sync bits */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_status = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Try default phy first */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_phy_addr) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status = gem_mii_read(dp, MII_STATUS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (status != 0xffff && status != 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_CONTROL, 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto PHY_found;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_phy_addr < 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_NOTE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: failed to probe default internal and/or non-MII PHY",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_NOTE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: failed to probe default MII PHY at %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, dp->mii_phy_addr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Try all possible address */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (phy = dp->gc.gc_mii_addr_min; phy < 32; phy++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_phy_addr = phy;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status = gem_mii_read(dp, MII_STATUS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (status != 0xffff && status != 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_CONTROL, 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto PHY_found;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (phy = dp->gc.gc_mii_addr_min; phy < 32; phy++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_phy_addr = phy;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_CONTROL, 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status = gem_mii_read(dp, MII_STATUS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (status != 0xffff && status != 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto PHY_found;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_NOTE, "!%s: no MII PHY found", dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_phy_addr = -1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffPHY_found:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_status = status;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_phy_id = (gem_mii_read(dp, MII_PHYIDH) << 16) |
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_read(dp, MII_PHYIDL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_phy_addr < 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: using internal/non-MII PHY(0x%08x)",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, dp->mii_phy_id);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: MII PHY (0x%08x) found at %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, dp->mii_phy_id, dp->mii_phy_addr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: PHY control:%b, status:%b, advert:%b, lpar:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_read(dp, MII_CONTROL), MII_CONTROL_BITS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status, MII_STATUS_BITS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_read(dp, MII_AN_ADVERT), MII_ABILITY_BITS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_read(dp, MII_AN_LPABLE), MII_ABILITY_BITS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_xstatus = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (status & MII_STATUS_XSTATUS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_xstatus = gem_mii_read(dp, MII_XSTATUS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT, "!%s: xstatus:%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, dp->mii_xstatus, MII_XSTATUS_BITS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* check if the phy can advertize pause abilities */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff adv_org = gem_mii_read(dp, MII_AN_ADVERT);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_AN_ADVERT,
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore MII_ABILITY_PAUSE | MII_ABILITY_ASMPAUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff adv = gem_mii_read(dp, MII_AN_ADVERT);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((adv & MII_ABILITY_PAUSE) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_flow_control &= ~1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore if ((adv & MII_ABILITY_ASMPAUSE) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_flow_control &= ~2;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_write(dp, MII_AN_ADVERT, adv_org);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mii_start(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* make a first call of check link */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_UNKNOWN;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_last_check = ddi_get_lbolt();
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->linkup_delay = dp->gc.gc_mii_linkdown_timeout;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_mii_link_watcher(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mii_stop(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Ensure timer routine stopped */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->link_watcher_id) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (untimeout(dp->link_watcher_id) == -1)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->link_watcher_id = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffboolean_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_get_mac_addr_conf(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff char propname[32];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff char *valstr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint8_t mac[ETHERADDRL];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff char *cp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int c;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int j;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint8_t v;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint8_t d;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint8_t ored;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Get ethernet address from .conf file
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) sprintf(propname, "mac-addr");
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dp->dip,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_PROP_DONTPASS, propname, &valstr)) !=
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_PROP_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (B_FALSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (strlen(valstr) != ETHERADDRL*3-1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto syntax_err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cp = valstr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff j = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ored = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (;;) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff v = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < 2; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff c = *cp++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (c >= 'a' && c <= 'f') {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff d = c - 'a' + 10;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (c >= 'A' && c <= 'F') {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff d = c - 'A' + 10;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (c >= '0' && c <= '9') {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff d = c - '0';
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto syntax_err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff v = (v << 4) | d;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mac[j++] = v;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ored |= v;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (j == ETHERADDRL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* done */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff c = *cp++;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (c != ':') {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto syntax_err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ored == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < ETHERADDRL; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->dev_addr.ether_addr_octet[i] = mac[i];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_prop_free(valstr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (B_TRUE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffsyntax_err:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: read mac addr: trying .conf: syntax err %s",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, valstr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_prop_free(valstr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (B_FALSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * internal start/stop interface
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mac_set_rx_filter(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return ((*dp->gc.gc_set_rx_filter)(dp));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * gem_mac_init: cold start
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mac_init(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mac_active = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_init_rx_ring(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_init_tx_ring(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* reset transmitter state */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_blocked = (clock_t)0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_busy = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_reclaim_busy = 0;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->tx_max_packets = dp->gc.gc_tx_buf_limit;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_init_chip)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_prepare_rx_buf(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * gem_mac_start: warm start
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mac_start(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->nic_state == NIC_STATE_ONLINE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->mii_state == MII_STATE_LINKUP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* enable tx and rx */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mac_active = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* setup rx buffers */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff (*dp->gc.gc_rx_start)(dp,
23d366e350386ec109bfa9b2cf91225729a1a26bduboff SLOT(dp->rx_active_head, dp->gc.gc_rx_ring_size),
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->rx_active_tail - dp->rx_active_head);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_start_chip)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "%s: %s: start_chip: failed",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* load untranmitted packets to the nic */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_softq_tail - dp->tx_softq_head >= 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->tx_softq_tail - dp->tx_softq_head > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_tx_load_descs_oo(dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_head, dp->tx_softq_tail,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff GEM_TXFLAG_HEAD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* issue preloaded tx buffers */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_tx_start_unit(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mac_stop(struct gem_dev *dp, uint_t flags)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int wait_time; /* in uS */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff clock_t now;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int ret = GEM_SUCCESS;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called, rx_buf_free:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, dp->rx_buf_freecnt));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(!mutex_owned(&dp->xmitlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Block transmits
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mac_active = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (dp->tx_busy > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cv_wait(&dp->tx_drain_cv, &dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((flags & GEM_RESTART_NOWAIT) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Wait for all tx buffers sent.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff wait_time =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff 2 * (8 * MAXPKTBUF(dp) / gem_speed_value[dp->speed]) *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->tx_active_tail - dp->tx_active_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "%s: %s: max drain time: %d uS",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, wait_time));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff i = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef GEM_DEBUG_LEVEL
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff now = ddi_get_lbolt();
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (dp->tx_active_tail != dp->tx_active_head) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (i > wait_time) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* timeout */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_NOTE, "%s: %s timeout: tx drain",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_reclaim_txbuf(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff drv_usecwait(100);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff i += 100;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_NOTE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: the nic have drained in %d uS, real %d mS",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, i,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff 10*((int)(ddi_get_lbolt() - now))));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Now we can stop the nic safely.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_stop_chip)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_NOTE, "%s: %s: resetting the chip to stop it",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_reset_chip)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "%s: %s: failed to reset chip",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Clear all rx buffers
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (flags & GEM_RESTART_KEEP_BUF) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_receive(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_clean_rx_buf(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Update final statistics
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_get_stats)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Clear all pended tx packets
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_active_tail == dp->tx_softq_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->tx_softq_tail == dp->tx_free_head);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (flags & GEM_RESTART_KEEP_BUF) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* restore active tx buffers */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_active_tail = dp->tx_active_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_softq_head = dp->tx_active_head;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_clean_tx_buf(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ret);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_add_multicast(struct gem_dev *dp, const uint8_t *ep)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int cnt;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mc_count_req++ < GEM_MAXMC) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* append the new address at the end of the mclist */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cnt = dp->mc_count;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff bcopy(ep, dp->mc_list[cnt].addr.ether_addr_octet,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ETHERADDRL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_multicast_hash) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mc_list[cnt].hash =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_multicast_hash)(dp, (uint8_t *)ep);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mc_count = cnt + 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mc_count_req != dp->mc_count) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* multicast address list overflow */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode |= RXMODE_MULTI_OVF;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode &= ~RXMODE_MULTI_OVF;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* tell new multicast list to the hardware */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = gem_mac_set_rx_filter(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_remove_multicast(struct gem_dev *dp, const uint8_t *ep)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff size_t len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int cnt;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (GEM_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mc_count_req--;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cnt = dp->mc_count;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < cnt; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (bcmp(ep, &dp->mc_list[i].addr, ETHERADDRL)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff continue;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* shrink the mclist by copying forward */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff len = (cnt - (i + 1)) * sizeof (*dp->mc_list);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (len > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff bcopy(&dp->mc_list[i+1], &dp->mc_list[i], len);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mc_count--;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mc_count_req != dp->mc_count) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* multicast address list overflow */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode |= RXMODE_MULTI_OVF;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode &= ~RXMODE_MULTI_OVF;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* In gem v2, don't hold xmitlock on calling set_rx_filter */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = gem_mac_set_rx_filter(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * ND interface
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffenum {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_AUTONEG_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_PAUSE_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ASYM_PAUSE_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_1000FDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_1000HDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_100T4_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_100FDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_100HDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_10FDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_10HDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_AUTONEG_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_PAUSE_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_ASYM_PAUSE_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_1000FDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_1000HDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_100T4_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_100FDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_100HDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_10FDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_10HDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_AUTONEG_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_PAUSE_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_ASYM_PAUSE_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_1000FDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_1000HDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_100T4_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_100FDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_100HDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_10FDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LP_10HDX_CAP,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LINK_STATUS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LINK_SPEED,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LINK_DUPLEX,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LINK_AUTONEG,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LINK_RX_PAUSE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LINK_TX_PAUSE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_LOOP_MODE,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_MSI_CNT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef DEBUG_RESUME
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_RESUME_TEST,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_COUNT
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff};
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffenum ioc_reply {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff IOC_INVAL = -1, /* bad, NAK with EINVAL */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff IOC_DONE, /* OK, reply sent */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff IOC_ACK, /* OK, just send ACK */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff IOC_REPLY, /* OK, just send reply */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff IOC_RESTART_ACK, /* OK, restart & ACK */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff IOC_RESTART_REPLY /* OK, restart & reply */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff};
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstruct gem_nd_arg {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int item;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff};
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_param_get(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *credp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp = ((struct gem_nd_arg *)(void *)arg)->dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int item = ((struct gem_nd_arg *)(void *)arg)->item;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff long val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called, item:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, item));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (item) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_AUTONEG_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "autoneg_cap:%d", val));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_PAUSE_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->gc.gc_flow_control & 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ASYM_PAUSE_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->gc.gc_flow_control & 2);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_1000FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_1000HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_100T4_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_100FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_100HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_10FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_10HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_10);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_AUTONEG_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_autoneg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_PAUSE_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->anadv_flow_control & 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_ASYM_PAUSE_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->anadv_flow_control & 2);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_1000FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_1000fdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_1000HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_1000hdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_100T4_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_100t4;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_100FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_100fdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_100HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_100hdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_10FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_10fdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_10HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_10hdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_AUTONEG_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_PAUSE_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_ASYM_PAUSE_CAP:
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASMPAUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_1000FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_1000HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_100T4_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_100FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_100HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_10FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LP_10HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LINK_STATUS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = (dp->mii_state == MII_STATE_LINKUP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LINK_SPEED:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gem_speed_value[dp->speed];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LINK_DUPLEX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_state == MII_STATE_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->full_duplex ? 2 : 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LINK_AUTONEG:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LINK_RX_PAUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->flow_control == FLOW_CONTROL_RX_PAUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_LINK_TX_PAUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->flow_control == FLOW_CONTROL_TX_PAUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef DEBUG_RESUME
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_RESUME_TEST:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff default:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "%s: unimplemented ndd control (%d)",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, item);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) mi_mpprintf(mp, "%ld", val);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t arg, cred_t *credp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp = ((struct gem_nd_arg *)(void *)arg)->dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int item = ((struct gem_nd_arg *)(void *)arg)->item;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff long val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff char *end;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ddi_strtol(value, &end, 10, &val)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (EINVAL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (end == value) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (EINVAL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (item) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_AUTONEG_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val && (dp->mii_status & MII_STATUS_CANAUTONEG) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_autoneg = (int)val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_PAUSE_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_flow_control |= 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_flow_control &= ~1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_ASYM_PAUSE_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_flow_control |= 2;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_flow_control &= ~2;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_1000FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val && (dp->mii_xstatus &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_XSTATUS_1000BASET_FD |
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff MII_XSTATUS_1000BASEX_FD)) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000fdx = (int)val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_1000HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val && (dp->mii_xstatus &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASEX)) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000hdx = (int)val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_100T4_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val && (dp->mii_status & MII_STATUS_100_BASE_T4) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100t4 = (int)val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_100FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val && (dp->mii_status & MII_STATUS_100_BASEX_FD) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100fdx = (int)val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_100HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val && (dp->mii_status & MII_STATUS_100_BASEX) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100hdx = (int)val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_10FDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val && (dp->mii_status & MII_STATUS_10_FD) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10fdx = (int)val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case PARAM_ADV_10HDX_CAP:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val != 0 && val != 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val && (dp->mii_status & MII_STATUS_10) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10hdx = (int)val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* sync with PHY */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_choose_forcedmode(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_state = MII_STATE_UNKNOWN;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_mii_hw_link_detection && dp->link_watcher_id == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* XXX - Can we ignore the return code ? */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_mii_link_check(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (EINVAL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_nd_load(struct gem_dev *dp, char *name, ndgetf_t gf, ndsetf_t sf, int item)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_nd_arg *arg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(item >= 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(item < PARAM_COUNT);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff arg = &((struct gem_nd_arg *)(void *)dp->nd_arg_p)[item];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff arg->dp = dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff arg->item = item;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT, "!%s: %s: name:%s, item:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, name, item));
23d366e350386ec109bfa9b2cf91225729a1a26bduboff (void) nd_load(&dp->nd_data_p, name, gf, sf, (caddr_t)arg);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_nd_setup(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called, mii_status:0x%b",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__, dp->mii_status, MII_STATUS_BITS));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->nd_arg_p == NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nd_arg_p =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff kmem_zalloc(sizeof (struct gem_nd_arg) * PARAM_COUNT, KM_SLEEP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define SETFUNC(x) ((x) ? gem_param_set : NULL)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "autoneg_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_AUTONEG_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "pause_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_PAUSE_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "asym_pause_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_ASYM_PAUSE_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "1000fdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_1000FDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "1000hdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_1000HDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "100T4_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_100T4_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "100fdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_100FDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "100hdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_100HDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "10fdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_10FDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "10hdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_10HDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Our advertised capabilities */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_autoneg_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC(dp->mii_status & MII_STATUS_CANAUTONEG),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_AUTONEG_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_pause_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC(dp->gc.gc_flow_control & 1),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_PAUSE_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_asym_pause_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC(dp->gc.gc_flow_control & 2),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_ASYM_PAUSE_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_1000fdx_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC(dp->mii_xstatus &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD)),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_1000FDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_1000hdx_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC(dp->mii_xstatus &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET)),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_1000HDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_100T4_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC((dp->mii_status & MII_STATUS_100_BASE_T4) &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff !dp->mii_advert_ro),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_100T4_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_100fdx_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC((dp->mii_status & MII_STATUS_100_BASEX_FD) &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff !dp->mii_advert_ro),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_100FDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_100hdx_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC((dp->mii_status & MII_STATUS_100_BASEX) &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff !dp->mii_advert_ro),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_100HDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_10fdx_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC((dp->mii_status & MII_STATUS_10_FD) &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff !dp->mii_advert_ro),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_10FDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "adv_10hdx_cap", gem_param_get,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff SETFUNC((dp->mii_status & MII_STATUS_10) &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff !dp->mii_advert_ro),
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff PARAM_ADV_10HDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Partner's advertised capabilities */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_autoneg_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_AUTONEG_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_pause_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_PAUSE_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_asym_pause_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_ASYM_PAUSE_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_1000fdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_1000FDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_1000hdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_1000HDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_100T4_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_100T4_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_100fdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_100FDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_100hdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_100HDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_10fdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_10FDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "lp_10hdx_cap",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LP_10HDX_CAP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Current operating modes */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "link_status",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LINK_STATUS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "link_speed",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LINK_SPEED);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "link_duplex",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LINK_DUPLEX);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "link_autoneg",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LINK_AUTONEG);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "link_rx_pause",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LINK_RX_PAUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "link_tx_pause",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_LINK_TX_PAUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef DEBUG_RESUME
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_load(dp, "resume_test",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_param_get, NULL, PARAM_RESUME_TEST);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#undef SETFUNC
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffenum ioc_reply
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_nd_ioctl(struct gem_dev *dp, queue_t *wq, mblk_t *mp, struct iocblk *iocp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff boolean_t ok;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(mutex_owned(&dp->intrlock));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (iocp->ioc_cmd) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ND_GET:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ok = nd_getset(wq, dp->nd_data_p, mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "%s: get %s", dp->name, ok ? "OK" : "FAIL"));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ok ? IOC_REPLY : IOC_INVAL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ND_SET:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ok = nd_getset(wq, dp->nd_data_p, mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "%s: set %s err %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, ok ? "OK" : "FAIL", iocp->ioc_error));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (!ok) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (IOC_INVAL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (iocp->ioc_error) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (IOC_REPLY);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (IOC_RESTART_REPLY);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "%s: invalid cmd 0x%x", dp->name, iocp->ioc_cmd);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (IOC_INVAL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_nd_cleanup(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->nd_data_p != NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->nd_arg_p != NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff nd_free(&dp->nd_data_p);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff kmem_free(dp->nd_arg_p, sizeof (struct gem_nd_arg) * PARAM_COUNT);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nd_arg_p = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mac_ioctl(struct gem_dev *dp, queue_t *wq, mblk_t *mp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct iocblk *iocp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff enum ioc_reply status;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int cmd;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Validate the command before bothering with the mutex ...
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff iocp = (void *)mp->b_rptr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff iocp->ioc_error = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmd = iocp->ioc_cmd;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "%s: %s cmd:0x%x", dp->name, __func__, cmd));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (cmd) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff default:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff _NOTE(NOTREACHED)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status = IOC_INVAL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ND_GET:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ND_SET:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff status = gem_nd_ioctl(dp, wq, mp, iocp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef DEBUG_RESUME
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (cmd == ND_GET) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_suspend(dp->dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_resume(dp->dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Finally, decide how to reply
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (status) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff default:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case IOC_INVAL:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Error, reply with a NAK and EINVAL or the specified error
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff EINVAL : iocp->ioc_error);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case IOC_DONE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * OK, reply already sent
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case IOC_RESTART_ACK:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case IOC_ACK:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * OK, reply with an ACK
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff miocack(wq, mp, 0, 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case IOC_RESTART_REPLY:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case IOC_REPLY:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * OK, send prepared reply as ACK or NAK
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp->b_datap->db_type =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff iocp->ioc_error == 0 ? M_IOCACK : M_IOCNAK;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff qreply(wq, mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifndef SYS_MAC_H
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define XCVR_UNDEFINED 0
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define XCVR_NONE 1
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define XCVR_10 2
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define XCVR_100T4 3
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define XCVR_100X 4
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define XCVR_100T2 5
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define XCVR_1000X 6
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define XCVR_1000T 7
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mac_xcvr_inuse(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int val = XCVR_UNDEFINED;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((dp->mii_status & MII_STATUS_XSTATUS) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_status & MII_STATUS_100_BASE_T4) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = XCVR_100T4;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (dp->mii_status &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_STATUS_100_BASEX_FD |
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff MII_STATUS_100_BASEX)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = XCVR_100X;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (dp->mii_status &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_STATUS_100_BASE_T2_FD |
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff MII_STATUS_100_BASE_T2)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = XCVR_100T2;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (dp->mii_status &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_STATUS_10_FD | MII_STATUS_10)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = XCVR_10;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (dp->mii_xstatus &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = XCVR_1000T;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if (dp->mii_xstatus &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASEX)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = XCVR_1000X;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (val);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * GLDv3 interface
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ============================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_m_getstat(void *, uint_t, uint64_t *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_m_start(void *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_m_stop(void *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_m_setpromisc(void *, boolean_t);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_m_multicst(void *, boolean_t, const uint8_t *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int gem_m_unicst(void *, const uint8_t *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic mblk_t *gem_m_tx(void *, mblk_t *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void gem_m_ioctl(void *, queue_t *, mblk_t *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic boolean_t gem_m_getcapab(void *, mac_capab_t, void *);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#define GEM_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic mac_callbacks_t gem_m_callbacks = {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff GEM_M_CALLBACK_FLAGS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_m_getstat,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_m_start,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_m_stop,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_m_setpromisc,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_m_multicst,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_m_unicst,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_m_tx,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_m_ioctl,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_m_getcapab,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff};
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_m_start(void *arg)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp = arg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = EIO;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto x;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_mac_init(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = EIO;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto x;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state = NIC_STATE_INITIALIZED;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* reset rx filter state */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mc_count = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mc_count_req = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* setup media mode if the link have been up */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_state == MII_STATE_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->gc.gc_set_media)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* setup initial rx filter */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff bcopy(dp->dev_addr.ether_addr_octet,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->cur_addr.ether_addr_octet, ETHERADDRL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode |= RXMODE_ENABLE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_mac_set_rx_filter(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = EIO;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto x;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state = NIC_STATE_ONLINE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_state == MII_STATE_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_mac_start(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = EIO;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto x;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->timeout_id = timeout((void (*)(void *))gem_tx_timeout,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void *)dp, dp->gc.gc_tx_timeout_interval);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffx:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state = NIC_STATE_STOPPED;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_m_stop(void *arg)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp = arg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* stop rx */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode &= ~RXMODE_ENABLE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_mac_set_rx_filter(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* stop tx timeout watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->timeout_id) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (untimeout(dp->timeout_id) == -1)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->timeout_id = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* make the nic state inactive */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state = NIC_STATE_STOPPED;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* we need deassert mac_active due to block interrupt handler */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mac_active = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* block interrupts */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (dp->intr_busy) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cv_wait(&dp->tx_drain_cv, &dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_mac_stop(dp, 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int ret;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp = arg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (add) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ret = gem_add_multicast(dp, ep);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ret = gem_remove_multicast(dp, ep);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ret != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = EIO;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_m_setpromisc(void *arg, boolean_t on)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err = 0; /* no error */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp = arg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (EIO);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (on) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode |= RXMODE_PROMISC;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode &= ~RXMODE_PROMISC;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_mac_set_rx_filter(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = EIO;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_m_getstat(void *arg, uint_t stat, uint64_t *valp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp = arg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_stats *gstp = &dp->stats;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint64_t val = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (mutex_owned(&dp->intrlock)) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->mac_suspended) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff return (EIO);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff } else {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff mutex_enter(&dp->intrlock);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->mac_suspended) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff mutex_exit(&dp->intrlock);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff return (EIO);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_get_stats)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (EIO);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (stat) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_IFSPEED:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gem_speed_value[dp->speed] *1000000ull;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_MULTIRCV:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->rmcast;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_BRDCSTRCV:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->rbcast;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_MULTIXMT:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->omcast;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_BRDCSTXMT:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->obcast;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_NORCVBUF:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->norcvbuf + gstp->missed;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_IERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->errrcv;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_NOXMTBUF:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->noxmtbuf;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_OERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->errxmt;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_COLLISIONS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->collisions;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_RBYTES:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->rbytes;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_IPACKETS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->rpackets;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_OBYTES:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->obytes;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_OPACKETS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->opackets;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_UNDERFLOWS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->underflow;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case MAC_STAT_OVERFLOWS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->overflow;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ALIGN_ERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->frame;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_FCS_ERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->crc;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_FIRST_COLLISIONS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->first_coll;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_MULTI_COLLISIONS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->multi_coll;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_SQE_ERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->sqe;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_DEFER_XMTS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->defer;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_TX_LATE_COLLISIONS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->xmtlatecoll;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_EX_COLLISIONS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->excoll;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_MACXMT_ERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->xmit_internal_err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CARRIER_ERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->nocarrier;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_TOOLONG_ERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->frame_too_long;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_MACRCV_ERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->rcv_internal_err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_XCVR_ADDR:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->mii_phy_addr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_XCVR_ID:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->mii_phy_id;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_XCVR_INUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gem_mac_xcvr_inuse(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_1000FDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_1000HDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_100FDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_100HDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_10FDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_10HDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_10);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_ASMPAUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->gc.gc_flow_control & 2);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_PAUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->gc.gc_flow_control & 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_AUTONEG:
23d366e350386ec109bfa9b2cf91225729a1a26bduboff val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_1000FDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_1000fdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_1000HDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_1000hdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_100FDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_100fdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_100HDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_100hdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_10FDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_10fdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_10HDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_10hdx;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_ASMPAUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->anadv_flow_control & 2);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_PAUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->anadv_flow_control & 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_AUTONEG:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_autoneg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_1000FDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_1000HDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_100FDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_100HDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_10FDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_10HDX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_ASMPAUSE:
bdb9230ac765cb7af3fc1f4119caf2c5720dceb3Garrett D'Amore val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASMPAUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_PAUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_AUTONEG:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LINK_ASMPAUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->flow_control & 2);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LINK_PAUSE:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->flow_control & 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LINK_AUTONEG:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_autoneg &&
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LINK_DUPLEX:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = (dp->mii_state == MII_STATE_LINKUP) ?
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (dp->full_duplex ? 2 : 1) : 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_TOOSHORT_ERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->runt;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_REMFAULT:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_AN_ADVERT_REMFAULT);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_JABBER_ERRORS:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gstp->jabber;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_CAP_100T4:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_ADV_CAP_100T4:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = dp->anadv_100t4;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case ETHER_STAT_LP_CAP_100T4:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff default:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#if GEM_DEBUG_LEVEL > 2
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "%s: unrecognized parameter value = %d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff __func__, stat);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ENOTSUP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff *valp = val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic int
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_m_unicst(void *arg, const uint8_t *mac)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int err = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp = arg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mac_suspended) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (EIO);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode |= RXMODE_ENABLE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_mac_set_rx_filter(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff err = EIO;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (err);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * gem_m_tx is used only for sending data packets into ethernet wire.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic mblk_t *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_m_tx(void *arg, mblk_t *mp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint32_t flags = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp = arg;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mblk_t *tp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp->nic_state == NIC_STATE_ONLINE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_state != MII_STATE_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Some nics hate to send packets when the link is down. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (mp) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tp = mp->b_next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp->b_next = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff freemsg(mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mp = tp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (gem_send_common(dp, mp, flags));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ((struct gem_dev *)arg)->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mac_ioctl((struct gem_dev *)arg, wq, mp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/* ARGSUSED */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic boolean_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return (B_FALSE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_gld3_init(struct gem_dev *dp, mac_register_t *macp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff macp->m_driver = dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff macp->m_dip = dp->dip;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff macp->m_src_addr = dp->dev_addr.ether_addr_octet;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff macp->m_callbacks = &gem_m_callbacks;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff macp->m_min_sdu = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff macp->m_max_sdu = dp->mtu;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->misc_flag & GEM_VLAN) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff macp->m_margin = VTAG_SIZE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ======================================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * attach/detatch support
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/* ======================================================================== */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstatic void
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_read_conf(struct gem_dev *dp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
23d366e350386ec109bfa9b2cf91225729a1a26bduboff int val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Get media mode infomation from .conf file
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_autoneg = gem_prop_get_int(dp, "adv_autoneg_cap", 1) != 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000fdx = gem_prop_get_int(dp, "adv_1000fdx_cap", 1) != 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000hdx = gem_prop_get_int(dp, "adv_1000hdx_cap", 1) != 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100t4 = gem_prop_get_int(dp, "adv_100T4_cap", 1) != 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100fdx = gem_prop_get_int(dp, "adv_100fdx_cap", 1) != 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100hdx = gem_prop_get_int(dp, "adv_100hdx_cap", 1) != 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10fdx = gem_prop_get_int(dp, "adv_10fdx_cap", 1) != 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10hdx = gem_prop_get_int(dp, "adv_10hdx_cap", 1) != 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((ddi_prop_exists(DDI_DEV_T_ANY, dp->dip,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_PROP_DONTPASS, "full-duplex"))) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = gem_prop_get_int(dp, "full-duplex", 1) != 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_autoneg = B_FALSE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (dp->full_duplex) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->anadv_1000hdx = B_FALSE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->anadv_100hdx = B_FALSE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->anadv_10hdx = B_FALSE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff } else {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->anadv_1000fdx = B_FALSE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->anadv_100fdx = B_FALSE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->anadv_10fdx = B_FALSE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((val = gem_prop_get_int(dp, "speed", 0)) > 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_autoneg = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff switch (val) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case 1000:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_1000;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100t4 = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100fdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100hdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10fdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10hdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case 100:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_100;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000fdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000hdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10fdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10hdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff case 10:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_10;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000fdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000hdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100t4 = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100fdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100hdx = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff default:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: property %s: illegal value:%d",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->name, "speed", val);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_autoneg = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = gem_prop_get_int(dp, "flow-control", dp->gc.gc_flow_control);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (val > FLOW_CONTROL_RX_PAUSE || val < FLOW_CONTROL_NONE) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: property %s: illegal value:%d",
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->name, "flow-control", val);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff val = min(val, dp->gc.gc_flow_control);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_flow_control = val;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_prop_get_int(dp, "nointr", 0)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->misc_flag |= GEM_NOINTR;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_NOTE, "!%s: polling mode enabled", dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mtu = gem_prop_get_int(dp, "mtu", dp->mtu);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->txthr = gem_prop_get_int(dp, "txthr", dp->txthr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxthr = gem_prop_get_int(dp, "rxthr", dp->rxthr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->txmaxdma = gem_prop_get_int(dp, "txmaxdma", dp->txmaxdma);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmaxdma = gem_prop_get_int(dp, "rxmaxdma", dp->rxmaxdma);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Gem kstat support
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#define GEM_LOCAL_DATA_SIZE(gc) \
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (sizeof (struct gem_dev) + \
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff sizeof (struct mcast_addr) * GEM_MAXMC + \
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff sizeof (struct txbuf) * ((gc)->gc_tx_buf_size) + \
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff sizeof (void *) * ((gc)->gc_tx_buf_size))
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffstruct gem_dev *
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_do_attach(dev_info_t *dip, int port,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_conf *gc, void *base, ddi_acc_handle_t *regs_handlep,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff void *lp, int lmsize)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_iblock_cookie_t c;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mac_register_t *macp = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int ret;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int unit;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int nports;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff unit = ddi_get_instance(dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((nports = gc->gc_nports) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff nports = 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (nports == 1) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_set_driver_private(dip, NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT, "!gem%d: gem_do_attach: called cmd:ATTACH",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff unit));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Allocate soft data structure
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp = kmem_zalloc(GEM_LOCAL_DATA_SIZE(gc), KM_SLEEP);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "!gem%d: %s: mac_alloc failed",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff unit, __func__);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* ddi_set_driver_private(dip, dp); */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* link to private area */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->private = lp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->priv_size = lmsize;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mc_list = (struct mcast_addr *)&dp[1];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->dip = dip;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) sprintf(dp->name, gc->gc_name, nports * unit + port);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Get iblock cookie
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ddi_get_iblock_cookie(dip, 0, &c) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: gem_do_attach: ddi_get_iblock_cookie: failed",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_free_private;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->iblock_cookie = c;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Initialize mutex's for this device.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_init(&dp->intrlock, NULL, MUTEX_DRIVER, (void *)c);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_init(&dp->xmitlock, NULL, MUTEX_DRIVER, (void *)c);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cv_init(&dp->tx_drain_cv, NULL, CV_DRIVER, NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * configure gem parameter
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->base_addr = base;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->regs_handle = *regs_handlep;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc = *gc;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc = &dp->gc;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* patch for simplify dma resource management */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gc->gc_tx_max_frags = 1;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gc->gc_tx_max_descs_per_pkt = 1;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gc->gc_tx_ring_size = gc->gc_tx_buf_size;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gc->gc_tx_ring_limit = gc->gc_tx_buf_limit;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gc->gc_tx_desc_write_oo = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc->gc_nports = nports; /* fix nports */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* fix copy threadsholds */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc->gc_tx_copy_thresh = max(ETHERMIN, gc->gc_tx_copy_thresh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc->gc_rx_copy_thresh = max(ETHERMIN, gc->gc_rx_copy_thresh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* fix rx buffer boundary for iocache line size */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(gc->gc_dma_attr_txbuf.dma_attr_align-1 == gc->gc_tx_buf_align);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(gc->gc_dma_attr_rxbuf.dma_attr_align-1 == gc->gc_rx_buf_align);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc->gc_rx_buf_align = max(gc->gc_rx_buf_align, IOC_LINESIZE - 1);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc->gc_dma_attr_rxbuf.dma_attr_align = gc->gc_rx_buf_align + 1;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* fix descriptor boundary for cache line size */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff gc->gc_dma_attr_desc.dma_attr_align =
23d366e350386ec109bfa9b2cf91225729a1a26bduboff max(gc->gc_dma_attr_desc.dma_attr_align, IOC_LINESIZE);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* patch get_packet method */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gc->gc_get_packet == NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc->gc_get_packet = &gem_get_packet_default;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* patch get_rx_start method */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gc->gc_rx_start == NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc->gc_rx_start = &gem_rx_start_default;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* calculate descriptor area */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gc->gc_rx_desc_unit_shift >= 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_desc_size =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ROUNDUP(gc->gc_rx_ring_size << gc->gc_rx_desc_unit_shift,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc->gc_dma_attr_desc.dma_attr_align);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gc->gc_tx_desc_unit_shift >= 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_desc_size =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ROUNDUP(gc->gc_tx_ring_size << gc->gc_tx_desc_unit_shift,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gc->gc_dma_attr_desc.dma_attr_align);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mtu = ETHERMTU;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_buf = (void *)&dp->mc_list[GEM_MAXMC];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* link tx buffers */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < dp->gc.gc_tx_buf_size; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->tx_buf[i].txb_next =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff &dp->tx_buf[SLOT(i + 1, dp->gc.gc_tx_buf_size)];
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->speed = GEM_SPD_10; /* default is 10Mbps */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->full_duplex = B_FALSE; /* default is half */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->flow_control = FLOW_CONTROL_NONE;
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->poll_pkt_delay = 8; /* typical coalease for rx packets */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* performance tuning parameters */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->txthr = ETHERMAX; /* tx fifo threshold */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->txmaxdma = 16*4; /* tx max dma burst size */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxthr = 128; /* rx fifo threshold */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmaxdma = 16*4; /* rx max dma burst size */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Get media mode information from .conf file
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_read_conf(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* rx_buf_len is required buffer length without padding for alignment */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_len = MAXPKTBUF(dp) + dp->gc.gc_rx_header_len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Reset the chip
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state = NIC_STATE_STOPPED;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ret = (*dp->gc.gc_reset_chip)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ret != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_free_regs;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * HW dependant paremeter initialization
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ret = (*dp->gc.gc_attach_chip)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ret != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_free_regs;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#ifdef DEBUG_MULTIFRAGS
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_tx_copy_thresh = dp->mtu;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* allocate tx and rx resources */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_alloc_memory(dp)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_free_regs;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: at 0x%x, %02x:%02x:%02x:%02x:%02x:%02x",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, (long)dp->base_addr,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->dev_addr.ether_addr_octet[0],
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->dev_addr.ether_addr_octet[1],
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->dev_addr.ether_addr_octet[2],
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->dev_addr.ether_addr_octet[3],
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->dev_addr.ether_addr_octet[4],
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->dev_addr.ether_addr_octet[5]));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* copy mac address */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->cur_addr = dp->dev_addr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_gld3_init(dp, macp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Probe MII phy (scan phy) */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_lpable = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_advert = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_exp = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_ctl1000 = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mii_stat1000 = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_mii_probe)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_free_ring;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* mask unsupported abilities */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->anadv_autoneg &= BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000fdx &=
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff BOOLEAN(dp->mii_xstatus &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_1000hdx &=
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff BOOLEAN(dp->mii_xstatus &
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100t4 &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100fdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_100hdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10fdx &= BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->anadv_10hdx &= BOOLEAN(dp->mii_status & MII_STATUS_10);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_choose_forcedmode(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* initialize MII phy if required */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_mii_init) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_mii_init)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_free_ring;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * initialize kstats including mii statistics
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_setup(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Add interrupt to system.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ret = mac_register(macp, &dp->mh)) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "!%s: mac_register failed, error:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, ret);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_release_stats;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mac_free(macp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff macp = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->misc_flag & GEM_SOFTINTR) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ddi_add_softintr(dip,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_SOFTINT_LOW, &dp->soft_id,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff NULL, NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (uint_t (*)(caddr_t))gem_intr,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (caddr_t)dp) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "!%s: ddi_add_softintr failed",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_unregister;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if ((dp->misc_flag & GEM_NOINTR) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (ddi_add_intr(dip, 0, NULL, NULL,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (uint_t (*)(caddr_t))gem_intr,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (caddr_t)dp) != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "!%s: ddi_add_intr failed", dp->name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_unregister;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Dont use interrupt.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * schedule first call of gem_intr_watcher
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->intr_watcher_id =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff timeout((void (*)(void *))gem_intr_watcher,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void *)dp, drv_usectohz(3*1000000));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* link this device to dev_info */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->next = (struct gem_dev *)ddi_get_driver_private(dip);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff dp->port = port;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_set_driver_private(dip, (caddr_t)dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* reset mii phy and start mii link watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_start(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT, "!gem_do_attach: return: success"));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr_unregister:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) mac_unregister(dp->mh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr_release_stats:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* release NDD resources */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_cleanup(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr_free_ring:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_free_memory(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr_free_regs:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_regs_map_free(&dp->regs_handle);
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr_free_locks:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_destroy(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_destroy(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cv_destroy(&dp->tx_drain_cv);
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr_free_private:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (macp) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mac_free(macp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff kmem_free((caddr_t)dp, GEM_LOCAL_DATA_SIZE(gc));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (NULL);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_do_detach(dev_info_t *dip)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *tmp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff caddr_t private;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int priv_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_acc_handle_t rh;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp = GEM_GET_DEV(dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp == NULL) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff rh = dp->regs_handle;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff private = dp->private;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff priv_size = dp->priv_size;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (dp) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff /* unregister with gld v3 */
23d366e350386ec109bfa9b2cf91225729a1a26bduboff if (mac_unregister(dp->mh) != 0) {
23d366e350386ec109bfa9b2cf91225729a1a26bduboff return (DDI_FAILURE);
23d366e350386ec109bfa9b2cf91225729a1a26bduboff }
23d366e350386ec109bfa9b2cf91225729a1a26bduboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* ensure any rx buffers are not used */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->rx_buf_allocated != dp->rx_buf_freecnt) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* resource is busy */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_PANIC,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s: %s: rxbuf is busy: allocated:%d, freecnt:%d",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rx_buf_allocated, dp->rx_buf_freecnt);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* NOT REACHED */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* stop mii link watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_stop(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* unregister interrupt handler */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->misc_flag & GEM_SOFTINTR) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_remove_softintr(dp->soft_id);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else if ((dp->misc_flag & GEM_NOINTR) == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_remove_intr(dip, 0, dp->iblock_cookie);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff } else {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* stop interrupt watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->intr_watcher_id) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (untimeout(dp->intr_watcher_id) == -1)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->intr_watcher_id = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* release NDD resources */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_nd_cleanup(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* release buffers, descriptors and dma resources */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_free_memory(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* release locks and condition variables */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_destroy(&dp->xmitlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_destroy(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cv_destroy(&dp->tx_drain_cv);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* release basic memory resources */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff tmp = dp->next;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff kmem_free((caddr_t)dp, GEM_LOCAL_DATA_SIZE(&dp->gc));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp = tmp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* release common private memory for the nic */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff kmem_free(private, priv_size);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* release register mapping resources */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_regs_map_free(&rh);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(2, (CE_CONT, "!%s%d: gem_do_detach: return: success",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_driver_name(dip), ddi_get_instance(dip)));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_suspend(dev_info_t *dip)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * stop the device
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp = GEM_GET_DEV(dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (; dp; dp = dp->next) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* stop mii link watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_stop(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* stop interrupt watcher for no-intr mode */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->misc_flag & GEM_NOINTR) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->intr_watcher_id) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (untimeout(dp->intr_watcher_id) == -1)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->intr_watcher_id = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* stop tx timeout watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->timeout_id) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (untimeout(dp->timeout_id) == -1)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->timeout_id = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* make the nic state inactive */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) gem_mac_stop(dp, 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(!dp->mac_active);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* no further register access */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mac_suspended = B_TRUE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* XXX - power down the nic */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_resume(dev_info_t *dip)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct gem_dev *dp;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * restart the device
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp = GEM_GET_DEV(dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (; dp; dp = dp->next) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Bring up the nic after power up
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* gem_xxx.c layer to setup power management state. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(!dp->mac_active);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* reset the chip, because we are just after power up. */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->mac_suspended = B_FALSE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state = NIC_STATE_STOPPED;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_reset_chip)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN, "%s: %s: failed to reset chip",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->name, __func__);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* initialize mii phy because we are just after power up */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->gc.gc_mii_init) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void) (*dp->gc.gc_mii_init)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->misc_flag & GEM_NOINTR) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * schedule first call of gem_intr_watcher
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * instead of interrupts.
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->intr_watcher_id =
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff timeout((void (*)(void *))gem_intr_watcher,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void *)dp, drv_usectohz(3*1000000));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* restart mii link watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff gem_mii_start(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* restart mac */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_mac_init(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_reset;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state = NIC_STATE_INITIALIZED;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* setup media mode if the link have been up */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_state == MII_STATE_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((dp->gc.gc_set_media)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_reset;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* enable mac address and rx filter */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->rxmode |= RXMODE_ENABLE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((*dp->gc.gc_set_rx_filter)(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_reset;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state = NIC_STATE_ONLINE;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* restart tx timeout watcher */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->timeout_id = timeout((void (*)(void *))gem_tx_timeout,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (void *)dp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->gc.gc_tx_timeout_interval);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* now the nic is fully functional */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->mii_state == MII_STATE_LINKUP) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (gem_mac_start(dp) != GEM_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto err_reset;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr_reset:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (dp->intr_watcher_id) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (untimeout(dp->intr_watcher_id) == -1)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->intr_watcher_id = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_enter(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff (*dp->gc.gc_reset_chip)(dp);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff dp->nic_state = NIC_STATE_STOPPED;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mutex_exit(&dp->intrlock);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615dubofferr:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * misc routines for PCI
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffuint8_t
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_search_pci_cap(dev_info_t *dip,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_acc_handle_t conf_handle, uint8_t target)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint8_t pci_cap_ptr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint32_t pci_cap;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* search power management capablities */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff pci_cap_ptr = pci_config_get8(conf_handle, PCI_CONF_CAP_PTR);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff while (pci_cap_ptr) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* read pci capability header */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff pci_cap = pci_config_get32(conf_handle, pci_cap_ptr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((pci_cap & 0xff) == target) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* found */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff break;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* get next_ptr */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff pci_cap_ptr = (pci_cap >> 8) & 0xff;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (pci_cap_ptr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_pci_set_power_state(dev_info_t *dip,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_acc_handle_t conf_handle, uint_t new_mode)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint8_t pci_cap_ptr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint32_t pmcsr;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t unit;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff const char *drv_name;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(new_mode < 4);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff unit = ddi_get_instance(dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff drv_name = ddi_driver_name(dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* search power management capablities */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff pci_cap_ptr = gem_search_pci_cap(dip, conf_handle, PCI_CAP_ID_PM);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if (pci_cap_ptr == 0) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s%d: doesn't have pci power management capability",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff drv_name, unit);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* read power management capabilities */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff pmcsr = pci_config_get32(conf_handle, pci_cap_ptr + PCI_PMCSR);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DPRINTF(0, (CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s%d: pmc found at 0x%x: pmcsr: 0x%08x",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff drv_name, unit, pci_cap_ptr, pmcsr));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * Is the resuested power mode supported?
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* not yet */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * move to new mode
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff pmcsr = (pmcsr & ~PCI_PMCSR_STATE_MASK) | new_mode;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff pci_config_put32(conf_handle, pci_cap_ptr + PCI_PMCSR, pmcsr);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_SUCCESS);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff/*
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * select suitable register for by specified address space or register
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff * offset in PCI config space
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffint
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_pci_regs_map_setup(dev_info_t *dip, uint32_t which, uint32_t mask,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct ddi_device_acc_attr *attrp,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff caddr_t *basep, ddi_acc_handle_t *hp)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff struct pci_phys_spec *regs;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t len;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t unit;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t n;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff uint_t i;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff int ret;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff const char *drv_name;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff unit = ddi_get_instance(dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff drv_name = ddi_driver_name(dip);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* Search IO-range or memory-range to be mapped */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff regs = NULL;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff len = 0;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((ret = ddi_prop_lookup_int_array(
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "reg", (void *)&regs, &len)) != DDI_PROP_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_WARN,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s%d: failed to get reg property (ret:%d)",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff drv_name, unit, ret);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff n = len / (sizeof (struct pci_phys_spec) / sizeof (int));
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ASSERT(regs != NULL && len > 0);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#if GEM_DEBUG_LEVEL > 0
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < n; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s%d: regs[%d]: %08x.%08x.%08x.%08x.%08x",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff drv_name, unit, i,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff regs[i].pci_phys_hi,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff regs[i].pci_phys_mid,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff regs[i].pci_phys_low,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff regs[i].pci_size_hi,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff regs[i].pci_size_low);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff#endif
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff for (i = 0; i < n; i++) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((regs[i].pci_phys_hi & mask) == which) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff /* it's the requested space */
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_prop_free(regs);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff goto address_range_found;
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff ddi_prop_free(regs);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (DDI_FAILURE);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffaddress_range_found:
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff if ((ret = ddi_regs_map_setup(dip, i, basep, 0, 0, attrp, hp))
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff != DDI_SUCCESS) {
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff cmn_err(CE_CONT,
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff "!%s%d: ddi_regs_map_setup failed (ret:%d)",
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff drv_name, unit, ret);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff }
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff return (ret);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffvoid
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mod_init(struct dev_ops *dop, char *name)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mac_init_ops(dop, name);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffvoid
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboffgem_mod_fini(struct dev_ops *dop)
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff{
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff mac_fini_ops(dop);
f8919bdadda3ebb97bd55cc14a16e0271ed57615duboff}