Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[intel] Work around broken reset mechanism in i219 devices
The i219 appears to have a seriously broken reset mechanism.  After
any transmit or receive activity, resetting the card will break both
the transmit and receive datapaths until the next PCI bus reset.

The Linux and BSD drivers include a convoluted workaround authored by
Intel which involves setting a bit in the undocumented FEXTNVM11
register, then transmitting a dummy 512-byte packet containing garbage
data, then reconfiguring the receive descriptor prefetch thresholds
and temporarily reenabling the receive datapath.  The comments in the
Intel fix do not even remotely match what the code actually does, and
the code accidentally leaves the transmitter enabled after use.

Experimentation suggests that an equivalent fix is to simply set the
undocumented bit in FEXTNVM11 before enabling the transmit or receive
descriptor rings.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Feb 3, 2018
1 parent c900751 commit 546dd51
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
31 changes: 22 additions & 9 deletions src/drivers/net/intel.c
Expand Up @@ -635,10 +635,23 @@ void intel_empty_rx ( struct intel_nic *intel ) {
static int intel_open ( struct net_device *netdev ) {
struct intel_nic *intel = netdev->priv;
union intel_receive_address mac;
uint32_t fextnvm11;
uint32_t tctl;
uint32_t rctl;
int rc;

/* Set undocumented bit in FEXTNVM11 to work around an errata
* in i219 devices that will otherwise cause a complete
* datapath hang at the next device reset.
*/
if ( intel->flags & INTEL_RST_HANG ) {
DBGC ( intel, "INTEL %p WARNING: applying reset hang "
"workaround\n", intel );
fextnvm11 = readl ( intel->regs + INTEL_FEXTNVM11 );
fextnvm11 |= INTEL_FEXTNVM11_WTF;
writel ( fextnvm11, intel->regs + INTEL_FEXTNVM11 );
}

/* Create transmit descriptor ring */
if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
goto err_create_tx;
Expand Down Expand Up @@ -1123,20 +1136,20 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x153b, "i217v", "I217-V", 0 ),
PCI_ROM ( 0x8086, 0x1559, "i218v", "I218-V", 0),
PCI_ROM ( 0x8086, 0x155a, "i218lm", "I218-LM", 0),
PCI_ROM ( 0x8086, 0x156f, "i219lm", "I219-LM", 0 ),
PCI_ROM ( 0x8086, 0x1570, "i219v", "I219-V", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x156f, "i219lm", "I219-LM", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x1570, "i219v", "I219-V", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x157b, "i210-2", "I210", 0 ),
PCI_ROM ( 0x8086, 0x15a0, "i218lm-2", "I218-LM", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15a1, "i218v-2", "I218-V", 0 ),
PCI_ROM ( 0x8086, 0x15a2, "i218lm-3", "I218-LM", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15a3, "i218v-3", "I218-V", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15b7, "i219lm-2", "I219-LM (2)", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15b8, "i219v-2", "I219-V (2)", 0 ),
PCI_ROM ( 0x8086, 0x15b9, "i219lm-3", "I219-LM (3)", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15d6, "i219v-5", "I219-V (5)", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15d7, "i219lm-4", "I219-LM (4)", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15d8, "i219v-4", "I219-V (4)", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15e3, "i219lm-5", "I219-LM (5)", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15b7, "i219lm-2", "I219-LM (2)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15b8, "i219v-2", "I219-V (2)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15b9, "i219lm-3", "I219-LM (3)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15d6, "i219v-5", "I219-V (5)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15d7, "i219lm-4", "I219-LM (4)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15d8, "i219v-4", "I219-V (4)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x15e3, "i219lm-5", "I219-LM (5)", INTEL_I219 ),
PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),
};
Expand Down
9 changes: 9 additions & 0 deletions src/drivers/net/intel.h
Expand Up @@ -195,6 +195,10 @@ struct intel_descriptor {
#define INTEL_RAH0 0x05404UL
#define INTEL_RAH0_AV 0x80000000UL /**< Address valid */

/** Future Extended NVM register 11 */
#define INTEL_FEXTNVM11 0x05bbcUL
#define INTEL_FEXTNVM11_WTF 0x00002000UL /**< Don't ask */

/** Receive address */
union intel_receive_address {
struct {
Expand Down Expand Up @@ -308,8 +312,13 @@ enum intel_flags {
INTEL_NO_PHY_RST = 0x0004,
/** ASDE is broken */
INTEL_NO_ASDE = 0x0008,
/** Reset may cause a complete device hang */
INTEL_RST_HANG = 0x0010,
};

/** The i219 has a seriously broken reset mechanism */
#define INTEL_I219 ( INTEL_NO_PHY_RST | INTEL_RST_HANG )

/**
* Dump diagnostic information
*
Expand Down

0 comments on commit 546dd51

Please sign in to comment.