dnet.c revision bdb9230ac765cb7af3fc1f4119caf2c5720dceb3
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* dnet -- DEC 21x4x
*
* Currently supports:
* 21040, 21041, 21140, 21142, 21143
* SROM versions 1, 3, 3.03, 4
* TP, AUI, BNC, 100BASETX, 100BASET4
*
* XXX NEEDSWORK
* All media SHOULD work, FX is untested
*
*/
#define BUG_4010796 /* See 4007871, 4010796 */
#include <sys/ethernet.h>
#include "dnet_mii.h"
#include "dnet.h"
char _depends_on[] = "misc/gld";
/*
* Declarations and Module Linkage
*/
#define IDENT "DNET 21x4x"
/*
* #define DNET_NOISY
* #define SROMDEBUG
* #define SROMDUMPSTRUCTURES
*/
#ifdef DNETDEBUG
#ifdef DNET_NOISY
int dnetdebug = -1;
#else
int dnetdebug = 0;
#endif
#endif
/* used for message allocated using desballoc() */
struct free_ptr {
};
struct rbuf_list {
};
/* Required system entry points */
static int dnetprobe(dev_info_t *);
/* Required driver entry points for GLD */
static int dnet_reset(gld_mac_info_t *);
static int dnet_start_board(gld_mac_info_t *);
static int dnet_stop_board(gld_mac_info_t *);
static int dnet_set_promiscuous(gld_mac_info_t *, int);
/* Internal functions used by the above entry points */
static void dnet_reset_board(gld_mac_info_t *);
static void dnet_init_board(gld_mac_info_t *);
static void dnet_chip_init(gld_mac_info_t *);
static int dnet_start(gld_mac_info_t *);
static int dnet_set_addr(gld_mac_info_t *);
static void dnet_getp(gld_mac_info_t *);
static void update_rx_stats(gld_mac_info_t *, int);
static void update_tx_stats(gld_mac_info_t *, int);
/* Media Selection Setup Routines */
/* Buffer Management Routines */
static int dnet_alloc_bufs(gld_mac_info_t *);
static void dnet_free_bufs(gld_mac_info_t *);
static void dnet_init_txrx_bufs(gld_mac_info_t *);
static int alloc_descriptor(gld_mac_info_t *);
static void dnet_reclaim_Tx_desc(gld_mac_info_t *);
static int dnet_rbuf_init(dev_info_t *, int);
static int dnet_rbuf_destroy();
static void dnet_rbuf_free(caddr_t);
static void dnet_freemsg_buf(struct free_ptr *);
/* SROM read functions */
uchar_t *, int);
uchar_t *, int *);
#ifdef BUG_4010796
static int dnethack(dev_info_t *);
#endif
static int dnet_hack_interrupts(gld_mac_info_t *, int);
/* SROM parsing functions */
static int check_srom_valid(uchar_t *);
static void setup_legacy_blocks();
/* Active Media Determination Routines */
static void find_active_media(gld_mac_info_t *);
static int send_test_packet(gld_mac_info_t *);
/* PHY MII Routines */
int reg_dat);
static void mii_tristate(struct dnetinstance *);
static void do_phy(gld_mac_info_t *);
#ifdef DNETDEBUG
void dnet_timestamp(struct dnetinstance *, char *);
#endif
static char *media_str[] = {
"10BaseT",
"10Base2",
"10Base5",
"100BaseTX",
"10BaseT FD",
"100BaseTX FD",
"100BaseT4",
"100BaseFX",
"100BaseFX FD",
"MII"
};
/* default SROM info for cards with no SROMs */
static LEAF_FORMAT leaf_default_100;
static LEAF_FORMAT leaf_asante;
static LEAF_FORMAT leaf_phylegacy;
static LEAF_FORMAT leaf_cogent_100;
static LEAF_FORMAT leaf_21041;
static LEAF_FORMAT leaf_21040;
int max_tx_desc = MAX_TX_DESC;
/* used for buffers allocated by ddi_dma_mem_alloc() */
static ddi_dma_attr_t dma_attr = {
DMA_ATTR_V0, /* dma_attr version */
0, /* dma_attr_addr_lo */
0x7FFFFFFF, /* dma_attr_count_max */
4, /* dma_attr_align */
0x3F, /* dma_attr_burstsizes */
1, /* dma_attr_minxfer */
1, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0, /* dma_attr_flags */
};
/* used for buffers allocated for rbuf, allow 2 cookies */
static ddi_dma_attr_t dma_attr_rb = {
DMA_ATTR_V0, /* dma_attr version */
0, /* dma_attr_addr_lo */
0x7FFFFFFF, /* dma_attr_count_max */
4, /* dma_attr_align */
0x3F, /* dma_attr_burstsizes */
1, /* dma_attr_minxfer */
2, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0, /* dma_attr_flags */
};
/* used for buffers which are NOT from ddi_dma_mem_alloc() - xmit side */
static ddi_dma_attr_t dma_attr_tx = {
DMA_ATTR_V0, /* dma_attr version */
0, /* dma_attr_addr_lo */
0x7FFFFFFF, /* dma_attr_count_max */
1, /* dma_attr_align */
0x3F, /* dma_attr_burstsizes */
1, /* dma_attr_minxfer */
0x7FFF, /* dma_attr_sgllen */
1, /* dma_attr_granular */
0, /* dma_attr_flags */
};
static ddi_device_acc_attr_t accattr = {
};
/* Standard Streams initialization */
static struct module_info minfo = {
};
};
};
/* Standard Module linkage initialization for a Streams driver */
extern struct mod_ops mod_driverops;
static struct cb_ops cb_dnetops = {
nulldev, /* cb_open */
nulldev, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
nodev, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
nodev, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
&dnetinfo, /* cb_stream */
};
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
gld_getinfo, /* devo_getinfo */
nulldev, /* devo_identify */
dnetprobe, /* devo_probe */
dnetattach, /* devo_attach */
dnetdetach, /* devo_detach */
nodev, /* devo_reset */
&cb_dnetops, /* devo_cb_ops */
NULL, /* devo_power */
ddi_quiesce_not_supported, /* devo_quiesce */
};
&mod_driverops, /* Type of module. This one is a driver */
IDENT, /* short description */
&dnetops /* driver specific ops */
};
static struct modlinkage modlinkage = {
};
/*
* Passed to the hacked interrupt for multiport Cogent and ZNYX cards with
* dodgy interrupt routing
*/
struct hackintr_inf
{
/* Ensures the interrupt doesn't get called while detaching */
};
static char hackintr_propname[] = "InterruptData";
static char macoffset_propname[] = "MAC_offset";
static char speed_propname[] = "speed";
static char ofloprob_propname[] = "dmaworkaround";
static char printsrom_propname[] = "print-srom";
/*
* ========== Module Loading Entry Points ==========
*/
int
_init(void)
{
int i;
/* Configure fake sroms for legacy cards */
if ((i = mod_install(&modlinkage)) != 0) {
}
return (i);
}
int
_fini(void)
{
int i;
/* loop until all the receive buffers are freed */
while (dnet_rbuf_destroy() != 0) {
#ifdef DNETDEBUG
#endif
}
}
return (i);
}
int
{
}
/*
* ========== DDI Entry Points ==========
*/
/*
* probe(9E) -- Determine if a device is present
*/
static int
{
#ifdef DNETDEBUG
#endif
return (DDI_PROBE_FAILURE);
if (vendorid != DEC_VENDOR_ID) {
return (DDI_PROBE_FAILURE);
}
switch (deviceid) {
case DEVICE_ID_21040:
case DEVICE_ID_21041:
case DEVICE_ID_21140:
case DEVICE_ID_21143: /* And 142 */
break;
default:
return (DDI_PROBE_FAILURE);
}
#ifndef BUG_4010796
return (DDI_PROBE_SUCCESS);
#else
#endif
}
#ifdef BUG_4010796
/*
* If we have a device, but we cannot presently access its SROM data,
* then we return DDI_PROBE_PARTIAL and hope that sometime later we
* will be able to get at the SROM data. This can only happen if we
* are a secondary port with no SROM, and the bootstrap failed to set
* our DNET_SROM property, and our primary sibling has not yet probed.
*/
static int
{
int secondary;
#define DNET_PCI_RNUMBER 1
#ifdef DNETDEBUG
#endif
return (DDI_PROBE_FAILURE);
/*
* Turn on Master Enable and IO Enable bits.
*/
/* Now map I/O register */
return (DDI_PROBE_FAILURE);
}
/*
* Reset the chip
*/
drv_usecwait(3);
drv_usecwait(8);
switch (secondary) {
case -1:
/* We can't access our SROM data! */
break;
case 0:
break;
default:
}
return (retval);
}
#endif /* BUG_4010796 */
/*
* attach(9E) -- Attach a device to the system
*
* Called once for each board successfully probed.
*/
static int
{
int secondary;
#define DNET_PCI_RNUMBER 1
#ifdef DNETDEBUG
#endif
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
/* Get the driver private (gld_mac_info_t) structure */
dnetp->need_gld_sched = 0;
(void) dnet_start(macinfo);
} else {
}
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
return (DDI_FAILURE);
switch (deviceid) {
case DEVICE_ID_21040:
case DEVICE_ID_21041:
case DEVICE_ID_21140:
case DEVICE_ID_21143: /* And 142 */
break;
default:
return (DDI_FAILURE);
}
/*
* Turn on Master Enable and IO Enable bits.
*/
/* Make sure the device is not asleep */
/*
* Allocate gld_mac_info_t and dnetinstance structures
*/
return (DDI_FAILURE);
if ((dnetp = (struct dnetinstance *)
return (DDI_FAILURE);
}
/* Now map I/O register */
return (DDI_FAILURE);
}
/*
* Initialize our private fields in macinfo and dnetinstance
*/
/*
* Initialize pointers to device specific functions which will be
* used by the generic layer.
*/
/*
* Initialize board characteristics needed by the generic layer.
*/
/* Other required initialization */
/*
* Get the iblock cookie with which to initialize the mutexes.
*/
!= DDI_SUCCESS)
goto fail;
/*
* Initialize mutex's for this device.
* Do this before registering the interrupt handler to avoid
* condition where interrupt handler can try using uninitialized
* mutex.
* Lock ordering rules: always lock intrlock first before
* txlock if both are required.
*/
/*
*/
"bncaui", -1);
/*
* For 21140 check the data rate set in the conf file. Default is
* 100Mb/s. Disallow connections at settings that would conflict
* with what's in the conf file
*/
speed_propname, 0);
dnetp->full_duplex =
duplex_propname, -1);
}
} else if (dnetp->full_duplex == 0) {
}
goto fail1;
printsrom_propname, 0))
/*
* determine whether to implement workaround from DEC
* for DMA overrun errata.
*/
/*
* Add the interrupt handler if dnet_hack_interrupts() returns 0.
* Otherwise dnet_hack_interrupts() itself adds the handler.
*/
}
/* Allocate the TX and RX descriptors/buffers. */
goto fail2;
}
/*
* Register ourselves with the GLD interface
*
* gld_register will:
* link us with the GLD system;
* set our ddi_set_driver_private(9F) data to the macinfo pointer;
* save the devinfo pointer in macinfo->gldm_devinfo;
* map the registers, putting the kvaddr into macinfo->gldm_memp;
* add the interrupt, putting the cookie in gldm_cookie;
* init the gldm_intrlock mutex which will block that interrupt;
* create the minor node.
*/
/* if the chosen media is non-MII, stop the port monitor */
}
#ifdef DNETDEBUG
#endif
/* XXX function return value ignored */
/* dropped intrlock as dnet_stop_board() grabs intrlock */
(void) dnet_stop_board(macinfo);
return (DDI_SUCCESS);
}
/* XXX function return value ignored */
/*
* dnet_detach_hacked_interrupt() will remove
* interrupt for the non-hacked case also.
*/
(void) dnet_detach_hacked_interrupt(devinfo);
fail:
return (DDI_FAILURE);
}
/*
* detach(9E) -- Detach a device from the system
*/
static int
{
#ifdef DNETDEBUG
#endif
/* Get the driver private (gld_mac_info_t) structure */
switch (cmd) {
case DDI_DETACH:
break;
case DDI_SUSPEND:
/*
* NB: dnetp->suspended can only be modified (marked true)
* if both intrlock and txlock are held. This keeps both
* tx and rx code paths excluded.
*/
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
/*
* Unregister ourselves from the GLD interface
*
* gld_unregister will:
* remove the minor node;
* unmap the registers;
* remove the interrupt;
* destroy the gldm_intrlock mutex;
* unlink us from the GLD system.
*/
return (DDI_FAILURE);
/* stop the board if it is running */
return (rc);
/* Free leaf information */
#ifdef BUG_4010796
return (DDI_SUCCESS);
/*
* We must remove the properties we added, because if we leave
* them in the devinfo nodes and the driver is unloaded, when
* the driver is reloaded the info will still be there, causing
* nodes which had returned PROBE_PARTIAL the first time to
* instead return PROBE_SUCCESS, in turn causing the nodes to be
* attached in a different order, causing their PPA numbers to
* be different the second time around, which is undesirable.
*/
"DNET_SROM");
"DNET_DEVNUM");
#endif
return (DDI_SUCCESS);
}
/*
* ========== GLD Entry Points ==========
*/
/*
* dnet_reset() -- reset the board to initial state;
*/
static int
{
#ifdef DNETDEBUG
#endif
/*
* Initialize internal data structures
*/
dnetp->need_saddr = 0;
return (0);
}
"reset_do_find_active_media", 0)) {
/* Go back to a good state */
}
return (0);
}
static void
{
/*
* before initializing the dnet should be in STOP state
*/
/* XXX function return value ignored */
/* (void) dnet_stop_board(macinfo); */
/*
* Reset the chip
*/
drv_usecwait(5);
}
/*
* dnet_init_board() -- initialize the specified network board short of
* actually starting the board. Call after dnet_reset_board().
* called with intrlock held.
*/
static void
{
#ifdef DNETDEBUG
#endif
}
/* dnet_chip_init() - called with intrlock held */
static void
{
(macinfo->gldm_private);
/*
* Initialize the TX and RX descriptors/buffers
*/
/*
* Set the base address of the Rx descriptor list in CSR3
*/
/*
* Set the base address of the Tx descrptor list in CSR4
*/
dnetp->transmitted_desc = 0;
}
/*
* dnet_start() -- start the board receiving and allow transmits.
* Called with intrlock held.
*/
static int
{
#ifdef DNETDEBUG
#endif
/*
* start the board and enable receiving
*/
val | START_TRANSMIT);
(void) dnet_set_addr(macinfo);
val | START_RECEIVE);
return (0);
}
/*
* dnet_start_board() -- start the board receiving and allow transmits.
*/
static int
{
#ifdef DNETDEBUG
#endif
/*
* start the board and enable receiving
*/
(void) dnet_start(macinfo);
return (0);
}
/*
* dnet_stop_board() -- stop board receiving
*/
static int
{
#ifdef DNETDEBUG
#endif
/*
*/
}
return (0);
}
/*
* dnet_set_addr() -- set the physical network address on the board
* Called with intrlock held.
*/
static int
{
struct tx_desc_type *desc;
int current_desc;
#ifdef DNETDEBUG
#endif
if (!(val & START_TRANSMIT))
return (0);
dnetp->need_saddr = 0;
#ifdef DNETDEBUG
#endif
return (0);
}
return (0);
}
/*
* dnet_set_mac_addr() -- set the physical network address on the board
*/
static int
{
#ifdef DNETDEBUG
#endif
/*
* As we are using Imperfect filtering, the broadcast address has to
* be set explicitly in the 512 bit hash table. Hence the index into
* the hash table is calculated and the bit set to enable reception
* of broadcast packets.
*
* We also use HASH_ONLY mode, without using the perfect filter for
* our station address, because there appears to be a bug in the
* 21140 where it fails to receive the specified perfect filter
* address.
*
* Since dlsdmult comes through here, it doesn't matter that the count
* is wrong for the two bits that correspond to the cases below. The
* worst that could happen is that we'd leave on a bit for an old
* macaddr, in the case where the macaddr gets changed, which is rare.
* Since filtering is imperfect, it is OK if that happens.
*/
(void) dnet_set_addr(macinfo);
return (0);
}
/*
* dnet_set_multicast() -- set (enable) or disable a multicast address
*
* in "mcast". Enable if "op" is non-zero, disable if zero.
*/
static int
{
#ifdef DNETDEBUG
#endif
if (op == GLD_MULTI_ENABLE) {
return (0);
}
} else {
return (0);
}
}
else
retval = 0;
return (retval);
}
/*
* A hashing function used for setting the
* node address or a multicast address
*/
static uint32_t
{
crc <<= 1;
crc |= 0x00000001;
}
currentbyte >>= 1;
}
}
}
return (index);
}
/*
* dnet_set_promiscuous() -- set or reset promiscuous mode on the board
*
* Enable if "on" is non-zero, disable if zero.
*/
static int
{
struct dnetinstance *dnetp;
#ifdef DNETDEBUG
#endif
return (SUCCESS);
}
if (on != GLD_MAC_PROMISC_NONE)
else
}
return (DDI_SUCCESS);
}
/*
* dnet_get_stats() -- update statistics
*
* GLD calls this routine just before it reads the driver's statistics
* structure. If your board maintains statistics, this is the time to
* read them in and update the values in the structure. If the driver
* maintains statistics continuously, this routine need do nothing.
*/
static int
{
#ifdef DNETDEBUG
#endif
/* stats from instance structure */
} else {
sp->glds_duplex =
}
return (DDI_SUCCESS);
}
/*
* dnet_send() -- send a packet
*
* Called when a packet is ready to be transmitted. A pointer to an
* M_DATA message that contains the packet is passed to this routine.
* The complete LLC header is contained in the message's first message
* block, and the remainder of the packet is contained within
* additional M_DATA message blocks linked to the first message block.
*/
static int
{
int avail;
int error;
int bufn;
int bp_count;
int retval;
#ifdef DNETDEBUG
#endif
/* if suspended, drop the packet on the floor, we missed it */
return (0);
}
if (dnetp->need_saddr) {
/* XXX function return value ignored */
(void) dnet_set_addr(macinfo);
}
/* reclaim any xmit descriptors completed */
/*
* Use the data buffers from the message and construct the
*/
totlen = 0;
bufn = 0;
if (++bp_count > DNET_MAX_FRAG) {
#ifndef DNET_NOISY
#else
else
"DNET: couldn't pullup send msg");
#endif
}
if (!mblen) { /* skip zero-length message blocks */
continue;
}
&dma_cookie, &ncookies);
switch (retval) {
case DDI_DMA_MAPPED:
break; /* everything's fine */
case DDI_DMA_NORESOURCES:
break;
case DDI_DMA_NOMAPPING:
case DDI_DMA_INUSE:
case DDI_DMA_TOOBIG:
default:
break;
}
/*
* we can use two cookies per descriptor (i.e buffer1 and
* buffer2) so we need at least (ncookies+1)/2 descriptors.
*/
error = 1;
break;
}
/* setup the descriptors for this data buffer */
while (ncookies) {
if (bufn % 2) {
} else {
/* initialize the descriptor */
}
bufn++;
if (--ncookies)
&dma_cookie);
}
}
if (error == 1) {
dnetp->stat_defer++;
return (GLD_TX_RESEND);
} else if (error) {
return (0); /* Drop packet, don't retry */
}
return (0); /* We don't want to repeat this attempt */
}
/*
* Remeber the message buffer pointer to do freemsg() at xmit
* interrupt time.
*/
/*
* Since the 21040 looks for these bits set in the
* first buffer, work backwards in multiple buffers.
*/
/*
* Safety check: make sure end-of-ring is set in last desc.
*/
/*
* Enable xmit interrupt if we are running out of xmit descriptors
* or there are more packets on the queue waiting to be transmitted.
*/
#ifdef GLD_INTR_WAIT /* XXX This relies on new GLD changes */
else
TX_INTERRUPT_MASK : 0;
#else
#endif
/*
* Kick the transmitter
*/
return (GLD_TX_OK); /* successful transmit attempt */
}
/*
* dnetintr() -- interrupt from board to inform us that a receive or
* transmit has completed.
*/
static uint_t
{
#ifdef DNETDEBUG
#endif
return (DDI_INTR_UNCLAIMED);
}
STATUS_REG));
/*
* If interrupt was not from this board
*/
return (DDI_INTR_UNCLAIMED);
}
if (int_status & GPTIMER_INTR) {
else
}
if (int_status & TX_INTR) {
if (dnetp->need_gld_sched) {
dnetp->need_gld_sched = 0;
}
/* reclaim any xmit descriptors that are completed */
}
/*
* Check if receive interrupt bit is set
*/
}
if (int_status & ABNORMAL_INTR_SUMM) {
/*
* Check for system error
*/
if (int_status & SYS_ERR) {
}
/*
* If the jabber has timed out then reset the chip
*/
if (int_status & TX_JABBER_TIMEOUT)
/*
* If an underflow has occurred, reset the chip
*/
if (int_status & TX_UNDERFLOW)
#ifdef DNETDEBUG
#endif
/* XXX function return value ignored */
(void) dnet_start(macinfo);
}
/*
* Enable the interrupts. Enable xmit interrupt only if we are
* running out of free descriptors or if there are packets
* in the queue waiting to be transmitted.
*/
#ifdef GLD_INTR_WAIT /* XXX This relies on new GLD changes */
else
TX_INTERRUPT_MASK : 0;
#else
#endif
return (DDI_INTR_CLAIMED); /* Indicate it was our interrupt */
}
static void
{
struct dnetinstance *dnetp =
int packet_length, index;
int misses;
#ifdef DNETDEBUG
#endif
if (!dnetp->overrun_workaround) {
/*
* If the workaround is not in place, we must still update
* the missed frame statistic from the on-chip counter.
*/
}
/* While host owns the current descriptor */
/*
* DMA overrun errata from DEC: avoid possible bus hangs
* and data corruption
*/
if (dnetp->overrun_workaround &&
int opn;
do {
dnetp->stat_missed +=
(misses & MISSED_FRAME_MASK);
if (misses & OVERFLOW_COUNTER_MASK) {
/*
* Overflow(s) have occurred : stop receiver,
* and wait until in stopped state
*/
opn & ~(START_RECEIVE));
do {
drv_usecwait(10);
RECEIVE_PROCESS_STATE) != 0);
#ifdef DNETDEBUG
#endif
/* Discard probably corrupt frames */
dnetp->stat_missed++;
}
/* restart the receiver */
opn | START_RECEIVE);
continue;
}
/*
* At this point, we know that all packets before
* "marker" were received before a dma overrun occurred
*/
}
/*
* If we get an oversized packet it could span multiple
* descriptors. If this happens an error bit should be set.
*/
return; /* not done receiving large packet */
}
#ifdef DNETDEBUG
#endif
}
/*
* Remove CRC from received data. This is an artefact of the
* 21x4x chip and should not be passed higher up the network
* stack.
*/
#ifdef DNETDEBUG
if (packet_length > ETHERMAX)
}
#endif
/* get the virtual address of the packet received */
/*
* If no packet errors then do:
* 1. Allocate a new receive buffer so that we can
* use the current buffer as streams buffer to
* avoid bcopy.
* 2. If we got a new receive buffer then allocate
* an mblk using desballoc().
* 3. Otherwise use the mblk from allocb() and do
* the bcopy.
*/
/*
* Allocate another receive buffer for this descriptor.
* If we fail to allocate then we do the normal bcopy.
*/
}
}
}
}
}
/* Update gld statistics */
else
dnetp->stat_norcvbuf++;
/*
* Reset ownership of the descriptor.
*/
/* Demand receive polling by the chip */
continue;
}
/* attach the new buffer to the rx descriptor */
/* discontiguous */
}
} else {
/* couldn't allocate another buffer; copy the data */
}
/*
* Increment receive desc index. This is for the scan of
* next packet
*/
/* Demand polling by chip */
/* send the packet upstream */
}
}
/*
* Function to update receive statistics
*/
static void
{
struct dnetinstance *dnetp =
/*
* Update gld statistics
*/
dnetp->stat_errrcv++;
/* FIFO Overrun */
dnetp->stat_overflow++;
}
/*EMPTY*/
/* Late Colllision on receive */
/* no appropriate counter */
}
/* CRC Error */
}
/* Runt Error */
dnetp->stat_short++;
}
/*EMPTY*/
/* Not enough receive descriptors */
/* This condition is accounted in dnetintr() */
/* macinfo->gldm_stats.glds_missed++; */
}
dnetp->stat_frame++;
}
}
/*
* Function to update transmit statistics
*/
static void
{
struct dnetinstance *dnetp =
int fd;
/* Update gld statistics */
dnetp->stat_errxmt++;
/* If we're in full-duplex don't count collisions or carrier loss. */
} else {
/* Rely on media code */
}
}
}
dnetp->stat_excoll++;
}
dnetp->stat_underflow++;
}
#if 0
/* no appropriate counter */
}
#endif
dnetp->stat_nocarrier++;
}
dnetp->stat_nocarrier++;
}
}
/*
* ========== Media Selection Setup Routines ==========
*/
static void
{
#ifdef DEBUG
if (dnetdebug & DNETREGCFG)
#endif
switch (dnetp->board_type) {
case DEVICE_ID_21143:
/* Set the correct bit for a control write */
if (val & GPR_CONTROL_WRITE)
/* Write to upper half of CSR15 */
break;
default:
/* Set the correct bit for a control write */
if (val & GPR_CONTROL_WRITE)
break;
}
}
static uint32_t
{
switch (dnetp->board_type) {
case DEVICE_ID_21143:
/* Read upper half of CSR15 */
default:
}
}
static void
{
int len;
int i;
&len) == DDI_PROP_SUCCESS) {
} else {
/*
* Write the reset sequence if this is the first time this
* block has been selected.
*/
/*
* XXX Legacy blocks do not have reset sequences, so the
* static blocks will never be modified by this
*/
}
/* write GPR sequence each time */
}
/* This has possibly caused a PHY to reset. Let MII know */
/* XXX function return value ignored */
drv_usecwait(5);
}
/* set_opr() - must be called with intrlock held */
static void
{
struct dnetinstance *dnetp =
int opnmode_len;
/* Check for custom "opnmode_reg" property */
opnmode_len = sizeof (val);
opnmode_len = 0;
/* Some bits exist only on 21140 and greater */
mb1 = OPN_REG_MB1;
} else {
}
if (opnmode_len) {
return;
}
/*
* Set each bit in CSR6 that we want
*/
/* Always want these bits set */
/* Promiscuous mode */
/* Scrambler for SYM style media */
SCRAMBLER_MODE : 0;
/* Full duplex */
} else {
/* Rely on media code */
}
/* Port select (and therefore, heartbeat disable) */
/* PCS function */
#ifdef DNETDEBUG
if (dnetdebug & DNETREGCFG)
#endif
}
static void
{
(macinfo->gldm_private);
int sia_delay;
#ifdef DNETDEBUG
if (dnetdebug & DNETREGCFG)
"SIA: CSR13: %x, CSR14: %x, CSR15: %x",
#endif
/*
* For '143, we need to write through a copy of the register
* to keep the GP half intact
*/
}
}
/*
* ========== Buffer Management Routines ==========
*/
/*
* This function (re)allocates the receive and transmit buffers and
* descriptors. It can be called more than once per instance, though
* currently it is only called from attach. It should only be called
* while the device is reset.
*/
static int
{
(macinfo->gldm_private);
int i;
int page_size;
int realloc = 0;
int nrecv_desc_old = 0;
/*
* descriptor ring sizes.
*/
realloc = 1;
realloc = 1;
/* free up the old buffers if we are reallocating them */
if (realloc) {
}
return (FAILURE);
return (FAILURE);
return (FAILURE);
return (FAILURE);
/* allocate setup buffer if necessary */
return (FAILURE);
return (FAILURE);
}
/* allocate xmit descriptor array of size dnetp->max_tx_desc */
return (FAILURE);
return (FAILURE);
dnetp->tx_msgbufp =
KM_SLEEP);
}
/* allocate receive descriptor array of size dnetp->max_rx_desc */
int ndesc;
return (FAILURE);
return (FAILURE);
KM_SLEEP);
KM_SLEEP);
/*
* Allocate or add to the pool of receive buffers. The pool
* is shared among all instances of dnet.
*
* XXX NEEDSWORK
*
* We arbitrarily allocate twice as many receive buffers as
* receive descriptors because we use the buffers for streams
* messages to pass the packets up the stream. We should
* instead have initialized constants reflecting
* MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
* probably have a total maximum for the free pool, so that we
* don't get out of hand when someone puts in an 8-port board.
* The maximum for the entire pool should be the total number
* of descriptors for all attached instances together, plus the
* total maximum for the free pool. This maximum would only be
* reached after some number of instances allocate buffers:
* each instance would add (max_rx_buf-max_rx_desc) to the free
* pool.
*/
if ((ndesc > 0) &&
return (FAILURE);
for (i = 0; i < dnetp->max_rx_desc; i++) {
return (FAILURE);
}
}
return (SUCCESS);
}
/*
* free descriptors/buffers allocated for this device instance. This routine
* should only be called while the device is reset.
*/
static void
{
int i;
(macinfo->gldm_private);
/* free up any xmit descriptors/buffers */
/* we use streams buffers for DMA in xmit process */
/* free up any streams message buffers unclaimed */
for (i = 0; i < dnetp->nxmit_desc; i++) {
}
}
}
dnetp->nxmit_desc = 0;
}
/* free up any receive descriptors/buffers */
/* free up the attached rbufs if any */
for (i = 0; i < dnetp->nrecv_desc; i++) {
if (dnetp->rx_buf_vaddr[i])
}
}
dnetp->nrecv_desc = 0;
}
}
}
}
}
}
}
/*
* Initialize transmit and receive descriptors.
*/
static void
{
int i;
(macinfo->gldm_private);
/*
* Initilize all the Tx descriptors
*/
for (i = 0; i < dnetp->nxmit_desc; i++) {
/*
* We may be resetting the device due to errors,
* so free up any streams message buffer unclaimed.
*/
}
}
/*
* Initialize the Rx descriptors
*/
for (i = 0; i < dnetp->nrecv_desc; i++) {
/* discontiguous */
}
}
}
static int
{
int index;
/* we do have free descriptors, right? */
#ifdef DNETDEBUG
#endif
return (FAILURE);
}
/* sanity, make sure the next descriptor is free for use (should be) */
#ifdef DNETDEBUG
"dnet: next descriptor is not free for use");
#endif
return (FAILURE);
}
if (dnetp->need_saddr) {
/* XXX function return value ignored */
(void) dnet_set_addr(macinfo);
goto alloctop;
}
/* hardware will own this descriptor when poll activated */
/* point to next free descriptor to be used */
#ifdef DNET_NOISY
#endif
return (SUCCESS);
}
/*
* dnet_reclaim_Tx_desc() - called with txlock held.
*/
static void
{
(macinfo->gldm_private);
int index;
#ifdef DNETDEBUG
(void *) macinfo);
#endif
/*
* Check for Tx Error that gets set
* in the last desc.
*/
/*
* If we have used the streams message buffer for this
* descriptor then free up the message now.
*/
}
}
}
/*
* Receive buffer allocation/freeing routines.
*
* There is a common pool of receive buffers shared by all dnet instances.
*
* XXX NEEDSWORK
*
* We arbitrarily allocate twice as many receive buffers as
* receive descriptors because we use the buffers for streams
* messages to pass the packets up the stream. We should
* instead have initialized constants reflecting
* MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
* probably have a total maximum for the free pool, so that we
* don't get out of hand when someone puts in an 8-port board.
* The maximum for the entire pool should be the total number
* of descriptors for all attached instances together, plus the
* total maximum for the free pool. This maximum would only be
* reached after some number of instances allocate buffers:
* each instance would add (max_rx_buf-max_rx_desc) to the free
* pool.
*/
static struct rbuf_list *rbuf_usedlist_head;
static struct rbuf_list *rbuf_freelist_head;
static int rbuf_freebufs; /* no. of free buffers in the pool */
static int rbuf_pool_size; /* total no. of buffers in the pool */
/* initialize/add 'nbufs' buffers to the rbuf pool */
/* ARGSUSED */
static int
{
int i;
/* allocate buffers and add them to the pool */
for (i = 0; i < nbufs; i++) {
/* allocate rbuf_list element */
goto fail_kfree;
/* allocate dma memory for the buffer */
goto fail_freehdl;
&ncookies) != DDI_DMA_MAPPED)
goto fail_free;
if (ncookies > 2)
goto fail_unbind;
if (ncookies == 1) {
rp->rbuf_endpaddr =
} else {
rp->rbuf_endpaddr =
}
}
return (0);
return (-1);
}
/*
* Try to free up all the rbufs in the pool. Returns 0 if it frees up all
* buffers. The buffers in the used list are considered busy so these
* buffers are not freed.
*/
static int
{
}
if (rbuf_pool_size) { /* pool is still not empty */
return (-1);
}
return (0);
}
static struct rbuf_list *
{
if (rbuf_freelist_head == NULL) {
if (!cansleep) {
return (NULL);
}
/* allocate rbuf_list element */
goto fail_kfree;
/* allocate dma memory for the buffer */
goto fail_freehdl;
&ncookies) != DDI_DMA_MAPPED)
goto fail_free;
if (ncookies > 2)
goto fail_unbind;
if (ncookies == 1) {
rp->rbuf_endpaddr =
} else {
rp->rbuf_endpaddr =
}
}
/* take the buffer from the head of the free list */
/* update the used list; put the entry at the end */
if (rbuf_usedlist_head == NULL)
else
return (rp);
return (NULL);
}
static void
{
/* find the entry in the used list */
break;
}
(void *)vaddr);
return;
}
/* update the used list and put the buffer back in the free list */
if (rbuf_usedlist_head != rp) {
if (rbuf_usedlist_end == rp)
} else {
if (rbuf_usedlist_end == rp)
}
}
/*
* Free the receive buffer used in a stream's message block allocated
* thru desballoc().
*/
static void
{
}
/*
* ========== SROM Read Routines ==========
*/
/*
* The following code gets the SROM information, either by reading it
* from the device or, failing that, by reading a property.
*/
static int
{
/*
* Load SROM into vendor_info
*/
if (board_type == DEVICE_ID_21040)
else
/* 21041/21140 serial rom */
/*
* If the dumpsrom property is present in the conf file, print
* the contents of the SROM to the console
*/
"dumpsrom", 0))
}
} else {
#ifdef BUG_4010796
#endif
return (0); /* Primary */
}
}
/*
* The function reads the ethernet address of the 21040 adapter
*/
static void
{
int i;
/* No point reading more than the ethernet address */
/* Reset ROM pointer */
for (i = 0; i < *len; i++) {
do {
} while (val & 0x80000000);
}
}
/*
* The function reads the SROM of the 21140 adapter
*/
static void
int maxlen)
{
uint32_t i, j;
rom_addr = 0;
for (i = 0; i < maxlen; i += 2) {
drv_nsecwait(30);
drv_nsecwait(50);
drv_nsecwait(250);
drv_nsecwait(100);
/* command */
drv_nsecwait(150);
drv_nsecwait(250);
drv_nsecwait(250);
drv_nsecwait(250);
drv_nsecwait(100);
drv_nsecwait(150);
drv_nsecwait(250);
drv_nsecwait(100);
/* Address */
drv_nsecwait(150);
drv_nsecwait(250);
drv_nsecwait(100);
}
drv_nsecwait(150);
/* Data */
word = 0;
for (j = 0x8000; j >= 1; j >>= 1) {
drv_nsecwait(100);
drv_nsecwait(150);
word |= j;
drv_nsecwait(250);
}
rom_addr++;
drv_nsecwait(100);
}
}
/*
* XXX NEEDSWORK
*
* Some lame multiport cards have only one SROM, which can be accessed
* only from the "first" 21x4x chip, whichever that one is. If we can't
* get at our SROM, we look for its contents in a property instead, which
* we rely on the bootstrap to have properly set.
* #ifdef BUG_4010796
* We also have a hack to try to set it ourselves, when the "first" port
* attaches, if it has not already been properly set. However, this method
* is not reliable, since it makes the unwarrented assumption that the
* "first" port will attach first.
* #endif
*/
static int
{
int l = len;
return (-1); /* Can't find it! */
/*
* The return value from this routine specifies which port number
* we are. The primary port is denoted port 0. On a QUAD card we
* should return 1, 2, and 3 from this routine. The return value
* is used to modify the ethernet address from the SROM data.
*/
#ifdef BUG_4010796
{
/*
* For the present, we remember the device number of our primary
* sibling and hope we and our other siblings are consecutively
* numbered up from there. In the future perhaps the bootstrap
* will pass us the necessary information telling us which physical
* port we really are.
*/
int assign_len;
int devnum;
int primary_devnum;
"DNET_DEVNUM", -1);
if (primary_devnum == -1)
return (1); /* XXX NEEDSWORK -- We have no better idea */
&assign_len)) != DDI_PROP_SUCCESS)
return (1); /* XXX NEEDSWORK -- We have no better idea */
return (devnum - primary_devnum);
}
#else
return (1); /* XXX NEEDSWORK -- We have no better idea */
#endif
}
#ifdef BUG_4010796
static void
{
int proplen;
int assign_len;
int devnum;
return; /* Already done! */
/* function return value ignored */
"DNET_HACK", "hack");
&assign_len)) == DDI_PROP_SUCCESS) {
/* function return value ignored */
(void) ddi_prop_update_int(DDI_DEV_T_NONE,
}
}
#endif
/*
* ========== SROM Parsing Routines ==========
*/
static int
{
/* verify that the number of controllers on the card is within range */
return (0);
/*
* version 1 and 3 of this card did not check the id block CRC value
* and this can't be changed without retesting every supported card
*
* however version 4 of the SROM can have this test applied
* without fear of breaking something that used to work.
* the CRC algorithm is taken from the Intel document
* "21x4 Serial ROM Format"
* version 4.09
* 3-Mar-1999
*/
switch (vi[SROM_VERSION]) {
case 1:
/* fallthru */
case 3:
case 4:
crc = 0xff;
bitval =
crc <<= 1;
if (bitval == 1) {
crc ^= 7;
}
}
default:
return (0);
}
}
/*
* ========== Active Media Determination Routines ==========
*/
/* This routine is also called for V3 Compact and extended type 0 SROMs */
static int
is_fdmedia(int media)
{
return (1);
else
return (0);
}
/*
* "Linkset" is used to merge media that use the same link test check. So,
* if the TP link is added to the linkset, so is the TP Full duplex link.
* Used to avoid checking the same link status twice.
*/
static void
{
}
static int
{
}
/*
* The following code detects which Media is connected for 21041/21140
* Expect to change this code to support new 21140 variants.
* find_active_media() - called with intrlock held.
*/
static void
{
int i;
(macinfo->gldm_private);
#ifdef SROMDEBUG
#endif
/* XXX return value ignored */
/*
* If the port monitor detects the link is already
* up, there is no point going through the rest of the
* link sense
*/
return;
}
}
}
/*
* Media is searched for in order of Precedence. This DEC SROM spec
* tells us that the first media entry in the SROM is the lowest
* precedence and should be checked last. This is why we go to the last
* Media block and work back to the beginning.
*
* However, some older SROMs (Cogent EM110's etc.) have this the wrong
* way around. As a result, following the SROM spec would result in a
* 10 link being chosen over a 100 link if both media are available.
* So we continue trying the media until we have at least tried the
* DEFAULT media.
*/
/* Search for an active medium, and select it */
/* User settings disallow selection of this block */
continue;
/* We may not be able to pick the default */
#ifdef DEBUG
#endif
case 2: /* SIA Media block: Best we can do is send a packet */
if (send_test_packet(macinfo)) {
if (!is_fdmedia(media))
return;
if (!fd_found)
}
break;
case 0:
send_test_packet(macinfo)) ||
}
/*
* Half Duplex is *always* the favoured media.
* Full Duplex can be set and forced via the
* conf file.
*/
if (!is_fdmedia(media) &&
leaf->default_block) {
/*
* Cogent cards have the media in
* opposite order to the spec.,
* this code forces the media test to
* keep going until the default media
* is tested.
*
* In Cogent case, 10, 10FD, 100FD, 100
* 100 is the default but 10 could have
* been detected and would have been
* chosen but now we force it through to
* 100.
*/
return;
} else if (!is_fdmedia(media)) {
/*
* This allows all the others to work
* properly by remembering the media
* that works and not defaulting to
* a FD link.
*/
/*
* No media have already been found
* so far, this is FD, it works so
* remember it and if no others are
* detected, use it.
*/
}
}
break;
/*
* MII block: May take up to a second or so to settle if
* setup causes a PHY reset
*/
case 1: case 3:
for (i = 0; ; i++) {
/* XXX function return value ignored */
&dnetp->mii_duplex);
return;
}
if (i == 10)
break;
}
break;
}
} /* for loop */
if (hd_found) {
} else if (fd_found) {
} else {
if (best_allowed == NULL)
}
}
/*
* Do anything neccessary to select the selected_media_block.
* setup_block() - called with intrlock held.
*/
static void
{
/* XXX function return value ignored */
(void) dnet_start(macinfo);
}
/* dnet_link_sense() - called with intrlock held */
static int
{
/*
* This routine makes use of the command word from the srom config.
* Details of the auto-sensing information contained in this can
* be found in the "Digital Semiconductor 21X4 Serial ROM Format v3.03"
* spec. Section 4.3.2.1, and 4.5.2.1.3
*/
(macinfo->gldm_private);
/* Don't autosense if the medium does not support it */
/* This should be the default block */
return (0);
}
/*
* Scrambler may need to be disabled for link sensing
* to work
*/
dnetp->disable_scrambler = 0;
else
if (link)
upsamples++;
else
upsamples = 0;
}
#ifdef DNETDEBUG
"mask:%x link:%x",
#endif
if (upsamples == 8)
return (1);
return (0);
}
static int
{
int packet_delay;
(macinfo->gldm_private);
struct tx_desc_type *desc;
int bufindex;
/*
* For a successful test packet, the card must have settled into
* its current setting. Almost all cards we've tested manage to
* do this with all media within 50ms. However, the SMC 8432
* requires 300ms to settle into BNC mode. We now only do this
* from attach, and we do sleeping delay() instead of drv_usecwait()
* so we hope this .2 second delay won't cause too much suffering.
* ALSO: with an autonegotiating hub, an aditional 1 second delay is
* required. This is done if the media type is TP
*/
} else {
}
"failed");
return (0);
}
/*
* use setup buffer as the buffer for the test packet
* instead of allocating one.
*/
/* Put something decent in dest address so we don't annoy other cards */
/*
* Give enough time for the chip to transmit the packet
*/
#if 1
del = 1000;
#else
del = 0x10000;
drv_usecwait(10);
#endif
#ifdef DNETDEBUG
#endif
return (0);
}
/* enable_interrupts - called with intrlock held */
static void
{
/* Don't enable interrupts if they have been forced off */
if (dnetp->interrupts_disabled)
return;
(enable_xmit ? TX_INTERRUPT_MASK : 0) |
}
/*
* Some older multiport cards are non-PCI compliant in their interrupt routing.
* Second and subsequent devices are incorrectly configured by the BIOS
* (either in their ILINE configuration or the MP Configuration Table for PC+MP
* systems).
* The hack stops gldregister() registering the interrupt routine for the
* FIRST device on the adapter, and registers its own. It builds up a table
* of macinfo structures for each device, and the new interrupt routine
* calls gldintr for each of them.
* Known cards that suffer from this problem are:
* All Cogent multiport cards;
* Znyx 314;
* Znyx 315.
*
* XXX NEEDSWORK -- see comments above get_alternative_srom_image(). This
* hack relies on the fact that the offending cards will have only one SROM.
* It uses this fact to identify devices that are on the same multiport
* adapter, as opposed to multiple devices from the same vendor (as
* indicated by "secondary")
*/
static int
{
int i;
struct hackintr_inf *hackintr_inf;
struct dnetinstance *dnetp =
"no_INTA_workaround", 0) != 0)
return (0);
for (i = 0; i < 3; i++)
/* Check wheather or not we need to implement the hack */
switch (oui) {
case ZNYX_ETHER:
/* Znyx multiport 21040 cards <<==>> ZX314 or ZX315 */
return (0);
break;
case COGENT_ETHER:
/* All known Cogent multiport cards */
break;
case ADAPTEC_ETHER:
/* Adaptec multiport cards */
break;
default:
/* Other cards work correctly */
return (0);
}
/* card is (probably) non-PCI compliant in its interrupt routing */
if (!secondary) {
/*
* If we have already registered a hacked interrupt, and
* this is also a 'primary' adapter, then this is NOT part of
* a multiport card, but a second card on the same PCI bus.
* BUGID: 4057747
*/
DDI_PROP_DONTPASS, hackintr_propname, 0) != 0)
return (0);
/* ... Primary not part of a multiport device */
#ifdef DNETDEBUG
"interrupt flaw workaround");
#endif
if (hackintr_inf == NULL)
goto fail;
/*
* Add a property to allow successive attaches to find the
* table
*/
sizeof (void *)) != DDI_PROP_SUCCESS)
goto fail;
/* Register our hacked interrupt routine */
(uint_t (*)(char *))dnet_hack_intr,
/* XXX function return value ignored */
(void) ddi_prop_remove(DDI_DEV_T_NONE,
goto fail;
}
/*
* Mutex required to ensure interrupt routine has completed
* when detaching devices
*/
/* Stop GLD registering an interrupt */
return (-1);
} else {
/* Add the macinfo for this secondary device to the table */
if (hackintr_inf == NULL)
goto fail;
/* Find an empty slot */
for (i = 0; i < MAX_INST; i++)
break;
/* More than 8 ports on adapter ?! */
if (i == MAX_INST)
goto fail;
/*
* Allow GLD to register a handler for this
* device. If the card is actually broken, as we suspect, this
* handler will never get called. However, by registering the
* interrupt handler, we can copy gracefully with new multiport
* Cogent cards that decide to fix the hardware problem
*/
return (0);
}
fail:
" routing problem");
return (0);
}
/*
* Call gld_intr for all adapters on a multiport card
*/
static uint_t
{
int i;
int claimed = DDI_INTR_UNCLAIMED;
/* Stop detaches while processing interrupts */
for (i = 0; i < MAX_INST; i++) {
if (hackintr_inf->macinfos[i] &&
}
return (claimed);
}
/*
* This removes the detaching device from the table procesed by the hacked
* interrupt routine. Because the interrupts from all devices come in to the
* same interrupt handler, ALL devices must stop interrupting once the
* primary device detaches. This isn't a problem at present, because all
* instances of a device are detached when the driver is unloaded.
*/
static int
{
int i;
struct hackintr_inf *hackintr_inf;
/*
* No hackintr_inf implies hack was not required or the primary has
* detached, and our interrupts are already disabled
*/
if (!hackintr_inf) {
/* remove the interrupt for the non-hacked case */
return (DDI_SUCCESS);
}
/* Remove this device from the handled table */
for (i = 0; i < MAX_INST; i++) {
break;
}
}
/* Not the primary card, we are done */
return (DDI_SUCCESS);
/*
* This is the primary card. All remaining adapters on this device
* must have their interrupts disabled before we remove the handler
*/
for (i = 0; i < MAX_INST; i++) {
struct dnetinstance *altdnetp =
}
}
/* It should now be safe to remove the interrupt handler */
/* XXX function return value ignored */
return (DDI_SUCCESS);
}
/*
* ========== PHY MII Routines ==========
*/
/* do_phy() - called with intrlock held */
static void
{
struct dnetinstance
int phy;
/*
* Find and configure the PHY media block. If NO PHY blocks are
* found on the SROM, but a PHY device is present, we assume the card
* is a legacy device, and that there is ONLY a PHY interface on the
* card (ie, no BNC or AUI, and 10BaseT is implemented by the PHY
*/
break;
}
}
/*
* If no MII block, select default, and hope this configuration will
*/
/* XXX function return value ignored */
/*
* We try PHY 0 LAST because it is less likely to be connected
*/
#ifdef DNETDEBUG
#endif
/* Legacy card, change the leaf node */
}
return;
}
#ifdef DNETDEBUG
#endif
}
static ushort_t
{
struct dnetinstance *dnetp;
int i;
int turned_around = 0;
/* Write Preamble */
/* Prepare command word */
/* Check that the PHY generated a zero bit the 2nd clock */
/* read data WORD */
for (i = 0; i < bits_in_ushort; i++) {
}
}
static void
{
struct dnetinstance *dnetp;
/* Prepare command word */
}
/*
* Write data size bits from mii_data to the MII control lines.
*/
static void
{
int i;
for (i = data_size; i > 0; i--) {
mii_data <<= 1;
}
}
/*
* Put the MDIO port in tri-state for the turn around bits
* in MII read and at end of MII management sequence.
*/
static void
{
}
static void
{
}
/*
* Callback from MII module. Makes sure that the CSR registers are
* configured properly if the PHY changes mode.
*/
/* ARGSUSED */
/* dnet_mii_link_cb - called with intrlock held */
static void
{
struct dnetinstance *dnetp =
if (state == phy_state_linkup) {
/* XXX function return value ignored */
&dnetp->mii_duplex);
} else {
/* NEEDSWORK: Probably can call find_active_media here */
dnetp->mii_duplex = 0;
}
}
/*
* SROM parsing routines.
* Refer to the Digital 3.03 SROM spec while reading this! (references refer
* to this document)
* Where possible ALL vendor specific changes should be localised here. The
* SROM data should be capable of describing any programmatic irregularities
* of DNET cards (via SIA or GP registers, in particular), so vendor specific
* code elsewhere should not be required
*/
static void
{
int i;
uchar_t *p;
DDI_PROP_DONTPASS, "no_sromconfig", 0))
/* Section 2/3: General SROM Format/ ID Block */
p = vi+18;
for (i = 0; i < 6; i++)
offset |= *p++ << 8;
}
/*
* 'Orrible hack for cogent cards. The 6911A board seems to
* have an incorrect SROM. (From the OEMDEMO program
* supplied by cogent, it seems that the ROM matches a setup
* or a board with a QSI or ICS PHY.
*/
for (i = 0; i < 3; i++)
if (ether_mfg == ADAPTEC_ETHER) {
switch (vi[COGENT_SROM_ID]) {
case COGENT_ANA6911A_C:
case COGENT_ANA6911AC_C:
#ifdef DNETDEBUG
"Suspected bad GPR sequence."
" Making a guess (821,0)");
#endif
/* XXX function return value ignored */
(void) ddi_prop_update_byte_array(
sizeof (cogent_gprseq));
break;
}
}
} else {
/*
* Adhoc SROM, check for some cards which need special handling
* Assume vendor info contains ether address in first six bytes
*/
for (i = 0; i < 6; i++)
for (i = 0; i < 3; i++)
switch (ether_mfg) {
case ASANTE_ETHER:
dnetp->vendor_revision = 0;
break;
case COGENT_ETHER:
case ADAPTEC_ETHER:
break;
default:
dnetp->vendor_revision = 0;
break;
}
}
}
}
/* Section 4.2, 4.3, 4.4, 4.5 */
static void
{
int i;
}
for (i = 0; i <= leaf->block_count; i++) {
}
/* No explicit default block: use last in the ROM */
}
static uchar_t *
{
int i;
/*
* There are three kinds of media block we need to worry about:
* The 21041 blocks.
* 21140 blocks from a version 1 SROM
* 2114[023] block from a version 3 SROM
*/
/* Section 4.2 */
if (*vi++ & 0x40) {
} else {
/* No media data (csrs 13,14,15). Insert defaults */
switch (block->media_code) {
case MEDIA_TP:
break;
case MEDIA_TP_FD:
break;
case MEDIA_BNC:
break;
case MEDIA_AUI:
break;
}
}
case 0: /* "non-MII": Section 4.3.2.2.1 */
break;
/* This is whats needed in CSR6 */
break;
case 2: /* SIA Media: Section 4.4.2.1.1 */
if (*vi++ & 0x40) {
} else {
/*
* SIA values not provided by SROM; provide
* defaults. See appendix D of 2114[23] manuals.
*/
switch (block->media_code) {
case MEDIA_BNC:
break;
case MEDIA_AUI:
break;
case MEDIA_TP:
break;
case MEDIA_TP_FD:
break;
default:
}
}
break;
}
}
break;
case 4: /* SYM Media: 4.5.2.1.3 */
/* Treat GP control and data as a GPR sequence */
break;
case 5: /* GPR reset sequence: Section 4.5.2.1.4 */
break;
default: /* Unknown media block. Skip it. */
break;
}
} else { /* Compact format (or V1 SROM): Section 4.3.2.1 */
}
return (vi);
}
/*
* An alternative to doing this would be to store the legacy ROMs in binary
* format in the conf file, and in read_srom, pick out the data. This would
* then allow the parser to continue on as normal. This makes it a little
* easier to read.
*/
static void
{
/* Default FAKE SROM */
leaf = &leaf_default_100;
block++;
block++;
block++;
/* COGENT FAKE SROM */
leaf = &leaf_cogent_100;
block++;
block++; /* 10BaseT */
block++; /* 100BaseTX-FD */
block++; /* 100BaseTX */
/* Generic legacy card with a PHY. */
leaf = &leaf_phylegacy;
/* ASANTE FAKE SROM */
leaf = &leaf_asante;
/* LEGACY 21041 card FAKE SROM */
leaf = &leaf_21041;
block++;
block++;
block++;
/* LEGACY 21040 card FAKE SROM */
leaf = &leaf_21040;
block++;
block++;
block++;
}
static void
{
int i;
"Addr:%x:%x:%x:%x:%x:%x",
a[0], a[1], a[2], a[3], a[4], a[5]);
}
static void
{
int i;
for (i = 0; i < leaf->block_count; i++)
}
static void
{
(void *)block,
case 1: case 3:
"%x, ttm %x, mediacap %x",
break;
case 2:
break;
}
}
/* Utility to print out binary info dumps. Handy for SROMs, etc */
static int
{
if (val <= 9)
return (val +'0');
if (val <= 15)
return (-1);
}
static void
{
int i, j;
if (!len)
return;
'.' : data[i];
}
*p++ = ' ';
if (q-ascii >= 8) {
*p = *q = 0;
p = hex;
q = ascii;
}
}
if (p != hex) {
*p++ = ' ';
*p = *q = 0;
}
}
#ifdef DNETDEBUG
void
{
}
{
0xffff);
}
/* ARGSUSED */
void
{
int firstdigit = 1;
while (*p++ = *buf++)
;
p--;
if (!firstdigit || digit) {
*p++ = digit + '0';
firstdigit = 0;
}
}
/* Actual zero, output it */
if (firstdigit)
*p++ = '0';
*p++ = '-';
*p++ = '>';
*p++ = 0;
}
#endif