/*
* usbgem.c: General USB to Fast Ethernet mac driver framework
*
* Copyright (c) 2002-2012 Masayuki Murayama. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
*
* 3. Neither the name of the author nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#pragma ident "@(#)usbgem.c 1.6 12/02/09"
/*
* Change log
*/
/*
* TODO:
* implement DELAYED_START
*/
/*
* System Header files.
*/
#include <sys/ethernet.h>
#ifndef USBGEM_CONFIG_GLDv3
#endif
#include <sys/byteorder.h>
#ifdef USBGEM_CONFIG_GLDv3
#endif
/* supplement definitions */
extern const char *usb_str_cr(usb_cr_t);
#ifndef USBGEM_CONFIG_GLDv3
#pragma weak gld_linkstate
#endif
#include "usbgem_mii.h"
#include "usbgem.h"
#ifdef MODULE
char ident[] = "usb general ethernet mac driver v" VERSION;
#else
extern char ident[];
#endif
/* Debugging support */
#ifdef USBGEM_DEBUG_LEVEL
#else
#endif
/*
* Useful macros and typedefs
*/
#define BOOLEAN(x) ((x) != 0)
/*
* configuration parameters
*/
#define USBDRV_MINOR_VER 0
/*
* Private functions
*/
static int usbgem_mii_start(struct usbgem_dev *);
static void usbgem_mii_stop(struct usbgem_dev *);
/* local buffer management */
static int usbgem_init_rx_buf(struct usbgem_dev *);
/* internal mac interfaces */
static void usbgem_tx_timeout(struct usbgem_dev *);
static void usbgem_mii_link_watcher(struct usbgem_dev *);
static int usbgem_mac_init(struct usbgem_dev *);
static int usbgem_mac_start(struct usbgem_dev *);
/* usb event support */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
#ifdef MODULE
extern struct mod_ops mod_miscops;
"usbgem v" VERSION,
};
};
/*
* _init : done
*/
int
_init(void)
{
int status;
return (status);
}
/*
* _fini : done
*/
int
_fini(void)
{
int status;
return (status);
}
int
{
}
#endif /* MODULE */
/* ============================================================== */
/*
* Ether CRC calculation utilities
*/
/* ============================================================== */
/*
* Ether CRC calculation according to 21143 data sheet
*/
{
int idx;
int bit;
crc = 0xffffffff;
}
}
return (crc);
}
{
int idx;
int bit;
crc = 0xffffffff;
}
}
return (crc);
}
int
{
}
static int
{
int i;
int cnt;
cnt = 0;
for (i = 0; i < 32; i++) {
if (x & (1 << i)) {
cnt++;
}
}
return (cnt);
}
static clock_t
{
now = ddi_get_lbolt();
}
#ifdef USBGEM_DEBUG_LEVEL
#ifdef USBGEM_DEBUG_VLAN
#ifdef notdef
#endif
static void
{
uint8_t *p;
int rest;
int len;
char *bp;
msg[0] = 0;
offset = 0;
if (rest == 0) {
break;
}
}
offset = 0;
/* ethernet address */
"ether: %02x:%02x:%02x:%02x:%02x:%02x"
" -> %02x:%02x:%02x:%02x:%02x:%02x",
p[6], p[7], p[8], p[9], p[10], p[11],
p[0], p[1], p[2], p[3], p[4], p[5]);
/* vlag tag and etherrtype */
ethertype = GET_ETHERTYPE(p);
ethertype = GET_ETHERTYPE(p);
}
/* ethernet packet length */
} else {
}
}
}
if (ethertype != ETHERTYPE_IP) {
goto x;
}
/* ip address */
offset += sizeof (struct ether_header);
ipproto = p[9];
p[12], p[13], p[14], p[15],
p[16], p[17], p[18], p[19],
/* cksum for psuedo header */
/* tcp or udp protocol header */
if (ipproto == IPPROTO_TCP) {
if (check_cksum) {
}
} else if (ipproto == IPPROTO_UDP) {
}
}
x:
}
#endif /* USBGEM_DEBUG_VLAN */
#endif /* USBGEM_DEBUG_LEVEL */
#ifdef GEM_GCC_RUNTIME
/*
* gcc3 runtime routines
*/
int
{
int i;
int ret;
ret = 0;
for (i = 0; i < n; i++) {
if (ret) {
return (ret);
}
}
return (0);
}
void *
{
if ((c & 0xff) == 0) {
bzero(s, n);
} else {
while (n--) {
((uint8_t *)s)[n] = c;
}
}
return (s);
}
void *
{
return (s1);
}
#endif /* GEM_GCC_RUNTIME */
/* ============================================================== */
/*
* hardware operations
*/
/* ============================================================== */
static int
{
int err;
return (err);
}
static int
{
int err;
return (err);
}
static int
{
int err;
return (err);
}
static int
{
int err;
return (err);
}
static int
{
int err;
return (err);
}
static int
{
int err;
return (err);
}
static int
{
int err;
return (err);
}
static int
{
int err;
return (err);
}
/* ============================================================== */
/*
* USB pipe management
*/
/* ============================================================== */
static boolean_t
{
int err;
goto err;
}
req->bulk_timeout = 0;
req->bulk_completion_reason = 0;
req->bulk_cb_flags = 0;
flags = 0;
if (err != USB_SUCCESS) {
/* free req and mp */
goto err;
}
return (B_TRUE);
err:
return (B_FALSE);
}
/* ============================================================== */
/*
*/
/* ============================================================== */
static int
{
int i;
"!%s: %s: failed to allocate bulkreq for rx",
return (USB_FAILURE);
}
return (USB_FAILURE);
}
dp->rx_busy_cnt++;
}
return (USB_SUCCESS);
}
/* ============================================================== */
/*
* memory resource management
*/
/* ============================================================== */
static int
{
/* free all tx requst structure */
dp->tx_free_list =
}
return (USB_SUCCESS);
}
static int
{
int i;
/* allocate tx requests */
"%s:%s failed to allocate tx requests",
/* free partially allocated tx requests */
(void) usbgem_free_memory(dp);
return (USB_FAILURE);
}
/* add the new one allocated into tx free list */
}
return (USB_SUCCESS);
}
/* ========================================================== */
/*
* Start transmission.
* Return zero on success,
*/
/* ========================================================== */
#ifdef TXTIMEOUT_TEST
static int usbgem_send_cnt = 0;
#endif
/*
* usbgem_send is used only to send data packet into ethernet line.
*/
static mblk_t *
{
int err;
int mcast;
int bcast;
int len;
#ifdef USBGEM_DEBUG_LEVEL
#endif
bcast = 0;
mcast = 0;
bcast = 1;
} else {
mcast = 1;
}
}
/*
* no memory resource. we don't stop downstream,
* we just discard the packet.
*/
return (NULL);
}
/*
* no tx free slot
*/
/* free reallocated message */
}
return (mp);
}
dp->tx_busy_cnt++;
}
if (intr) {
dp->tx_intr_pended++;
}
#ifdef USBGEM_DEBUG_LEVEL
dp->tx_seq_num++;
#endif
}
req->bulk_attributes = 0;
req->bulk_completion_reason = 0;
req->bulk_cb_flags = 0;
if (intr) {
}
!= USB_SUCCESS) {
/* failed to transfer the packet, discard it. */
/* recycle the request block */
dp->tx_busy_cnt--;
"%s: %s: usb_pipe_bulk_xfer: failed: err:%d",
/* we use another flag to indicate error state. */
}
} else {
/* record the start time */
}
}
}
return (NULL);
}
int
{
int ret;
int flags = 0;
/*
* ensure to stop the nic
*/
}
/* now the nic become quiescent, reset the chip */
goto err;
}
/*
* restore the nic state step by step
*/
goto done;
}
goto err;
}
/* setup mac address and enable rx filter */
if (ret != USB_SUCCESS) {
goto err;
}
/*
* update the link state asynchronously
*/
/*
* XXX - a panic happened because of linkdown.
* We must check mii_state here, because the link can be down just
* before the restart event happen. If the link is down now,
* gem_mac_start() will be called from gem_mii_link_check() when
* the link become up later.
*/
goto err;
}
goto done;
}
(void) usbgem_mac_start(dp);
}
done:
return (USB_SUCCESS);
err:
#ifdef GEM_CONFIG_FMA
#endif
return (USB_FAILURE);
}
static void
{
int ret;
for (; ; ) {
if (dp->tx_watcher_stop) {
break;
}
now = ddi_get_lbolt();
dp->fatal_error &&
dp->tx_busy_cnt != 0 &&
/*
* Upgrade dev_state_lock from shared mode
* to exclusive mode to restart nic
*/
goto again;
}
" fatal_error:%ld nic_state:%d"
" mac_state:%d starttime:%ld",
(void) usbgem_restart_nic(dp);
}
}
}
static int
{
int err;
/* make a first call of uwgem_lw_link_check() */
dp->tx_watcher_stop = 0;
"!%s: %s: failed to create a tx_watcher thread",
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
static void
{
if (dp->tx_watcher_did) {
/* Ensure timer routine stopped */
}
}
/* ================================================================== */
/*
* Callback handlers
*/
/* ================================================================== */
static void
{
int pkts = 0;
int bcast = 0;
int mcast = 0;
/*
* we cannot acquire dev_state_lock because the routine
* must be executed during usbgem_mac_stop() to avoid
* dead lock.
* we use a simle membar operation to get the state correctly.
*/
/* the message has been reallocated, free old one */
}
/* the message may includes one or more ethernet packets */
pkts++;
ETHERADDRL) == 0) {
bcast++;
} else {
mcast++;
}
}
}
/* send up if it is a valid packet */
#ifdef USBGEM_CONFIG_GLDv3
#else
while (newmp) {
}
#endif
} else {
len = 0;
}
/* update rx_active */
}
}
/* prepare to receive the next packets */
/* we successed */
goto done;
}
"!%s: %s: failed to fill next rx packet",
/*
* we use another flag to indicate error state.
* if we acquire dev_state_lock for RW_WRITER here,
* usbgem_mac_stop() may hang.
*/
}
} else {
/* no need to prepare the next packets */
}
dp->rx_busy_cnt--;
if (dp->rx_busy_cnt == 0) {
/* wake up someone waits for me */
}
done:
;
}
static void
{
"!%s: %s: cr:%s(%d) cb_flags:0x%x head:%d tail:%d",
dp->tx_busy_cnt));
/* we have finished to transfer the packet into tx fifo */
}
if (intr) {
/* find the last interrupt we have scheduled */
if (--(dp->tx_intr_pended) == 0) {
}
}
dp->tx_busy_cnt--;
#ifdef CONFIG_TX_LIMITER
if (tx_sched) {
dp->tx_max_packets =
}
#endif
}
if (tx_sched) {
#ifdef USBGEM_CONFIG_GLDv3
#else
#endif
}
}
static void
{
}
/* free the request and data */
}
/* ======================================================================== */
/*
* MII support routines
*/
/* ======================================================================== */
static void
{
/* choose media mode */
} else if (dp->anadv_100hdx) {
} else {
}
}
static uint16_t
{
return (val);
}
static void
{
}
static int
{
int err;
return (err);
}
static int
{
int err;
return (err);
}
#define fc_cap_decode(x) \
((((x) & MII_ABILITY_PAUSE) != 0 ? 1 : 0) | \
(((x) & MII_ABILITY_ASM_DIR) != 0 ? 2 : 0))
int
{
/*
* Configure bits in advertisement register
*/
if ((mii_stat & MII_STATUS_ABILITY_TECH) == 0) {
/* it's funny */
return (USB_FAILURE);
}
/* Do not change the rest of ability bits in advert reg */
if (*errp != USB_SUCCESS) {
goto usberr;
}
"!%s: %s: 100T4:%d 100F:%d 100H:%d 10F:%d 10H:%d",
/* set technology bits */
if (dp->anadv_100t4) {
}
if (dp->anadv_100fdx) {
}
if (dp->anadv_100hdx) {
}
if (dp->anadv_10fdx) {
}
if (dp->anadv_10hdx) {
}
/* set flow control capabilities */
if (dp->anadv_pause) {
val |= MII_ABILITY_PAUSE;
}
if (dp->anadv_asmpause) {
}
"!%s: %s: setting MII_AN_ADVERT reg:%b, pause:%d, asmpause:%d",
if (*errp != USB_SUCCESS) {
goto usberr;
}
/*
* 1000Base-T GMII support
*/
if (!dp->anadv_autoneg) {
/* enable manual configuration */
}
} else {
val = 0;
if (dp->anadv_1000fdx) {
}
if (dp->anadv_1000hdx) {
}
switch (dp->anadv_1000t_ms) {
case 1:
/* slave */
val |= MII_1000TC_CFG_EN;
break;
case 2:
/* master */
break;
default:
/* auto: do nothing */
break;
}
}
"!%s: %s: setting MII_1000TC reg:%b",
if (*errp != USB_SUCCESS) {
goto usberr;
}
}
return (USB_SUCCESS);
return (*errp);
}
static char *usbgem_fc_type[] = {
"without",
"with symmetric",
"with tx",
"with rx",
};
#ifdef USBGEM_CONFIG_GLDv3
#else
if (gld_linkstate) { \
}
if (gld_linkstate) { \
}
#endif
/* none */
/* sym */
/* tx */
};
static boolean_t
{
int linkdown_action;
int err;
} else {
}
/* save old mii state */
/* stop periodic execution of the link watcher */
dp->mii_interval = 0;
goto next;
}
now = ddi_get_lbolt();
/*
* For NWAM, don't show linkdown state right
* when the device is attached.
*/
if (dp->linkup_delay > 0) {
} else {
/* link up timeout */
}
}
case MII_STATE_UNKNOWN:
goto reset_phy;
case MII_STATE_RESETTING:
/* don't read phy registers in resetting */
goto next;
}
if (err != USB_SUCCESS) {
goto usberr;
}
if (val & MII_CONTROL_RESET) {
"!%s: time:%ld resetting phy not complete."
" mii_control:0x%b",
}
/* ensure neither isolated nor pwrdown nor auto-nego mode */
if (err != USB_SUCCESS) {
goto usberr;
}
#if USBGEM_DEBUG_LEVEL > 10
#endif
/* As resetting PHY has completed, configure PHY registers */
/* we failed to configure PHY */
goto usberr;
}
/* prepare for forced mode */
dp->mii_lpable = 0;
dp->mii_advert = 0;
dp->mii_ctl1000 = 0;
dp->mii_stat1000 = 0;
if (!dp->anadv_autoneg) {
/* skip auto-negotiation phase */
goto next_nowait;
}
/* issue an auto-negotiation command */
goto autonego;
/*
* Autonegotiation in progress
*/
> 0) {
/* wait for minimum time (2.3 - 2.5 sec) */
goto next;
}
/* read PHY status */
if (err != USB_SUCCESS) {
goto usberr;
}
"!%s: %s: called: mii_state:%d MII_STATUS reg:%b",
if (status & MII_STATUS_REMFAULT) {
/*
* The link parnert told me something wrong happend.
* What do we do ?
*/
"!%s: auto-negotiation failed: remote fault",
goto autonego;
}
if ((status & MII_STATUS_ANDONE) == 0) {
/*
* Auto-negotiation has been timed out,
* Reset PHY and try again.
*/
if (!dp->mii_supress_msg) {
"!%s: auto-negotiation failed:"
" timeout",
}
goto autonego;
}
/*
* Auto-negotiation is in progress. Wait for a while.
*/
goto next;
}
/*
* Auto-negotiation has been completed. Let's go to AN_DONE.
*/
"!%s: auto-negotiation completed, MII_STATUS:%b",
goto next;
}
diff = 0;
goto next_nowait;
case MII_STATE_AN_DONE:
/*
* Auto-negotiation has done. Now we can set up media.
*/
/* wait for a while */
goto next;
}
/*
* Setup speed and duplex mode according with
* the result of auto negotiation.
*/
/*
* Read registers required to determin current
* duplex mode and media speed.
*/
/* the 'status' variable is not initialized yet */
if (err != USB_SUCCESS) {
goto usberr;
}
}
if (err != USB_SUCCESS) {
goto usberr;
}
if (err != USB_SUCCESS) {
goto usberr;
}
if (err != USB_SUCCESS) {
goto usberr;
}
if (exp == 0xffff) {
/* some phys don't have exp register */
exp = 0;
}
ctl1000 = 0;
stat1000 = 0;
if (err != USB_SUCCESS) {
goto usberr;
}
if (err != USB_SUCCESS) {
goto usberr;
}
}
"!%s: auto-negotiation done: "
"status:%b, advert:%b, lpable:%b, exp:%b",
"! MII_1000TC reg:%b, MII_1000TS reg:%b",
}
(exp & MII_AN_EXP_LPCANAN) == 0) {
"!%s: but the link partner doesn't seem"
" to have auto-negotiation capability."
" please check the link configuration.",
}
/*
* it should be a result of pararell detection,
* which cannot detect duplex mode.
*/
/* no common technology, try 10M half mode */
}
} else if (lpable == 0) {
goto reset_phy;
}
/*
* configure current link mode according to AN priority.
*/
if ((ctl1000 & MII_1000TC_ADV_FULL) &&
(stat1000 & MII_1000TS_LP_FULL)) {
/* 1000BaseT & full duplex */
} else if ((ctl1000 & MII_1000TC_ADV_HALF) &&
(stat1000 & MII_1000TS_LP_HALF)) {
/* 1000BaseT & half duplex */
} else if ((val & MII_ABILITY_100BASE_TX_FD)) {
/* 100BaseTx & fullduplex */
} else if ((val & MII_ABILITY_100BASE_T4)) {
/* 100BaseTx & fullduplex */
} else if ((val & MII_ABILITY_100BASE_TX)) {
/* 100BaseTx & half duplex */
} else if ((val & MII_ABILITY_10BASE_T_FD)) {
/* 10BaseT & full duplex */
} else if ((val & MII_ABILITY_10BASE_T)) {
/* 10BaseT & half duplex */
} else {
/*
* the link partner doesn't seem to have
* auto-negotiation capability and our PHY
* could not report current mode correctly.
* We guess current mode by mii_control register.
*/
if (err != USB_SUCCESS) {
goto usberr;
}
/* select 100m half or 10m half */
"!%s: auto-negotiation done but "
"common ability not found.\n"
"PHY state: control:%b advert:%b lpable:%b\n"
"guessing %d Mbps %s duplex mode",
}
if (dp->full_duplex) {
dp->flow_control =
[fc_cap_decode(lpable)];
} else {
}
goto next_nowait;
case MII_STATE_MEDIA_SETUP:
/* assume the link state is down */
/* use short interval */
if ((!dp->anadv_autoneg) ||
/*
* write the result of auto negotiation back.
*/
if (err != USB_SUCCESS) {
goto usberr;
}
if (dp->full_duplex) {
}
case USBGEM_SPD_1000:
break;
case USBGEM_SPD_100:
val |= MII_CONTROL_100MB;
break;
default:
/* FALLTHROUGH */
case USBGEM_SPD_10:
/* for USBGEM_SPD_10, do nothing */
break;
}
if (err != USB_SUCCESS) {
goto usberr;
}
}
if (err != USB_SUCCESS) {
goto usberr;
}
}
/*
* XXX -- nic state should be one of
* NIC_STATE_DISCONNECTED
* NIC_STATE_STOPPED
* NIC_STATE_INITIALIZED
* NIC_STATE_ONLINE
*/
/* notify the result of autonegotiation to mac */
goto usberr;
}
}
goto next_nowait;
case MII_STATE_LINKDOWN:
if (err != USB_SUCCESS) {
goto usberr;
}
if (status & MII_STATUS_LINKUP) {
/*
* Link is going up
*/
"!%s: link up detected: status:%b",
/*
* MII_CONTROL_100MB and MII_CONTROL_FDUPLEX are
* ignored when MII_CONTROL_ANE is set.
*/
"!%s: Link up: %d Mbps %s duplex %s flow control",
dp->mii_interval =
dp->mii_interval = 0;
}
(void) usbgem_mac_start(dp);
}
}
goto next;
}
if (dp->anadv_autoneg) {
/*
* the link down timer expired.
* need to restart auto-negotiation.
*/
goto restart_autonego;
}
}
/* don't change mii_state */
goto next;
case MII_STATE_LINKUP:
/* first pass, read mii status */
if (err != USB_SUCCESS) {
goto usberr;
}
}
if ((status & MII_STATUS_LINKUP) == 0) {
/*
* Link is going down
*/
"!%s: link down detected: status:%b",
/*
* Acquire exclusive lock to change mii_state
*/
goto again;
}
/*
* As we may change the state of the device,
* let us acquire exclusive lock for the state.
*/
(void) usbgem_restart_nic(dp);
/* drain tx */
}
if (dp->anadv_autoneg) {
/* need to restart auto-negotiation */
goto restart_autonego;
}
/*
* don't use hw link down detection until the link
* status become stable for a while.
*/
dp->mii_interval =
goto next;
}
/*
* still link up, no need to change mii_state
*/
/*
* no need to check link status periodicly
* if nic can generate interrupts when link go down.
*/
dp->mii_interval = 0;
}
goto next;
}
/* NOTREACHED */
/*
* Actions for new state.
*/
switch (linkdown_action) {
case MII_ACTION_RESET:
if (!dp->mii_supress_msg) {
}
goto reset_phy;
case MII_ACTION_NONE:
goto autonego;
}
/* PHY will restart autonego automatically */
goto next;
case MII_ACTION_RSA:
if (!dp->mii_supress_msg) {
}
goto autonego;
default:
}
/* NOTREACHED */
if (!dp->mii_supress_msg) {
}
if (err != USB_SUCCESS) {
goto usberr;
}
}
goto next;
if (!dp->mii_supress_msg) {
}
if (err != USB_SUCCESS) {
goto usberr;
}
if (val & MII_CONTROL_ANE) {
val |= MII_CONTROL_RSAN;
}
if (err != USB_SUCCESS) {
goto usberr;
}
goto next;
next:
return (tx_sched);
}
static void
{
int old_mii_state;
int new_mii_state;
for (; ; ) {
if (dp->mii_interval) {
} else {
&dp->link_watcher_lock);
}
if (dp->link_watcher_stop) {
break;
}
/* we block callbacks from disconnect/suspend and restart */
/*
* gld v2 notifier functions are not able to
* be called with any locks in this layer.
*/
if (tx_sched) {
/* kick potentially stopped downstream */
#ifdef USBGEM_CONFIG_GLDv3
#else
#endif
}
if (old_mii_state != new_mii_state) {
/* notify new mii link state */
if (new_mii_state == MII_STATE_LINKUP) {
dp->linkup_delay = 0;
} else if (dp->linkup_delay <= 0) {
}
} else if (dp->linkup_delay < 0) {
/* first linkup timeout */
dp->linkup_delay = 0;
}
}
thread_exit();
}
void
{
}
int
{
int phy;
int err;
/*
* Scan PHY
*/
dp->mii_status = 0;
/* Try default phy first */
if (dp->mii_phy_addr) {
if (err != USB_SUCCESS) {
goto usberr;
}
goto PHY_found;
}
if (dp->mii_phy_addr < 0) {
return (USB_FAILURE);
}
"!%s: failed to probe default MII PHY at %d",
}
/* Try all possible address */
if (err != USB_SUCCESS) {
"!%s: %s: mii_read(status) failed",
goto usberr;
}
if (err != USB_SUCCESS) {
"!%s: %s: mii_write(control) failed",
goto usberr;
}
goto PHY_found;
}
}
if (err != USB_SUCCESS) {
"!%s: %s: mii_write(control) failed",
goto usberr;
}
if (err != USB_SUCCESS) {
"!%s: %s: mii_read(status) failed",
goto usberr;
}
goto PHY_found;
}
}
return (USB_FAILURE);
if (err != USB_SUCCESS) {
"!%s: %s: mii_read(PHYIDH) failed",
goto usberr;
}
if (err != USB_SUCCESS) {
"!%s: %s: mii_read(PHYIDL) failed",
goto usberr;
}
if (dp->mii_phy_addr < 0) {
} else {
}
"!%s: PHY control:%b, status:%b, advert:%b, lpar:%b, exp:%b",
dp->mii_xstatus = 0;
if (status & MII_STATUS_XSTATUS) {
}
/* check if the phy can advertize pause abilities */
if (err != USB_SUCCESS) {
goto usberr;
}
if (err != USB_SUCCESS) {
goto usberr;
}
if (err != USB_SUCCESS) {
goto usberr;
}
if ((adv & MII_ABILITY_PAUSE) == 0) {
}
if ((adv & MII_ABILITY_ASM_DIR) == 0) {
}
if (err != USB_SUCCESS) {
goto usberr;
}
return (USB_SUCCESS);
return (USB_FAILURE);
}
int
{
/* ENPTY */
return (USB_SUCCESS);
}
static int
{
int err;
/* make a first call of usbgem_mii_link_check() */
dp->link_watcher_stop = 0;
"!%s: %s: failed to create a link watcher thread",
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
static void
{
/* Ensure timer routine stopped */
}
/* ============================================================== */
/*
* internal mac register operation interface
*/
/* ============================================================== */
/*
* usbgem_mac_init: cold start
*/
static int
{
int err;
/* pretend we succeeded */
return (USB_SUCCESS);
}
/* reset fatal error timestamp */
/* reset tx side state */
dp->tx_busy_cnt = 0;
/* reset rx side state */
dp->rx_busy_cnt = 0;
if (err == USB_SUCCESS) {
}
return (err);
}
/*
* usbgem_mac_start: warm start
*/
static int
{
int err;
int i;
#ifdef USBGEM_DEBUG_LEVEL
#endif
/* do nothing but don't return failure */
return (USB_SUCCESS);
}
/* don't return failer */
"!%s: %s: mac_state(%d) is not MAC_STATE_INITIALIZED",
goto x;
}
"!%s: %s: usb error was detected during start_chip",
goto x;
}
#ifdef USBGEM_DEBUG_LEVEL
#endif /* USBGEM_DEBUG_LEVEL */
/* make a request for interrupt */
goto x;
}
req->intr_timeout = 0;
req->intr_completion_reason = 0;
req->intr_cb_flags = 0;
if (err != USB_SUCCESS) {
"%s: err:%d failed to start polling of intr pipe",
goto x;
}
}
/* kick to receive the first packet */
goto err_stop_intr;
}
return (USB_SUCCESS);
/* stop the interrupt pipe */
}
x:
/* we use another flag to indicate error state. */
}
return (USB_FAILURE);
}
static int
{
/*
* we must have writer lock for dev_state_lock
*/
/* stop polling interrupt pipe */
}
/* stop the nic hardware completely */
(void) usbgem_hal_reset_chip(dp);
}
}
/* stop preparing new rx packets and sending new packets */
/* other processors must get mac_state correctly after here */
/* cancel all requests we have sent */
"!%s: %s: rx_busy_cnt:%d tx_busy_cnt:%d",
/*
* Here all rx packets has been cancelled and their call back
* function has been exeuted, because we called usb_pipe_reset
* synchronously.
* So actually we just ensure rx_busy_cnt == 0.
*/
while (dp->rx_busy_cnt > 0) {
}
while (dp->tx_busy_cnt > 0) {
}
return (USB_SUCCESS);
}
static int
{
int cnt;
int err;
/* append the new address at the end of the mclist */
}
}
/* multicast address list overflow */
} else {
}
/* tell new multicast list to the hardware */
}
return (err);
}
static int
{
int i;
int cnt;
int err;
dp->mc_count_req--;
for (i = 0; i < cnt; i++) {
continue;
}
/* shrink the mclist by copying forward */
if (len > 0) {
}
break;
}
/* multicast address list overflow */
} else {
}
}
return (err);
}
/* ============================================================== */
/*
* ioctl
*/
/* ============================================================== */
enum ioc_reply {
};
#ifdef USBGEM_CONFIG_MAC_PROP
static int
{
int err = 0;
ASSERT(pr_valsize > 0);
switch (pr_num) {
case MAC_PROP_AUTONEG:
break;
case MAC_PROP_FLOWCTRL:
if (pr_valsize < sizeof (link_flowctrl_t)) {
return (EINVAL);
}
case FLOW_CONTROL_NONE:
break;
case FLOW_CONTROL_SYMMETRIC:
break;
case FLOW_CONTROL_TX_PAUSE:
break;
case FLOW_CONTROL_RX_PAUSE:
break;
}
break;
case MAC_PROP_ADV_1000FDX_CAP:
case MAC_PROP_EN_1000FDX_CAP:
break;
case MAC_PROP_ADV_1000HDX_CAP:
case MAC_PROP_EN_1000HDX_CAP:
break;
case MAC_PROP_ADV_100T4_CAP:
case MAC_PROP_EN_100T4_CAP:
break;
case MAC_PROP_ADV_100FDX_CAP:
case MAC_PROP_EN_100FDX_CAP:
break;
case MAC_PROP_ADV_100HDX_CAP:
case MAC_PROP_EN_100HDX_CAP:
break;
case MAC_PROP_ADV_10FDX_CAP:
case MAC_PROP_EN_10FDX_CAP:
break;
case MAC_PROP_ADV_10HDX_CAP:
case MAC_PROP_EN_10HDX_CAP:
break;
default:
break;
}
return (err);
}
#ifdef MAC_VERSION_V1
static void
{
/*
* otherwise by the driver.
*/
switch (pr_num) {
case MAC_PROP_DUPLEX:
case MAC_PROP_SPEED:
case MAC_PROP_STATUS:
case MAC_PROP_ADV_1000FDX_CAP:
case MAC_PROP_ADV_1000HDX_CAP:
case MAC_PROP_ADV_100FDX_CAP:
case MAC_PROP_ADV_100HDX_CAP:
case MAC_PROP_ADV_10FDX_CAP:
case MAC_PROP_ADV_10HDX_CAP:
case MAC_PROP_ADV_100T4_CAP:
case MAC_PROP_EN_100T4_CAP:
break;
case MAC_PROP_EN_1000FDX_CAP:
== 0) {
} else {
}
break;
case MAC_PROP_EN_1000HDX_CAP:
} else {
}
break;
case MAC_PROP_EN_100FDX_CAP:
} else {
}
break;
case MAC_PROP_EN_100HDX_CAP:
} else {
}
break;
case MAC_PROP_EN_10FDX_CAP:
} else {
}
break;
case MAC_PROP_EN_10HDX_CAP:
} else {
}
break;
case MAC_PROP_AUTONEG:
} else {
}
break;
case MAC_PROP_FLOWCTRL:
case FLOW_CONTROL_NONE:
break;
case FLOW_CONTROL_SYMMETRIC:
break;
case FLOW_CONTROL_TX_PAUSE:
break;
case FLOW_CONTROL_RX_PAUSE:
break;
}
break;
case MAC_PROP_MTU:
break;
case MAC_PROP_PRIVATE:
break;
}
}
#endif
static int
{
int err = 0;
switch (pr_num) {
case MAC_PROP_EN_1000FDX_CAP:
}
} else {
}
break;
case MAC_PROP_EN_1000HDX_CAP:
}
} else {
}
break;
case MAC_PROP_EN_100FDX_CAP:
}
} else {
}
break;
case MAC_PROP_EN_100HDX_CAP:
}
} else {
}
break;
case MAC_PROP_EN_10FDX_CAP:
}
} else {
}
break;
case MAC_PROP_EN_10HDX_CAP:
}
} else {
}
break;
case MAC_PROP_AUTONEG:
}
} else {
}
break;
case MAC_PROP_FLOWCTRL:
switch (flowctrl) {
default:
break;
case LINK_FLOWCTRL_NONE:
}
break;
case LINK_FLOWCTRL_RX:
}
break;
case LINK_FLOWCTRL_TX:
}
break;
case LINK_FLOWCTRL_BI:
}
break;
}
break;
case MAC_PROP_ADV_1000FDX_CAP:
case MAC_PROP_ADV_1000HDX_CAP:
case MAC_PROP_ADV_100FDX_CAP:
case MAC_PROP_ADV_100HDX_CAP:
case MAC_PROP_ADV_10FDX_CAP:
case MAC_PROP_ADV_10HDX_CAP:
case MAC_PROP_STATUS:
case MAC_PROP_SPEED:
case MAC_PROP_DUPLEX:
break;
case MAC_PROP_MTU:
}
break;
case MAC_PROP_PRIVATE:
break;
default:
break;
}
if (update) {
/* sync with PHY */
}
return (err);
}
static int
#ifdef MAC_VERSION_V1
#else
#endif
{
int err = 0;
if (pr_valsize == 0) {
return (EINVAL);
}
#ifndef MAC_VERSION_V1
*perm = MAC_PROP_PERM_RW;
#endif
#ifndef MAC_VERSION_V1
}
#endif
switch (pr_num) {
case MAC_PROP_DUPLEX:
#ifndef MAC_VERSION_V1
#endif
if (pr_valsize >= sizeof (link_duplex_t)) {
} else if (dp->full_duplex) {
} else {
}
} else {
}
break;
case MAC_PROP_SPEED:
#ifndef MAC_VERSION_V1
#endif
if (pr_valsize >= sizeof (uint64_t)) {
case USBGEM_SPD_1000:
tmp = 1000000000;
break;
case USBGEM_SPD_100:
tmp = 100000000;
break;
case USBGEM_SPD_10:
tmp = 10000000;
break;
default:
tmp = 0;
}
} else {
}
break;
case MAC_PROP_AUTONEG:
#ifndef MAC_VERSION_V1
}
#endif
break;
case MAC_PROP_FLOWCTRL:
if (pr_valsize >= sizeof (link_flowctrl_t)) {
switch (dp->flow_control) {
case FLOW_CONTROL_NONE:
break;
case FLOW_CONTROL_RX_PAUSE:
break;
case FLOW_CONTROL_TX_PAUSE:
break;
case FLOW_CONTROL_SYMMETRIC:
break;
}
} else {
}
break;
case MAC_PROP_ADV_1000FDX_CAP:
case MAC_PROP_ADV_1000HDX_CAP:
case MAC_PROP_ADV_100FDX_CAP:
case MAC_PROP_ADV_100HDX_CAP:
case MAC_PROP_ADV_10FDX_CAP:
case MAC_PROP_ADV_10HDX_CAP:
case MAC_PROP_ADV_100T4_CAP:
break;
case MAC_PROP_EN_1000FDX_CAP:
#ifndef MAC_VERSION_V1
}
#endif
break;
case MAC_PROP_EN_1000HDX_CAP:
#ifndef MAC_VERSION_V1
}
#endif
break;
case MAC_PROP_EN_100FDX_CAP:
#ifndef MAC_VERSION_V1
}
#endif
break;
case MAC_PROP_EN_100HDX_CAP:
#ifndef MAC_VERSION_V1
}
#endif
break;
case MAC_PROP_EN_10FDX_CAP:
#ifndef MAC_VERSION_V1
}
#endif
break;
case MAC_PROP_EN_10HDX_CAP:
#ifndef MAC_VERSION_V1
}
#endif
break;
case MAC_PROP_EN_100T4_CAP:
#ifndef MAC_VERSION_V1
}
#endif
break;
case MAC_PROP_PRIVATE:
break;
#ifndef MAC_VERSION_V1
case MAC_PROP_MTU: {
if (!(pr_flags & MAC_PROP_POSSIBLE)) {
break;
}
if (pr_valsize < sizeof (mac_propval_range_t)) {
break;
}
break;
}
#endif
default:
break;
}
return (err);
}
#endif /* USBGEM_CONFIG_MAC_PROP */
#ifdef USBGEM_CONFIG_ND
/* ============================================================== */
/*
* ND interface
*/
/* ============================================================== */
enum {
#ifdef DEBUG_RESUME
#endif
};
struct usbgem_nd_arg {
int item;
};
static int
{
long val;
switch (item) {
case PARAM_AUTONEG_CAP:
break;
case PARAM_PAUSE_CAP:
break;
case PARAM_ASYM_PAUSE_CAP:
break;
case PARAM_1000FDX_CAP:
break;
case PARAM_1000HDX_CAP:
break;
case PARAM_100T4_CAP:
break;
case PARAM_100FDX_CAP:
break;
case PARAM_100HDX_CAP:
break;
case PARAM_10FDX_CAP:
break;
case PARAM_10HDX_CAP:
break;
case PARAM_ADV_AUTONEG_CAP:
break;
case PARAM_ADV_PAUSE_CAP:
break;
case PARAM_ADV_ASYM_PAUSE_CAP:
break;
case PARAM_ADV_1000FDX_CAP:
break;
case PARAM_ADV_1000HDX_CAP:
break;
case PARAM_ADV_100T4_CAP:
break;
case PARAM_ADV_100FDX_CAP:
break;
case PARAM_ADV_100HDX_CAP:
break;
case PARAM_ADV_10FDX_CAP:
break;
case PARAM_ADV_10HDX_CAP:
break;
case PARAM_ADV_1000T_MS:
break;
case PARAM_LP_AUTONEG_CAP:
break;
case PARAM_LP_PAUSE_CAP:
break;
case PARAM_LP_ASYM_PAUSE_CAP:
break;
case PARAM_LP_1000FDX_CAP:
break;
case PARAM_LP_1000HDX_CAP:
break;
case PARAM_LP_100T4_CAP:
break;
case PARAM_LP_100FDX_CAP:
break;
case PARAM_LP_100HDX_CAP:
break;
case PARAM_LP_10FDX_CAP:
break;
case PARAM_LP_10HDX_CAP:
break;
case PARAM_LINK_STATUS:
break;
case PARAM_LINK_SPEED:
break;
case PARAM_LINK_DUPLEX:
val = 0;
}
break;
case PARAM_LINK_AUTONEG:
break;
case PARAM_LINK_RX_PAUSE:
break;
case PARAM_LINK_TX_PAUSE:
break;
#ifdef DEBUG_RESUME
case PARAM_RESUME_TEST:
val = 0;
break;
#endif
default:
break;
}
return (0);
}
static int
{
long val;
char *end;
return (EINVAL);
}
return (EINVAL);
}
switch (item) {
case PARAM_ADV_AUTONEG_CAP:
goto err;
}
goto err;
}
break;
case PARAM_ADV_PAUSE_CAP:
goto err;
}
goto err;
}
break;
case PARAM_ADV_ASYM_PAUSE_CAP:
goto err;
}
if (val &&
goto err;
}
break;
case PARAM_ADV_1000FDX_CAP:
goto err;
}
MII_XSTATUS_1000BASEX_FD)) == 0) {
goto err;
}
break;
case PARAM_ADV_1000HDX_CAP:
goto err;
}
(MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASEX)) == 0) {
goto err;
}
break;
case PARAM_ADV_100T4_CAP:
goto err;
}
goto err;
}
break;
case PARAM_ADV_100FDX_CAP:
goto err;
}
goto err;
}
break;
case PARAM_ADV_100HDX_CAP:
goto err;
}
goto err;
}
break;
case PARAM_ADV_10FDX_CAP:
goto err;
}
goto err;
}
break;
case PARAM_ADV_10HDX_CAP:
goto err;
}
goto err;
}
break;
case PARAM_ADV_1000T_MS:
goto err;
}
(MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASET_FD)) == 0) {
goto err;
}
break;
#ifdef DEBUG_RESUME
case PARAM_RESUME_TEST:
break;
#endif
}
/* sync with PHY */
/* wake up link watcher possiblely sleeps */
}
return (0);
err:
return (EINVAL);
}
static void
{
}
static void
{
/* Our advertised capabilities */
!dp->mii_advert_ro),
!dp->mii_advert_ro),
!dp->mii_advert_ro),
!dp->mii_advert_ro),
!dp->mii_advert_ro),
/* Partner's advertised capabilities */
/* Current operating modes */
#ifdef DEBUG_RESUME
#endif
}
static
enum ioc_reply
{
case ND_GET:
case ND_SET:
if (!ok) {
return (IOC_INVAL);
}
return (IOC_REPLY);
}
return (IOC_RESTART_REPLY);
}
return (IOC_INVAL);
}
static void
{
}
#endif /* USBGEM_CONFIG_ND */
static void
{
int cmd;
/*
* Validate the command before bothering with the mutex ...
*/
#ifdef USBGEM_CONFIG_ND
switch (cmd) {
default:
break;
case ND_GET:
case ND_SET:
break;
}
/*
* Finally, decide how to reply
*/
switch (status) {
default:
case IOC_INVAL:
/*
* Error, reply with a NAK and EINVAL or the specified error
*/
break;
case IOC_DONE:
/*
* OK, reply already sent
*/
break;
case IOC_RESTART_ACK:
case IOC_ACK:
/*
* OK, reply with an ACK
*/
break;
case IOC_RESTART_REPLY:
case IOC_REPLY:
/*
* OK, send prepared reply as ACK or NAK
*/
break;
}
#else
return;
#endif /* USBGEM_CONFIG_GLDv3 */
}
#ifndef SYS_MAC_H
#define XCVR_UNDEFINED 0
#endif
static int
{
val = XCVR_100T4;
} else if (dp->mii_status &
} else if (dp->mii_status &
val = XCVR_100T2;
} else if (dp->mii_status &
(MII_STATUS_10_FD | MII_STATUS_10)) {
}
} else if (dp->mii_xstatus &
val = XCVR_1000T;
} else if (dp->mii_xstatus &
val = XCVR_1000X;
}
return (val);
}
#ifdef USBGEM_CONFIG_GLDv3
/* ============================================================== */
/*
* GLDv3 interface
*/
/* ============================================================== */
static int usbgem_m_start(void *);
static void usbgem_m_stop(void *);
static int usbgem_m_setpromisc(void *, boolean_t);
static int usbgem_m_unicst(void *, const uint8_t *);
#ifdef GEM_CONFIG_MAC_PROP
static int usbgem_m_setprop(void *, const char *, mac_prop_id_t,
uint_t, const void *);
#ifdef MAC_VERSION_V1
static int usbgem_m_getprop(void *, const char *, mac_prop_id_t,
uint_t, void *);
#else
static int usbgem_m_getprop(void *, const char *, mac_prop_id_t,
#endif
#endif
#ifdef _SYS_MAC_PROVIDER_H
#else
#endif
#ifdef USBGEM_CONFIG_MAC_PROP
#ifdef MAC_VERSION_V1
#else
#endif
#else
#endif
#ifdef _SYS_MAC_PROVIDER_H
#ifdef MAC_VERSION_V1
NULL,
#endif
#else
NULL, /* m_resources */
#endif
NULL, /* m_getcapab */
#ifdef USBGEM_CONFIG_MAC_PROP
NULL,
NULL,
#endif
#ifdef MAC_VERSION_V1
#endif
};
static int
{
int ret;
int err;
err = 0;
goto x;
}
goto x;
}
/* initialize rx filter state */
dp->mc_count_req = 0;
if (ret != USB_SUCCESS) {
goto x;
}
/* setup media mode if the link have been up */
goto x;
}
goto x;
}
}
err = 0;
x:
return (err);
}
static void
{
/* stop rx gracefully */
(void) usbgem_hal_set_rx_filter(dp);
}
/* make the nic state inactive */
/* stop mac completely */
}
}
static int
{
int err;
int ret;
if (add) {
} else {
}
err = 0;
if (ret != USB_SUCCESS) {
#ifdef GEM_CONFIG_FMA
#endif
}
return (err);
}
static int
{
int err;
if (on) {
} else {
}
err = 0;
}
}
#ifdef GEM_CONFIG_FMA
if (err != 0) {
}
#endif
return (err);
}
int
{
int ret;
return (0);
}
#ifdef GEM_CONFIG_FMA
if (ret != USB_SUCCESS) {
return (EIO);
}
#endif
switch (stat) {
case MAC_STAT_IFSPEED:
break;
case MAC_STAT_MULTIRCV:
break;
case MAC_STAT_BRDCSTRCV:
break;
case MAC_STAT_MULTIXMT:
break;
case MAC_STAT_BRDCSTXMT:
break;
case MAC_STAT_NORCVBUF:
break;
case MAC_STAT_IERRORS:
break;
case MAC_STAT_NOXMTBUF:
break;
case MAC_STAT_OERRORS:
break;
case MAC_STAT_COLLISIONS:
break;
case MAC_STAT_RBYTES:
break;
case MAC_STAT_IPACKETS:
break;
case MAC_STAT_OBYTES:
break;
case MAC_STAT_OPACKETS:
break;
case MAC_STAT_UNDERFLOWS:
break;
case MAC_STAT_OVERFLOWS:
break;
case ETHER_STAT_ALIGN_ERRORS:
break;
case ETHER_STAT_FCS_ERRORS:
break;
break;
break;
case ETHER_STAT_SQE_ERRORS:
break;
case ETHER_STAT_DEFER_XMTS:
break;
break;
case ETHER_STAT_EX_COLLISIONS:
break;
case ETHER_STAT_MACXMT_ERRORS:
break;
break;
break;
case ETHER_STAT_MACRCV_ERRORS:
break;
case ETHER_STAT_XCVR_ADDR:
break;
case ETHER_STAT_XCVR_ID:
break;
case ETHER_STAT_XCVR_INUSE:
break;
case ETHER_STAT_CAP_1000FDX:
break;
case ETHER_STAT_CAP_1000HDX:
break;
case ETHER_STAT_CAP_100FDX:
break;
case ETHER_STAT_CAP_100HDX:
break;
case ETHER_STAT_CAP_10FDX:
break;
case ETHER_STAT_CAP_10HDX:
break;
case ETHER_STAT_CAP_ASMPAUSE:
break;
case ETHER_STAT_CAP_PAUSE:
break;
case ETHER_STAT_CAP_AUTONEG:
break;
break;
break;
break;
break;
case ETHER_STAT_ADV_CAP_10FDX:
break;
case ETHER_STAT_ADV_CAP_10HDX:
break;
break;
case ETHER_STAT_ADV_CAP_PAUSE:
break;
break;
break;
break;
case ETHER_STAT_LP_CAP_100FDX:
break;
case ETHER_STAT_LP_CAP_100HDX:
break;
case ETHER_STAT_LP_CAP_10FDX:
break;
case ETHER_STAT_LP_CAP_10HDX:
break;
break;
case ETHER_STAT_LP_CAP_PAUSE:
break;
break;
case ETHER_STAT_LINK_ASMPAUSE:
break;
case ETHER_STAT_LINK_PAUSE:
break;
case ETHER_STAT_LINK_AUTONEG:
break;
case ETHER_STAT_LINK_DUPLEX:
break;
break;
#ifdef NEVER /* it doesn't make sense */
case ETHER_STAT_CAP_REMFAULT:
break;
case ETHER_STAT_ADV_REMFAULT:
break;
#endif
case ETHER_STAT_LP_REMFAULT:
break;
case ETHER_STAT_JABBER_ERRORS:
break;
case ETHER_STAT_CAP_100T4:
break;
case ETHER_STAT_ADV_CAP_100T4:
break;
case ETHER_STAT_LP_CAP_100T4:
break;
default:
#if GEM_DEBUG_LEVEL > 2
"%s: unrecognized parameter value = %d",
#endif
*valp = 0;
return (ENOTSUP);
}
return (0);
}
static int
{
int err;
err = 0;
}
}
#ifdef GEM_CONFIG_FMA
if (err != 0) {
}
#endif
return (err);
}
/*
* usbgem_m_tx is used only for sending data packets into ethernet wire.
*/
static mblk_t *
{
int limit;
flags = 0;
/* some nics hate to send packets during the link is down */
}
goto x;
}
break;
}
}
#ifdef CONFIG_TX_LIMITER
/* no packets were sent, descrease allocation limit */
}
#endif
x:
return (mp);
}
static void
{
}
static void
{
}
}
#else
/* ============================================================== */
/*
* GLDv2 interface
*/
/* ============================================================== */
static int usbgem_gld_reset(gld_mac_info_t *);
static int usbgem_gld_start(gld_mac_info_t *);
static int usbgem_gld_stop(gld_mac_info_t *);
static int usbgem_gld_set_promiscuous(gld_mac_info_t *, int);
static int
{
int err;
err = GLD_SUCCESS;
err = GLD_FAILURE;
goto x;
}
/* setup media mode if the link have been up */
(void) usbgem_hal_set_media(dp);
}
}
x:
return (err);
}
static int
{
int err;
/* sema_v(&dp->mii_lock); */
err = GLD_FAILURE;
goto x;
}
}
/*
* XXX - don't call gld_linkstate() here,
* otherwise it cause recursive mutex call.
*/
err = GLD_SUCCESS;
x:
return (err);
}
static int
{
/* try to stop rx gracefully */
(void) usbgem_hal_set_rx_filter(dp);
}
/* make the nic state inactive */
!= USB_SUCCESS) {
err = GLD_FAILURE;
}
}
return (err);
}
static int
{
int err;
int ret;
if (flag == GLD_MULTI_ENABLE) {
} else {
}
err = GLD_SUCCESS;
if (ret != USB_SUCCESS) {
#ifdef GEM_CONFIG_FMA
#endif
err = GLD_FAILURE;
}
return (err);
}
static int
{
if (flag == GLD_MAC_PROMISC_NONE) {
} else if (flag == GLD_MAC_PROMISC_MULTI) {
} else if (flag == GLD_MAC_PROMISC_PHYS) {
} else {
/* mode unchanged */
}
if (need_to_change) {
(void) usbgem_hal_set_rx_filter(dp);
}
}
return (GLD_SUCCESS);
}
static int
{
(void) usbgem_hal_set_rx_filter(dp);
}
return (GLD_SUCCESS);
}
static int
{
#ifdef GEM_CONFIG_FMA
#endif
return (USB_FAILURE);
}
/* all before here must be kept in place for v0 compatibility */
/* gs->glds_media_specific */
gs->glds_dot3_sqe_error = 0;
gs->glds_dot3_mac_xmt_error = 0;
gs->glds_dot3_mac_rcv_error = 0;
return (GLD_SUCCESS);
}
static int
{
return (GLD_SUCCESS);
}
/*
* gem_gld_send is used only for sending data packets into ethernet wire.
*/
static int
{
int ret;
/* nic state must be online of suspended */
/* Some nics hate to send packets while the link is down. */
/* we discard the untransmitted packets silently */
#ifdef GEM_CONFIG_FMA
/* FIXME - should we ignore the error? */
#endif
return (GLD_SUCCESS);
}
return (ret);
}
/*
* usbgem_gld_send is used only for sending data packets into ethernet wire.
*/
static int
{
/*
* Some nics hate to send packets while the link is down.
*/
/* we dicard the untransmitted packets silently */
#ifdef GEM_CONFIG_FMA
/* FIXME - should we ignore the error? */
#endif
return (GLD_SUCCESS);
}
#ifdef notyet
#endif
}
static void
{
/*
* configure GLD
*/
macinfo->gldm_ident = ident;
macinfo->gldm_minpkt = 0;
#ifdef GLD_CAP_LINKSTATE
#endif
}
#endif /* USBGEM_CONFIG_GLDv3 */
/* ======================================================================== */
/*
* .conf interface
*/
/* ======================================================================== */
void
{
extern char hw_serial[];
char *hw_serial_p;
int i;
"!%s: using temp ether address,"
" do not use this for long time",
/* prefer a fixed address for DHCP */
hw_serial_p = &hw_serial[0];
key = 0;
for (i = 0; i < USBGEM_NAME_LEN; i++) {
break;
}
}
/* generate a local address */
mac[0] = 0x02;
}
{
char *valstr;
char *cp;
int c;
int i;
int j;
uint8_t v;
uint8_t d;
/*
* Get ethernet address from .conf file
*/
return (B_FALSE);
}
goto syntax_err;
}
j = 0;
ored = 0;
for (;;) {
v = 0;
for (i = 0; i < 2; i++) {
c = *cp++;
if (c >= 'a' && c <= 'f') {
d = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
d = c - 'A' + 10;
} else if (c >= '0' && c <= '9') {
d = c - '0';
} else {
goto syntax_err;
}
v = (v << 4) | d;
}
mac[j++] = v;
ored |= v;
if (j == ETHERADDRL) {
/* done */
break;
}
c = *cp++;
if (c != ':') {
goto syntax_err;
}
}
if (ored == 0) {
}
for (i = 0; i < ETHERADDRL; i++) {
}
return (B_TRUE);
"!%s: read mac addr: trying .conf: syntax err %s",
return (B_FALSE);
}
static void
{
int val;
/*
* Get media mode infomation from .conf file
*/
DDI_PROP_DONTPASS, "full-duplex"))) {
dp->full_duplex =
if (dp->full_duplex) {
} else {
}
}
switch (val) {
case 1000:
break;
case 100:
break;
case 10:
break;
default:
"!%s: property %s: illegal value:%d",
break;
}
}
"!%s: property %s: illegal value:%d",
} else {
}
#ifdef GEM_CONFIG_POLLING
dp->poll_pkt_delay =
#endif
}
/*
* usbem kstat support
*/
#ifndef GEM_CONFIG_GLDv3
/* kstat items based from dmfe driver */
struct usbgem_kstat_named {
#ifdef NEVER
#endif
#ifdef NEVER
#endif
};
static int
{
if (rw != KSTAT_READ) {
return (0);
}
#ifdef NEVER
#endif
#ifdef NEVER
#endif
return (0);
}
static int
{
int i;
ksp = kstat_create(
return (USB_FAILURE);
}
#ifdef NEVER
#endif
#ifdef NEVER
#endif
return (USB_SUCCESS);
}
#endif /* GEM_CONFIG_GLDv3 */
/* ======================================================================== */
/*
*/
/* ======================================================================== */
int
{
int i;
int ret;
"reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x "
"bp:0x%p nic_state:%d",
return (USB_PIPE_ERROR);
}
if (size > 0) {
return (USB_FAILURE);
}
}
for (i = usbgem_ctrl_retry; i > 0; i--) {
completion_reason = 0;
cb_flags = 0;
if (ret == USB_SUCCESS) {
break;
}
if (i == 1) {
"!%s: %s failed: "
"reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
"ret:%d cr:%s(%d), cb_flags:0x%x %s",
(i > 1) ? "retrying..." : "fatal");
}
}
}
return (ret);
}
int
{
int i;
int ret;
int reclen;
"!%s: %s:"
" reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x"
" bp:x%p mac_state:%d",
return (USB_PIPE_ERROR);
}
for (i = usbgem_ctrl_retry; i > 0; i--) {
completion_reason = 0;
cb_flags = 0;
&completion_reason, &cb_flags, 0);
if (ret == USB_SUCCESS) {
break;
}
if (i == 1) {
"!%s: %s failed: "
"reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
"ret:%d cr:%s(%d) cb_flags:0x%x %s",
(i > 1) ? "retrying..." : "fatal");
}
}
if (data) {
}
return (ret);
}
int
uint32_t v)
{
/* convert to little endian from native byte order */
switch (len) {
case 4:
/* FALLTHROUGH */
case 2:
/* FALLTHROUGH */
case 1:
buf[0] = v;
}
}
int
void *valp)
{
uint_t v;
int err;
#ifdef SANITY
#endif
if (err == USB_SUCCESS) {
v = 0;
switch (len) {
case 4:
/* FALLTHROUGH */
case 2:
/* FALLTHROUGH */
case 1:
v |= buf[0];
}
switch (len) {
case 4:
break;
case 2:
break;
case 1:
break;
}
}
return (err);
}
/*
* Attach / detach / disconnect / reconnect management
*/
static int
{
int i;
int ret;
int ifnum;
int alt;
if (ep_tree_node == NULL) {
goto err;
}
if (ep_tree_node == NULL) {
goto err;
}
if (ep_tree_node) {
} else {
/* don't care */
}
/* XXX -- no need to open default pipe */
/* open bulk out pipe */
"!%s: %s: err:%x: failed to open bulk-out pipe",
goto err;
}
/* open bulk in pipe */
"!%s: %s: ret:%x failed to open bulk-in pipe",
goto err;
}
/* open interrupt pipe */
"!%s: %s: ret:%x failed to open interrupt pipe",
goto err;
}
}
return (USB_SUCCESS);
err:
if (dp->bulkin_pipe) {
}
if (dp->bulkout_pipe) {
}
}
return (USB_FAILURE);
}
static int
{
}
return (USB_SUCCESS);
}
static int
{
/* stop nic activity */
/*
* Here we free all memory resource allocated, because it will
* cause to panic the system that we free usb_bulk_req objects
* during the usb device is disconnected.
*/
(void) usbgem_free_memory(dp);
return (USB_SUCCESS);
}
static int
{
int ret;
/* start serialize */
/* end of serialize */
return (ret);
}
static int
{
int err;
err = USB_SUCCESS;
/* reinitialize the usb connection */
goto x;
}
/* initialize nic state */
/* allocate memory resources again */
goto x;
}
/* restart nic and recover state */
(void) usbgem_restart_nic(dp);
/* kick potentially stopped house keeping thread */
x:
return (err);
}
static int
{
#ifdef notdef
/* check device changes after disconnect */
return (DDI_SUCCESS);
}
#endif
/* start serialize */
}
/* end of serialize */
}
int
{
/* start serialize */
}
/* end of serialize */
}
int
{
#ifdef notdef
/* check device changes after disconnect */
return (DDI_SUCCESS);
}
#endif
/* start serialize */
}
/* end of serialize */
}
(sizeof (struct usbgem_dev) + USBGEM_MCALLOC)
struct usbgem_dev *
{
int i;
#ifdef USBGEM_CONFIG_GLDv3
#else
void *tmp;
#endif
int ret;
int unit;
int err;
/*
* Allocate soft data structure
*/
#ifndef USBGEM_CONFIG_GLDv3
#endif
return (NULL);
}
#ifdef USBGEM_CONFIG_GLDv3
return (NULL);
}
#else
#endif
/* link to private area */
/*
* register with usb service
*/
"%s: %s: usb_client_attach failed",
goto err_free_private;
}
USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
goto err_unregister_client;
}
#ifdef USBGEM_DEBUG_LEVEL
#endif
/* failed to open pipes */
goto err_unregister_client;
}
/*
* Initialize mutexs and condition variables
*/
/*
* Initialize configuration
*/
/* performance tuning parameters */
/*
* Get media mode infomation from .conf file
*/
/* rx_buf_len depend on MTU */
/*
* Reset the chip
*/
"!%s: %s: failed to reset the usb device",
goto err_destroy_locks;
}
/*
* HW dependant paremeter initialization
*/
"!%s: %s: failed to attach the usb device",
goto err_destroy_locks;
}
/* allocate resources */
goto err_destroy_locks;
}
"!%s: %02x:%02x:%02x:%02x:%02x:%02x",
/* copy mac address */
/* pre-calculated tx timeout in second for performance */
#ifdef USBGEM_CONFIG_GLDv3
#else
#endif
/* Probe MII phy (scan phy) */
dp->mii_lpable = 0;
dp->mii_advert = 0;
dp->mii_ctl1000 = 0;
dp->mii_stat1000 = 0;
dp->mii_status_ro = 0;
dp->mii_xstatus_ro = 0;
goto err_free_memory;
}
/* mask unsupported abilities */
dp->anadv_1000fdx &=
dp->anadv_1000hdx &=
goto err_free_memory;
}
/*
* initialize kstats including mii statistics
*/
#ifdef USBGEM_CONFIG_GLDv3
#ifdef USBGEM_CONFIG_ND
#endif
#else
goto err_free_memory;
}
#endif
/*
* Add interrupt to system.
*/
#ifdef USBGEM_CONFIG_GLDv3
goto err_release_stats;
}
#else
/* gld_register will corrupts driver_private */
if (gld_register(dip,
goto err_release_stats;
}
/* restore driver private */
#endif /* USBGEM_CONFIG_GLDv3 */
"!%s: %s: failed to register hotplug cbs",
goto err_unregister_gld;
}
/* reset mii and start mii link watcher */
goto err_unregister_hotplug;
}
/* start tx watchdow watcher */
if (usbgem_tx_watcher_start(dp)) {
goto err_usbgem_mii_stop;
}
return (dp);
#ifdef USBGEM_CONFIG_GLDv3
#else
#endif
#ifdef USBGEM_CONFIG_GLDv3
#ifdef USBGEM_CONFIG_ND
/* release NDD resources */
#endif
#else
#endif
(void) usbgem_close_pipes(dp);
#ifdef USBGEM_CONFIG_GLDv3
if (macp) {
}
#else
#endif
return (NULL);
}
int
{
#ifdef USBGEM_CONFIG_GLDv3
/* unregister with gld v3 */
return (DDI_FAILURE);
}
#else
/* unregister with gld v2 */
return (DDI_FAILURE);
}
#endif
/* unregister with hotplug service */
/* stop tx watchdog watcher */
/* stop the link manager */
/* unregister with usb service */
(void) usbgem_free_memory(dp);
(void) usbgem_close_pipes(dp);
/* unregister with kernel statistics */
#ifdef USBGEM_CONFIG_GLDv3
#ifdef USBGEM_CONFIG_ND
/* release ndd resources */
#endif
#else
/* destroy kstat objects */
#endif
/* release locks and condition variables */
/* release basic memory resources */
#ifndef USBGEM_CONFIG_GLDv3
#endif
return (DDI_SUCCESS);
}
int
{
#ifdef USBGEM_CONFIG_GLDv3
if (major == DDI_MAJOR_T_NONE) {
return (DDI_FAILURE);
}
#endif
return (DDI_SUCCESS);
}
void
{
#ifdef USBGEM_CONFIG_GLDv3
#endif
}
int
{
(void) usbgem_hal_reset_chip(dp);
}
}
/* devo_quiesce() must return DDI_SUCCESS always */
return (DDI_SUCCESS);
}