summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorpdeuskar <pdeuskar@FreeBSD.org>2002-11-08 18:14:17 +0000
committerpdeuskar <pdeuskar@FreeBSD.org>2002-11-08 18:14:17 +0000
commit9918575c8a3c567575e9ef1744c2464690eb828e (patch)
tree5cda9c577e262fc3a48696655bdee05cc2c2d6a9 /sys
parentf3748b0c0b9b7ae4a57068095ab2eb98aaea333d (diff)
downloadFreeBSD-src-9918575c8a3c567575e9ef1744c2464690eb828e.zip
FreeBSD-src-9918575c8a3c567575e9ef1744c2464690eb828e.tar.gz
- Set RS (Report Status) bit on all descriptors of a packet instead of just the last one.
- Set RDTR to zero by default instead of 28. - Fixed a problem with TX hangs with jumbo frames when number of fragments in the mbuf chain is large. - Added support for 82540EP based cards. MFC after: 3 days
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/em/README6
-rw-r--r--sys/dev/em/if_em.c894
-rw-r--r--sys/dev/em/if_em.h141
-rw-r--r--sys/dev/em/if_em_hw.c175
-rw-r--r--sys/dev/em/if_em_hw.h60
-rw-r--r--sys/dev/em/if_em_osdep.h2
6 files changed, 763 insertions, 515 deletions
diff --git a/sys/dev/em/README b/sys/dev/em/README
index 4603056..7288074 100644
--- a/sys/dev/em/README
+++ b/sys/dev/em/README
@@ -2,7 +2,7 @@ $FreeBSD$
FreeBSD* Driver for the Intel(R) PRO/1000 Family of Adapters
============================================================
-July 2, 2002
+September 11, 2002
Contents
@@ -21,7 +21,7 @@ Contents
In This Release
===============
-This file describes the FreeBSD* driver, version 1.3.x, for the Intel(R)
+This file describes the FreeBSD* driver, version 1.4.x, for the Intel(R)
PRO/1000 Family of Adapters. This driver has been developed for use with
FreeBSD, version 4.6. As a new feature for this release, the driver is now
compiled by default into the FreeBSD 4.6 kernel.
@@ -155,7 +155,7 @@ NOTE: You must have kernel sources installed in order to compile the driver
Remove the following lines from the /usr/src/sys/conf/files.i386 file, if
they exist:
- /dev/em/if_em_fxhw.c optional em
+ /dev/em/if_em_fx_hw.c optional em
/dev/em/if_em_phy.c optional em
Compile and install the kernel.
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index 8859b88..1915e91 100644
--- a/sys/dev/em/if_em.c
+++ b/sys/dev/em/if_em.c
@@ -51,7 +51,7 @@ struct adapter *em_adapter_list = NULL;
* Driver version
*********************************************************************/
-char em_driver_version[] = "1.3.14";
+char em_driver_version[] = "1.4.7";
/*********************************************************************
@@ -74,15 +74,18 @@ static em_vendor_info_t em_vendor_info_array[] =
{ 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0},
- { 0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0},
/* required last entry */
{ 0, 0, 0, 0, 0}
};
-
/*********************************************************************
* Table of branding strings for all supported NICs.
*********************************************************************/
@@ -130,7 +133,6 @@ static void em_receive_checksum(struct adapter *,
struct mbuf *);
static void em_transmit_checksum_setup(struct adapter *,
struct mbuf *,
- struct em_tx_buffer *,
u_int32_t *,
u_int32_t *);
static void em_set_promisc(struct adapter *);
@@ -139,8 +141,9 @@ static void em_set_multi(struct adapter *);
static void em_print_hw_stats(struct adapter *);
static void em_print_link_status(struct adapter *);
static int em_get_buf(struct em_rx_buffer *, struct adapter *,
- struct mbuf *);
+ struct mbuf *);
static void em_enable_vlans(struct adapter *adapter);
+static int em_encap(struct adapter *adapter, struct mbuf *m_head);
/*********************************************************************
* FreeBSD Device Interface Entry Points
@@ -256,10 +259,10 @@ em_attach(device_t dev)
em_identify_hardware(adapter);
/* Parameters (to be read from user) */
- adapter->num_tx_desc = MAX_TXD;
- adapter->num_rx_desc = MAX_RXD;
- adapter->tx_int_delay = TIDV;
- adapter->rx_int_delay = RIDV;
+ adapter->num_tx_desc = EM_MAX_TXD;
+ adapter->num_rx_desc = EM_MAX_RXD;
+ adapter->tx_int_delay = EM_TIDV;
+ adapter->rx_int_delay = EM_RDTR;
adapter->hw.autoneg = DO_AUTO_NEG;
adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT;
adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
@@ -431,6 +434,12 @@ em_detach(device_t dev)
return(0);
}
+/*********************************************************************
+ *
+ * Shutdown entry point
+ *
+ **********************************************************************/
+
static int
em_shutdown(device_t dev)
{
@@ -439,7 +448,6 @@ em_shutdown(device_t dev)
return(0);
}
-
/*********************************************************************
* Transmit entry point
*
@@ -454,128 +462,34 @@ static void
em_start(struct ifnet *ifp)
{
int s;
- struct mbuf *m_head, *mp;
- vm_offset_t virtual_addr;
- u_int32_t txd_upper;
- u_int32_t txd_lower;
- struct em_tx_buffer *tx_buffer;
- struct em_tx_desc *current_tx_desc = NULL;
- struct adapter * adapter = ifp->if_softc;
+ struct mbuf *m_head;
+ struct adapter *adapter = ifp->if_softc;
if (!adapter->link_active)
return;
s = splimp();
while (ifp->if_snd.ifq_head != NULL) {
- struct ifvlan *ifv = NULL;
-
+
IF_DEQUEUE(&ifp->if_snd, m_head);
if (m_head == NULL) break;
- if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD)
- em_clean_transmit_interrupts(adapter);
-
- if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD) {
+ if (em_encap(adapter, m_head)) {
ifp->if_flags |= IFF_OACTIVE;
IF_PREPEND(&ifp->if_snd, m_head);
- adapter->no_tx_desc_avail++;
break;
}
- tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list);
- if (!tx_buffer) {
- adapter->no_tx_buffer_avail1++;
- /*
- * OK so we should not get here but I've seen it so let
- * us try to clean up and then try to get a tx_buffer
- * again and only break if we still don't get one.
- */
- em_clean_transmit_interrupts(adapter);
- tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list);
- if (!tx_buffer) {
- ifp->if_flags |= IFF_OACTIVE;
- IF_PREPEND(&ifp->if_snd, m_head);
- adapter->no_tx_buffer_avail2++;
- break;
- }
- }
- STAILQ_REMOVE_HEAD(&adapter->free_tx_buffer_list, em_tx_entry);
-
- tx_buffer->num_tx_desc_used = 0;
- tx_buffer->m_head = m_head;
-
- if (ifp->if_hwassist > 0) {
- em_transmit_checksum_setup(adapter, m_head, tx_buffer,
- &txd_upper, &txd_lower);
- } else {
- txd_upper = 0;
- txd_lower = 0;
- }
-
- /* Find out if we are in vlan mode */
- if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
- m_head->m_pkthdr.rcvif != NULL &&
- m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
- ifv = m_head->m_pkthdr.rcvif->if_softc;
-
-
- for (mp = m_head; mp != NULL; mp = mp->m_next) {
- if (mp->m_len == 0)
- continue;
- current_tx_desc = adapter->next_avail_tx_desc;
- virtual_addr = mtod(mp, vm_offset_t);
- current_tx_desc->buffer_addr = vtophys(virtual_addr);
-
- current_tx_desc->lower.data = (txd_lower | mp->m_len);
- current_tx_desc->upper.data = (txd_upper);
-
- if (current_tx_desc == adapter->last_tx_desc)
- adapter->next_avail_tx_desc =
- adapter->first_tx_desc;
- else
- adapter->next_avail_tx_desc++;
-
- adapter->num_tx_desc_avail--;
- tx_buffer->num_tx_desc_used++;
- }
-
- /* Put this tx_buffer at the end in the "in use" list */
- STAILQ_INSERT_TAIL(&adapter->used_tx_buffer_list, tx_buffer,
- em_tx_entry);
-
- if (ifv != NULL) {
- /* Tell hardware to add tag */
- current_tx_desc->lower.data |= E1000_TXD_CMD_VLE;
-
- /* Set the vlan id */
- current_tx_desc->upper.fields.special = ifv->ifv_tag;
- }
-
- /*
- * Last Descriptor of Packet needs End Of Packet (EOP), Report Status
- * (RS) and append Ethernet CRC (IFCS) bits set.
- */
- current_tx_desc->lower.data |= (adapter->txd_cmd | E1000_TXD_CMD_EOP);
-
/* Send a copy of the frame to the BPF listener */
if (ifp->if_bpf)
bpf_mtap(ifp, m_head);
- /*
- * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
- * that this frame is available to transmit.
- */
- E1000_WRITE_REG(&adapter->hw, TDT,
- (((uintptr_t) adapter->next_avail_tx_desc -
- (uintptr_t) adapter->first_tx_desc) >> 4));
- } /* end of while loop */
+ /* Set timeout in case hardware has problems transmitting */
+ ifp->if_timer = EM_TX_TIMEOUT;
+ }
splx(s);
-
- /* Set timeout in case chip has problems transmitting */
- ifp->if_timer = EM_TX_TIMEOUT;
-
return;
}
@@ -667,107 +581,6 @@ em_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data)
return(error);
}
-static void
-em_set_promisc(struct adapter * adapter)
-{
-
- u_int32_t reg_rctl;
- struct ifnet *ifp = &adapter->interface_data.ac_if;
-
- reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
-
- if (ifp->if_flags & IFF_PROMISC) {
- reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
- E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
- } else if (ifp->if_flags & IFF_ALLMULTI) {
- reg_rctl |= E1000_RCTL_MPE;
- reg_rctl &= ~E1000_RCTL_UPE;
- E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
- }
-
- return;
-}
-
-static void
-em_disable_promisc(struct adapter * adapter)
-{
- u_int32_t reg_rctl;
-
- reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
-
- reg_rctl &= (~E1000_RCTL_UPE);
- reg_rctl &= (~E1000_RCTL_MPE);
- E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
-
- return;
-}
-
-
-/*********************************************************************
- * Multicast Update
- *
- * This routine is called whenever multicast address list is updated.
- *
- **********************************************************************/
-
-static void
-em_set_multi(struct adapter * adapter)
-{
- u_int32_t reg_rctl = 0;
- u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
- u_int16_t pci_cmd_word;
- struct ifmultiaddr *ifma;
- int mcnt = 0;
- struct ifnet *ifp = &adapter->interface_data.ac_if;
-
- IOCTL_DEBUGOUT("em_set_multi: begin");
-
- if (adapter->hw.mac_type == em_82542_rev2_0) {
- reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
- if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- pci_cmd_word = adapter->hw.pci_cmd_word &
- ~CMD_MEM_WRT_INVALIDATE;
- pci_write_config(adapter->dev, PCIR_COMMAND, pci_cmd_word, 2);
- }
- reg_rctl |= E1000_RCTL_RST;
- E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
- msec_delay(5);
- }
-
-#if __FreeBSD_version < 500000
- LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
-#else
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
-#endif
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
-
- bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
- &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
- mcnt++;
- }
-
- if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) {
- reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
- reg_rctl |= E1000_RCTL_MPE;
- E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
- } else
- em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0);
-
- if (adapter->hw.mac_type == em_82542_rev2_0) {
- reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
- reg_rctl &= ~E1000_RCTL_RST;
- E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
- msec_delay(5);
- if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- pci_write_config(adapter->dev, PCIR_COMMAND,
- adapter->hw.pci_cmd_word, 2);
- }
- }
-
- return;
-}
-
/*********************************************************************
* Watchdog entry point
*
@@ -801,62 +614,6 @@ em_watchdog(struct ifnet *ifp)
}
/*********************************************************************
- * Timer routine
- *
- * This routine checks for link status and updates statistics.
- *
- **********************************************************************/
-
-static void
-em_local_timer(void *arg)
-{
- int s;
- struct ifnet *ifp;
- struct adapter * adapter = arg;
- ifp = &adapter->interface_data.ac_if;
-
- s = splimp();
-
- em_check_for_link(&adapter->hw);
- em_print_link_status(adapter);
- em_update_stats_counters(adapter);
- if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) {
- em_print_hw_stats(adapter);
- }
- adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz);
-
- splx(s);
- return;
-}
-
-static void
-em_print_link_status(struct adapter * adapter)
-{
- if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
- if (adapter->link_active == 0) {
- em_get_speed_and_duplex(&adapter->hw,
- &adapter->link_speed,
- &adapter->link_duplex);
- printf("em%d: Link is up %d Mbps %s\n",
- adapter->unit,
- adapter->link_speed,
- ((adapter->link_duplex == FULL_DUPLEX) ?
- "Full Duplex" : "Half Duplex"));
- adapter->link_active = 1;
- }
- } else {
- if (adapter->link_active == 1) {
- adapter->link_speed = 0;
- adapter->link_duplex = 0;
- printf("em%d: Link is Down\n", adapter->unit);
- adapter->link_active = 0;
- }
- }
-
- return;
-}
-
-/*********************************************************************
* Init entry point
*
* This routine is used in two ways. It is used by the stack as
@@ -932,35 +689,6 @@ em_init(void *arg)
return;
}
-
-/*********************************************************************
- *
- * This routine disables all traffic on the adapter by issuing a
- * global reset on the MAC and deallocates TX/RX buffers.
- *
- **********************************************************************/
-
-static void
-em_stop(void *arg)
-{
- struct ifnet *ifp;
- struct adapter * adapter = arg;
- ifp = &adapter->interface_data.ac_if;
-
- INIT_DEBUGOUT("em_stop: begin\n");
- em_disable_intr(adapter);
- em_reset_hw(&adapter->hw);
- untimeout(em_local_timer, adapter, adapter->timer_handle);
- em_free_transmit_structures(adapter);
- em_free_receive_structures(adapter);
-
-
- /* Tell the stack that the interface is no longer active */
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
-
- return;
-}
-
/*********************************************************************
*
* Interrupt Service routine
@@ -1130,7 +858,320 @@ em_media_change(struct ifnet *ifp)
return(0);
}
-/* Section end: Other registered entry points */
+
+
+/*********************************************************************
+ *
+ * This routine maps the mbufs to tx descriptors.
+ *
+ * return 0 on success, positive on failure
+ **********************************************************************/
+
+static int
+em_encap(struct adapter *adapter, struct mbuf *m_head)
+{
+ vm_offset_t virtual_addr;
+ u_int32_t txd_upper;
+ u_int32_t txd_lower;
+ u_int16_t txd_used, count;
+
+ struct mbuf *mp;
+ struct ifvlan *ifv = NULL;
+ struct em_tx_buffer *tx_buffer;
+ struct em_tx_desc *saved_tx_desc = NULL;
+ struct em_tx_desc *current_tx_desc = NULL;
+ struct ifnet *ifp = &adapter->interface_data.ac_if;
+
+ /* Force a cleanup if number of descriptors available hit the threshold */
+ if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD)
+ em_clean_transmit_interrupts(adapter);
+
+ if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+ adapter->no_tx_desc_avail1++;
+ return (ENOBUFS);
+ }
+
+ /* Find out number of fragments in a mbuf chain */
+ count = 0;
+ for (mp = m_head; mp != NULL; mp = mp->m_next) {
+ if (mp->m_len == 0)
+ continue;
+ count++;
+ }
+
+ /* Bail out if we don't have enough descriptors */
+ if (adapter->num_tx_desc_avail <= count) {
+ em_clean_transmit_interrupts(adapter);
+ adapter->no_tx_desc_avail2++;
+ return (ENOBUFS);
+ }
+
+ tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list);
+ if (!tx_buffer) {
+ adapter->no_tx_buffer_avail1++;
+ return (ENOBUFS);
+ }
+
+ /* Setup checksum context */
+ if (ifp->if_hwassist > 0) {
+ em_transmit_checksum_setup(adapter, m_head,
+ &txd_upper, &txd_lower);
+ } else {
+ txd_upper = 0;
+ txd_lower = 0;
+ }
+
+ /* Find out if we are in vlan mode */
+ if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
+ m_head->m_pkthdr.rcvif != NULL &&
+ m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
+ ifv = m_head->m_pkthdr.rcvif->if_softc;
+
+
+ txd_used = 0;
+ saved_tx_desc = adapter->next_avail_tx_desc;
+ for (mp = m_head; mp != NULL; mp = mp->m_next) {
+ if (mp->m_len == 0)
+ continue;
+
+ tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list);
+ if (!tx_buffer) {
+ adapter->no_tx_buffer_avail2++;
+ adapter->next_avail_tx_desc = saved_tx_desc;
+ return (ENOBUFS);
+ }
+
+ current_tx_desc = adapter->next_avail_tx_desc;
+ virtual_addr = mtod(mp, vm_offset_t);
+ current_tx_desc->buffer_addr = vtophys(virtual_addr);
+
+ current_tx_desc->lower.data = (adapter->txd_cmd | txd_lower | mp->m_len);
+ current_tx_desc->upper.data = (txd_upper);
+
+ if (current_tx_desc == adapter->last_tx_desc)
+ adapter->next_avail_tx_desc =
+ adapter->first_tx_desc;
+ else
+ adapter->next_avail_tx_desc++;
+
+ txd_used++;
+
+ tx_buffer->m_head = NULL;
+ tx_buffer->used_tx_desc = current_tx_desc;
+ STAILQ_REMOVE_HEAD(&adapter->free_tx_buffer_list, em_tx_entry);
+ STAILQ_INSERT_TAIL(&adapter->used_tx_buffer_list, tx_buffer,
+ em_tx_entry);
+ }
+ adapter->num_tx_desc_avail-= txd_used;
+
+ if (ifv != NULL) {
+ /* Tell hardware to add tag */
+ current_tx_desc->lower.data |= E1000_TXD_CMD_VLE;
+
+ /* Set the vlan id */
+ current_tx_desc->upper.fields.special = ifv->ifv_tag;
+ }
+
+ /* Last Descriptor of Packet needs End Of Packet (EOP) bit set. */
+ current_tx_desc->lower.data |= E1000_TXD_CMD_EOP;
+
+ /* Save mbuf chain so that we can free it during transmit cleanup */
+ tx_buffer->m_head = m_head;
+
+ /*
+ * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
+ * that this frame is available to transmit.
+ */
+ E1000_WRITE_REG(&adapter->hw, TDT,
+ (((uintptr_t) adapter->next_avail_tx_desc -
+ (uintptr_t) adapter->first_tx_desc) >> 4));
+
+ return(0);
+}
+
+
+static void
+em_set_promisc(struct adapter * adapter)
+{
+
+ u_int32_t reg_rctl;
+ struct ifnet *ifp = &adapter->interface_data.ac_if;
+
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+ if (ifp->if_flags & IFF_PROMISC) {
+ reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+ } else if (ifp->if_flags & IFF_ALLMULTI) {
+ reg_rctl |= E1000_RCTL_MPE;
+ reg_rctl &= ~E1000_RCTL_UPE;
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+ }
+
+ return;
+}
+
+static void
+em_disable_promisc(struct adapter * adapter)
+{
+ u_int32_t reg_rctl;
+
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+ reg_rctl &= (~E1000_RCTL_UPE);
+ reg_rctl &= (~E1000_RCTL_MPE);
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+
+ return;
+}
+
+
+/*********************************************************************
+ * Multicast Update
+ *
+ * This routine is called whenever multicast address list is updated.
+ *
+ **********************************************************************/
+
+static void
+em_set_multi(struct adapter * adapter)
+{
+ u_int32_t reg_rctl = 0;
+ u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
+ struct ifmultiaddr *ifma;
+ int mcnt = 0;
+ struct ifnet *ifp = &adapter->interface_data.ac_if;
+
+ IOCTL_DEBUGOUT("em_set_multi: begin");
+
+ if (adapter->hw.mac_type == em_82542_rev2_0) {
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+ em_pci_clear_mwi(&adapter->hw);
+ }
+ reg_rctl |= E1000_RCTL_RST;
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+ msec_delay(5);
+ }
+
+#if __FreeBSD_version < 500000
+ LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+#else
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+#endif
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+
+ bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
+ mcnt++;
+ }
+
+ if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) {
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ reg_rctl |= E1000_RCTL_MPE;
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+ } else
+ em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0);
+
+ if (adapter->hw.mac_type == em_82542_rev2_0) {
+ reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ reg_rctl &= ~E1000_RCTL_RST;
+ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
+ msec_delay(5);
+ if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+ em_pci_set_mwi(&adapter->hw);
+ }
+ }
+
+ return;
+}
+
+
+/*********************************************************************
+ * Timer routine
+ *
+ * This routine checks for link status and updates statistics.
+ *
+ **********************************************************************/
+
+static void
+em_local_timer(void *arg)
+{
+ int s;
+ struct ifnet *ifp;
+ struct adapter * adapter = arg;
+ ifp = &adapter->interface_data.ac_if;
+
+ s = splimp();
+
+ em_check_for_link(&adapter->hw);
+ em_print_link_status(adapter);
+ em_update_stats_counters(adapter);
+ if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) {
+ em_print_hw_stats(adapter);
+ }
+ adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz);
+
+ splx(s);
+ return;
+}
+
+static void
+em_print_link_status(struct adapter * adapter)
+{
+ if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
+ if (adapter->link_active == 0) {
+ em_get_speed_and_duplex(&adapter->hw,
+ &adapter->link_speed,
+ &adapter->link_duplex);
+ printf("em%d: Link is up %d Mbps %s\n",
+ adapter->unit,
+ adapter->link_speed,
+ ((adapter->link_duplex == FULL_DUPLEX) ?
+ "Full Duplex" : "Half Duplex"));
+ adapter->link_active = 1;
+ }
+ } else {
+ if (adapter->link_active == 1) {
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+ printf("em%d: Link is Down\n", adapter->unit);
+ adapter->link_active = 0;
+ }
+ }
+
+ return;
+}
+
+
+/*********************************************************************
+ *
+ * This routine disables all traffic on the adapter by issuing a
+ * global reset on the MAC and deallocates TX/RX buffers.
+ *
+ **********************************************************************/
+
+static void
+em_stop(void *arg)
+{
+ struct ifnet *ifp;
+ struct adapter * adapter = arg;
+ ifp = &adapter->interface_data.ac_if;
+
+ INIT_DEBUGOUT("em_stop: begin\n");
+ em_disable_intr(adapter);
+ em_reset_hw(&adapter->hw);
+ untimeout(em_local_timer, adapter, adapter->timer_handle);
+ em_free_transmit_structures(adapter);
+ em_free_receive_structures(adapter);
+
+
+ /* Tell the stack that the interface is no longer active */
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ return;
+}
/*********************************************************************
@@ -1147,9 +1188,9 @@ em_identify_hardware(struct adapter * adapter)
adapter->hw.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
if (!((adapter->hw.pci_cmd_word & PCIM_CMD_BUSMASTEREN) &&
(adapter->hw.pci_cmd_word & PCIM_CMD_MEMEN))) {
- printf("em%d: Memory Access and/or Bus Master bits were not set!\n",
+ printf("em%d: Memory Access and/or Bus Master bits were not set!\n",
adapter->unit);
- adapter->hw.pci_cmd_word |=
+ adapter->hw.pci_cmd_word |=
(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN);
pci_write_config(dev, PCIR_COMMAND, adapter->hw.pci_cmd_word, 2);
}
@@ -1161,37 +1202,10 @@ em_identify_hardware(struct adapter * adapter)
adapter->hw.subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2);
adapter->hw.subsystem_id = pci_read_config(dev, PCIR_SUBDEV_0, 2);
+ /* Identify the MAC */
+ if (em_set_mac_type(&adapter->hw))
+ printf("em%d: Unknown MAC Type\n", adapter->unit);
- /* Set MacType, etc. based on this PCI info */
- switch (adapter->hw.device_id) {
- case E1000_DEV_ID_82542:
- adapter->hw.mac_type = (adapter->hw.revision_id == 3) ?
- em_82542_rev2_1 : em_82542_rev2_0;
- break;
- case E1000_DEV_ID_82543GC_FIBER:
- case E1000_DEV_ID_82543GC_COPPER:
- adapter->hw.mac_type = em_82543;
- break;
- case E1000_DEV_ID_82544EI_FIBER:
- case E1000_DEV_ID_82544EI_COPPER:
- case E1000_DEV_ID_82544GC_COPPER:
- case E1000_DEV_ID_82544GC_LOM:
- adapter->hw.mac_type = em_82544;
- break;
- case E1000_DEV_ID_82540EM:
- adapter->hw.mac_type = em_82540;
- break;
- case E1000_DEV_ID_82545EM_FIBER:
- case E1000_DEV_ID_82545EM_COPPER:
- adapter->hw.mac_type = em_82545;
- break;
- case E1000_DEV_ID_82546EB_FIBER:
- case E1000_DEV_ID_82546EB_COPPER:
- adapter->hw.mac_type = em_82546;
- break;
- default:
- INIT_DEBUGOUT1("Unknown device id 0x%x", adapter->hw.device_id);
- }
return;
}
@@ -1465,7 +1479,6 @@ em_setup_transmit_structures(struct adapter * adapter)
/* Setup TX descriptor pointers */
adapter->next_avail_tx_desc = adapter->first_tx_desc;
- adapter->oldest_used_tx_desc = adapter->first_tx_desc;
/* Set number of descriptors available */
adapter->num_tx_desc_avail = adapter->num_tx_desc;
@@ -1591,14 +1604,14 @@ em_free_transmit_structures(struct adapter * adapter)
*
**********************************************************************/
static void
-em_transmit_checksum_setup(struct adapter * adapter,
+em_transmit_checksum_setup(struct adapter *adapter,
struct mbuf *mp,
- struct em_tx_buffer *tx_buffer,
u_int32_t *txd_upper,
u_int32_t *txd_lower)
{
struct em_context_desc *TXD;
struct em_tx_desc * current_tx_desc;
+ struct em_tx_buffer *tx_buffer;
if (mp->m_pkthdr.csum_flags) {
@@ -1632,8 +1645,9 @@ em_transmit_checksum_setup(struct adapter * adapter,
* needs to be reset.
*/
current_tx_desc = adapter->next_avail_tx_desc;
- TXD = (struct em_context_desc *)current_tx_desc;
+ tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list);
+ TXD = (struct em_context_desc *)current_tx_desc;
TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN;
TXD->lower_setup.ip_fields.ipcso =
ETHER_HDR_LEN + offsetof(struct ip, ip_sum);
@@ -1655,7 +1669,7 @@ em_transmit_checksum_setup(struct adapter * adapter,
}
TXD->tcp_seg_setup.data = 0;
- TXD->cmd_and_length = E1000_TXD_CMD_DEXT;
+ TXD->cmd_and_length = (adapter->txd_cmd | E1000_TXD_CMD_DEXT);
if (current_tx_desc == adapter->last_tx_desc)
adapter->next_avail_tx_desc = adapter->first_tx_desc;
@@ -1664,7 +1678,80 @@ em_transmit_checksum_setup(struct adapter * adapter,
adapter->num_tx_desc_avail--;
- tx_buffer->num_tx_desc_used++;
+ tx_buffer->used_tx_desc = current_tx_desc;
+ STAILQ_REMOVE_HEAD(&adapter->free_tx_buffer_list, em_tx_entry);
+ STAILQ_INSERT_TAIL(&adapter->used_tx_buffer_list, tx_buffer, em_tx_entry);
+ return;
+}
+
+/**********************************************************************
+ *
+ * Examine each tx_buffer in the used queue. If the hardware is done
+ * processing the packet then free associated resources. The
+ * tx_buffer is put back on the free queue.
+ *
+ **********************************************************************/
+static void
+em_clean_transmit_interrupts(struct adapter * adapter)
+{
+ struct em_tx_buffer *tx_buffer;
+ struct em_tx_desc *tx_desc;
+ int s;
+ struct ifnet *ifp;
+
+ s = splimp();
+#ifdef DBG_STATS
+ adapter->clean_tx_interrupts++;
+#endif
+
+ for (tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list);
+ tx_buffer;
+ tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list)) {
+
+ /*
+ * Get hold of the next descriptor that the hardware will report status
+ * back to. There is 1/1 correspondence between a tx descriptor
+ * and tx_buffer.
+ */
+
+ tx_desc = tx_buffer->used_tx_desc;
+
+ /*
+ * If the descriptor done bit is set, free tx_buffer and associated
+ * resources
+ */
+ if (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
+
+ tx_desc->upper.data = 0;
+ adapter->num_tx_desc_avail++;
+
+ if (tx_buffer->m_head) {
+ m_freem(tx_buffer->m_head);
+ tx_buffer->m_head = NULL;
+ }
+
+ STAILQ_REMOVE_HEAD(&adapter->used_tx_buffer_list,
+ em_tx_entry);
+ /* Return this tx_buffer back to the "free" list */
+ STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list,
+ tx_buffer, em_tx_entry);
+ } else {
+ /*
+ * Found a tx_buffer that the em is not done with then there is
+ * no reason to check the rest of the queue.
+ */
+ break;
+ }
+ } /* end for each tx_buffer */
+
+ ifp = &adapter->interface_data.ac_if;
+
+ /* Tell the stack that it is OK to send packets */
+ if (adapter->num_tx_desc_avail > EM_TX_CLEANUP_THRESHOLD) {
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+ splx(s);
return;
}
@@ -2136,33 +2223,57 @@ em_disable_intr(struct adapter *adapter)
return;
}
-void em_write_pci_cfg(struct em_hw *hw,
- uint32_t reg,
- uint16_t *value)
+void
+em_write_pci_cfg(struct em_hw *hw,
+ uint32_t reg,
+ uint16_t *value)
{
pci_write_config(((struct em_osdep *)hw->back)->dev, reg,
*value, 2);
}
-void em_read_pci_cfg(struct em_hw *hw, uint32_t reg,
- uint16_t *value)
+void
+em_read_pci_cfg(struct em_hw *hw, uint32_t reg,
+ uint16_t *value)
{
*value = pci_read_config(((struct em_osdep *)hw->back)->dev,
reg, 2);
return;
}
-uint32_t em_io_read(struct em_hw *hw, uint32_t port)
+
+void
+em_pci_set_mwi(struct em_hw *hw)
+{
+ pci_write_config(((struct em_osdep *)hw->back)->dev,
+ PCIR_COMMAND,
+ (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2);
+ return;
+}
+
+void
+em_pci_clear_mwi(struct em_hw *hw)
+{
+ pci_write_config(((struct em_osdep *)hw->back)->dev,
+ PCIR_COMMAND,
+ (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2);
+ return;
+}
+
+uint32_t
+em_io_read(struct em_hw *hw, uint32_t port)
{
return(inl(port));
}
-void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value)
+void
+em_io_write(struct em_hw *hw, uint32_t port, uint32_t value)
{
outl(port, value);
return;
}
+
/**********************************************************************
*
* Update the board statistics counters.
@@ -2288,8 +2399,10 @@ em_print_hw_stats(struct adapter *adapter)
adapter->clean_tx_interrupts);
#endif
- printf("em%d: Tx Descriptors not Avail = %ld\n", unit,
- adapter->no_tx_desc_avail);
+ printf("em%d: Tx Descriptors not avail1 = %ld\n", unit,
+ adapter->no_tx_desc_avail1);
+ printf("em%d: Tx Descriptors not avail2 = %ld\n", unit,
+ adapter->no_tx_desc_avail2);
printf("em%d: Tx Buffer not avail1 = %ld\n", unit,
adapter->no_tx_buffer_avail1);
printf("em%d: Tx Buffer not avail2 = %ld\n", unit,
@@ -2298,6 +2411,8 @@ em_print_hw_stats(struct adapter *adapter)
adapter->mbuf_alloc_failed);
printf("em%d: Std Cluster Failed = %ld\n",unit,
adapter->mbuf_cluster_failed);
+ printf("em%d: Number of TX desc avail = %d\n", unit,
+ adapter->num_tx_desc_avail);
printf("em%d: Symbol errors = %lld\n", unit,
(long long)adapter->stats.symerrs);
@@ -2340,92 +2455,3 @@ em_print_hw_stats(struct adapter *adapter)
return;
}
-
-/**********************************************************************
- *
- * Examine each tx_buffer in the used queue. If the hardware is done
- * processing the packet then free associated resources. The
- * tx_buffer is put back on the free queue.
- *
- **********************************************************************/
-static void
-em_clean_transmit_interrupts(struct adapter * adapter)
-{
- struct em_tx_buffer *tx_buffer;
- struct em_tx_desc *tx_desc;
- int s;
- struct ifnet *ifp;
-
- s = splimp();
-#ifdef DBG_STATS
- adapter->clean_tx_interrupts++;
-#endif
-
- for (tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list);
- tx_buffer;
- tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list)) {
-
- /*
- * Get hold of the next descriptor that the em will report status
- * back to (this will be the last descriptor of a given tx_buffer). We
- * only want to free the tx_buffer (and it resources) if the driver is
- * done with ALL of the descriptors. If the driver is done with the
- * last one then it is done with all of them.
- */
-
- tx_desc = adapter->oldest_used_tx_desc +
- (tx_buffer->num_tx_desc_used - 1);
-
- /* Check for wrap case */
- if (tx_desc > adapter->last_tx_desc)
- tx_desc -= adapter->num_tx_desc;
-
-
- /*
- * If the descriptor done bit is set free tx_buffer and associated
- * resources
- */
- if (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
-
- STAILQ_REMOVE_HEAD(&adapter->used_tx_buffer_list,
- em_tx_entry);
-
- if ((tx_desc == adapter->last_tx_desc))
- adapter->oldest_used_tx_desc =
- adapter->first_tx_desc;
- else
- adapter->oldest_used_tx_desc = (tx_desc + 1);
-
- /* Make available the descriptors that were previously used */
- adapter->num_tx_desc_avail +=
- tx_buffer->num_tx_desc_used;
-
- tx_buffer->num_tx_desc_used = 0;
-
- if (tx_buffer->m_head) {
- m_freem(tx_buffer->m_head);
- tx_buffer->m_head = NULL;
- }
- /* Return this "Software packet" back to the "free" list */
- STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list,
- tx_buffer, em_tx_entry);
- } else {
- /*
- * Found a tx_buffer that the em is not done with then there is
- * no reason to check the rest of the queue.
- */
- break;
- }
- } /* end for each tx_buffer */
-
- ifp = &adapter->interface_data.ac_if;
-
- /* Tell the stack that it is OK to send packets */
- if (adapter->num_tx_desc_avail > TX_CLEANUP_THRESHOLD) {
- ifp->if_timer = 0;
- ifp->if_flags &= ~IFF_OACTIVE;
- }
- splx(s);
- return;
-}
-
diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h
index f292966..d280837 100644
--- a/sys/dev/em/if_em.h
+++ b/sys/dev/em/if_em.h
@@ -75,23 +75,129 @@ POSSIBILITY OF SUCH DAMAGE.
#include <dev/em/if_em_hw.h>
-/* Tunables */
-#define MAX_TXD 256
-#define MAX_RXD 256
-#define TX_CLEANUP_THRESHOLD MAX_TXD / 8
-#define TIDV 128
-#define RIDV 28
-#define DO_AUTO_NEG 1
-#define WAIT_FOR_AUTO_NEG_DEFAULT 1
-#define AUTONEG_ADV_DEFAULT (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
- ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
- ADVERTISE_1000_FULL)
+/* Tunables -- Begin */
+
+/*
+ * FlowControl
+ * Valid Range: 0-3 (0=none, 1=Rx only, 2=Tx only, 3=Rx&Tx)
+ * Default: Read flow control settings from the EEPROM
+ * This parameter controls the automatic generation(Tx) and response(Rx) to
+ * Ethernet PAUSE frames.
+ */
+
+
+/*
+ * TxDescriptors
+ * Valid Range: 80-256 for 82542 and 82543-based adapters
+ * 80-4096 for 82540, 82544, 82545, and 82546-based adapters
+ * Default Value: 256
+ * This value is the number of transmit descriptors allocated by the driver.
+ * Increasing this value allows the driver to queue more transmits. Each
+ * descriptor is 16 bytes.
+ */
+#define EM_MAX_TXD 256
+
+/*
+ * RxDescriptors
+ * Valid Range: 80-256 for 82542 and 82543-based adapters
+ * 80-4096 for 82540, 82544, 82545, and 82546-based adapters
+ * Default Value: 256
+ * This value is the number of receive descriptors allocated by the driver.
+ * Increasing this value allows the driver to buffer more incoming packets.
+ * Each descriptor is 16 bytes. A receive buffer is also allocated for each
+ * descriptor. The maximum MTU size is 16110.
+ *
+ */
+#define EM_MAX_RXD 256
+
+/*
+ * TxIntDelay
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ * This value delays the generation of transmit interrupts in units of
+ * 1.024 microseconds. Transmit interrupt reduction can improve CPU
+ * efficiency if properly tuned for specific network traffic. If the
+ * system is reporting dropped transmits, this value may be set too high
+ * causing the driver to run out of available transmit descriptors.
+ */
+#define EM_TIDV 128
+
+/*
+ * RxIntDelay
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 0
+ * This value delays the generation of receive interrupts in units of 1.024
+ * microseconds. Receive interrupt reduction can improve CPU efficiency if
+ * properly tuned for specific network traffic. Increasing this value adds
+ * extra latency to frame reception and can end up decreasing the throughput
+ * of TCP traffic. If the system is reporting dropped receives, this value
+ * may be set too high, causing the driver to run out of available receive
+ * descriptors.
+ *
+ * CAUTION: When setting RxIntDelay to a value other than 0, adapters
+ * may hang (stop transmitting) under certain network conditions.
+ * If this occurs a WATCHDOG message is logged in the system event log.
+ * In addition, the controller is automatically reset, restoring the
+ * network connection. To eliminate the potential for the hang
+ * ensure that RxIntDelay is set to 0.
+ */
+#define EM_RDTR 0
+
+
+/*
+ * This parameter controls the maximum no of times the driver will loop
+ * in the isr.
+ * Minimum Value = 1
+ */
+#define EM_MAX_INTR 3
+
+
+/*
+ * This parameter determines when the hardware will report that it is
+ * done with the packet.
+ * 0 - "Done" is reported when the packet has been sent on the wire
+ * 1 - "Done" is reported when the packet has been DMA'ed and is on chip.
+ * 2 - Determine the best method.
+ */
#define EM_REPORT_TX_EARLY 2
+
+/*
+ * Inform the stack about transmit checksum offload capabilities.
+ */
#define EM_CHECKSUM_FEATURES (CSUM_TCP | CSUM_UDP)
-#define EM_MAX_INTR 3
+
+/*
+ * This parameter controls the duration of transmit watchdog timer.
+ */
#define EM_TX_TIMEOUT 5 /* set to 5 seconds */
+/*
+ * This parameter controls when the driver calls the routine to reclaim
+ * transmit descriptors.
+ */
+#define EM_TX_CLEANUP_THRESHOLD EM_MAX_TXD / 8
+
+/*
+ * This parameter controls whether or not autonegotation is enabled.
+ * 0 - Disable autonegotiation
+ * 1 - Enable autonegotiation
+ */
+#define DO_AUTO_NEG 1
+
+/*
+ * This parameter control whether or not the driver will wait for
+ * autonegotiation to complete.
+ * 1 - Wait for autonegotiation to complete
+ * 0 - Don't wait for autonegotiation to complete
+ */
+#define WAIT_FOR_AUTO_NEG_DEFAULT 1
+
+
+/* Tunables -- End */
+#define AUTONEG_ADV_DEFAULT (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
+ ADVERTISE_1000_FULL)
#define EM_VENDOR_ID 0x8086
#define EM_MMBA 0x0010 /* Mem base address */
#define EM_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
@@ -138,8 +244,7 @@ POSSIBILITY OF SUCH DAMAGE.
* should load.
*
* ******************************************************************************/
-typedef struct _em_vendor_info_t
-{
+typedef struct _em_vendor_info_t {
unsigned int vendor_id;
unsigned int device_id;
unsigned int subvendor_id;
@@ -151,10 +256,9 @@ typedef struct _em_vendor_info_t
struct em_tx_buffer {
STAILQ_ENTRY(em_tx_buffer) em_tx_entry;
struct mbuf *m_head;
- u_int32_t num_tx_desc_used;
+ struct em_tx_desc *used_tx_desc;
};
-
/* ******************************************************************************
* This structure stores information about the 2k aligned receive buffer
* into which the E1000 DMA's frames.
@@ -204,7 +308,6 @@ struct adapter {
struct em_tx_desc *first_tx_desc;
struct em_tx_desc *last_tx_desc;
struct em_tx_desc *next_avail_tx_desc;
- struct em_tx_desc *oldest_used_tx_desc;
struct em_tx_desc *tx_desc_base;
volatile u_int16_t num_tx_desc_avail;
u_int16_t num_tx_desc;
@@ -232,8 +335,8 @@ struct adapter {
unsigned long dropped_pkts;
unsigned long mbuf_alloc_failed;
unsigned long mbuf_cluster_failed;
- unsigned long xmit_pullup;
- unsigned long no_tx_desc_avail;
+ unsigned long no_tx_desc_avail1;
+ unsigned long no_tx_desc_avail2;
unsigned long no_tx_buffer_avail1;
unsigned long no_tx_buffer_avail2;
#ifdef DBG_STATS
diff --git a/sys/dev/em/if_em_hw.c b/sys/dev/em/if_em_hw.c
index 165e317..88bf617 100644
--- a/sys/dev/em/if_em_hw.c
+++ b/sys/dev/em/if_em_hw.c
@@ -53,9 +53,71 @@ static void em_lower_ee_clk(struct em_hw *hw, uint32_t *eecd);
static void em_shift_out_ee_bits(struct em_hw *hw, uint16_t data, uint16_t count);
static uint16_t em_shift_in_ee_bits(struct em_hw *hw);
static void em_setup_eeprom(struct em_hw *hw);
+static void em_clock_eeprom(struct em_hw *hw);
+static void em_cleanup_eeprom(struct em_hw *hw);
static void em_standby_eeprom(struct em_hw *hw);
static int32_t em_id_led_init(struct em_hw * hw);
+
+
+
+/******************************************************************************
+ * Set the mac type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_set_mac_type(struct em_hw *hw)
+{
+ DEBUGFUNC("em_set_mac_type");
+
+ switch (hw->device_id) {
+ case E1000_DEV_ID_82542:
+ switch (hw->revision_id) {
+ case E1000_82542_2_0_REV_ID:
+ hw->mac_type = em_82542_rev2_0;
+ break;
+ case E1000_82542_2_1_REV_ID:
+ hw->mac_type = em_82542_rev2_1;
+ break;
+ default:
+ /* Invalid 82542 revision ID */
+ return -E1000_ERR_MAC_TYPE;
+ }
+ break;
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ hw->mac_type = em_82543;
+ break;
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ hw->mac_type = em_82544;
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ case E1000_DEV_ID_82540EP:
+ case E1000_DEV_ID_82540EP_LOM:
+ case E1000_DEV_ID_82540EP_LP:
+ hw->mac_type = em_82540;
+ break;
+ case E1000_DEV_ID_82545EM_COPPER:
+ case E1000_DEV_ID_82545EM_FIBER:
+ hw->mac_type = em_82545;
+ break;
+ case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_FIBER:
+ hw->mac_type = em_82546;
+ break;
+ default:
+ /* Should never have loaded on this device */
+ return -E1000_ERR_MAC_TYPE;
+ }
+
+
+ return E1000_SUCCESS;
+}
/******************************************************************************
* Reset the transmit and receive units; mask and clear all interrupts.
*
@@ -68,17 +130,13 @@ em_reset_hw(struct em_hw *hw)
uint32_t ctrl_ext;
uint32_t icr;
uint32_t manc;
- uint16_t pci_cmd_word;
DEBUGFUNC("em_reset_hw");
/* For 82542 (rev 2.0), disable MWI before issuing a device reset */
if(hw->mac_type == em_82542_rev2_0) {
- if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
- pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
- em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
- }
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ em_pci_clear_mwi(hw);
}
/* Clear interrupt mask to stop board from generating interrupts */
@@ -91,6 +149,7 @@ em_reset_hw(struct em_hw *hw)
*/
E1000_WRITE_REG(hw, RCTL, 0);
E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+ E1000_WRITE_FLUSH(hw);
/* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
hw->tbi_compatibility_on = FALSE;
@@ -120,6 +179,7 @@ em_reset_hw(struct em_hw *hw)
ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
ctrl_ext |= E1000_CTRL_EXT_EE_RST;
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
/* Wait for EEPROM reload */
msec_delay(2);
} else {
@@ -141,7 +201,7 @@ em_reset_hw(struct em_hw *hw)
/* If MWI was previously enabled, reenable it. */
if(hw->mac_type == em_82542_rev2_0) {
if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
- em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+ em_pci_set_mwi(hw);
}
}
@@ -162,7 +222,6 @@ em_init_hw(struct em_hw *hw)
uint32_t ctrl, status;
uint32_t i;
int32_t ret_val;
- uint16_t pci_cmd_word;
uint16_t pcix_cmd_word;
uint16_t pcix_stat_hi_word;
uint16_t cmd_mmrbc;
@@ -205,12 +264,10 @@ em_init_hw(struct em_hw *hw)
/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
if(hw->mac_type == em_82542_rev2_0) {
- if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
- pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
- em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
- }
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ em_pci_clear_mwi(hw);
E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+ E1000_WRITE_FLUSH(hw);
msec_delay(5);
}
@@ -222,9 +279,10 @@ em_init_hw(struct em_hw *hw)
/* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
if(hw->mac_type == em_82542_rev2_0) {
E1000_WRITE_REG(hw, RCTL, 0);
+ E1000_WRITE_FLUSH(hw);
msec_delay(1);
if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
- em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+ em_pci_set_mwi(hw);
}
/* Zero out the Multicast HASH table */
@@ -249,6 +307,8 @@ em_init_hw(struct em_hw *hw)
PCIX_COMMAND_MMRBC_SHIFT;
stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
PCIX_STATUS_HI_MMRBC_SHIFT;
+ if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+ stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
if(cmd_mmrbc > stat_mmrbc) {
pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
@@ -259,6 +319,13 @@ em_init_hw(struct em_hw *hw)
/* Call a subroutine to configure the link and setup flow control. */
ret_val = em_setup_link(hw);
+ /* Set the transmit descriptor write-back policy */
+ if(hw->mac_type > em_82544) {
+ ctrl = E1000_READ_REG(hw, TXDCTL);
+ ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+ E1000_WRITE_REG(hw, TXDCTL, ctrl);
+ }
+
/* Clear all of the statistics registers (clear on read). It is
* important that we do this after we have tried to establish link
* because the symbol error count will increment wildly if there
@@ -384,7 +451,6 @@ em_setup_link(struct em_hw *hw)
* Sets up link for a fiber based adapter
*
* hw - Struct containing variables accessed by shared code
- * ctrl - Current value of the device control register
*
* Manipulates Physical Coding Sublayer functions in order to configure
* link. Assumes the hardware has been previously reset and the transmitter
@@ -470,6 +536,7 @@ em_setup_fiber_link(struct em_hw *hw)
E1000_WRITE_REG(hw, TXCW, txcw);
E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
hw->txcw = txcw;
msec_delay(1);
@@ -514,7 +581,6 @@ em_setup_fiber_link(struct em_hw *hw)
* Detects which PHY is present and the speed and duplex
*
* hw - Struct containing variables accessed by shared code
-* ctrl - current value of the device control register
******************************************************************************/
static int32_t
em_setup_copper_link(struct em_hw *hw)
@@ -603,14 +669,17 @@ em_setup_copper_link(struct em_hw *hw)
return -E1000_ERR_PHY;
}
phy_data |= M88E1000_EPSCR_TX_CLK_25;
- /* Configure Master and Slave downshift values */
- phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
- M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
- phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
- M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
- if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
- DEBUGOUT("PHY Write Error\n");
- return -E1000_ERR_PHY;
+
+ if (hw->phy_revision < M88E1011_I_REV_4) {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
}
/* SW Reset the PHY so all changes take effect */
@@ -956,7 +1025,6 @@ em_phy_force_speed_duplex(struct em_hw *hw)
/* Write the configured values back to the Device Control Reg. */
E1000_WRITE_REG(hw, CTRL, ctrl);
- /* Write the MII Control Register with the new PHY configuration. */
if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
DEBUGOUT("PHY Read Error\n");
return -E1000_ERR_PHY;
@@ -971,9 +1039,11 @@ em_phy_force_speed_duplex(struct em_hw *hw)
return -E1000_ERR_PHY;
}
DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
-
+
/* Need to reset the PHY or these changes will be ignored */
mii_ctrl_reg |= MII_CR_RESET;
+
+ /* Write back the modified PHY MII control register. */
if(em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
DEBUGOUT("PHY Write Error\n");
return -E1000_ERR_PHY;
@@ -1083,6 +1153,7 @@ em_config_collision_dist(struct em_hw *hw)
tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
E1000_WRITE_REG(hw, TCTL, tctl);
+ E1000_WRITE_FLUSH(hw);
}
/******************************************************************************
@@ -1680,6 +1751,7 @@ em_raise_mdi_clk(struct em_hw *hw,
* bit), and then delay 2 microseconds.
*/
E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+ E1000_WRITE_FLUSH(hw);
usec_delay(2);
}
@@ -1697,6 +1769,7 @@ em_lower_mdi_clk(struct em_hw *hw,
* bit), and then delay 2 microseconds.
*/
E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+ E1000_WRITE_FLUSH(hw);
usec_delay(2);
}
@@ -1739,6 +1812,7 @@ em_shift_out_mdi_bits(struct em_hw *hw,
else ctrl &= ~E1000_CTRL_MDIO;
E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
usec_delay(2);
@@ -1747,9 +1821,6 @@ em_shift_out_mdi_bits(struct em_hw *hw,
mask = mask >> 1;
}
-
- /* Clear the data bit just before leaving this routine. */
- ctrl &= ~E1000_CTRL_MDIO;
}
/******************************************************************************
@@ -1780,6 +1851,7 @@ em_shift_in_mdi_bits(struct em_hw *hw)
ctrl &= ~E1000_CTRL_MDIO;
E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
/* Raise and Lower the clock before reading in the data. This accounts for
* the turnaround bits. The first clock occurred when we clocked out the
@@ -1800,9 +1872,6 @@ em_shift_in_mdi_bits(struct em_hw *hw)
em_raise_mdi_clk(hw, &ctrl);
em_lower_mdi_clk(hw, &ctrl);
- /* Clear the MDIO bit just before leaving this routine. */
- ctrl &= ~E1000_CTRL_MDIO;
-
return data;
}
@@ -1976,8 +2045,10 @@ em_phy_hw_reset(struct em_hw *hw)
*/
ctrl = E1000_READ_REG(hw, CTRL);
E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+ E1000_WRITE_FLUSH(hw);
msec_delay(10);
E1000_WRITE_REG(hw, CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
} else {
/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
* bit to put the PHY into reset. Then, take it out of reset.
@@ -1986,9 +2057,11 @@ em_phy_hw_reset(struct em_hw *hw)
ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
msec_delay(10);
ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
}
usec_delay(150);
}
@@ -2045,7 +2118,8 @@ em_detect_gig_phy(struct em_hw *hw)
return -E1000_ERR_PHY;
}
hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
-
+ hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
switch(hw->mac_type) {
case em_82543:
if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
@@ -2176,6 +2250,8 @@ em_validate_mdi_setting(struct em_hw *hw)
return 0;
}
+
+
/******************************************************************************
* Raises the EEPROM's clock input.
*
@@ -2187,10 +2263,11 @@ em_raise_ee_clk(struct em_hw *hw,
uint32_t *eecd)
{
/* Raise the clock input to the EEPROM (by setting the SK bit), and then
- * wait 50 microseconds.
+ * wait <delay> microseconds.
*/
*eecd = *eecd | E1000_EECD_SK;
E1000_WRITE_REG(hw, EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
usec_delay(50);
}
@@ -2209,6 +2286,7 @@ em_lower_ee_clk(struct em_hw *hw,
*/
*eecd = *eecd & ~E1000_EECD_SK;
E1000_WRITE_REG(hw, EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
usec_delay(50);
}
@@ -2246,6 +2324,7 @@ em_shift_out_ee_bits(struct em_hw *hw,
eecd |= E1000_EECD_DI;
E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
usec_delay(50);
@@ -2273,11 +2352,11 @@ em_shift_in_ee_bits(struct em_hw *hw)
uint32_t i;
uint16_t data;
- /* In order to read a register from the EEPROM, we need to shift 16 bits
- * in from the EEPROM. Bits are "shifted in" by raising the clock input to
- * the EEPROM (setting the SK bit), and then reading the value of the "DO"
- * bit. During this "shifting in" process the "DI" bit should always be
- * clear..
+ /* In order to read a register from the EEPROM, we need to shift 'count'
+ * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+ * input to the EEPROM (setting the SK bit), and then reading the value of
+ * the "DO" bit. During this "shifting in" process the "DI" bit should
+ * always be clear.
*/
eecd = E1000_READ_REG(hw, EECD);
@@ -2340,21 +2419,25 @@ em_standby_eeprom(struct em_hw *hw)
/* Deselct EEPROM */
eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
usec_delay(50);
/* Clock high */
eecd |= E1000_EECD_SK;
E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
usec_delay(50);
/* Select EEPROM */
eecd |= E1000_EECD_CS;
E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
usec_delay(50);
/* Clock low */
eecd &= ~E1000_EECD_SK;
E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
usec_delay(50);
}
@@ -2373,11 +2456,13 @@ em_clock_eeprom(struct em_hw *hw)
/* Rising edge of clock */
eecd |= E1000_EECD_SK;
E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
usec_delay(50);
/* Falling edge of clock */
eecd &= ~E1000_EECD_SK;
E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
usec_delay(50);
}
@@ -3076,6 +3161,9 @@ em_setup_led(struct em_hw *hw)
ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT);
E1000_WRITE_REG(hw, LEDCTL, ledctl);
break;
+ case E1000_DEV_ID_82540EP:
+ case E1000_DEV_ID_82540EP_LOM:
+ case E1000_DEV_ID_82540EP_LP:
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
@@ -3109,6 +3197,9 @@ em_cleanup_led(struct em_hw *hw)
case E1000_DEV_ID_82544GC_LOM:
/* No cleanup necessary */
break;
+ case E1000_DEV_ID_82540EP:
+ case E1000_DEV_ID_82540EP_LOM:
+ case E1000_DEV_ID_82540EP_LP:
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
@@ -3159,6 +3250,9 @@ em_led_on(struct em_hw *hw)
ctrl |= E1000_CTRL_SWDPIO0;
E1000_WRITE_REG(hw, CTRL, ctrl);
break;
+ case E1000_DEV_ID_82540EP:
+ case E1000_DEV_ID_82540EP_LOM:
+ case E1000_DEV_ID_82540EP_LP:
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
@@ -3206,6 +3300,9 @@ em_led_off(struct em_hw *hw)
ctrl |= E1000_CTRL_SWDPIO0;
E1000_WRITE_REG(hw, CTRL, ctrl);
break;
+ case E1000_DEV_ID_82540EP:
+ case E1000_DEV_ID_82540EP_LOM:
+ case E1000_DEV_ID_82540EP_LP:
case E1000_DEV_ID_82540EM:
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
diff --git a/sys/dev/em/if_em_hw.h b/sys/dev/em/if_em_hw.h
index 662508f..9e6172d 100644
--- a/sys/dev/em/if_em_hw.h
+++ b/sys/dev/em/if_em_hw.h
@@ -48,7 +48,8 @@ struct em_hw_stats;
/* Enumerated types specific to the e1000 hardware */
/* Media Access Controlers */
typedef enum {
- em_82542_rev2_0 = 0,
+ em_undefined = 0,
+ em_82542_rev2_0,
em_82542_rev2_1,
em_82543,
em_82544,
@@ -58,6 +59,7 @@ typedef enum {
em_num_macs
} em_mac_type;
+
/* Media Types */
typedef enum {
em_media_type_copper = 0,
@@ -127,6 +129,7 @@ typedef enum {
em_rev_polarity_undefined = 0xFF
} em_rev_polarity;
+
typedef enum {
em_polarity_reversal_enabled = 0,
em_polarity_reversal_disabled,
@@ -147,6 +150,7 @@ typedef enum {
em_1000t_rx_status_undefined = 0xFF
} em_1000t_rx_status;
+
struct em_phy_info {
em_cable_length cable_length;
em_10bt_ext_dist_enable extended_10bt_distance;
@@ -165,16 +169,18 @@ struct em_phy_stats {
/* Error Codes */
-#define E1000_SUCCESS 0
-#define E1000_ERR_EEPROM 1
-#define E1000_ERR_PHY 2
-#define E1000_ERR_CONFIG 3
-#define E1000_ERR_PARAM 4
+#define E1000_SUCCESS 0
+#define E1000_ERR_EEPROM 1
+#define E1000_ERR_PHY 2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM 4
+#define E1000_ERR_MAC_TYPE 5
/* Function prototypes */
/* Initialization */
void em_reset_hw(struct em_hw *hw);
int32_t em_init_hw(struct em_hw *hw);
+int32_t em_set_mac_type(struct em_hw *hw);
/* Link Configuration */
int32_t em_setup_link(struct em_hw *hw);
@@ -225,6 +231,8 @@ void em_reset_adaptive(struct em_hw *hw);
void em_update_adaptive(struct em_hw *hw);
void em_tbi_adjust_stats(struct em_hw *hw, struct em_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
void em_get_bus_info(struct em_hw *hw);
+void em_pci_set_mwi(struct em_hw *hw);
+void em_pci_clear_mwi(struct em_hw *hw);
void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
/* Port I/O is only supported on 82544 and newer */
@@ -232,26 +240,30 @@ uint32_t em_io_read(struct em_hw *hw, uint32_t port);
uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset);
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);
+
#define E1000_READ_REG_IO(a, reg) \
em_read_reg_io((a), E1000_##reg)
#define E1000_WRITE_REG_IO(a, reg, val) \
em_write_reg_io((a), E1000_##reg, val)
/* PCI Device IDs */
-#define E1000_DEV_ID_82542 0x1000
-#define E1000_DEV_ID_82543GC_FIBER 0x1001
-#define E1000_DEV_ID_82543GC_COPPER 0x1004
-#define E1000_DEV_ID_82544EI_COPPER 0x1008
-#define E1000_DEV_ID_82544EI_FIBER 0x1009
-#define E1000_DEV_ID_82544GC_COPPER 0x100C
-#define E1000_DEV_ID_82544GC_LOM 0x100D
-#define E1000_DEV_ID_82540EM 0x100E
-#define E1000_DEV_ID_82540EM_LOM 0x1015
-#define E1000_DEV_ID_82545EM_COPPER 0x100F
-#define E1000_DEV_ID_82545EM_FIBER 0x1011
-#define E1000_DEV_ID_82546EB_COPPER 0x1010
-#define E1000_DEV_ID_82546EB_FIBER 0x1012
-#define NUM_DEV_IDS 13
+#define E1000_DEV_ID_82542 0x1000
+#define E1000_DEV_ID_82543GC_FIBER 0x1001
+#define E1000_DEV_ID_82543GC_COPPER 0x1004
+#define E1000_DEV_ID_82544EI_COPPER 0x1008
+#define E1000_DEV_ID_82544EI_FIBER 0x1009
+#define E1000_DEV_ID_82544GC_COPPER 0x100C
+#define E1000_DEV_ID_82544GC_LOM 0x100D
+#define E1000_DEV_ID_82540EM 0x100E
+#define E1000_DEV_ID_82540EM_LOM 0x1015
+#define E1000_DEV_ID_82540EP_LOM 0x1016
+#define E1000_DEV_ID_82540EP 0x1017
+#define E1000_DEV_ID_82540EP_LP 0x101E
+#define E1000_DEV_ID_82545EM_COPPER 0x100F
+#define E1000_DEV_ID_82545EM_FIBER 0x1011
+#define E1000_DEV_ID_82546EB_COPPER 0x1010
+#define E1000_DEV_ID_82546EB_FIBER 0x1012
+#define NUM_DEV_IDS 16
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@@ -852,6 +864,7 @@ struct em_hw {
em_bus_type bus_type;
uint32_t io_base;
uint32_t phy_id;
+ uint32_t phy_revision;
uint32_t phy_addr;
uint32_t original_fc;
uint32_t txcw;
@@ -981,6 +994,7 @@ struct em_hw {
#define E1000_EERD_DATA_SHIFT 16
#define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */
+
/* Extended Device Control */
#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */
#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */
@@ -1189,6 +1203,7 @@ struct em_hw {
#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */
#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
/* Transmit Configuration Word */
#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */
@@ -1428,6 +1443,8 @@ struct em_hw {
#define PCIX_COMMAND_MMRBC_SHIFT 0x2
#define PCIX_STATUS_HI_MMRBC_MASK 0x0060
#define PCIX_STATUS_HI_MMRBC_SHIFT 0x5
+#define PCIX_STATUS_HI_MMRBC_4K 0x3
+#define PCIX_STATUS_HI_MMRBC_2K 0x2
/* The number of bits that we need to shift right to move the "pause"
@@ -1541,6 +1558,7 @@ struct em_hw {
#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
/* PHY Control Register */
@@ -1747,12 +1765,14 @@ struct em_hw {
#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+
/* Bit definitions for valid PHY IDs. */
#define M88E1000_E_PHY_ID 0x01410C50
#define M88E1000_I_PHY_ID 0x01410C30
#define M88E1011_I_PHY_ID 0x01410C20
#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+#define M88E1011_I_REV_4 0x04
/* Miscellaneous PHY bit definitions. */
#define PHY_PREAMBLE 0xFFFFFFFF
diff --git a/sys/dev/em/if_em_osdep.h b/sys/dev/em/if_em_osdep.h
index b75eea8..2a50b5a 100644
--- a/sys/dev/em/if_em_osdep.h
+++ b/sys/dev/em/if_em_osdep.h
@@ -89,6 +89,8 @@ struct em_osdep
struct device *dev;
};
+#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
+
#define E1000_READ_REG(a, reg) (\
((a)->mac_type >= em_82543) ? \
bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
OpenPOWER on IntegriCloud