summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci/if_em.c
diff options
context:
space:
mode:
authordms <dms@openbsd.org>2009-11-25 13:28:13 +0000
committerdms <dms@openbsd.org>2009-11-25 13:28:13 +0000
commit391fd4d0bddd4fef45526066b3f04e0001b33058 (patch)
treeaea502747eb17b362464c580994831d99c9b69f7 /sys/dev/pci/if_em.c
parentJust some minor cleanup. OK deraadt@ (diff)
downloadwireguard-openbsd-391fd4d0bddd4fef45526066b3f04e0001b33058.tar.xz
wireguard-openbsd-391fd4d0bddd4fef45526066b3f04e0001b33058.zip
Add support for em(4) interfaces found on intel EP80579 SoC. The MAC part is
basicly 82545, but the PHY's are separated form the chip and they are accessed through a special PCI device called GCU which has the MDIO interface. Since there is no direct relationship between MAC and PHY, so for the moment they are assigned to each other the way its done on Axiomtek NA-200, that was danted to us by them. This also adds a device driver for the GCU. tested by me on Axiomtek board reviewed by claudio@, kettenis@, deraadt@ 'commit that as is' deraadt@
Diffstat (limited to 'sys/dev/pci/if_em.c')
-rw-r--r--sys/dev/pci/if_em.c106
1 files changed, 93 insertions, 13 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c
index 4fe22eee806..8548434d964 100644
--- a/sys/dev/pci/if_em.c
+++ b/sys/dev/pci/if_em.c
@@ -31,10 +31,11 @@ POSSIBILITY OF SUCH DAMAGE.
***************************************************************************/
-/* $OpenBSD: if_em.c,v 1.228 2009/10/13 23:55:20 deraadt Exp $ */
+/* $OpenBSD: if_em.c,v 1.229 2009/11/25 13:28:13 dms Exp $ */
/* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */
#include <dev/pci/if_em.h>
+#include <dev/pci/if_em_soc.h>
#ifdef EM_DEBUG
/*********************************************************************
@@ -145,7 +146,10 @@ const struct pci_matchid em_devices[] = {
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ICH10_D_BM_LM },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ICH10_R_BM_LF },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ICH10_R_BM_LM },
- { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ICH10_R_BM_V }
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ICH10_R_BM_V },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_1 },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_2 },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_3 }
};
/*********************************************************************
@@ -153,6 +157,7 @@ const struct pci_matchid em_devices[] = {
*********************************************************************/
int em_probe(struct device *, void *, void *);
void em_attach(struct device *, struct device *, void *);
+void em_defer_attach(struct device*);
int em_detach(struct device *, int);
int em_intr(void *);
void em_power(int, void *);
@@ -248,6 +253,45 @@ em_probe(struct device *parent, void *match, void *aux)
sizeof(em_devices)/sizeof(em_devices[0])));
}
+void
+em_defer_attach(struct device *self)
+{
+ struct em_softc *sc = (struct em_softc *)self;
+ struct pci_attach_args *pa = &sc->osdep.em_pa;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ void *gcu;
+
+ if ((gcu = em_lookup_gcu(self)) == 0) {
+ printf("%s: No GCU found, defered attachment failed\n",
+ sc->sc_dv.dv_xname);
+
+ if (sc->sc_intrhand)
+ pci_intr_disestablish(pc, sc->sc_intrhand);
+ sc->sc_intrhand = 0;
+
+ if (sc->sc_powerhook != NULL)
+ powerhook_disestablish(sc->sc_powerhook);
+
+ em_stop(sc, 1);
+
+ em_free_pci_resources(sc);
+ em_dma_free(sc, &sc->rxdma);
+ em_dma_free(sc, &sc->txdma);
+
+ return;
+ }
+
+ sc->hw.gcu = gcu;
+
+ em_attach_miibus(self);
+
+ em_setup_interface(sc);
+
+ em_update_link_status(sc);
+
+ em_setup_link(&sc->hw);
+}
+
/*********************************************************************
* Device initialization routine
*
@@ -262,8 +306,9 @@ em_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
struct em_softc *sc;
- int tsize, rsize;
-
+ int tsize, rsize;
+ int defer = 0;
+
INIT_DEBUGOUT("em_attach: begin");
sc = (struct em_softc *)self;
@@ -393,10 +438,14 @@ em_attach(struct device *parent, struct device *self, void *aux)
sc->rx_desc_base = (struct em_rx_desc *) sc->rxdma.dma_vaddr;
/* Initialize the hardware */
- if (em_hardware_init(sc)) {
- printf("%s: Unable to initialize the hardware\n",
- sc->sc_dv.dv_xname);
- goto err_hw_init;
+ if ((defer = em_hardware_init(sc))) {
+ if (defer == EAGAIN)
+ config_defer(self, em_defer_attach);
+ else {
+ printf("%s: Unable to initialize the hardware\n",
+ sc->sc_dv.dv_xname);
+ goto err_hw_init;
+ }
}
/* Copy the permanent MAC address out of the EEPROM */
@@ -412,16 +461,18 @@ em_attach(struct device *parent, struct device *self, void *aux)
}
bcopy(sc->hw.mac_addr, sc->interface_data.ac_enaddr,
- ETHER_ADDR_LEN);
+ ETHER_ADDR_LEN);
/* Setup OS specific network interface */
- em_setup_interface(sc);
+ if (!defer)
+ em_setup_interface(sc);
/* Initialize statistics */
em_clear_hw_cntrs(&sc->hw);
em_update_stats_counters(sc);
sc->hw.get_link_status = 1;
- em_update_link_status(sc);
+ if (!defer)
+ em_update_link_status(sc);
printf(", address %s\n", ether_sprintf(sc->interface_data.ac_enaddr));
@@ -437,6 +488,9 @@ em_attach(struct device *parent, struct device *self, void *aux)
sc->pcix_82544 = TRUE;
else
sc->pcix_82544 = FALSE;
+
+ sc->hw.icp_xxxx_is_link_up = FALSE;
+
INIT_DEBUGOUT("em_attach: end");
sc->sc_powerhook = powerhook_establish(em_power, sc);
return;
@@ -628,7 +682,6 @@ em_watchdog(struct ifnet *ifp)
ifp->if_timer = EM_TX_TIMEOUT;
return;
}
-
printf("%s: watchdog timeout -- resetting\n", sc->sc_dv.dv_xname);
em_init(sc);
@@ -1552,6 +1605,7 @@ em_allocate_pci_resources(struct em_softc *sc)
return (ENXIO);
}
+ sc->osdep.dev = (struct device *)sc;
sc->hw.back = &sc->osdep;
intrstr = pci_intr_string(pc, ih);
@@ -1566,6 +1620,27 @@ em_allocate_pci_resources(struct em_softc *sc)
}
printf(": %s", intrstr);
+ /*
+ * the ICP_xxxx device has multiple, duplicate register sets for
+ * use when it is being used as a network processor. Disable those
+ * registers here, as they are not necessary in this context and
+ * can confuse the system
+ */
+ if(sc->hw.mac_type == em_icp_xxxx) {
+ uint8_t offset;
+ pcireg_t val;
+
+ if (!pci_get_capability(sc->osdep.em_pa.pa_pc,
+ sc->osdep.em_pa.pa_tag, PCI_CAP_ID_ST, (int*) &offset,
+ &val)) {
+ return (0);
+ }
+ offset += PCI_ST_SMIA_OFFSET;
+ pci_conf_write(sc->osdep.em_pa.pa_pc, sc->osdep.em_pa.pa_tag,
+ offset, 0x06);
+ E1000_WRITE_REG(&sc->hw, IMC1, ~0x0);
+ E1000_WRITE_REG(&sc->hw, IMC2, ~0x0);
+ }
return (0);
}
@@ -1606,6 +1681,7 @@ em_free_pci_resources(struct em_softc *sc)
int
em_hardware_init(struct em_softc *sc)
{
+ uint32_t ret_val;
u_int16_t rx_buffer_size;
INIT_DEBUGOUT("em_hardware_init: begin");
@@ -1674,7 +1750,11 @@ em_hardware_init(struct em_softc *sc)
sc->hw.fc_send_xon = TRUE;
sc->hw.fc = E1000_FC_FULL;
- if (em_init_hw(&sc->hw) < 0) {
+ if ((ret_val = em_init_hw(&sc->hw)) != 0) {
+ if (ret_val == E1000_DEFER_INIT) {
+ INIT_DEBUGOUT("\nHardware Initialization Deferred ");
+ return (EAGAIN);
+ }
printf("%s: Hardware Initialization Failed",
sc->sc_dv.dv_xname);
return (EIO);