- Code cleanup

- In the receive routine handle the case where last descriptor could have
  less than 4 bytes of data.
- Handle race between detach/ioctl routine.

MFC after:	3 days
This commit is contained in:
Prafulla Deuskar 2003-11-14 18:02:25 +00:00
parent d1f42ac2ee
commit 3c2ef4e7e2
4 changed files with 48 additions and 105 deletions

View file

@ -51,7 +51,7 @@ struct adapter *em_adapter_list = NULL;
* Driver version
*********************************************************************/
char em_driver_version[] = "1.7.16";
char em_driver_version[] = "1.7.19";
/*********************************************************************
@ -529,6 +529,7 @@ em_detach(device_t dev)
INIT_DEBUGOUT("em_detach: begin");
EM_LOCK(adapter);
adapter->in_detach = 1;
em_stop(adapter);
em_phy_hw_reset(&adapter->hw);
EM_UNLOCK(adapter);
@ -662,6 +663,8 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
struct adapter * adapter = ifp->if_softc;
if (adapter->in_detach) return(error);
switch (command) {
case SIOCSIFADDR:
case SIOCGIFADDR:
@ -686,8 +689,6 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
EM_LOCK(adapter);
if (ifp->if_flags & IFF_UP) {
if (!(ifp->if_flags & IFF_RUNNING)) {
bcopy(IF_LLADDR(ifp), adapter->hw.mac_addr,
ETHER_ADDR_LEN);
em_init_locked(adapter);
}
@ -796,6 +797,10 @@ em_init_locked(struct adapter * adapter)
em_stop(adapter);
/* Get the latest mac address, User can use a LAA */
bcopy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr,
ETHER_ADDR_LEN);
/* Initialize the hardware */
if (em_hardware_init(adapter)) {
printf("em%d: Unable to initialize the hardware\n",
@ -825,6 +830,9 @@ em_init_locked(struct adapter * adapter)
return;
}
em_initialize_receive_unit(adapter);
/* Don't loose promiscuous settings */
em_set_promisc(adapter);
ifp = &adapter->interface_data.ac_if;
ifp->if_flags |= IFF_RUNNING;
@ -2601,7 +2609,6 @@ em_initialize_receive_unit(struct adapter * adapter)
/* Enable Receives */
E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
em_set_promisc(adapter);
return;
}
@ -2661,7 +2668,7 @@ em_process_receive_interrupts(struct adapter * adapter, int count)
#endif
u_int8_t accept_frame = 0;
u_int8_t eop = 0;
u_int16_t len, desc_len;
u_int16_t len, desc_len, prev_len_adj;
int i;
/* Pointer to the receive descriptor being examined. */
@ -2687,11 +2694,18 @@ em_process_receive_interrupts(struct adapter * adapter, int count)
BUS_DMASYNC_POSTREAD);
accept_frame = 1;
prev_len_adj = 0;
desc_len = le16toh(current_desc->length);
if (current_desc->status & E1000_RXD_STAT_EOP) {
count--;
eop = 1;
len = desc_len - ETHER_CRC_LEN;
if (desc_len < ETHER_CRC_LEN) {
len = 0;
prev_len_adj = ETHER_CRC_LEN - desc_len;
}
else {
len = desc_len - ETHER_CRC_LEN;
}
} else {
eop = 0;
len = desc_len;
@ -2713,7 +2727,7 @@ em_process_receive_interrupts(struct adapter * adapter, int count)
&adapter->stats,
pkt_len,
adapter->hw.mac_addr);
len--;
if (len > 0) len--;
}
else {
accept_frame = 0;
@ -2742,6 +2756,14 @@ em_process_receive_interrupts(struct adapter * adapter, int count)
} else {
/* Chain mbuf's together */
mp->m_flags &= ~M_PKTHDR;
/*
* Adjust length of previous mbuf in chain if we
* received less than 4 bytes in the last descriptor.
*/
if (prev_len_adj > 0) {
adapter->lmp->m_len -= prev_len_adj;
adapter->fmp->m_pkthdr.len -= prev_len_adj;
}
adapter->lmp->m_next = mp;
adapter->lmp = adapter->lmp->m_next;
adapter->fmp->m_pkthdr.len += len;

View file

@ -416,6 +416,7 @@ struct adapter {
/* For 82544 PCIX Workaround */
boolean_t pcix_82544;
boolean_t in_detach;
#ifdef DBG_STATS
unsigned long no_pkts_avail;

View file

@ -844,18 +844,16 @@ em_setup_fiber_serdes_link(struct em_hw *hw)
if(i == (LINK_UP_TIMEOUT / 10)) {
DEBUGOUT("Never got a valid link from auto-neg!!!\n");
hw->autoneg_failed = 1;
if(hw->media_type == em_media_type_fiber) {
/* AutoNeg failed to achieve a link, so we'll call
* em_check_for_link. This routine will force the link up if
* we detect a signal. This will allow us to communicate with
* non-autonegotiating link partners.
*/
if((ret_val = em_check_for_link(hw))) {
DEBUGOUT("Error while checking for link\n");
return ret_val;
}
hw->autoneg_failed = 0;
/* AutoNeg failed to achieve a link, so we'll call
* em_check_for_link. This routine will force the link up if
* we detect a signal. This will allow us to communicate with
* non-autonegotiating link partners.
*/
if((ret_val = em_check_for_link(hw))) {
DEBUGOUT("Error while checking for link\n");
return ret_val;
}
hw->autoneg_failed = 0;
} else {
hw->autoneg_failed = 0;
DEBUGOUT("Valid Link Found\n");
@ -1873,11 +1871,12 @@ em_config_fc_after_link_up(struct em_hw *hw)
* be asked to delay transmission of packets than asking
* our link partner to pause transmission of frames.
*/
else if(hw->original_fc == em_fc_none ||
hw->original_fc == em_fc_tx_pause) {
else if((hw->original_fc == em_fc_none ||
hw->original_fc == em_fc_tx_pause) ||
hw->fc_strict_ieee) {
hw->fc = em_fc_none;
DEBUGOUT("Flow Control = NONE.\r\n");
} else if(!hw->fc_strict_ieee) {
} else {
hw->fc = em_fc_rx_pause;
DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
}
@ -2053,9 +2052,10 @@ em_check_for_link(struct em_hw *hw)
* auto-negotiation time to complete, in case the cable was just plugged
* in. The autoneg_failed flag does this.
*/
else if((hw->media_type == em_media_type_fiber) &&
else if((((hw->media_type == em_media_type_fiber) &&
((ctrl & E1000_CTRL_SWDPIN1) == signal)) ||
(hw->media_type == em_media_type_internal_serdes)) &&
(!(status & E1000_STATUS_LU)) &&
((ctrl & E1000_CTRL_SWDPIN1) == signal) &&
(!(rxcw & E1000_RXCW_C))) {
if(hw->autoneg_failed == 0) {
hw->autoneg_failed = 1;
@ -2082,7 +2082,8 @@ em_check_for_link(struct em_hw *hw)
* Device Control register in an attempt to auto-negotiate with our link
* partner.
*/
else if((hw->media_type == em_media_type_fiber) &&
else if(((hw->media_type == em_media_type_fiber) ||
(hw->media_type == em_media_type_internal_serdes)) &&
(ctrl & E1000_CTRL_SLU) &&
(rxcw & E1000_RXCW_C)) {
DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
@ -4901,77 +4902,6 @@ em_config_dsp_after_link_change(struct em_hw *hw,
return E1000_SUCCESS;
}
/***************************************************************************
*
* Workaround for the 82547 long TTL on noisy 100HD hubs.
*
* This function, specific to 82547 hardware only, needs to be called every
* second. It checks if a parallel detect fault has occurred. If a fault
* occurred, disable/enable the DSP reset mechanism up to 5 times (once per
* second). If link is established, stop the workaround and ensure the DSP
* reset is enabled.
*
* hw: Struct containing variables accessed by shared code
*
* returns: - E1000_ERR_PHY if fail to read/write the PHY
* E1000_SUCCESS in any other case
*
****************************************************************************/
int32_t
em_igp_ttl_workaround(struct em_hw *hw)
{
int32_t ret_val;
uint16_t phy_data = 0;
uint16_t dsp_value = DSP_RESET_ENABLE;
if(((hw->mac_type != em_82541) && (hw->mac_type != em_82547)) ||
(!hw->ttl_wa_activation)) {
return E1000_SUCCESS;
}
/* Check for link first */
if((ret_val = em_read_phy_reg(hw, PHY_STATUS, &phy_data)))
return ret_val;
if(phy_data & MII_SR_LINK_STATUS) {
/* If link is established during the workaround, the DSP mechanism must
* be enabled. */
if(hw->dsp_reset_counter) {
hw->dsp_reset_counter = 0;
dsp_value = DSP_RESET_ENABLE;
} else
return E1000_SUCCESS;
} else {
if(hw->dsp_reset_counter == 0) {
/* Workaround not activated, check if it needs activation */
if((ret_val = em_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data)))
return ret_val;
/* Activate the workaround if there was a parallel detect fault */
if(phy_data & NWAY_ER_PAR_DETECT_FAULT)
hw->dsp_reset_counter++;
else
return E1000_SUCCESS;
}
if(hw->dsp_reset_counter) {
/* After 5 times, stop the workaround */
if(hw->dsp_reset_counter > E1000_MAX_DSP_RESETS) {
hw->dsp_reset_counter = 0;
dsp_value = DSP_RESET_ENABLE;
} else {
dsp_value = (hw->dsp_reset_counter & 1) ? DSP_RESET_DISABLE :
DSP_RESET_ENABLE;
hw->dsp_reset_counter++;
}
}
}
if((ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_DSP_RESET, dsp_value)))
return ret_val;
return E1000_SUCCESS;
}
/*****************************************************************************
*
* This function sets the lplu state according to the active flag. When

View file

@ -329,7 +329,6 @@ void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value);
void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
int32_t em_config_dsp_after_link_change(struct em_hw *hw, boolean_t link_up);
int32_t em_set_d3_lplu_state(struct em_hw *hw, boolean_t active);
int32_t em_igp_ttl_workaround(struct em_hw *hw);
#define E1000_READ_REG_IO(a, reg) \
em_read_reg_io((a), E1000_##reg)
@ -1002,7 +1001,6 @@ struct em_hw {
uint32_t ledctl_mode1;
uint32_t ledctl_mode2;
uint16_t phy_spd_default;
uint16_t dsp_reset_counter;
uint16_t autoneg_advertised;
uint16_t pci_cmd_word;
uint16_t fc_high_water;
@ -1027,7 +1025,6 @@ struct em_hw {
uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
boolean_t disable_polarity_correction;
boolean_t speed_downgraded;
boolean_t ttl_wa_activation;
em_dsp_config dsp_config_state;
boolean_t get_link_status;
boolean_t tbi_compatibility_en;
@ -2117,11 +2114,4 @@ struct em_hw {
#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds*/
#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds*/
#define TANAX_TTL_WA_RESET(hw) { \
if((hw)->dsp_reset_counter) { \
em_write_phy_reg((hw), IGP01E1000_PHY_DSP_RESET, 0x0000); \
(hw)->dsp_reset_counter = 0; \
} \
}
#endif /* _EM_HW_H_ */