summaryrefslogtreecommitdiffstats
path: root/sys/dev/em/if_em.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/em/if_em.c')
-rw-r--r--sys/dev/em/if_em.c894
1 files changed, 460 insertions, 434 deletions
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;
-}
-
OpenPOWER on IntegriCloud