diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/io/e1000g/README | 13 | ||||
-rw-r--r-- | usr/src/uts/common/io/e1000g/e1000g_debug.h | 9 | ||||
-rw-r--r-- | usr/src/uts/common/io/e1000g/e1000g_main.c | 330 | ||||
-rw-r--r-- | usr/src/uts/common/io/e1000g/e1000g_ndd.c | 63 | ||||
-rw-r--r-- | usr/src/uts/common/io/e1000g/e1000g_stat.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/io/e1000g/e1000g_sw.h | 41 | ||||
-rw-r--r-- | usr/src/uts/common/io/e1000g/e1000g_tx.c | 127 |
7 files changed, 356 insertions, 231 deletions
diff --git a/usr/src/uts/common/io/e1000g/README b/usr/src/uts/common/io/e1000g/README index 2f443692b0..8a6311eb34 100644 --- a/usr/src/uts/common/io/e1000g/README +++ b/usr/src/uts/common/io/e1000g/README @@ -485,3 +485,16 @@ Notes on packaging: 6502458 e1000g is open source, move the source from usr/closed to use/src 6505360 e1000g Makefile should not include "-N drv/dld" in the LDFLAGS +5.1.7 +====== + This version has the following fix: + 6454375 e1000g link flaps at initialization, triggering failovers + 6472255 e1000g can't restore to 1000M with ndd setting + 6496763 e1000g should free packets when link is down + 6501294 "eeprom checksum failed" with pci8086,108c device + 6504688 e1000g.conf settings are inconsistent with ndd output + 6505445 e1000g : when all advertised capabilities are set to 0, ndd puts all of them 1 + 6519690 e1000g should not print the link up/down messages to console + 6531474 Fatal PCIe Fabric Error panics on T2000 when using jumbo frames on e1000g interfaces + 6535712 e1000g: the processing of the checksum flags should be protected by tx_lock + diff --git a/usr/src/uts/common/io/e1000g/e1000g_debug.h b/usr/src/uts/common/io/e1000g/e1000g_debug.h index 4f1e7abf47..6bb192cbce 100644 --- a/usr/src/uts/common/io/e1000g/e1000g_debug.h +++ b/usr/src/uts/common/io/e1000g/e1000g_debug.h @@ -81,8 +81,6 @@ extern "C" { #ifdef e1000g_DEBUG static int e1000g_debug = DEFAULTDEBUGLEVEL; -static int e1000g_display_only = DEFAULTDISPLAYONLY; -static int e1000g_print_only = DEFAULTPRINTONLY; static int e1000g_debug_hw = 1; #define e1000g_ERRS_LEVEL 0x001 /* (1) Errors */ @@ -122,10 +120,6 @@ static int e1000g_debug_hw = 1; #else static int e1000g_debug = 0; -static int e1000g_display_only = 1; /* 1 - Yes Display, */ - /* 0 - Don't Display */ -static int e1000g_print_only = 1; /* 1 - Yes Print to Msg Log, */ - /* 0 - Don't Print to Msg Log */ static int e1000g_debug_hw = 0; #define e1000g_DEBUGLOG_0(Adapter, Level, fmt) @@ -144,6 +138,9 @@ static int e1000g_debug_hw = 0; void e1000g_log(struct e1000g *Adapter, int level, char *fmt, ...); void e1000g_log_hw(char *msg, void *cptr, int length); +static int e1000g_display_only = DEFAULTDISPLAYONLY; +static int e1000g_print_only = DEFAULTPRINTONLY; + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/io/e1000g/e1000g_main.c b/usr/src/uts/common/io/e1000g/e1000g_main.c index 461cfaf739..38cb97028e 100644 --- a/usr/src/uts/common/io/e1000g/e1000g_main.c +++ b/usr/src/uts/common/io/e1000g/e1000g_main.c @@ -53,9 +53,9 @@ #define E1000_RX_INTPT_TIME 128 #define E1000_RX_PKT_CNT 8 -static char ident[] = "Intel PRO/1000 Ethernet 5.1.6"; +static char ident[] = "Intel PRO/1000 Ethernet 5.1.7"; static char e1000g_string[] = "Intel(R) PRO/1000 Network Connection"; -static char e1000g_version[] = "Driver Ver. 5.1.6"; +static char e1000g_version[] = "Driver Ver. 5.1.7"; /* * Proto types for DDI entry points @@ -75,7 +75,6 @@ static void e1000g_intr_work(struct e1000g *, uint32_t); static int e1000g_init(struct e1000g *); static int e1000g_start(struct e1000g *); static void e1000g_stop(struct e1000g *); -static boolean_t e1000g_reset(struct e1000g *); static int e1000g_m_start(void *); static void e1000g_m_stop(void *); static int e1000g_m_promisc(void *, boolean_t); @@ -101,8 +100,10 @@ static int e1000g_unicst_set(struct e1000g *, const uint8_t *, mac_addr_slot_t); /* * Local routines */ +static void e1000g_tx_drop(struct e1000g *Adapter); +static void e1000g_link_timer(void *); static void e1000g_LocalTimer(void *); -static boolean_t e1000g_LocalTimerWork(struct e1000g *); +static boolean_t e1000g_link_check(struct e1000g *); static boolean_t e1000g_stall_check(struct e1000g *); static void e1000g_smartspeed(struct e1000g *); static void e1000g_getparam(struct e1000g *Adapter); @@ -560,12 +561,6 @@ e1000gattach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) cmn_err(CE_CONT, "!%s, %s\n", e1000g_string, e1000g_version); - /* - * Tell the world about the link state of e1000g - */ - mac_link_update(Adapter->mh, - (Adapter->LinkIsActive) ? LINK_STATE_UP : LINK_STATE_DOWN); - return (DDI_SUCCESS); attach_fail: @@ -686,6 +681,8 @@ e1000g_set_driver_params(struct e1000g *Adapter) /* Get conf file properties */ e1000g_getparam(Adapter); + hw->forced_speed_duplex = e1000_100_full; + hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; e1000g_force_speed_duplex(Adapter); e1000g_get_max_frame_size(Adapter); @@ -779,6 +776,8 @@ e1000g_set_driver_params(struct e1000g *Adapter) hw->master_slave = e1000_ms_hw_default; /* E1000_MASTER_SLAVE */ } + Adapter->link_state = LINK_STATE_UNKNOWN; + return (DDI_SUCCESS); } @@ -1006,10 +1005,10 @@ e1000g_suspend(dev_info_t *devinfo) static int e1000g_init(struct e1000g *Adapter) { - UINT16 LineSpeed, Duplex; uint32_t pba; uint32_t ctrl; struct e1000_hw *hw; + clock_t link_timeout; hw = &Adapter->Shared; @@ -1027,8 +1026,17 @@ e1000g_init(struct e1000g *Adapter) (void) e1000_init_eeprom_params(hw); if (e1000_validate_eeprom_checksum(hw) < 0) { - e1000g_log(Adapter, CE_WARN, "Eeprom checksum failed"); - goto init_fail; + /* + * Some PCI-E parts fail the first check due to + * the link being in sleep state. Call it again, + * if it fails a second time its a real issue. + */ + if (e1000_validate_eeprom_checksum(hw) < 0) { + e1000g_log(Adapter, CE_WARN, + "Invalid EEPROM checksum. Please contact " + "the vendor to update the EEPROM."); + goto init_fail; + } } #ifdef __sparc @@ -1172,19 +1180,21 @@ e1000g_init(struct e1000g *Adapter) /* Setup Interrupt Throttling Register */ E1000_WRITE_REG(hw, ITR, Adapter->intr_throttling_rate); - /* - * Check for link status - */ - if (e1000g_link_up(Adapter)) { - e1000_get_speed_and_duplex(hw, &LineSpeed, &Duplex); - Adapter->link_speed = LineSpeed; - Adapter->link_duplex = Duplex; - Adapter->LinkIsActive = B_TRUE; + /* Start the timer for link setup */ + if (hw->autoneg) + link_timeout = PHY_AUTO_NEG_TIME * drv_usectohz(100000); + else + link_timeout = PHY_FORCE_TIME * drv_usectohz(100000); + + mutex_enter(&Adapter->e1000g_linklock); + if (hw->wait_autoneg_complete) { + Adapter->link_complete = B_TRUE; } else { - Adapter->link_speed = 0; - Adapter->link_duplex = 0; - Adapter->LinkIsActive = B_FALSE; + Adapter->link_complete = B_FALSE; + Adapter->link_tid = timeout(e1000g_link_timer, + (void *)Adapter, link_timeout); } + mutex_exit(&Adapter->e1000g_linklock); /* Enable PCI-Ex master */ if (hw->bus_type == e1000_bus_type_pci_express) { @@ -1359,12 +1369,6 @@ e1000g_m_start(void *arg) static int e1000g_start(struct e1000g *Adapter) { - /* - * We set Adapter->PseudoLinkChanged here, so that e1000g_LocalTimer - * will tell the upper network modules about the link state of e1000g - */ - Adapter->PseudoLinkChanged = B_TRUE; - if (!(Adapter->attach_progress & ATTACH_PROGRESS_INIT)) { if (e1000g_init(Adapter) != DDI_SUCCESS) { e1000g_log(Adapter, CE_WARN, @@ -1400,12 +1404,9 @@ e1000g_m_stop(void *arg) static void e1000g_stop(struct e1000g *Adapter) { - PTX_SW_PACKET packet; timeout_id_t tid; e1000g_tx_ring_t *tx_ring; - e1000g_msg_chain_t *msg_chain; - mblk_t *mp; - mblk_t *nmp; + boolean_t link_changed; tx_ring = Adapter->tx_ring; @@ -1423,17 +1424,25 @@ e1000g_stop(struct e1000g *Adapter) /* Disable timers */ disable_timeout(Adapter); + /* Disable the tx timer for 82547 chipset */ mutex_enter(&tx_ring->tx_lock); - tx_ring->timer_enable_82547 = B_FALSE; tid = tx_ring->timer_id_82547; tx_ring->timer_id_82547 = 0; - mutex_exit(&tx_ring->tx_lock); if (tid != 0) (void) untimeout(tid); + /* Disable the link timer */ + mutex_enter(&Adapter->e1000g_linklock); + tid = Adapter->link_tid; + Adapter->link_tid = 0; + mutex_exit(&Adapter->e1000g_linklock); + + if (tid != 0) + (void) untimeout(tid); + /* Stop the chip and release pending resources */ rw_enter(&Adapter->chip_lock, RW_WRITER); @@ -1442,6 +1451,31 @@ e1000g_stop(struct e1000g *Adapter) e1000_reset_hw(&Adapter->Shared); /* Release resources still held by the TX descriptors */ + e1000g_tx_drop(Adapter); + + /* Clean the pending rx jumbo packet fragment */ + if (Adapter->rx_mblk != NULL) { + freemsg(Adapter->rx_mblk); + Adapter->rx_mblk = NULL; + Adapter->rx_mblk_tail = NULL; + Adapter->rx_packet_len = 0; + } + + rw_exit(&Adapter->chip_lock); +} + +static void +e1000g_tx_drop(struct e1000g *Adapter) +{ + e1000g_tx_ring_t *tx_ring; + e1000g_msg_chain_t *msg_chain; + PTX_SW_PACKET packet; + mblk_t *mp; + mblk_t *nmp; + uint32_t packet_count; + + tx_ring = Adapter->tx_ring; + /* * Here we don't need to protect the lists using * the usedlist_lock and freelist_lock, for they @@ -1449,6 +1483,7 @@ e1000g_stop(struct e1000g *Adapter) */ mp = NULL; nmp = NULL; + packet_count = 0; packet = (PTX_SW_PACKET) QUEUE_GET_HEAD(&tx_ring->used_list); while (packet != NULL) { if (packet->mp != NULL) { @@ -1465,6 +1500,7 @@ e1000g_stop(struct e1000g *Adapter) } FreeTxSwPacket(packet); + packet_count++; packet = (PTX_SW_PACKET) QUEUE_GET_NEXT(&tx_ring->used_list, &packet->Link); @@ -1483,20 +1519,20 @@ e1000g_stop(struct e1000g *Adapter) mutex_exit(&msg_chain->lock); } - QUEUE_APPEND(&tx_ring->free_list, &tx_ring->used_list); - QUEUE_INIT_LIST(&tx_ring->used_list); + ddi_intr_trigger_softint(Adapter->tx_softint_handle, NULL); - /* Clean the pending rx jumbo packet fragment */ - if (Adapter->rx_mblk != NULL) { - freemsg(Adapter->rx_mblk); - Adapter->rx_mblk = NULL; - Adapter->rx_mblk_tail = NULL; - Adapter->rx_packet_len = 0; - } + if (packet_count > 0) { + QUEUE_APPEND(&tx_ring->free_list, &tx_ring->used_list); + QUEUE_INIT_LIST(&tx_ring->used_list); - rw_exit(&Adapter->chip_lock); + /* Setup TX descriptor pointers */ + tx_ring->tbd_next = tx_ring->tbd_first; + tx_ring->tbd_oldest = tx_ring->tbd_first; - (void) e1000g_tx_freemsg((caddr_t)Adapter, NULL); + /* Setup our HW Tx Head & Tail descriptor pointers */ + E1000_WRITE_REG(&Adapter->Shared, TDH, 0); + E1000_WRITE_REG(&Adapter->Shared, TDT, 0); + } } static boolean_t @@ -1535,7 +1571,7 @@ e1000g_rx_drain(struct e1000g *Adapter) return (done); } -static boolean_t +boolean_t e1000g_reset(struct e1000g *Adapter) { e1000g_stop(Adapter); @@ -1650,8 +1686,9 @@ e1000g_intr(caddr_t arg) * Return Value: * * * * Functions called: * - * ProcessRxInterruptArray * - * e1000g_LocalTimerWork * + * e1000g_receive * + * e1000g_link_check * + * e1000g_recycle * * * * ********************************************************************** */ @@ -1690,7 +1727,8 @@ e1000g_intr_work(struct e1000g *Adapter, uint32_t ICRContents) if ((ICRContents & E1000_ICR_RXSEQ) || (ICRContents & E1000_ICR_LSC) || (ICRContents & E1000_ICR_GPI_EN1)) { - boolean_t linkstate_changed; + boolean_t link_changed; + timeout_id_t tid = 0; /* * Encountered RX Sequence Error!!! Link maybe forced and @@ -1703,14 +1741,29 @@ e1000g_intr_work(struct e1000g *Adapter, uint32_t ICRContents) stop_timeout(Adapter); mutex_enter(&Adapter->e1000g_linklock); - /* e1000g_LocalTimerWork takes care of link status change */ - linkstate_changed = e1000g_LocalTimerWork(Adapter); + /* e1000g_link_check takes care of link status change */ + link_changed = e1000g_link_check(Adapter); + /* + * If the link timer has not timed out, we'll not notify + * the upper layer with any link state until the link + * is up. + */ + if (link_changed && !Adapter->link_complete) { + if (Adapter->link_state == LINK_STATE_UP) { + Adapter->link_complete = B_TRUE; + tid = Adapter->link_tid; + Adapter->link_tid = 0; + } else { + link_changed = B_FALSE; + } + } mutex_exit(&Adapter->e1000g_linklock); - if (linkstate_changed) { - mac_link_update(Adapter->mh, - (Adapter->LinkIsActive) ? - LINK_STATE_UP : LINK_STATE_DOWN); + if (link_changed) { + if (tid != 0) + (void) untimeout(tid); + + mac_link_update(Adapter->mh, Adapter->link_state); } start_timeout(Adapter); @@ -2425,12 +2478,11 @@ e1000g_getprop(struct e1000g *Adapter, /* point to per-adapter structure */ } static boolean_t -e1000g_LocalTimerWork(struct e1000g *Adapter) +e1000g_link_check(struct e1000g *Adapter) { - UINT16 LineSpeed, Duplex, phydata; - boolean_t linkstate_changed = B_FALSE; + uint16_t speed, duplex, phydata; + boolean_t link_changed = B_FALSE; struct e1000_hw *hw; - e1000g_ether_addr_t ether_addr; uint32_t reg_tarc; hw = &Adapter->Shared; @@ -2439,51 +2491,45 @@ e1000g_LocalTimerWork(struct e1000g *Adapter) /* * The Link is up, check whether it was marked as down earlier */ - if (!Adapter->LinkIsActive) { - e1000_get_speed_and_duplex(hw, &LineSpeed, &Duplex); - Adapter->link_speed = LineSpeed; - Adapter->link_duplex = Duplex; - - if (!Adapter->PseudoLinkChanged) { - if ((hw->mac_type == e1000_82571) || - (hw->mac_type == e1000_82572)) { - reg_tarc = E1000_READ_REG(hw, TARC0); - if (LineSpeed == SPEED_1000) - reg_tarc |= (1 << 21); - else - reg_tarc &= ~(1 << 21); - E1000_WRITE_REG(hw, TARC0, reg_tarc); - } - - e1000g_log(Adapter, CE_NOTE, - "Adapter %dMbps %s %s link is up.", - LineSpeed, - ((Duplex == FULL_DUPLEX) ? - "full duplex" : "half duplex"), - ((hw->media_type == - e1000_media_type_copper) ? - "copper" : "fiber")); + if (Adapter->link_state != LINK_STATE_UP) { + e1000_get_speed_and_duplex(hw, &speed, &duplex); + Adapter->link_speed = speed; + Adapter->link_duplex = duplex; + Adapter->link_state = LINK_STATE_UP; + link_changed = B_TRUE; + + Adapter->tx_link_down_timeout = 0; + + if ((hw->mac_type == e1000_82571) || + (hw->mac_type == e1000_82572)) { + reg_tarc = E1000_READ_REG(hw, TARC0); + if (speed == SPEED_1000) + reg_tarc |= (1 << 21); + else + reg_tarc &= ~(1 << 21); + E1000_WRITE_REG(hw, TARC0, reg_tarc); } - Adapter->LinkIsActive = B_TRUE; - linkstate_changed = B_TRUE; + e1000g_log(Adapter, CE_NOTE, + "Adapter %dMbps %s %s link is up.", speed, + ((duplex == FULL_DUPLEX) ? + "full duplex" : "half duplex"), + ((hw->media_type == e1000_media_type_copper) ? + "copper" : "fiber")); } Adapter->smartspeed = 0; } else { - if (Adapter->LinkIsActive) { + if (Adapter->link_state != LINK_STATE_DOWN) { Adapter->link_speed = 0; Adapter->link_duplex = 0; + Adapter->link_state = LINK_STATE_DOWN; + link_changed = B_TRUE; - if (!Adapter->PseudoLinkChanged) { - e1000g_log(Adapter, CE_NOTE, - "Adapter %s link is down.", - ((hw->media_type == - e1000_media_type_copper) ? - "copper" : "fiber")); - } + e1000g_log(Adapter, CE_NOTE, + "Adapter %s link is down.", + ((hw->media_type == e1000_media_type_copper) ? + "copper" : "fiber")); - Adapter->LinkIsActive = B_FALSE; - linkstate_changed = B_TRUE; /* * SmartSpeed workaround for Tabor/TanaX, When the * driver loses link disable auto master/slave @@ -2506,8 +2552,54 @@ e1000g_LocalTimerWork(struct e1000g *Adapter) } else { e1000g_smartspeed(Adapter); } + + if (Adapter->started) { + if (Adapter->tx_link_down_timeout < + MAX_TX_LINK_DOWN_TIMEOUT) { + Adapter->tx_link_down_timeout++; + } else if (Adapter->tx_link_down_timeout == + MAX_TX_LINK_DOWN_TIMEOUT) { + rw_enter(&Adapter->chip_lock, RW_WRITER); + e1000g_tx_drop(Adapter); + rw_exit(&Adapter->chip_lock); + Adapter->tx_link_down_timeout++; + } + } + } + + return (link_changed); +} + +static void +e1000g_LocalTimer(void *ws) +{ + struct e1000g *Adapter = (struct e1000g *)ws; + struct e1000_hw *hw; + e1000g_ether_addr_t ether_addr; + boolean_t link_changed; + + hw = &Adapter->Shared; + + (void) e1000g_tx_freemsg((caddr_t)Adapter, NULL); + + if (e1000g_stall_check(Adapter)) { + e1000g_DEBUGLOG_0(Adapter, e1000g_INFO_LEVEL, + "Tx stall detected. Activate automatic recovery.\n"); + Adapter->StallWatchdog = 0; + Adapter->tx_recycle_fail = 0; + Adapter->reset_count++; + (void) e1000g_reset(Adapter); } + link_changed = B_FALSE; + mutex_enter(&Adapter->e1000g_linklock); + if (Adapter->link_complete) + link_changed = e1000g_link_check(Adapter); + mutex_exit(&Adapter->e1000g_linklock); + + if (link_changed) + mac_link_update(Adapter->mh, Adapter->link_state); + /* * With 82571 controllers, any locally administered address will * be overwritten when there is a reset on the other port. @@ -2541,7 +2633,8 @@ e1000g_LocalTimerWork(struct e1000g *Adapter) * These properties should only be set for 10/100 */ if ((hw->media_type == e1000_media_type_copper) && - (Adapter->link_speed != SPEED_1000)) { + ((Adapter->link_speed == SPEED_100) || + (Adapter->link_speed == SPEED_10))) { e1000_update_adaptive(hw); } /* @@ -2549,38 +2642,26 @@ e1000g_LocalTimerWork(struct e1000g *Adapter) */ E1000_WRITE_REG(hw, ICS, E1000_IMS_RXT0); - return (linkstate_changed); + restart_timeout(Adapter); } +/* + * The function e1000g_link_timer() is called when the timer for link setup + * is expired, which indicates the completion of the link setup. The link + * state will not be updated until the link setup is completed. And the + * link state will not be sent to the upper layer through mac_link_update() + * in this function. It will be updated in the local timer routine or the + * interrupt service routine after the interface is started (plumbed). + */ static void -e1000g_LocalTimer(void *ws) +e1000g_link_timer(void *arg) { - struct e1000g *Adapter = (struct e1000g *)ws; - boolean_t linkstate_changed; - - (void) e1000g_tx_freemsg((caddr_t)Adapter, NULL); - - if (e1000g_stall_check(Adapter)) { - e1000g_DEBUGLOG_0(Adapter, e1000g_INFO_LEVEL, - "Tx stall detected. Activate automatic recovery.\n"); - Adapter->StallWatchdog = 0; - Adapter->tx_recycle_fail = 0; - Adapter->reset_count++; - (void) e1000g_reset(Adapter); - } + struct e1000g *Adapter = (struct e1000g *)arg; mutex_enter(&Adapter->e1000g_linklock); - linkstate_changed = e1000g_LocalTimerWork(Adapter); + Adapter->link_complete = B_TRUE; + Adapter->link_tid = 0; mutex_exit(&Adapter->e1000g_linklock); - - if (linkstate_changed || Adapter->PseudoLinkChanged) { - mac_link_update(Adapter->mh, - (Adapter->LinkIsActive) ? - LINK_STATE_UP : LINK_STATE_DOWN); - Adapter->PseudoLinkChanged = B_FALSE; - } - - restart_timeout(Adapter); } /* @@ -3033,7 +3114,7 @@ is_valid_mac_addr(uint8_t *mac_addr) static boolean_t e1000g_stall_check(struct e1000g *Adapter) { - if (!Adapter->LinkIsActive) + if (Adapter->link_state != LINK_STATE_UP) return (B_FALSE); if (Adapter->tx_recycle_fail > 0) @@ -3360,7 +3441,6 @@ e1000g_loopback_ioctl(struct e1000g *Adapter, struct iocblk *iocp, mblk_t *mp) if (iocp->ioc_count != sizeof (uint32_t)) return (IOC_INVAL); - Adapter->PseudoLinkChanged = B_TRUE; lbmp = (uint32_t *)mp->b_cont->b_rptr; if (!e1000g_set_loopback_mode(Adapter, *lbmp)) return (IOC_INVAL); diff --git a/usr/src/uts/common/io/e1000g/e1000g_ndd.c b/usr/src/uts/common/io/e1000g/e1000g_ndd.c index 32a22be650..3a2df6f9a9 100644 --- a/usr/src/uts/common/io/e1000g/e1000g_ndd.c +++ b/usr/src/uts/common/io/e1000g/e1000g_ndd.c @@ -100,7 +100,8 @@ static const nd_param_t nd_template[] = { { PARAM_LP_10HDX_CAP, 0, 1, 0, NULL, "-lp_10hdx_cap" }, /* Force Speed and Duplex */ -{ PARAM_FORCE_SPEED_DUPLEX, 1, 4, 4, NULL, "?force_speed_duplex" }, +{ PARAM_FORCE_SPEED_DUPLEX, GDIAG_10_HALF, GDIAG_100_FULL, GDIAG_100_FULL, + NULL, "?force_speed_duplex" }, /* Current operating modes */ { PARAM_LINK_STATUS, 0, 1, 0, NULL, "-link_status" }, @@ -444,10 +445,24 @@ e1000g_nd_get_param_val(nd_param_t *ndp) /* Force Speed and Duplex Parameter */ case PARAM_FORCE_SPEED_DUPLEX: + switch (Adapter->Shared.forced_speed_duplex) { + case e1000_10_half: + ndp->ndp_val = GDIAG_10_HALF; + break; + case e1000_10_full: + ndp->ndp_val = GDIAG_10_FULL; + break; + case e1000_100_half: + ndp->ndp_val = GDIAG_100_HALF; + break; + case e1000_100_full: + ndp->ndp_val = GDIAG_100_FULL; + break; + } break; /* Link States */ case PARAM_LINK_STATUS: - ndp->ndp_val = Adapter->LinkIsActive; + ndp->ndp_val = (Adapter->link_state == LINK_STATE_UP) ? 1 : 0; break; case PARAM_LINK_SPEED: ndp->ndp_val = Adapter->link_speed; @@ -512,6 +527,7 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) struct e1000g *Adapter; uint16_t autoneg_advertised; uint8_t forced_speed_duplex; + boolean_t autoneg_enable; boolean_t link_change; Adapter = ndp->ndp_instance; @@ -519,6 +535,7 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) autoneg_advertised = 0; forced_speed_duplex = 0; + autoneg_enable = B_FALSE; link_change = B_FALSE; rw_enter(&Adapter->chip_lock, RW_WRITER); @@ -599,16 +616,16 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) } switch (Adapter->param_force_speed_duplex) { - case 1: + case GDIAG_10_HALF: forced_speed_duplex = e1000_10_half; break; - case 2: + case GDIAG_10_FULL: forced_speed_duplex = e1000_10_full; break; - case 3: + case GDIAG_100_HALF: forced_speed_duplex = e1000_100_half; break; - case 4: + case GDIAG_100_FULL: forced_speed_duplex = e1000_100_full; break; default: @@ -620,6 +637,7 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) /* Auto-Negotiation Advertisement Capabilities */ case PARAM_ADV_AUTONEG_CAP: if (value != ndp->ndp_val) { + autoneg_enable = (value == 1) ? B_TRUE : B_FALSE; link_change = B_TRUE; } break; @@ -631,6 +649,7 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) "adv_autoneg_cap enabled"); goto finished; } + autoneg_enable = B_TRUE; link_change = B_TRUE; if (value == 1) { autoneg_advertised |= ADVERTISE_1000_FULL; @@ -647,6 +666,7 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) "adv_autoneg_cap enabled"); goto finished; } + autoneg_enable = B_TRUE; link_change = B_TRUE; if (value == 1) { autoneg_advertised |= ADVERTISE_100_FULL; @@ -663,6 +683,7 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) "adv_autoneg_cap enabled"); goto finished; } + autoneg_enable = B_TRUE; link_change = B_TRUE; if (value == 1) { autoneg_advertised |= ADVERTISE_100_HALF; @@ -679,6 +700,7 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) "adv_autoneg_cap enabled"); goto finished; } + autoneg_enable = B_TRUE; link_change = B_TRUE; if (value == 1) { autoneg_advertised |= ADVERTISE_10_FULL; @@ -695,6 +717,7 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) "adv_autoneg_cap enabled"); goto finished; } + autoneg_enable = B_TRUE; link_change = B_TRUE; if (value == 1) { autoneg_advertised |= ADVERTISE_10_HALF; @@ -711,18 +734,19 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) "adv_autoneg_cap disabled"); goto finished; } + autoneg_enable = B_FALSE; link_change = B_TRUE; switch (value) { - case 1: + case GDIAG_10_HALF: forced_speed_duplex = e1000_10_half; break; - case 2: + case GDIAG_10_FULL: forced_speed_duplex = e1000_10_full; break; - case 3: + case GDIAG_100_HALF: forced_speed_duplex = e1000_100_half; break; - case 4: + case GDIAG_100_FULL: forced_speed_duplex = e1000_100_full; break; default: @@ -736,9 +760,14 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) } if (link_change) { - ndp->ndp_val = value; + if (autoneg_enable) { + if (autoneg_advertised == 0) { + e1000g_log(Adapter, CE_WARN, + "ndd set: there must be at least one " + "advertised capability enabled"); + goto finished; + } - if (Adapter->param_adv_autoneg == 1) { Adapter->Shared.autoneg = B_TRUE; Adapter->Shared.autoneg_advertised = autoneg_advertised; @@ -748,11 +777,11 @@ e1000g_nd_set_param_val(nd_param_t *ndp, uint32_t value) forced_speed_duplex; } - if (e1000_setup_link(&Adapter->Shared) != E1000_SUCCESS) { - e1000g_log(Adapter, CE_WARN, - "ndd set: update link failed"); - goto finished; - } + ndp->ndp_val = value; + + rw_exit(&Adapter->chip_lock); + (void) e1000g_reset(Adapter); + return; } finished: diff --git a/usr/src/uts/common/io/e1000g/e1000g_stat.c b/usr/src/uts/common/io/e1000g/e1000g_stat.c index c1834feb80..6490957dbc 100644 --- a/usr/src/uts/common/io/e1000g/e1000g_stat.c +++ b/usr/src/uts/common/io/e1000g/e1000g_stat.c @@ -202,7 +202,6 @@ UpdateStatsCounters(IN kstat_t *ksp, int rw) e1000g_ksp = (e1000gstat *)ksp->ks_data; ASSERT(e1000g_ksp != NULL); - e1000g_ksp->link_up.value.ul = Adapter->LinkIsActive; e1000g_ksp->link_speed.value.ul = Adapter->link_speed; e1000g_ksp->rx_none.value.ul = Adapter->rx_none; e1000g_ksp->rx_error.value.ul = Adapter->rx_error; @@ -870,9 +869,6 @@ InitStatsCounters(IN struct e1000g *Adapter) /* * Initialize all the statistics */ - kstat_named_init(&e1000g_ksp->link_up, "link_up", - KSTAT_DATA_ULONG); - kstat_named_init(&e1000g_ksp->link_speed, "link_speed", KSTAT_DATA_ULONG); diff --git a/usr/src/uts/common/io/e1000g/e1000g_sw.h b/usr/src/uts/common/io/e1000g/e1000g_sw.h index 5bdfe39c0d..3935fae4cb 100644 --- a/usr/src/uts/common/io/e1000g/e1000g_sw.h +++ b/usr/src/uts/common/io/e1000g/e1000g_sw.h @@ -203,14 +203,12 @@ extern "C" { #define E1000G_RX_SW_SENDUP 0x1 #define E1000G_RX_SW_DETACHED 0x2 -#ifdef e1000g_DEBUG -#define DEFAULTDEBUGLEVEL 0x004 -#define DEFAULTDISPLAYONLY 1 -#define DEFAULTPRINTONLY 1 /* - * By default it will do both i.e. print as well as log + * By default it will print only to log */ -#endif +#define DEFAULTDEBUGLEVEL 0x004 +#define DEFAULTDISPLAYONLY 0 +#define DEFAULTPRINTONLY 1 /* * definitions for smartspeed workaround @@ -288,6 +286,8 @@ extern "C" { /* Defines for Tx stall check */ #define E1000G_STALL_WATCHDOG_COUNT 8 +#define MAX_TX_LINK_DOWN_TIMEOUT 8 + /* Defines for DVMA */ #ifdef __sparc #define E1000G_DEFAULT_DVMA_PAGE_NUM 2 @@ -673,6 +673,13 @@ typedef struct _e1000g_msg_chain { kmutex_t lock; } e1000g_msg_chain_t; +typedef struct _cksum_data { + uint32_t ether_header_size; + uint32_t cksum_flags; + uint32_t cksum_start; + uint32_t cksum_stuff; +} cksum_data_t; + /* * MultiCast Command Block (MULTICAST_CB) The multicast * structure contains an array of multicast addresses and @@ -698,7 +705,6 @@ typedef union _e1000g_ether_addr { typedef struct _e1000gstat { - kstat_named_t link_up; /* Link Status */ kstat_named_t link_speed; /* Link Speed */ kstat_named_t rx_none; /* Rx No Incoming Data */ kstat_named_t rx_error; /* Rx Error in Packet */ @@ -825,10 +831,7 @@ typedef struct _e1000g_tx_ring { /* * TCP/UDP checksum offload */ - uint_t cksum_start; - uint_t cksum_stuff; - uint_t cksum_flags; - uint8_t ether_header_size; + cksum_data_t cksum_data; /* * Timer definitions for 82547 */ @@ -874,10 +877,9 @@ typedef struct e1000g { struct e1000_hw Shared; struct e1000g_osdep osdep; - UINT LinkIsActive; + link_state_t link_state; UINT link_speed; UINT link_duplex; - timeout_id_t WatchDogTimer_id; UINT NumRxDescriptors; UINT NumRxFreeList; UINT NumTxDescriptors; @@ -898,6 +900,9 @@ typedef struct e1000g { size_t RxBufferSize; boolean_t intr_adaptive; uint32_t intr_throttling_rate; + timeout_id_t WatchDogTimer_id; + timeout_id_t link_tid; + boolean_t link_complete; /* * The e1000g_timeout_lock must be held when updateing the @@ -906,9 +911,9 @@ typedef struct e1000g { */ kmutex_t e1000g_timeout_lock; /* - * link notification order ??? I think it protects the - * link field in struct e1000g (such as LinkIsActive, - * FullDuplex etc) and struct e1000_hw. + * The e1000g_linklock protects the link fields in struct e1000g, + * such as link_state, link_speed, link_duplex, link_complete, and + * link_tid. */ kmutex_t e1000g_linklock; kmutex_t TbiCntrMutex; @@ -928,6 +933,7 @@ typedef struct e1000g { uint32_t tx_recycle_low_water; uint32_t tx_recycle_num; uint32_t tx_frags_limit; + uint32_t tx_link_down_timeout; boolean_t tx_intr_enable; ddi_softint_handle_t tx_softint_handle; @@ -1006,8 +1012,6 @@ typedef struct e1000g { */ boolean_t resched_needed; - boolean_t PseudoLinkChanged; - #ifdef __sparc ulong_t sys_page_sz; uint_t dvma_page_num; @@ -1084,6 +1088,7 @@ void e1000g_free_rx_sw_packet(PRX_SW_PACKET packet); void SetupTransmitStructures(struct e1000g *Adapter); void SetupReceiveStructures(struct e1000g *Adapter); void SetupMulticastTable(struct e1000g *Adapter); +boolean_t e1000g_reset(struct e1000g *Adapter); int e1000g_recycle(e1000g_tx_ring_t *tx_ring); void FreeTxSwPacket(PTX_SW_PACKET packet); diff --git a/usr/src/uts/common/io/e1000g/e1000g_tx.c b/usr/src/uts/common/io/e1000g/e1000g_tx.c index 8e2521c84d..9da6fe5ac4 100644 --- a/usr/src/uts/common/io/e1000g/e1000g_tx.c +++ b/usr/src/uts/common/io/e1000g/e1000g_tx.c @@ -58,9 +58,10 @@ static boolean_t e1000g_send(struct e1000g *, mblk_t *); static int e1000g_tx_copy(struct e1000g *, PTX_SW_PACKET, mblk_t *, uint32_t); static int e1000g_tx_bind(struct e1000g *, PTX_SW_PACKET, mblk_t *); +static boolean_t check_cksum_context(e1000g_tx_ring_t *, cksum_data_t *); static int e1000g_fill_tx_ring(e1000g_tx_ring_t *, LIST_DESCRIBER *, - uint_t, boolean_t); -static void e1000g_fill_context_descriptor(e1000g_tx_ring_t *, + cksum_data_t *); +static void e1000g_fill_context_descriptor(cksum_data_t *, struct e1000_context_desc *); static int e1000g_fill_tx_desc(struct e1000g *, PTX_SW_PACKET, uint64_t, size_t); @@ -78,6 +79,7 @@ static void e1000g_82547_tx_move_tail_work(e1000g_tx_ring_t *); #ifndef e1000g_DEBUG #pragma inline(e1000g_tx_copy) #pragma inline(e1000g_tx_bind) +#pragma inline(check_cksum_context) #pragma inline(e1000g_fill_tx_ring) #pragma inline(e1000g_fill_context_descriptor) #pragma inline(e1000g_fill_tx_desc) @@ -182,7 +184,7 @@ e1000g_m_tx(void *arg, mblk_t *mp) rw_enter(&Adapter->chip_lock, RW_READER); - if (!Adapter->started) { + if (!Adapter->started || (Adapter->link_state != LINK_STATE_UP)) { freemsgchain(mp); mp = NULL; } @@ -238,12 +240,7 @@ e1000g_send(struct e1000g *Adapter, mblk_t *mp) mblk_t *nmp; mblk_t *tmp; e1000g_tx_ring_t *tx_ring; - /* IP Head/TCP/UDP checksum offload */ - uint_t cksum_start; - uint_t cksum_stuff; - uint_t cksum_flags; - boolean_t cksum_load; - uint8_t ether_header_size; + cksum_data_t cksum; /* Get the total size and frags number of the message */ force_bcopy = 0; @@ -303,7 +300,8 @@ e1000g_send(struct e1000g *Adapter, mblk_t *mp) * If there are many frags of the message, then bcopy them * into one tx descriptor buffer will get better performance. */ - if (frag_count >= Adapter->tx_frags_limit) { + if ((frag_count >= Adapter->tx_frags_limit) && + (msg_size <= Adapter->TxBufferSize)) { Adapter->tx_exceed_frags++; force_bcopy |= FORCE_BCOPY_EXCEED_FRAGS; } @@ -323,30 +321,14 @@ e1000g_send(struct e1000g *Adapter, mblk_t *mp) QUEUE_INIT_LIST(&pending_list); /* Retrieve checksum info */ - hcksum_retrieve(mp, NULL, NULL, &cksum_start, &cksum_stuff, - NULL, NULL, &cksum_flags); - - cksum_load = B_FALSE; - if (cksum_flags) { - if (((struct ether_vlan_header *)mp->b_rptr)->ether_tpid == - htons(ETHERTYPE_VLAN)) - ether_header_size = sizeof (struct ether_vlan_header); - else - ether_header_size = sizeof (struct ether_header); - - if ((ether_header_size != tx_ring->ether_header_size) || - (cksum_flags != tx_ring->cksum_flags) || - (cksum_stuff != tx_ring->cksum_stuff) || - (cksum_start != tx_ring->cksum_start)) { + hcksum_retrieve(mp, NULL, NULL, &cksum.cksum_start, &cksum.cksum_stuff, + NULL, NULL, &cksum.cksum_flags); - tx_ring->ether_header_size = ether_header_size; - tx_ring->cksum_flags = cksum_flags; - tx_ring->cksum_start = cksum_start; - tx_ring->cksum_stuff = cksum_stuff; - - cksum_load = B_TRUE; - } - } + if (((struct ether_vlan_header *)mp->b_rptr)->ether_tpid == + htons(ETHERTYPE_VLAN)) + cksum.ether_header_size = sizeof (struct ether_vlan_header); + else + cksum.ether_header_size = sizeof (struct ether_header); /* Process each mblk fragment and fill tx descriptors */ packet = NULL; @@ -440,8 +422,7 @@ e1000g_send(struct e1000g *Adapter, mblk_t *mp) goto tx_send_failed; } - desc_count = e1000g_fill_tx_ring(tx_ring, &pending_list, - cksum_flags, cksum_load); + desc_count = e1000g_fill_tx_ring(tx_ring, &pending_list, &cksum); mutex_exit(&tx_ring->tx_lock); @@ -500,14 +481,36 @@ tx_no_resource: return (B_FALSE); } +static boolean_t +check_cksum_context(e1000g_tx_ring_t *tx_ring, cksum_data_t *cksum) +{ + boolean_t cksum_load; + cksum_data_t *last; + + cksum_load = B_FALSE; + last = &tx_ring->cksum_data; + + if (cksum->cksum_flags != 0) { + if ((cksum->ether_header_size != last->ether_header_size) || + (cksum->cksum_flags != last->cksum_flags) || + (cksum->cksum_stuff != last->cksum_stuff) || + (cksum->cksum_start != last->cksum_start)) { + + cksum_load = B_TRUE; + } + } + + return (cksum_load); +} + static int e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, - uint_t cksum_flags, boolean_t cksum_load) + cksum_data_t *cksum) { struct e1000g *Adapter; PTX_SW_PACKET first_packet; PTX_SW_PACKET packet; - struct e1000_context_desc *cksum_desc; + boolean_t cksum_load; struct e1000_tx_desc *first_data_desc; struct e1000_tx_desc *next_desc; struct e1000_tx_desc *descriptor; @@ -519,22 +522,22 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, Adapter = tx_ring->adapter; desc_count = 0; - cksum_desc = NULL; + first_packet = NULL; first_data_desc = NULL; descriptor = NULL; - first_packet = (PTX_SW_PACKET) QUEUE_GET_HEAD(pending_list); - ASSERT(first_packet); - next_desc = tx_ring->tbd_next; /* IP Head/TCP/UDP checksum offload */ + cksum_load = check_cksum_context(tx_ring, cksum); + if (cksum_load) { - descriptor = next_desc; + first_packet = (PTX_SW_PACKET) QUEUE_GET_HEAD(pending_list); - cksum_desc = (struct e1000_context_desc *)descriptor; + descriptor = next_desc; - e1000g_fill_context_descriptor(tx_ring, cksum_desc); + e1000g_fill_context_descriptor(cksum, + (struct e1000_context_desc *)descriptor); /* Check the wrap-around case */ if (descriptor == tx_ring->tbd_last) @@ -545,9 +548,6 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, desc_count++; } - if (cksum_desc == NULL) - first_packet = NULL; - first_data_desc = next_desc; packet = (PTX_SW_PACKET) QUEUE_GET_HEAD(pending_list); @@ -601,11 +601,11 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, ASSERT(descriptor); - if (cksum_flags) { - if (cksum_flags & HCK_IPV4_HDRCKSUM) + if (cksum->cksum_flags) { + if (cksum->cksum_flags & HCK_IPV4_HDRCKSUM) ((struct e1000_data_desc *)first_data_desc)-> upper.fields.popts |= E1000_TXD_POPTS_IXSM; - if (cksum_flags & HCK_PARTIALCKSUM) + if (cksum->cksum_flags & HCK_PARTIALCKSUM) ((struct e1000_data_desc *)first_data_desc)-> upper.fields.popts |= E1000_TXD_POPTS_TXSM; } @@ -662,6 +662,10 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, QUEUE_APPEND(&tx_ring->used_list, pending_list); mutex_exit(&tx_ring->usedlist_lock); + /* Store the cksum data */ + if (cksum_load) + tx_ring->cksum_data = *cksum; + return (desc_count); } @@ -823,9 +827,10 @@ SetupTransmitStructures(struct e1000g *Adapter) } /* For TCP/UDP checksum offload */ - tx_ring->cksum_stuff = 0; - tx_ring->cksum_start = 0; - tx_ring->cksum_flags = 0; + tx_ring->cksum_data.cksum_stuff = 0; + tx_ring->cksum_data.cksum_start = 0; + tx_ring->cksum_data.cksum_flags = 0; + tx_ring->cksum_data.ether_header_size = 0; /* Initialize tx parameters */ Adapter->tx_bcopy_thresh = DEFAULTTXBCOPYTHRESHOLD; @@ -1323,22 +1328,22 @@ e1000g_tx_bind(struct e1000g *Adapter, PTX_SW_PACKET packet, mblk_t *mp) } static void -e1000g_fill_context_descriptor(e1000g_tx_ring_t *tx_ring, +e1000g_fill_context_descriptor(cksum_data_t *cksum, struct e1000_context_desc *cksum_desc) { - if (tx_ring->cksum_flags & HCK_IPV4_HDRCKSUM) { + if (cksum->cksum_flags & HCK_IPV4_HDRCKSUM) { cksum_desc->lower_setup.ip_fields.ipcss = - tx_ring->ether_header_size; + cksum->ether_header_size; cksum_desc->lower_setup.ip_fields.ipcso = - tx_ring->ether_header_size + + cksum->ether_header_size + offsetof(struct ip, ip_sum); cksum_desc->lower_setup.ip_fields.ipcse = - tx_ring->ether_header_size + + cksum->ether_header_size + sizeof (struct ip) - 1; } else cksum_desc->lower_setup.ip_config = 0; - if (tx_ring->cksum_flags & HCK_PARTIALCKSUM) { + if (cksum->cksum_flags & HCK_PARTIALCKSUM) { /* * The packet with same protocol has the following * stuff and start offset: @@ -1350,9 +1355,9 @@ e1000g_fill_context_descriptor(e1000g_tx_ring_t *tx_ring, * | IPv6 + UDP | 0x14 | 0x10 | No */ cksum_desc->upper_setup.tcp_fields.tucss = - tx_ring->cksum_start + tx_ring->ether_header_size; + cksum->cksum_start + cksum->ether_header_size; cksum_desc->upper_setup.tcp_fields.tucso = - tx_ring->cksum_stuff + tx_ring->ether_header_size; + cksum->cksum_stuff + cksum->ether_header_size; cksum_desc->upper_setup.tcp_fields.tucse = 0; } else cksum_desc->upper_setup.tcp_config = 0; |