summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_em.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/if_em.c')
-rw-r--r--sys/dev/pci/if_em.c1199
1 files changed, 937 insertions, 262 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c
index 1cefa52f786..e0fcaf25d41 100644
--- a/sys/dev/pci/if_em.c
+++ b/sys/dev/pci/if_em.c
@@ -31,8 +31,8 @@ POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
-/*$FreeBSD: if_em.c,v 1.26 2003/06/05 17:51:37 pdeuskar Exp $*/
-/* $OpenBSD: if_em.c,v 1.18 2004/04/03 18:51:01 grange Exp $ */
+/*$FreeBSD: if_em.c,v 1.38 2004/03/17 17:50:31 njl Exp $*/
+/* $OpenBSD: if_em.c,v 1.19 2004/04/18 04:15:00 henric Exp $ */
#include "bpfilter.h"
#include "vlan.h"
@@ -75,12 +75,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <dev/pci/if_em.h>
-#ifdef DEBUG
-#define EM_KASSERT(exp,msg) do { if (!(exp)) panic msg; } while (0)
-#else
-#define EM_KASSERT(exp,msg)
-#endif
-
/*********************************************************************
* Set this to one to display debug statistics
*********************************************************************/
@@ -97,9 +91,68 @@ struct em_softc *em_adapter_list = NULL;
* Driver version
*********************************************************************/
-char em_driver_version[] = "1.6.6";
+char em_driver_version[] = "1.7.25";
+
+#ifdef __FreeBSD__
+/*********************************************************************
+ * PCI Device ID Table
+ *
+ * Used by probe to select devices to load on
+ * Last field stores an index into em_strings
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
+ *********************************************************************/
+
+em_vendor_info_t em_vendor_info_array[] =
+{
+ /* Intel(R) PRO/1000 Network Connection */
+ { 0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 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, 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, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1014, 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, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x101A, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0},
+ /* required last entry */
+ { 0, 0, 0, 0, 0}
+};
+
+/*********************************************************************
+ * Table of branding strings for all supported NICs.
+ *********************************************************************/
+char *em_strings[] = {
+ "Intel(R) PRO/1000 Network Connection"
+};
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
/*********************************************************************
* PCI Device ID Table
*********************************************************************/
@@ -117,40 +170,49 @@ const struct pci_matchid em_devices[] = {
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82545EM_SC },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546EB_SC },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541EI },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541ER2 },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EM_LOM },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EP_LOM },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EP },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541EP },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82547EI },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82547EI_LOM },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546EB_QUAD },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EP_LP },
- { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546GB_COPPER },
- { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546GB_FIBER },
- { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546GB_SERDES },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82545GM_COPPER },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82545GM_FIBER },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82545GM_SERDES },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82547GI },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541GI },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541GI_MOBILE },
- { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541ER }
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541ER },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546GB_COPPER },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546GB_FIBER },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546GB_SERDES }
};
+#endif /* __OpenBSD__ */
/*********************************************************************
* Function prototypes
*********************************************************************/
+#ifdef __FreeBSD__
+int em_probe(device_t);
+int em_attach(device_t);
+int em_detach(device_t);
+int em_shutdown(device_t);
+void em_intr(void *);
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
int em_probe(struct device *, void *, void *);
void em_attach(struct device *, struct device *, void *);
-
-#if 0
-int em_detach(void *);
-int em_shutdown(void *);
-#endif
int em_intr(void *);
+#endif /* __OpenBSD__ */
void em_start(struct ifnet *);
+void em_start_locked(struct ifnet *);
int em_ioctl(struct ifnet *, u_long, caddr_t);
void em_watchdog(struct ifnet *);
void em_init(void *);
+void em_init_locked(struct em_softc *);
void em_stop(void *);
void em_media_status(struct ifnet *, struct ifmediareq *);
int em_media_change(struct ifnet *);
@@ -159,7 +221,12 @@ int em_allocate_pci_resources(struct em_softc *);
void em_free_pci_resources(struct em_softc *);
void em_local_timer(void *);
int em_hardware_init(struct em_softc *);
+#ifdef __FreeBSD__
+void em_setup_interface(device_t, struct em_softc *);
+#endif
+#ifdef __OpenBSD__
void em_setup_interface(struct em_softc *);
+#endif
int em_setup_transmit_structures(struct em_softc *);
void em_initialize_transmit_unit(struct em_softc *);
int em_setup_receive_structures(struct em_softc *);
@@ -185,6 +252,7 @@ void em_disable_promisc(struct em_softc *);
void em_set_multi(struct em_softc *);
void em_print_hw_stats(struct em_softc *);
void em_print_link_status(struct em_softc *);
+void em_update_link_status(struct em_softc *);
int em_get_buf(int i, struct em_softc *,
struct mbuf *);
void em_enable_vlans(struct em_softc *);
@@ -193,17 +261,52 @@ void em_smartspeed(struct em_softc *);
int em_82547_fifo_workaround(struct em_softc *, int);
void em_82547_update_fifo_head(struct em_softc *, int);
int em_82547_tx_fifo_reset(struct em_softc *);
-void em_82547_move_tail(void *);
+void em_82547_move_tail(void *arg);
+void em_82547_move_tail_locked(struct em_softc *);
int em_dma_malloc(struct em_softc *, bus_size_t,
struct em_dma_alloc *, int);
void em_dma_free(struct em_softc *, struct em_dma_alloc *);
void em_print_debug_info(struct em_softc *);
int em_is_valid_ether_addr(u_int8_t *);
+#ifdef __FreeBSD__
+int em_sysctl_stats(SYSCTL_HANDLER_ARGS);
+int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
+#endif /* __FreeBSD__ */
+u_int32_t em_fill_descriptors (u_int64_t address,
+ u_int32_t length,
+ PDESC_ARRAY desc_array);
+#ifdef __FreeBSD__
+int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
+void em_add_int_delay_sysctl(struct em_softc *, const char *,
+ const char *, struct em_int_delay_info *,
+ int, int);
+#endif /* __FreeBSD__ */
/*********************************************************************
* FreeBSD Device Interface Entry Points
*********************************************************************/
+#ifdef __FreeBSD__
+device_method_t em_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, em_probe),
+ DEVMETHOD(device_attach, em_attach),
+ DEVMETHOD(device_detach, em_detach),
+ DEVMETHOD(device_shutdown, em_shutdown),
+ {0, 0}
+};
+
+driver_t em_driver = {
+ "em", em_methods, sizeof(struct em_softc ),
+};
+
+devclass_t em_devclass;
+DRIVER_MODULE(em, pci, em_driver, em_devclass, 0, 0);
+MODULE_DEPEND(em, pci, 1, 1, 1);
+MODULE_DEPEND(em, ether, 1, 1, 1);
+#endif /* __FreeBSD__ */
+
+#ifdef __OpenBSD__
struct cfattach em_ca = {
sizeof(struct em_softc), em_probe, em_attach
};
@@ -211,6 +314,26 @@ struct cfattach em_ca = {
struct cfdriver em_cd = {
0, "em", DV_IFNET
};
+#endif /* __OpenBSD__ */
+
+/*********************************************************************
+ * Tunable default values.
+ *********************************************************************/
+
+#define E1000_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000)
+#define E1000_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024)
+
+int em_tx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TIDV);
+int em_rx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RDTR);
+int em_tx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TADV);
+int em_rx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RADV);
+
+#ifdef __FreeBSD__
+TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt);
+TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt);
+TUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt);
+TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt);
+#endif /* __FreeBSD__ */
/*********************************************************************
* Device identification routine
@@ -221,6 +344,52 @@ struct cfdriver em_cd = {
* return 0 on success, positive on failure
*********************************************************************/
+#ifdef __FreeBSD__
+int
+em_probe(device_t dev)
+{
+ em_vendor_info_t *ent;
+
+ u_int16_t pci_vendor_id = 0;
+ u_int16_t pci_device_id = 0;
+ u_int16_t pci_subvendor_id = 0;
+ u_int16_t pci_subdevice_id = 0;
+ char adapter_name[60];
+
+ INIT_DEBUGOUT("em_probe: begin");
+
+ pci_vendor_id = pci_get_vendor(dev);
+ if (pci_vendor_id != EM_VENDOR_ID)
+ return(ENXIO);
+
+ pci_device_id = pci_get_device(dev);
+ pci_subvendor_id = pci_get_subvendor(dev);
+ pci_subdevice_id = pci_get_subdevice(dev);
+
+ ent = em_vendor_info_array;
+ while (ent->vendor_id != 0) {
+ if ((pci_vendor_id == ent->vendor_id) &&
+ (pci_device_id == ent->device_id) &&
+
+ ((pci_subvendor_id == ent->subvendor_id) ||
+ (ent->subvendor_id == PCI_ANY_ID)) &&
+
+ ((pci_subdevice_id == ent->subdevice_id) ||
+ (ent->subdevice_id == PCI_ANY_ID))) {
+ sprintf(adapter_name, "%s, Version - %s",
+ em_strings[ent->index],
+ em_driver_version);
+ device_set_desc_copy(dev, adapter_name);
+ return(0);
+ }
+ ent++;
+ }
+
+ return(ENXIO);
+}
+#endif /* __FreeBSD__ */
+
+#ifdef __OpenBSD__
int
em_probe(struct device *parent, void *match, void *aux)
{
@@ -229,6 +398,7 @@ em_probe(struct device *parent, void *match, void *aux)
return (pci_matchbyid((struct pci_attach_args *)aux, em_devices,
sizeof(em_devices)/sizeof(em_devices[0])));
}
+#endif /* __OpenBSD__ */
/*********************************************************************
* Device initialization routine
@@ -240,35 +410,42 @@ em_probe(struct device *parent, void *match, void *aux)
* return 0 on success, positive on failure
*********************************************************************/
+#ifdef __FreeBSD__
+int
+em_attach(device_t dev)
+{
+ pci_chipset_tag_t pc = pa->pa_pc;
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
void
em_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
-#if 0
- pci_chipset_tag_t pc = pa->pa_pc;
-#endif
- struct em_softc *sc = (struct em_softc *)self;
- int s;
+#endif /* __OpenBSD__ */
+ struct em_softc *sc;
int tsize, rsize;
int error = 0;
INIT_DEBUGOUT("em_attach: begin");
- s = splimp();
#ifdef __FreeBSD__
/* Allocate, clear, and link in our sc structure */
if (!(sc = device_get_softc(dev))) {
printf("em: sc structure allocation failed\n");
- splx(s);
return(ENOMEM);
}
bzero(sc, sizeof(struct em_softc ));
sc->dev = dev;
sc->osdep.dev = dev;
sc->sc_dv.dv_xname = device_get_unit(dev);
+ EM_LOCK_INIT(sc, device_get_nameunit(dev));
#endif /* __FreeBSD__ */
+
+#ifdef __OpenBSD__
+ sc = (struct em_softc *)self;
sc->osdep.em_pa = *pa;
+#endif
if (em_adapter_list != NULL)
em_adapter_list->prev = sc;
@@ -301,23 +478,43 @@ em_attach(struct device *parent, struct device *self, void *aux)
(void *)sc, 0,
em_sysctl_stats, "I", "Statistics");
- callout_handle_init(&sc->timer_handle);
- callout_handle_init(&sc->tx_fifo_timer_handle);
+ callout_init(&sc->timer, CALLOUT_MPSAFE);
+ callout_init(&sc->tx_fifo_timer, CALLOUT_MPSAFE);
#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
timeout_set(&sc->timer_handle, em_local_timer, sc);
timeout_set(&sc->tx_fifo_timer_handle, em_82547_move_tail, sc);
+#endif /* __OpenBSD__ */
/* Determine hardware revision */
em_identify_hardware(sc);
+#ifdef __FreeBSD__
+ /* Set up some sysctls for the tunable interrupt delays */
+ em_add_int_delay_sysctl(sc, "rx_int_delay",
+ "receive interrupt delay in usecs", &sc->rx_int_delay,
+ E1000_REG_OFFSET(&sc->hw, RDTR), em_rx_int_delay_dflt);
+ em_add_int_delay_sysctl(sc, "tx_int_delay",
+ "transmit interrupt delay in usecs", &sc->tx_int_delay,
+ E1000_REG_OFFSET(&sc->hw, TIDV), em_tx_int_delay_dflt);
+ if (sc->hw.mac_type >= em_82540) {
+ em_add_int_delay_sysctl(sc, "rx_abs_int_delay",
+ "receive interrupt delay limit in usecs",
+ &sc->rx_abs_int_delay,
+ E1000_REG_OFFSET(&sc->hw, RADV),
+ em_rx_abs_int_delay_dflt);
+ em_add_int_delay_sysctl(sc, "tx_abs_int_delay",
+ "transmit interrupt delay limit in usecs",
+ &sc->tx_abs_int_delay,
+ E1000_REG_OFFSET(&sc->hw, TADV),
+ em_tx_abs_int_delay_dflt);
+ }
+#endif /* __FreeBSD__ */
+
/* Parameters (to be read from user) */
sc->num_tx_desc = EM_MAX_TXD;
sc->num_rx_desc = EM_MAX_RXD;
- sc->tx_int_delay = EM_TIDV;
- sc->tx_abs_int_delay = EM_TADV;
- sc->rx_int_delay = EM_RDTR;
- sc->rx_abs_int_delay = EM_RADV;
sc->hw.autoneg = DO_AUTO_NEG;
sc->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT;
sc->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
@@ -335,7 +532,13 @@ em_attach(struct device *parent, struct device *self, void *aux)
sc->hw.fc = em_fc_full;
sc->hw.phy_init_script = 1;
+ sc->hw.phy_reset_disable = FALSE;
+#ifndef EM_MASTER_SLAVE
+ sc->hw.master_slave = em_ms_hw_default;
+#else
+ sc->hw.master_slave = EM_MASTER_SLAVE;
+#endif
/*
* Set the max frame size assuming standard ethernet
* sized frames
@@ -413,8 +616,6 @@ em_attach(struct device *parent, struct device *self, void *aux)
bcopy(sc->hw.mac_addr, sc->interface_data.ac_enaddr,
ETHER_ADDR_LEN);
- printf(", address: %s\n", ether_sprintf(sc->interface_data.ac_enaddr));
-
/* Setup OS specific network interface */
em_setup_interface(sc);
@@ -425,14 +626,39 @@ em_attach(struct device *parent, struct device *self, void *aux)
em_check_for_link(&sc->hw);
/* Print the link status */
- if (sc->link_active == 1) {
- em_get_speed_and_duplex(&sc->hw, &sc->link_speed,
- &sc->link_duplex);
+ if (sc->link_active == 1) {
+ em_get_speed_and_duplex(&sc->hw, &sc->link_speed,
+ &sc->link_duplex);
+#ifdef __FreeBSD__
+ printf("%s: Speed:%d Mbps Duplex:%s\n",
+ sc->sc_dv.dv_xname,
+ sc->link_speed,
+ sc->link_duplex == FULL_DUPLEX ? "Full" : "Half");
+ } else
+ printf("%s: Speed:N/A Duplex:N/A\n", sc->sc_dv.dv_xname);
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
}
+ printf(", address: %s\n", ether_sprintf(sc->interface_data.ac_enaddr));
+#endif /* __OpenBSD__ */
+
+ /* Identify 82544 on PCIX */
+ em_get_bus_info(&sc->hw);
+ if(sc->hw.bus_type == em_bus_type_pcix &&
+ sc->hw.mac_type == em_82544) {
+ sc->pcix_82544 = TRUE;
+ }
+ else {
+ sc->pcix_82544 = FALSE;
+ }
INIT_DEBUGOUT("em_attach: end");
- splx(s);
+#ifdef __FreeBSD__
+ return(0);
+#endif
+#ifdef __OpenBSD__
return;
+#endif
err_mac_addr:
err_hw_init:
@@ -444,10 +670,9 @@ err_pci:
em_free_pci_resources(sc);
#ifdef __FreeBSD__
sysctl_ctx_free(&sc->sysctl_ctx);
+err_sysctl:
+ return(error);
#endif /* __FreeBSD__ */
-/*err_sysctl:*/
- splx(s);
- return;
}
@@ -460,52 +685,61 @@ err_pci:
*
* return 0 on success, positive on failure
*********************************************************************/
+
#ifdef __FreeBSD__
int
-em_detach(void* arg)
+em_detach(device_t dev)
{
- struct em_softc *sc = arg;
- struct ifnet *ifp = &sc->interface_data.ac_if;
- int s;
-
- INIT_DEBUGOUT("em_detach: begin");
- s = splimp();
-
- em_stop(sc);
- em_phy_hw_reset(&sc->hw);
-#if __FreeBSD_version < 500000
- ether_ifdetach(&sc->interface_data.ac_if, ETHER_BPF_SUPPORTED);
+ struct em_softc * sc = device_get_softc(dev);
+ struct ifnet *ifp = &sc->interface_data.ac_if;
+ EM_LOCK_STATE();
+
+ INIT_DEBUGOUT("em_detach: begin");
+
+ EM_LOCK(sc);
+ sc->in_detach = 1;
+ em_stop(sc);
+ em_phy_hw_reset(&sc->hw);
+ EM_UNLOCK(sc);
+#if __FreeBSD_version < 500000
+ ether_ifdetach(&sc->interface_data.ac_if, ETHER_BPF_SUPPORTED);
#else
- ether_ifdetach(&sc->interface_data.ac_if);
+ ether_ifdetach(&sc->interface_data.ac_if);
#endif
- em_free_pci_resources(sc);
+ em_free_pci_resources(sc);
+ bus_generic_detach(dev);
- /* Free Transmit Descriptor ring */
- if (sc->tx_desc_base) {
- em_dma_free(sc, &sc->txdma);
- sc->tx_desc_base = NULL;
- }
+ /* Free Transmit Descriptor ring */
+ if (sc->tx_desc_base) {
+ em_dma_free(sc, &sc->txdma);
+ sc->tx_desc_base = NULL;
+ }
- /* Free Receive Descriptor ring */
- if (sc->rx_desc_base) {
- em_dma_free(sc, &sc->rxdma);
- sc->rx_desc_base = NULL;
- }
+ /* Free Receive Descriptor ring */
+ if (sc->rx_desc_base) {
+ em_dma_free(sc, &sc->rxdma);
+ sc->rx_desc_base = NULL;
+ }
- /* Remove from the adapter list */
- if (em_adapter_list == sc)
- em_adapter_list = sc->next;
- if (sc->next != NULL)
- sc->next->prev = sc->prev;
- if (sc->prev != NULL)
- sc->prev->next = sc->next;
+ /* Free the sysctl tree */
+ sysctl_ctx_free(&sc->sysctl_ctx);
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
- ifp->if_timer = 0;
+ /* Remove from the sc list */
+ if (em_adapter_list == sc)
+ em_adapter_list = sc->next;
+ if (sc->next != NULL)
+ sc->next->prev = sc->prev;
+ if (sc->prev != NULL)
+ sc->prev->next = sc->next;
- splx(s);
- return(0);
+ EM_LOCK_DESTROY(sc);
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ ifp->if_timer = 0;
+
+ return(0);
}
+#endif /* __FreeBSD__ */
/*********************************************************************
*
@@ -513,16 +747,21 @@ em_detach(void* arg)
*
**********************************************************************/
+#ifdef __FreeBSD__
int
-em_shutdown(void* arg)
+em_shutdown(device_t dev)
{
- struct em_softc *sc = arg;
- em_stop(sc);
- return(0);
-}
+ struct em_softc *sc = device_get_softc(dev);
+ EM_LOCK_STATE();
+ EM_LOCK(sc);
+ em_stop(sc);
+ EM_UNLOCK(sc);
+ return(0);
+}
#endif /* __FreeBSD__ */
+
/*********************************************************************
* Transmit entry point
*
@@ -534,17 +773,16 @@ em_shutdown(void* arg)
**********************************************************************/
void
-em_start(struct ifnet *ifp)
+em_start_locked(struct ifnet *ifp)
{
- int s;
struct mbuf *m_head;
struct em_softc *sc = ifp->if_softc;
+ mtx_assert(&sc->mtx, MA_OWNED);
+
if (!sc->link_active)
return;
- s = splimp();
-
for (;;) {
IFQ_POLL(&ifp->if_snd, m_head);
@@ -567,7 +805,18 @@ em_start(struct ifnet *ifp)
ifp->if_timer = EM_TX_TIMEOUT;
}
- splx(s);
+ return;
+}
+
+void
+em_start(struct ifnet *ifp)
+{
+ struct em_softc *sc = ifp->if_softc;
+ EM_LOCK_STATE();
+
+ EM_LOCK(sc);
+ em_start_locked(ifp);
+ EM_UNLOCK(sc);
return;
}
@@ -583,17 +832,21 @@ em_start(struct ifnet *ifp)
int
em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
- int s, error = 0;
+ int error = 0;
struct ifreq *ifr = (struct ifreq *) data;
- struct ifaddr *ifa = (struct ifaddr *)data;
struct em_softc * sc = ifp->if_softc;
+ EM_LOCK_STATE();
- s = splimp();
+#ifdef __OpenBSD__
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ EM_LOCK(sc);
+ error = ether_ioctl(ifp, &sc->interface_data, command, data);
+ EM_UNLOCK(sc);
- if ((error = ether_ioctl(ifp, &sc->interface_data, command, data)) > 0) {
- splx(s);
+ if (error > 0)
return (error);
- }
+#endif /* __OpenBSD__ */
+ if (sc->in_detach) return(error);
switch (command) {
case SIOCSIFADDR:
@@ -603,6 +856,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
ether_ioctl(ifp, command, data);
break;
#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFADDR (Set Interface "
"Addr)");
ifp->if_flags |= IFF_UP;
@@ -617,22 +871,27 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
}
break;
+#endif /* __OpenBSD__ */
case SIOCSIFMTU:
IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN) {
error = EINVAL;
} else {
+ EM_LOCK(sc);
ifp->if_mtu = ifr->ifr_mtu;
sc->hw.max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
- em_init(sc);
+ em_init_locked(sc);
+ EM_UNLOCK(sc);
}
break;
case SIOCSIFFLAGS:
IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)");
+ EM_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
- if (!(ifp->if_flags & IFF_RUNNING))
- em_init(sc);
+ if (!(ifp->if_flags & IFF_RUNNING)) {
+ em_init_locked(sc);
+ }
em_disable_promisc(sc);
em_set_promisc(sc);
@@ -641,28 +900,35 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
em_stop(sc);
}
}
+ EM_UNLOCK(sc);
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
+#ifdef __OpenBSD__
error = (command == SIOCADDMULTI)
? ether_addmulti(ifr, &sc->interface_data)
: ether_delmulti(ifr, &sc->interface_data);
if (error == ENETRESET) {
+#endif /* __OpenBSD__ */
if (ifp->if_flags & IFF_RUNNING) {
+ EM_LOCK(sc);
em_disable_intr(sc);
em_set_multi(sc);
if (sc->hw.mac_type == em_82542_rev2_0) {
em_initialize_receive_unit(sc);
}
#ifdef DEVICE_POLLING
- if (!(ifp->if_ipending & IFF_POLLING))
+ if (!(ifp->if_flags & IFF_POLLING))
#endif
em_enable_intr(sc);
+ EM_UNLOCK(sc);
}
+#ifdef __OpenBSD__
error = 0;
}
+#endif /* __OpenBSD__ */
break;
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
@@ -684,11 +950,10 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
#endif /* __FreeBSD__ */
default:
- IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%d)\n", (int)command);
+ IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)\n", (int)command);
error = EINVAL;
}
- splx(s);
return(error);
}
@@ -713,11 +978,11 @@ em_watchdog(struct ifnet *ifp)
return;
}
- printf("%s: watchdog timeout -- resetting\n", sc->sc_dv.dv_xname);
+ if (em_check_for_link(&sc->hw))
+ printf("%s: watchdog timeout -- resetting\n", sc->sc_dv.dv_xname);
ifp->if_flags &= ~IFF_RUNNING;
- em_stop(sc);
em_init(sc);
ifp->if_oerrors++;
@@ -736,23 +1001,26 @@ em_watchdog(struct ifnet *ifp)
**********************************************************************/
void
-em_init(void *arg)
+em_init_locked(struct em_softc *sc)
{
- int s;
struct ifnet *ifp;
- struct em_softc * sc = arg;
INIT_DEBUGOUT("em_init: begin");
- s = splimp();
+ mtx_assert(&sc->mtx, MA_OWNED);
em_stop(sc);
+#ifdef __FreeBSD__
+ /* Get the latest mac address, User can use a LAA */
+ bcopy(sc->interface_data.ac_enaddr, sc->hw.mac_addr,
+ ETHER_ADDR_LEN);
+#endif /* __FreeBSD__ */
+
/* Initialize the hardware */
if (em_hardware_init(sc)) {
printf("%s: Unable to initialize the hardware\n",
sc->sc_dv.dv_xname);
- splx(s);
return;
}
@@ -763,7 +1031,6 @@ em_init(void *arg)
printf("%s: Could not setup transmit structures\n",
sc->sc_dv.dv_xname);
em_stop(sc);
- splx(s);
return;
}
em_initialize_transmit_unit(sc);
@@ -776,11 +1043,13 @@ em_init(void *arg)
printf("%s: Could not setup receive structures\n",
sc->sc_dv.dv_xname);
em_stop(sc);
- splx(s);
return;
}
em_initialize_receive_unit(sc);
+ /* Don't loose promiscuous settings */
+ em_set_promisc(sc);
+
ifp = &sc->interface_data.ac_if;
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
@@ -792,59 +1061,86 @@ em_init(void *arg)
else
ifp->if_hwassist = 0;
}
-#endif /* __FreeBSD__ */
+ callout_reset(&sc->timer, 2*hz, em_local_timer, sc);
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
timeout_add(&sc->timer_handle, 2*hz);
+#endif
em_clear_hw_cntrs(&sc->hw);
#ifdef DEVICE_POLLING
/*
* Only enable interrupts if we are not polling, make sure
* they are off otherwise.
*/
- if (ifp->if_ipending & IFF_POLLING)
+ if (ifp->if_flags & IFF_POLLING)
em_disable_intr(sc);
else
#endif /* DEVICE_POLLING */
em_enable_intr(sc);
- /* Don't reset the phy next time init gets called */
- sc->hw.phy_reset_disable = TRUE;
+ /* Don't reset the phy next time init gets called */
+ sc->hw.phy_reset_disable = TRUE;
- splx(s);
return;
}
+void
+em_init(void *arg)
+{
+ struct em_softc * sc = arg;
+ EM_LOCK_STATE();
+
+ EM_LOCK(sc);
+ em_init_locked(sc);
+ EM_UNLOCK(sc);
+ return;
+}
+
#ifdef DEVICE_POLLING
-static poll_handler_t em_poll;
+poll_handler_t em_poll;
-static void
-em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+void
+em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
{
- struct em_softc *sc = ifp->if_softc;
- u_int32_t reg_icr;
+ struct em_softc *sc = ifp->if_softc;
+ u_int32_t reg_icr;
- if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
- em_enable_intr(sc);
- return;
- }
- if (cmd == POLL_AND_CHECK_STATUS) {
- reg_icr = E1000_READ_REG(&sc->hw, ICR);
- if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
- untimeout(em_local_timer, sc, sc->timer_handle);
- sc->hw.get_link_status = 1;
- em_check_for_link(&sc->hw);
- em_print_link_status(sc);
- sc->timer_handle = timeout(em_local_timer, sc, 2*hz);
- }
- }
- if (ifp->if_flags & IFF_RUNNING) {
- em_process_receive_interrupts(sc, count);
- em_clean_transmit_interrupts(sc);
- }
+ mtx_assert(&sc->mtx, MA_OWNED);
- if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
- em_start(ifp);
+ if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
+ em_enable_intr(sc);
+ return;
+ }
+ if (cmd == POLL_AND_CHECK_STATUS) {
+ reg_icr = E1000_READ_REG(&sc->hw, ICR);
+ if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ callout_stop(&sc->timer);
+ sc->hw.get_link_status = 1;
+ em_check_for_link(&sc->hw);
+ em_update_link_status(sc);
+ callout_reset(&sc->timer, 2*hz, em_local_timer, sc);
+ }
+ }
+ if (ifp->if_flags & IFF_RUNNING) {
+ em_process_receive_interrupts(sc, count);
+ em_clean_transmit_interrupts(sc);
+ }
+
+ if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
+ em_start_locked(ifp);
+}
+
+void
+em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct em_softc *sc = ifp->if_softc;
+ EM_LOCK_STATE();
+
+ EM_LOCK(sc);
+ em_poll_locked(ifp, cmd, count);
+ EM_UNLOCK(sc);
}
#endif /* DEVICE_POLLING */
@@ -853,38 +1149,66 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
* Interrupt Service routine
*
**********************************************************************/
+#ifdef __FreeBSD__
+void
+#endif
+#ifdef __OpenBSD__
int
+#endif
em_intr(void *arg)
{
u_int32_t loop_cnt = EM_MAX_INTR;
u_int32_t reg_icr;
struct ifnet *ifp;
- struct em_softc *sc = arg;
+ struct em_softc *sc = arg;
+ EM_LOCK_STATE();
+
+ EM_LOCK(sc);
ifp = &sc->interface_data.ac_if;
#ifdef DEVICE_POLLING
- if (ifp->if_ipending & IFF_POLLING)
- return;
+ if (ifp->if_flags & IFF_POLLING) {
+ EM_UNLOCK(sc);
+ return;
+ }
- if (ether_poll_register(em_poll, ifp)) {
- em_disable_intr(sc);
- em_poll(ifp, 0, 1);
- return;
- }
+ if (ether_poll_register(em_poll, ifp)) {
+ em_disable_intr(sc);
+ em_poll_locked(ifp, 0, 1);
+ EM_UNLOCK(sc);
+ return;
+ }
#endif /* DEVICE_POLLING */
+
reg_icr = E1000_READ_REG(&sc->hw, ICR);
if (!reg_icr) {
+ EM_UNLOCK(sc);
+#ifdef __FreeBSD__
+ return;
+#endif
+#ifdef __OpenBSD__
return (0);
+#endif
}
/* Link status change */
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+#ifdef __FreeBSD__
+ callout_stop(&sc->timer);
+#endif
+#ifdef __OpenBSD__
timeout_del(&sc->timer_handle);
+#endif
sc->hw.get_link_status = 1;
em_check_for_link(&sc->hw);
- em_print_link_status(sc);
+ em_update_link_status(sc);
+#ifdef __FreeBSD__
+ callout_reset(&sc->timer, 2*hz, em_local_timer, sc);
+#endif
+#ifdef __OpenBSD__
timeout_add(&sc->timer_handle, 2*hz);
+#endif
}
while (loop_cnt > 0) {
@@ -895,10 +1219,21 @@ em_intr(void *arg)
loop_cnt--;
}
+#ifdef __FreeBSD__
+ if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
+#endif
+#ifdef __OpenBSD__
if (ifp->if_flags & IFF_RUNNING && IFQ_IS_EMPTY(&ifp->if_snd) == 0)
- em_start(ifp);
+#endif
+ em_start_locked(ifp);
+ EM_UNLOCK(sc);
+#ifdef __FreeBSD__
+ return;
+#endif
+#ifdef __OpenBSD__
return (1);
+#endif
}
@@ -953,7 +1288,11 @@ em_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
ifmr->ifm_active |= IFM_100_TX;
break;
case 1000:
+#if defined(__FreeBSD__) && __FreeBSD_version < 500000
+ ifmr->ifm_active |= IFM_1000_TX;
+#else
ifmr->ifm_active |= IFM_1000_T;
+#endif
break;
}
if (sc->link_duplex == FULL_DUPLEX)
@@ -989,7 +1328,11 @@ em_media_change(struct ifnet *ifp)
sc->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
break;
case IFM_1000_SX:
- case IFM_1000_T:
+#if defined(__FreeBSD__) && __FreeBSD_version < 500000
+ case IFM_1000_TX:
+#else
+ case IFM_1000_T:
+#endif
sc->hw.autoneg = DO_AUTO_NEG;
sc->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
@@ -1013,10 +1356,10 @@ em_media_change(struct ifnet *ifp)
printf("%s: Unsupported media type\n", sc->sc_dv.dv_xname);
}
- /* As the speed/duplex settings my have changed we need to
- * reset the PHY.
- */
- sc->hw.phy_reset_disable = FALSE;
+ /* As the speed/duplex settings my have changed we need to
+ * reset the PHY.
+ */
+ sc->hw.phy_reset_disable = FALSE;
em_init(sc);
@@ -1031,7 +1374,7 @@ em_tx_cb(void *arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize, int e
if (error)
return;
- EM_KASSERT(nsegs <= EM_MAX_SCATTER,
+ KASSERT(nsegs <= EM_MAX_SCATTER,
("Too many DMA segments returned when mapping tx packet"));
q->nsegs = nsegs;
bcopy(seg, q->segs, nsegs * sizeof(seg[0]));
@@ -1052,8 +1395,14 @@ int
em_encap(struct em_softc *sc, struct mbuf *m_head)
{
u_int32_t txd_upper;
- u_int32_t txd_lower;
+ u_int32_t txd_lower, txd_used = 0, txd_saved = 0;
int i, j, error;
+ u_int64_t address;
+
+ /* For 82544 Workaround */
+ DESC_ARRAY desc_array;
+ u_int32_t array_elements;
+ u_int32_t counter;
#if NVLAN > 0
struct ifvlan *ifv = NULL;
#endif
@@ -1079,7 +1428,7 @@ em_encap(struct em_softc *sc, struct mbuf *m_head)
* Map the packet for DMA.
*/
if (bus_dmamap_create(sc->txtag, MCLBYTES, 32, 0, 0, BUS_DMA_NOWAIT,
- &q.map)) {
+ &q.map)) {
sc->no_tx_map_avail++;
return (ENOMEM);
}
@@ -1117,23 +1466,66 @@ em_encap(struct em_softc *sc, struct mbuf *m_head)
#endif
i = sc->next_avail_tx_desc;
+ if (sc->pcix_82544) {
+ txd_saved = i;
+ txd_used = 0;
+ }
for (j = 0; j < q.map->dm_nsegs; j++) {
- tx_buffer = &sc->tx_buffer_area[i];
- current_tx_desc = &sc->tx_desc_base[i];
-
- current_tx_desc->buffer_addr = htole64(q.map->dm_segs[j].ds_addr);
- current_tx_desc->lower.data = htole32(
- sc->txd_cmd | txd_lower | q.map->dm_segs[j].ds_len);
- current_tx_desc->upper.data = htole32(txd_upper);
-
- if (++i == sc->num_tx_desc)
- i = 0;
+ /* If sc is 82544 and on PCIX bus */
+ if(sc->pcix_82544) {
+ array_elements = 0;
+ address = htole64(q.map->dm_segs[j].ds_addr);
+ /*
+ * Check the Address and Length combination and
+ * split the data accordingly
+ */
+ array_elements = em_fill_descriptors(address,
+ htole32(q.map->dm_segs[j].ds_len),
+ &desc_array);
+ for (counter = 0; counter < array_elements; counter++) {
+ if (txd_used == sc->num_tx_desc_avail) {
+ sc->next_avail_tx_desc = txd_saved;
+ sc->no_tx_desc_avail2++;
+ bus_dmamap_destroy(sc->txtag, q.map);
+ return (ENOBUFS);
+ }
+ tx_buffer = &sc->tx_buffer_area[i];
+ current_tx_desc = &sc->tx_desc_base[i];
+ current_tx_desc->buffer_addr = htole64(
+ desc_array.descriptor[counter].address);
+ current_tx_desc->lower.data = htole32(
+ (sc->txd_cmd | txd_lower |
+ (u_int16_t)desc_array.descriptor[counter].length));
+ current_tx_desc->upper.data = htole32((txd_upper));
+ if (++i == sc->num_tx_desc)
+ i = 0;
+
+ tx_buffer->m_head = NULL;
+ txd_used++;
+ }
+ } else {
+ tx_buffer = &sc->tx_buffer_area[i];
+ current_tx_desc = &sc->tx_desc_base[i];
+
+ current_tx_desc->buffer_addr = htole64(q.map->dm_segs[j].ds_addr);
+ current_tx_desc->lower.data = htole32(
+ sc->txd_cmd | txd_lower | q.map->dm_segs[j].ds_len);
+ current_tx_desc->upper.data = htole32(txd_upper);
+
+ if (++i == sc->num_tx_desc)
+ i = 0;
- tx_buffer->m_head = NULL;
+ tx_buffer->m_head = NULL;
+ }
}
- sc->num_tx_desc_avail -= q.map->dm_nsegs;
sc->next_avail_tx_desc = i;
+ if (sc->pcix_82544) {
+ sc->num_tx_desc_avail -= txd_used;
+ }
+ else {
+ sc->num_tx_desc_avail -= q.map->dm_nsegs;
+ }
#if NVLAN > 0
if (ifv != NULL) {
@@ -1161,7 +1553,7 @@ em_encap(struct em_softc *sc, struct mbuf *m_head)
*/
if (sc->hw.mac_type == em_82547 &&
sc->link_duplex == HALF_DUPLEX) {
- em_82547_move_tail(sc);
+ em_82547_move_tail_locked(sc);
} else {
E1000_WRITE_REG(&sc->hw, TDT, i);
if (sc->hw.mac_type == em_82547) {
@@ -1177,21 +1569,20 @@ em_encap(struct em_softc *sc, struct mbuf *m_head)
* 82547 workaround to avoid controller hang in half-duplex environment.
* The workaround is to avoid queuing a large packet that would span
* the internal Tx FIFO ring boundary. We need to reset the FIFO pointers
- * in this case. We do that only when FIFO is queiced.
+ * in this case. We do that only when FIFO is quiescent.
*
**********************************************************************/
void
-em_82547_move_tail(void *arg)
+em_82547_move_tail_locked(struct em_softc *sc)
{
- int s;
- struct em_softc *sc = arg;
uint16_t hw_tdt;
uint16_t sw_tdt;
struct em_tx_desc *tx_desc;
uint16_t length = 0;
boolean_t eop = 0;
- s = splimp();
+ EM_LOCK_ASSERT(sc);
+
hw_tdt = E1000_READ_REG(&sc->hw, TDT);
sw_tdt = sc->next_avail_tx_desc;
@@ -1205,21 +1596,34 @@ em_82547_move_tail(void *arg)
if(eop) {
if (em_82547_fifo_workaround(sc, length)) {
sc->tx_fifo_wrk++;
+#ifdef __FreeBSD__
+ callout_reset(&sc->tx_fifo_timer, 1,
+ em_82547_move_tail, sc);
+#endif
+#ifdef __OpenBSD__
timeout_add(&sc->tx_fifo_timer_handle, 1);
- splx(s);
- return;
- }
- else {
- E1000_WRITE_REG(&sc->hw, TDT, hw_tdt);
- em_82547_update_fifo_head(sc, length);
- length = 0;
+#endif
+ break;
}
+ E1000_WRITE_REG(&sc->hw, TDT, hw_tdt);
+ em_82547_update_fifo_head(sc, length);
+ length = 0;
}
}
- splx(s);
return;
}
+void
+em_82547_move_tail(void *arg)
+{
+ struct em_softc *sc = arg;
+ EM_LOCK_STATE();
+
+ EM_LOCK(sc);
+ em_82547_move_tail_locked(sc);
+ EM_UNLOCK(sc);
+}
+
int
em_82547_fifo_workaround(struct em_softc *sc, int len)
{
@@ -1343,11 +1747,16 @@ em_set_multi(struct em_softc * sc)
{
u_int32_t reg_rctl = 0;
u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
+#ifdef __FreeBSD__
+ struct ifmultiaddr *ifma;
+#endif
+ int mcnt = 0;
+ struct ifnet *ifp = &sc->interface_data.ac_if;
+#ifdef __OpenBSD__
struct arpcom *ac = &sc->interface_data;
struct ether_multi *enm;
struct ether_multistep step;
- int mcnt = 0;
- struct ifnet *ifp = &sc->interface_data.ac_if;
+#endif /* __OpenBSD__ */
IOCTL_DEBUGOUT("em_set_multi: begin");
@@ -1361,6 +1770,23 @@ em_set_multi(struct em_softc * sc)
msec_delay(5);
}
+#ifdef __FreeBSD__
+#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;
+
+ if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) break;
+
+ bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
+ mcnt++;
+ }
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
ETHER_FIRST_MULTI(step, ac, enm);
while (enm != NULL) {
if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
@@ -1374,13 +1800,14 @@ em_set_multi(struct em_softc * sc)
mcnt++;
ETHER_NEXT_MULTI(step, enm);
}
+#endif /* __OpenBSD__ */
if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
reg_rctl |= E1000_RCTL_MPE;
E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
} else
- em_mc_addr_list_update(&sc->hw, mta, mcnt, 0);
+ em_mc_addr_list_update(&sc->hw, mta, mcnt, 0, 1);
if (sc->hw.mac_type == em_82542_rev2_0) {
reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
@@ -1406,47 +1833,82 @@ em_set_multi(struct em_softc * sc)
void
em_local_timer(void *arg)
{
- int s;
struct ifnet *ifp;
struct em_softc * sc = arg;
+ EM_LOCK_STATE();
+
ifp = &sc->interface_data.ac_if;
- s = splimp();
+ EM_LOCK(sc);
em_check_for_link(&sc->hw);
- em_print_link_status(sc);
+ em_update_link_status(sc);
em_update_stats_counters(sc);
if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) {
em_print_hw_stats(sc);
}
em_smartspeed(sc);
+#ifdef __FreeBSD__
+ callout_reset(&sc->timer, 2*hz, em_local_timer, sc);
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
timeout_add(&sc->timer_handle, 2*hz);
+#endif /* __OpenBSD__ */
- splx(s);
+ EM_UNLOCK(sc);
return;
}
void
em_print_link_status(struct em_softc * sc)
{
- if (E1000_READ_REG(&sc->hw, STATUS) & E1000_STATUS_LU) {
- if (sc->link_active == 0) {
- em_get_speed_and_duplex(&sc->hw,
- &sc->link_speed,
- &sc->link_duplex);
- sc->link_active = 1;
- sc->smartspeed = 0;
- }
- } else {
- if (sc->link_active == 1) {
- sc->link_speed = 0;
- sc->link_duplex = 0;
- sc->link_active = 0;
- }
- }
+ if (E1000_READ_REG(&sc->hw, STATUS) & E1000_STATUS_LU) {
+ if (sc->link_active == 0) {
+ em_get_speed_and_duplex(&sc->hw,
+ &sc->link_speed,
+ &sc->link_duplex);
+ printf("%s: Link is up %d Mbps %s\n",
+ sc->sc_dv.dv_xname,
+ sc->link_speed,
+ ((sc->link_duplex == FULL_DUPLEX) ?
+ "Full Duplex" : "Half Duplex"));
+ sc->link_active = 1;
+ sc->smartspeed = 0;
+ }
+ } else {
+ if (sc->link_active == 1) {
+ sc->link_speed = 0;
+ sc->link_duplex = 0;
+ printf("%s: Link is Down\n", sc->sc_dv.dv_xname);
+ sc->link_active = 0;
+ }
+ }
+
+ return;
+}
+
+void
+em_update_link_status(struct em_softc * sc)
+{
+ if (E1000_READ_REG(&sc->hw, STATUS) & E1000_STATUS_LU) {
+ if (sc->link_active == 0) {
+ em_get_speed_and_duplex(&sc->hw,
+ &sc->link_speed,
+ &sc->link_duplex);
+ sc->link_active = 1;
+ sc->smartspeed = 0;
+ }
+ } else {
+ if (sc->link_active == 1) {
+ sc->link_speed = 0;
+ sc->link_duplex = 0;
+ sc->link_active = 0;
+ }
+ }
+
+ return;
- return;
}
/*********************************************************************
@@ -1463,11 +1925,19 @@ em_stop(void *arg)
struct em_softc * sc = arg;
ifp = &sc->interface_data.ac_if;
- INIT_DEBUGOUT("em_stop: begin\n");
+ mtx_assert(&sc->mtx, MA_OWNED);
+
+ INIT_DEBUGOUT("em_stop: begin");
em_disable_intr(sc);
em_reset_hw(&sc->hw);
+#ifdef __FreeBSD__
+ callout_stop(&sc->timer);
+ callout_stop(&sc->tx_fifo_timer);
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
timeout_del(&sc->timer_handle);
timeout_del(&sc->tx_fifo_timer_handle);
+#endif /* __OpenBSD__ */
em_free_transmit_structures(sc);
em_free_receive_structures(sc);
@@ -1519,6 +1989,12 @@ em_identify_hardware(struct em_softc * sc)
if (em_set_mac_type(&sc->hw))
printf("%s: Unknown MAC Type\n", sc->sc_dv.dv_xname);
+ if(sc->hw.mac_type == em_82541 ||
+ sc->hw.mac_type == em_82541_rev_2 ||
+ sc->hw.mac_type == em_82547 ||
+ sc->hw.mac_type == em_82547_rev_2)
+ sc->hw.phy_init_script = TRUE;
+
return;
}
@@ -1533,7 +2009,7 @@ em_allocate_pci_resources(struct em_softc * sc)
val = pci_conf_read(pa->pa_pc, pa->pa_tag, EM_MMBA);
if (PCI_MAPREG_TYPE(val) != PCI_MAPREG_TYPE_MEM) {
- printf(": mmba isn't memory\n");
+ printf(": mmba isn't memory");
return (ENXIO);
}
if (pci_mapreg_map(pa, EM_MMBA, PCI_MAPREG_MEM_TYPE(val), 0,
@@ -1562,6 +2038,14 @@ em_allocate_pci_resources(struct em_softc * sc)
printf(": can't find io space\n");
return (ENXIO);
}
+
+#ifdef __FreeBSD__
+ sc->hw.io_base =
+ rman_get_start(sc->res_ioport);
+#endif
+#ifdef __OpenBSD__
+ sc->hw.io_base = 0;
+#endif
}
if (pci_intr_map(pa, &ih)) {
@@ -1619,6 +2103,7 @@ em_free_pci_resources(struct em_softc* sc)
int
em_hardware_init(struct em_softc * sc)
{
+ INIT_DEBUGOUT("em_hardware_init: begin");
/* Issue a global reset */
em_reset_hw(&sc->hw);
@@ -1668,12 +2153,24 @@ em_hardware_init(struct em_softc * sc)
*
**********************************************************************/
void
+#ifdef __FreeBSD__
+em_setup_interface(device_t dev, struct em_softc * sc)
+#endif
+#ifdef __OpenBSD__
em_setup_interface(struct em_softc * sc)
+#endif
{
struct ifnet *ifp;
INIT_DEBUGOUT("em_setup_interface: begin");
ifp = &sc->interface_data.ac_if;
+#ifdef __FreeBSD__
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+#endif
+#ifdef __OpenBSD__
+ strlcpy(ifp->if_xname, sc->sc_dv.dv_xname, IFNAMSIZ);
+#endif
+
ifp->if_mtu = ETHERMTU;
ifp->if_output = ether_output;
ifp->if_baudrate = 1000000000;
@@ -1685,11 +2182,14 @@ em_setup_interface(struct em_softc * sc)
ifp->if_ioctl = em_ioctl;
ifp->if_start = em_start;
ifp->if_watchdog = em_watchdog;
+#ifdef __FreeBSD__
+ ifp->if_snd.ifq_maxlen = sc->num_tx_desc - 1;
+#endif
+#ifdef __OpenBSD__
IFQ_SET_MAXLEN(&ifp->if_snd, sc->num_tx_desc - 1);
IFQ_SET_READY(&ifp->if_snd);
+#endif
- strlcpy(ifp->if_xname, sc->sc_dv.dv_xname, IFNAMSIZ);
-
#ifdef __FreeBSD__
if (sc->hw.mac_type >= em_82543) {
ifp->if_capabilities = IFCAP_HWCSUM;
@@ -1699,7 +2199,7 @@ em_setup_interface(struct em_softc * sc)
/*
* Tell the upper layer(s) we support long frames.
*/
- ifp->if_data.ifi_hdrlen = sizeof(struct ehter_vlan_header);
+ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
#if __FreeBSD_version >= 500000
ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
#endif
@@ -1735,9 +2235,10 @@ em_setup_interface(struct em_softc * sc)
ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
+#ifdef __OpenBSD__
if_attach(ifp);
ether_ifattach(ifp);
-
+#endif
return;
}
@@ -1806,7 +2307,6 @@ em_smartspeed(struct em_softc *sc)
/*
* Manage DMA'able memory.
*/
-
#ifdef __FreeBSD__
void
em_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
@@ -1834,6 +2334,8 @@ em_dma_malloc(struct em_softc *sc, bus_size_t size,
1, /* nsegments */
size, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
+ NULL, /* lockfunc */
+ NULL, /* lockarg */
&dma->dma_tag);
if (r != 0) {
printf("%s: em_dma_malloc: bus_dma_tag_create failed; "
@@ -1843,10 +2345,11 @@ em_dma_malloc(struct em_softc *sc, bus_size_t size,
r = bus_dmamap_create(dma->dma_tag, BUS_DMA_NOWAIT, &dma->dma_map);
#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
dma->dma_tag = sc->osdep.em_pa.pa_dmat;
r = bus_dmamap_create(dma->dma_tag, size, 1,
size, 0, BUS_DMA_NOWAIT, &dma->dma_map);
-
+#endif /* __OpenBSD__ */
if (r != 0) {
printf("%s: em_dma_malloc: bus_dmamap_create failed; "
"error %u\n", sc->sc_dv.dv_xname, r);
@@ -1893,7 +2396,7 @@ fail_2:
bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg);
fail_1:
bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
- /* bus_dma_tag_destroy(dma->dma_tag); */
+ bus_dma_tag_destroy(dma->dma_tag);
fail_0:
dma->dma_map = NULL;
/* dma->dma_tag = NULL; */
@@ -1907,7 +2410,7 @@ em_dma_free(struct em_softc *sc, struct em_dma_alloc *dma)
bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, dma->dma_size);
bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg);
bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
- /* bus_dma_tag_destroy(dma->dma_tag); */
+ bus_dma_tag_destroy(dma->dma_tag);
}
@@ -1956,13 +2459,17 @@ em_setup_transmit_structures(struct em_softc* sc)
EM_MAX_SCATTER, /* nsegments */
MCLBYTES * 8, /* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
+ NULL, /* lockfunc */
+ NULL, /* lockarg */
&sc->txtag)) {
printf("%s: Unable to allocate TX DMA tag\n", sc->sc_dv.dv_xname);
return (ENOMEM);
}
#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
sc->txtag = sc->osdep.em_pa.pa_dmat;
+#endif
if (em_allocate_transmit_structures(sc))
return (ENOMEM);
@@ -1994,6 +2501,7 @@ em_initialize_transmit_unit(struct em_softc * sc)
u_int32_t reg_tipg = 0;
u_int64_t bus_addr;
+ INIT_DEBUGOUT("em_initialize_transmit_unit: begin");
/* Setup the Base and Length of the Tx Descriptor Ring */
bus_addr = sc->txdma.dma_map->dm_segs[0].ds_addr;
E1000_WRITE_REG(&sc->hw, TDBAL, (u_int32_t)bus_addr);
@@ -2029,9 +2537,10 @@ em_initialize_transmit_unit(struct em_softc * sc)
}
E1000_WRITE_REG(&sc->hw, TIPG, reg_tipg);
- E1000_WRITE_REG(&sc->hw, TIDV, sc->tx_int_delay);
+ E1000_WRITE_REG(&sc->hw, TIDV, sc->tx_int_delay.value);
if(sc->hw.mac_type >= em_82540)
- E1000_WRITE_REG(&sc->hw, TADV, sc->tx_abs_int_delay);
+ E1000_WRITE_REG(&sc->hw, TADV,
+ sc->tx_abs_int_delay.value);
/* Program the Transmit Control Register */
reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
@@ -2046,7 +2555,7 @@ em_initialize_transmit_unit(struct em_softc * sc)
/* Setup Transmit Descriptor Settings for this adapter */
sc->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS;
- if (sc->tx_int_delay > 0)
+ if (sc->tx_int_delay.value > 0)
sc->txd_cmd |= E1000_TXD_CMD_IDE;
return;
@@ -2081,9 +2590,7 @@ em_free_transmit_structures(struct em_softc* sc)
sc->tx_buffer_area = NULL;
}
if (sc->txtag != NULL) {
-#ifdef __FreeBSD__
bus_dma_tag_destroy(sc->txtag);
-#endif
sc->txtag = NULL;
}
return;
@@ -2187,16 +2694,16 @@ em_transmit_checksum_setup(struct em_softc * sc,
void
em_clean_transmit_interrupts(struct em_softc* sc)
{
- int s;
int i, num_avail;
struct em_buffer *tx_buffer;
struct em_tx_desc *tx_desc;
struct ifnet *ifp = &sc->interface_data.ac_if;
+ mtx_assert(&sc->mtx, MA_OWNED);
+
if (sc->num_tx_desc_avail == sc->num_tx_desc)
return;
- s = splimp();
#ifdef DBG_STATS
sc->clean_tx_interrupts++;
#endif
@@ -2246,7 +2753,6 @@ em_clean_transmit_interrupts(struct em_softc* sc)
ifp->if_timer = EM_TX_TIMEOUT;
}
sc->num_tx_desc_avail = num_avail;
- splx(s);
return;
}
@@ -2354,7 +2860,9 @@ em_allocate_receive_structures(struct em_softc* sc)
goto fail_0;
}
#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
sc->rxtag = sc->osdep.em_pa.pa_dmat;
+#endif
rx_buffer = sc->rx_buffer_area;
for (i = 0; i < sc->num_rx_desc; i++, rx_buffer++) {
@@ -2381,7 +2889,7 @@ em_allocate_receive_structures(struct em_softc* sc)
return(0);
fail_1:
- /* bus_dma_tag_destroy(sc->rxtag); */
+ bus_dma_tag_destroy(sc->rxtag);
/* fail_0: */
sc->rxtag = NULL;
free(sc->rx_buffer_area, M_DEVBUF);
@@ -2423,6 +2931,7 @@ em_initialize_receive_unit(struct em_softc * sc)
struct ifnet *ifp;
u_int64_t bus_addr;
+ INIT_DEBUGOUT("em_initialize_receive_unit: begin");
ifp = &sc->interface_data.ac_if;
/* Make sure receives are disabled while setting up the descriptor ring */
@@ -2430,10 +2939,11 @@ em_initialize_receive_unit(struct em_softc * sc)
/* Set the Receive Delay Timer Register */
E1000_WRITE_REG(&sc->hw, RDTR,
- sc->rx_int_delay | E1000_RDT_FPDB);
+ sc->rx_int_delay.value | E1000_RDT_FPDB);
if(sc->hw.mac_type >= em_82540) {
- E1000_WRITE_REG(&sc->hw, RADV, sc->rx_abs_int_delay);
+ E1000_WRITE_REG(&sc->hw, RADV,
+ sc->rx_abs_int_delay.value);
/* Set the interrupt throttling rate. Value is calculated
* as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
@@ -2443,7 +2953,12 @@ em_initialize_receive_unit(struct em_softc * sc)
}
/* Setup the Base and Length of the Rx Descriptor Ring */
+#ifdef __FreeBSD__
+ bus_addr = sc->rxdma.dma_paddr;
+#endif
+#ifdef __OpenBSD__
bus_addr = sc->rxdma.dma_map->dm_segs[0].ds_addr;
+#endif
E1000_WRITE_REG(&sc->hw, RDBAL, (u_int32_t)bus_addr);
E1000_WRITE_REG(&sc->hw, RDBAH, (u_int32_t)(bus_addr >> 32));
E1000_WRITE_REG(&sc->hw, RDLEN, sc->num_rx_desc *
@@ -2527,7 +3042,7 @@ em_free_receive_structures(struct em_softc * sc)
sc->rx_buffer_area = NULL;
}
if (sc->rxtag != NULL) {
- /* bus_dma_tag_destroy(sc->rxtag); */
+ bus_dma_tag_destroy(sc->rxtag);
sc->rxtag = NULL;
}
return;
@@ -2549,16 +3064,20 @@ em_process_receive_interrupts(struct em_softc* sc, int count)
struct ifnet *ifp;
struct mbuf *mp;
#ifdef __FreeBSD__
+#if __FreeBSD_version < 500000
struct ether_header *eh;
#endif
+#endif /* __FreeBSD__ */
u_int8_t accept_frame = 0;
u_int8_t eop = 0;
- u_int16_t len, desc_len;
+ u_int16_t len, desc_len, prev_len_adj;
int i;
/* Pointer to the receive descriptor being examined. */
struct em_rx_desc *current_desc;
+ mtx_assert(&sc->mtx, MA_OWNED);
+
ifp = &sc->interface_data.ac_if;
i = sc->next_rx_desc_to_check;
current_desc = &sc->rx_desc_base[i];
@@ -2579,11 +3098,18 @@ em_process_receive_interrupts(struct em_softc* sc, int count)
bus_dmamap_unload(sc->rxtag, sc->rx_buffer_area[i].map);
accept_frame = 1;
+ prev_len_adj = 0;
desc_len = letoh16(current_desc->length);
if (current_desc->status & E1000_RXD_STAT_EOP) {
count--;
eop = 1;
- len = desc_len - ETHER_CRC_LEN;
+ if (desc_len < ETHER_CRC_LEN) {
+ len = 0;
+ prev_len_adj = ETHER_CRC_LEN - desc_len;
+ }
+ else {
+ len = desc_len - ETHER_CRC_LEN;
+ }
} else {
eop = 0;
len = desc_len;
@@ -2605,7 +3131,7 @@ em_process_receive_interrupts(struct em_softc* sc, int count)
&sc->stats,
pkt_len,
sc->hw.mac_addr);
- len--;
+ if (len > 0) len--;
}
else {
accept_frame = 0;
@@ -2634,15 +3160,24 @@ em_process_receive_interrupts(struct em_softc* sc, int count)
} else {
/* Chain mbuf's together */
mp->m_flags &= ~M_PKTHDR;
- sc->lmp->m_next = mp;
- sc->lmp = sc->lmp->m_next;
- sc->fmp->m_pkthdr.len += len;
+ /*
+ * Adjust length of previous mbuf in chain if we
+ * received less than 4 bytes in the last descriptor.
+ */
+ if (prev_len_adj > 0) {
+ sc->lmp->m_len -= prev_len_adj;
+ sc->fmp->m_pkthdr.len -= prev_len_adj;
+ }
+ sc->lmp->m_next = mp;
+ sc->lmp = sc->lmp->m_next;
+ sc->fmp->m_pkthdr.len += len;
}
if (eop) {
sc->fmp->m_pkthdr.rcvif = ifp;
ifp->if_ipackets++;
+#ifdef __OpenBSD__
#if NBPFILTER > 0
/*
* Handle BPF listeners. Let the BPF
@@ -2651,26 +3186,40 @@ em_process_receive_interrupts(struct em_softc* sc, int count)
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, sc->fmp);
#endif
-
+ em_receive_checksum(sc, current_desc,
+ sc->fmp);
+ ether_input_mbuf(ifp, sc->fmp);
+#endif /* __OpenBSD__ */
#ifdef __FreeBSD__
+#if __FreeBSD_version < 500000
eh = mtod(sc->fmp, struct ether_header *);
/* Remove ethernet header from mbuf */
m_adj(sc->fmp, sizeof(struct ether_header));
-#endif
- em_receive_checksum(sc, current_desc,
- sc->fmp);
-
-#ifdef __FreeBSD__
- if (current_desc->status & E1000_RXD_STAT_VP)
- VLAN_INPUT_TAG(eh, sc->fmp,
- (letoh16(current_desc->special) &
- E1000_RXD_SPC_VLAN_MASK));
- else
- ether_input(ifp, eh, sc->fmp);
-#else /* __FreeBSD__ */
- ether_input_mbuf(ifp, sc->fmp);
-#endif /* !__FreeBSD__ */
+ em_receive_checksum(sc, current_desc,
+ sc->fmp);
+ if (current_desc->status & E1000_RXD_STAT_VP)
+ VLAN_INPUT_TAG(eh, sc->fmp,
+ (current_desc->special &
+ E1000_RXD_SPC_VLAN_MASK));
+ else
+ ether_input(ifp, eh, sc->fmp);
+#else
+ em_receive_checksum(sc, current_desc,
+ sc->fmp);
+ if (current_desc->status & E1000_RXD_STAT_VP)
+ VLAN_INPUT_TAG(ifp, sc->fmp,
+ (current_desc->special &
+ E1000_RXD_SPC_VLAN_MASK),
+ sc->fmp = NULL);
+
+ if (sc->fmp != NULL) {
+ EM_UNLOCK(sc);
+ (*ifp->if_input)(ifp, sc->fmp);
+ EM_LOCK(sc);
+ }
+#endif
+#endif /* __FreeBSD__ */
sc->fmp = NULL;
sc->lmp = NULL;
}
@@ -2743,7 +3292,8 @@ em_receive_checksum(struct em_softc *sc,
}
return;
-#else /* __FreeBSD__ */
+#endif /* __FreeBSD__ */
+#ifdef __OpenBSD__
/* 82543 or newer only */
if ((sc->hw.mac_type < em_82543) ||
/* Ignore Checksum bit is set */
@@ -2758,11 +3308,12 @@ em_receive_checksum(struct em_softc *sc,
E1000_RXD_STAT_TCPCS|E1000_RXD_ERR_TCPE)) ==
(E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_IPCS))
mp->m_pkthdr.csum |= M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
-#endif /* __FreeBSD__ */
+#endif /* __OpenBSD__ */
}
-void em_enable_vlans(struct em_softc * sc)
+void
+em_enable_vlans(struct em_softc * sc)
{
uint32_t ctrl;
@@ -2845,20 +3396,72 @@ em_pci_clear_mwi(struct em_hw *hw)
}
-uint32_t
-em_io_read(struct em_hw *hw, uint32_t port)
+#ifdef __FreeBSD__
+int32_t
+em_io_read(struct em_hw *hw, unsigned long port)
{
- return bus_space_read_4(((struct em_osdep *)(hw)->back)->em_iobtag,
- ((struct em_osdep *)(hw)->back)->em_iobhandle, port);
+ return(inl(port));
}
void
-em_io_write(struct em_hw *hw, uint32_t port, uint32_t value)
+em_io_write(struct em_hw *hw, unsigned long port, uint32_t value)
{
- bus_space_write_4(((struct em_osdep *)(hw)->back)->em_iobtag,
- ((struct em_osdep *)(hw)->back)->em_iobhandle, port,
- value);
- return;
+ outl(port, value);
+ return;
+}
+#endif /* __FreeBSD__ */
+
+/*********************************************************************
+* 82544 Coexistence issue workaround.
+* There are 2 issues.
+* 1. Transmit Hang issue.
+* To detect this issue, following equation can be used...
+* SIZE[3:0] + ADDR[2:0] = SUM[3:0].
+* If SUM[3:0] is in between 1 to 4, we will have this issue.
+*
+* 2. DAC issue.
+* To detect this issue, following equation can be used...
+* SIZE[3:0] + ADDR[2:0] = SUM[3:0].
+* If SUM[3:0] is in between 9 to c, we will have this issue.
+*
+*
+* WORKAROUND:
+* Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c (DAC)
+*
+*** *********************************************************************/
+u_int32_t
+em_fill_descriptors (u_int64_t address,
+ u_int32_t length,
+ PDESC_ARRAY desc_array)
+{
+ /* Since issue is sensitive to length and address.*/
+ /* Let us first check the address...*/
+ u_int32_t safe_terminator;
+ if (length <= 4) {
+ desc_array->descriptor[0].address = address;
+ desc_array->descriptor[0].length = length;
+ desc_array->elements = 1;
+ return desc_array->elements;
+ }
+ safe_terminator = (u_int32_t)((((u_int32_t)address & 0x7) + (length & 0xF)) & 0xF);
+ /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */
+ if (safe_terminator == 0 ||
+ (safe_terminator > 4 &&
+ safe_terminator < 9) ||
+ (safe_terminator > 0xC &&
+ safe_terminator <= 0xF)) {
+ desc_array->descriptor[0].address = address;
+ desc_array->descriptor[0].length = length;
+ desc_array->elements = 1;
+ return desc_array->elements;
+ }
+
+ desc_array->descriptor[0].address = address;
+ desc_array->descriptor[0].length = length - 4;
+ desc_array->descriptor[1].address = address + (length - 4);
+ desc_array->descriptor[1].length = 4;
+ desc_array->elements = 2;
+ return desc_array->elements;
}
/**********************************************************************
@@ -2871,8 +3474,12 @@ em_update_stats_counters(struct em_softc *sc)
{
struct ifnet *ifp;
+ if(sc->hw.media_type == em_media_type_copper ||
+ (E1000_READ_REG(&sc->hw, STATUS) & E1000_STATUS_LU)) {
+ sc->stats.symerrs += E1000_READ_REG(&sc->hw, SYMERRS);
+ sc->stats.sec += E1000_READ_REG(&sc->hw, SEC);
+ }
sc->stats.crcerrs += E1000_READ_REG(&sc->hw, CRCERRS);
- sc->stats.symerrs += E1000_READ_REG(&sc->hw, SYMERRS);
sc->stats.mpc += E1000_READ_REG(&sc->hw, MPC);
sc->stats.scc += E1000_READ_REG(&sc->hw, SCC);
sc->stats.ecol += E1000_READ_REG(&sc->hw, ECOL);
@@ -2881,7 +3488,6 @@ em_update_stats_counters(struct em_softc *sc)
sc->stats.latecol += E1000_READ_REG(&sc->hw, LATECOL);
sc->stats.colc += E1000_READ_REG(&sc->hw, COLC);
sc->stats.dc += E1000_READ_REG(&sc->hw, DC);
- sc->stats.sec += E1000_READ_REG(&sc->hw, SEC);
sc->stats.rlec += E1000_READ_REG(&sc->hw, RLEC);
sc->stats.xonrxc += E1000_READ_REG(&sc->hw, XONRXC);
sc->stats.xontxc += E1000_READ_REG(&sc->hw, XONTXC);
@@ -2977,6 +3583,15 @@ void
em_print_debug_info(struct em_softc *sc)
{
const char * const unit = sc->sc_dv.dv_xname;
+ uint8_t *hw_addr = sc->hw.hw_addr;
+
+ printf("%s: Adapter hardware address = %p \n", unit, hw_addr);
+ printf("%s:tx_int_delay = %d, tx_abs_int_delay = %d\n", unit,
+ E1000_READ_REG(&sc->hw, TIDV),
+ E1000_READ_REG(&sc->hw, TADV));
+ printf("%s:rx_int_delay = %d, rx_abs_int_delay = %d\n", unit,
+ E1000_READ_REG(&sc->hw, RDTR),
+ E1000_READ_REG(&sc->hw, RADV));
#ifdef DBG_STATS
printf("%s: Packets not Avail = %ld\n", unit,
@@ -2990,7 +3605,7 @@ em_print_debug_info(struct em_softc *sc)
printf("%s: hw tdh = %d, hw tdt = %d\n", unit,
E1000_READ_REG(&sc->hw, TDH),
E1000_READ_REG(&sc->hw, TDT));
- printf("%s: Num Tx Descriptors avail = %ld\n", unit,
+ printf("%s: Num Tx descriptors avail = %d\n", unit,
sc->num_tx_desc_avail);
printf("%s: Tx Descriptors not avail1 = %ld\n", unit,
sc->no_tx_desc_avail1);
@@ -3095,5 +3710,65 @@ em_sysctl_stats(SYSCTL_HANDLER_ARGS)
return error;
}
+
+int
+em_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
+{
+ struct em_int_delay_info *info;
+ struct em_softc *sc;
+ u_int32_t regval;
+ int error;
+ int usecs;
+ int ticks;
+ int s;
+
+ info = (struct em_int_delay_info *)arg1;
+ sc = info->sc;
+ usecs = info->value;
+ error = sysctl_handle_int(oidp, &usecs, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return error;
+ if (usecs < 0 || usecs > E1000_TICKS_TO_USECS(65535))
+ return EINVAL;
+ info->value = usecs;
+ ticks = E1000_USECS_TO_TICKS(usecs);
+
+ s = splimp();
+ regval = E1000_READ_OFFSET(&sc->hw, info->offset);
+ regval = (regval & ~0xffff) | (ticks & 0xffff);
+ /* Handle a few special cases. */
+ switch (info->offset) {
+ case E1000_RDTR:
+ case E1000_82542_RDTR:
+ regval |= E1000_RDT_FPDB;
+ break;
+ case E1000_TIDV:
+ case E1000_82542_TIDV:
+ if (ticks == 0) {
+ sc->txd_cmd &= ~E1000_TXD_CMD_IDE;
+ /* Don't write 0 into the TIDV register. */
+ regval++;
+ } else
+ sc->txd_cmd |= E1000_TXD_CMD_IDE;
+ break;
+ }
+ E1000_WRITE_OFFSET(&sc->hw, info->offset, regval);
+ splx(s);
+ return 0;
+}
+
+void
+em_add_int_delay_sysctl(struct em_softc *sc, const char *name,
+ const char *description, struct em_int_delay_info *info,
+ int offset, int value)
+{
+ info->sc = sc;
+ info->offset = offset;
+ info->value = value;
+ SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree),
+ OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW,
+ info, 0, em_sysctl_int_delay, "I", description);
+}
#endif /* __FreeBSD__ */