diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/files.pci | 9 | ||||
-rw-r--r-- | sys/dev/pci/gcu.c | 78 | ||||
-rw-r--r-- | sys/dev/pci/gcu.h | 27 | ||||
-rw-r--r-- | sys/dev/pci/gcu_reg.h | 71 | ||||
-rw-r--r-- | sys/dev/pci/if_em.c | 106 | ||||
-rw-r--r-- | sys/dev/pci/if_em.h | 3 | ||||
-rw-r--r-- | sys/dev/pci/if_em_hw.c | 185 | ||||
-rw-r--r-- | sys/dev/pci/if_em_hw.h | 35 | ||||
-rw-r--r-- | sys/dev/pci/if_em_soc.c | 136 | ||||
-rw-r--r-- | sys/dev/pci/if_em_soc.h | 28 |
10 files changed, 628 insertions, 50 deletions
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 973c8a6a495..2648aa63036 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $OpenBSD: files.pci,v 1.266 2009/11/14 16:55:11 damien Exp $ +# $OpenBSD: files.pci,v 1.267 2009/11/25 13:28:13 dms Exp $ # $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $ # # Config file and device description for machine-independent PCI code. @@ -351,6 +351,7 @@ device em: ether, ifnet, ifmedia attach em at pci file dev/pci/if_em.c em file dev/pci/if_em_hw.c em +file dev/pci/if_em_soc.c em # Intel Pro/10GbE device ixgb: ether, ifnet, ifmedia @@ -788,3 +789,9 @@ file dev/pci/kate.c kate device km attach km at pci file dev/pci/km.c km + +# Intel SOC GCU +device gcu +attach gcu at pci +file dev/pci/gcu.c gcu + diff --git a/sys/dev/pci/gcu.c b/sys/dev/pci/gcu.c new file mode 100644 index 00000000000..a0df00effa2 --- /dev/null +++ b/sys/dev/pci/gcu.c @@ -0,0 +1,78 @@ +/* $OpenBSD: gcu.c,v 1.1 2009/11/25 13:28:13 dms Exp $ */ + +/* + * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Driver for a GCU device that apears on embeded intel systems, like 80579 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <dev/pci/pcidevs.h> +#include <dev/pci/gcu.h> + +int gcu_probe(struct device *, void *, void *); +void gcu_attach(struct device *, struct device *, void *); +int gcu_detach(struct device *, int); + +const struct pci_matchid gcu_devices[] = { + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_GCU } +}; + +struct cfdriver gcu_cd = { + NULL, "gcu", DV_IFNET +}; + +struct cfattach gcu_ca = { + sizeof(struct gcu_softc), gcu_probe, gcu_attach +}; + +int +gcu_probe(struct device *parent, void *match, void *aux) +{ + return (pci_matchbyid((struct pci_attach_args *)aux, gcu_devices, + sizeof(gcu_devices)/sizeof(gcu_devices[0]))); +} + +void +gcu_attach(struct device *parent, struct device *self, void *aux) +{ + struct gcu_softc *sc = (struct gcu_softc *)self; + struct pci_attach_args *pa = aux; + int val; + + val = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x10); + if (PCI_MAPREG_TYPE(val) != PCI_MAPREG_TYPE_MEM) { + printf(": mmba is not mem space\n"); + return; + } + + if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_MEM_TYPE(val), 0, &sc->tag, + &sc->handle, &sc->addr, &sc->size, 0)) { + printf(": cannot find mem space\n"); + return; + } + + mtx_init(&sc->mdio_mtx, IPL_NET); + + printf("\n"); +} diff --git a/sys/dev/pci/gcu.h b/sys/dev/pci/gcu.h new file mode 100644 index 00000000000..9611e078e00 --- /dev/null +++ b/sys/dev/pci/gcu.h @@ -0,0 +1,27 @@ +/* $OpenBSD: gcu.h,v 1.1 2009/11/25 13:28:13 dms Exp $ */ + +/* + * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct gcu_softc { + struct device sc_dev; + + bus_addr_t addr; + bus_size_t size; + bus_space_tag_t tag; + bus_space_handle_t handle; + struct mutex mdio_mtx; +}; diff --git a/sys/dev/pci/gcu_reg.h b/sys/dev/pci/gcu_reg.h new file mode 100644 index 00000000000..970f84b3b62 --- /dev/null +++ b/sys/dev/pci/gcu_reg.h @@ -0,0 +1,71 @@ +/* $OpenBSD: gcu_reg.h,v 1.1 2009/11/25 13:28:13 dms Exp $ */ + +/* + * Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * version: Embedded.B.1.0.3-146 + */ + +/* + * gcu_reg.h + * Macros and constants related to the registers available on the GCU + */ + +#ifndef GCU_REG_H +#define GCU_REG_H + +/* Register Offsets within memory map register space */ +#define MDIO_STATUS_REG 0x00000010UL +#define MDIO_COMMAND_REG 0x00000014UL + +/* MDIO_STATUS_REG fields */ +#define MDIO_STATUS_STATUS_MASK 0x80000000UL /* bit 31 = 1 on error */ +#define MDIO_STATUS_READ_DATA_MASK 0x0000FFFFUL + +/* MDIO_COMMAND_REG fields */ +#define MDIO_COMMAND_GO_MASK 0x80000000UL /* bit 31 = 1 during read or + * write, 0 on completion */ +#define MDIO_COMMAND_OPER_MASK 0x04000000UL /* bit = 1 is a write */ +#define MDIO_COMMAND_PHY_ADDR_MASK 0x03E00000UL +#define MDIO_COMMAND_PHY_REG_MASK 0x001F0000UL +#define MDIO_COMMAND_WRITE_DATA_MASK 0x0000FFFFUL + +#define MDIO_COMMAND_GO_OFFSET 31 +#define MDIO_COMMAND_OPER_OFFSET 26 +#define MDIO_COMMAND_PHY_ADDR_OFFSET 21 +#define MDIO_COMMAND_PHY_REG_OFFSET 16 +#define MDIO_COMMAND_WRITE_DATA_OFFSET 0 + +#define MDIO_COMMAND_PHY_ADDR_MAX 2 /* total phys supported by GCU */ +#define MDIO_COMMAND_PHY_REG_MAX 31 /* total registers available on + * the M88 Phy used on truxton */ + +#endif /* ifndef GCU_REG_H */ + 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); diff --git a/sys/dev/pci/if_em.h b/sys/dev/pci/if_em.h index 2173d461c5d..4c2355e6a21 100644 --- a/sys/dev/pci/if_em.h +++ b/sys/dev/pci/if_em.h @@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ /* $FreeBSD: if_em.h,v 1.26 2004/09/01 23:22:41 pdeuskar Exp $ */ -/* $OpenBSD: if_em.h,v 1.45 2009/08/10 19:41:05 deraadt Exp $ */ +/* $OpenBSD: if_em.h,v 1.46 2009/11/25 13:28:13 dms Exp $ */ #ifndef _EM_H_DEFINED_ #define _EM_H_DEFINED_ @@ -417,7 +417,6 @@ struct em_softc { /* For 82544 PCI-X Workaround */ boolean_t pcix_82544; - struct em_hw_stats stats; }; diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c index 5c80164c0e1..43c5e9b7ee8 100644 --- a/sys/dev/pci/if_em_hw.c +++ b/sys/dev/pci/if_em_hw.c @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.c,v 1.41 2009/10/11 23:54:49 dms Exp $ */ +/* $OpenBSD: if_em_hw.c,v 1.42 2009/11/25 13:28:13 dms Exp $ */ /* if_em_hw.c * Shared functions for accessing and configuring the MAC @@ -70,6 +70,7 @@ __FBSDID("$FreeBSD: if_em_hw.c,v 1.16 2005/05/26 23:32:02 tackerman Exp $"); #include <dev/pci/pcidevs.h> #include <dev/pci/if_em_hw.h> +#include <dev/pci/if_em_soc.h> #define STATIC @@ -221,6 +222,9 @@ em_set_phy_type(struct em_hw *hw) case IFE_C_E_PHY_ID: hw->phy_type = em_phy_ife; break; + case M88E1141_E_PHY_ID: + hw->phy_type = em_phy_oem; + break; case BME1000_E_PHY_ID: if (hw->phy_revision == 1) { hw->phy_type = em_phy_bm; @@ -494,6 +498,18 @@ em_set_mac_type(struct em_hw *hw) case E1000_DEV_ID_ICH10_D_BM_LM: hw->mac_type = em_ich10lan; break; + case E1000_DEV_ID_EP80579_LAN_1: + hw->mac_type = em_icp_xxxx; + hw->icp_xxxx_port_num = 0; + break; + case E1000_DEV_ID_EP80579_LAN_2: + hw->mac_type = em_icp_xxxx; + hw->icp_xxxx_port_num = 1; + break; + case E1000_DEV_ID_EP80579_LAN_3: + hw->mac_type = em_icp_xxxx; + hw->icp_xxxx_port_num = 2; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; @@ -555,6 +571,11 @@ em_set_media_type(struct em_hw *hw) case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: hw->media_type = em_media_type_internal_serdes; break; + case E1000_DEV_ID_EP80579_LAN_1: + case E1000_DEV_ID_EP80579_LAN_2: + case E1000_DEV_ID_EP80579_LAN_3: + hw->media_type = em_media_type_oem; + break; default: switch (hw->mac_type) { case em_82542_rev2_0: @@ -756,16 +777,21 @@ em_reset_hw(struct em_hw *hw) E1000_WRITE_FLUSH(hw); } /* FALLTHROUGH */ - default: + /* Auto read done will delay 5ms or poll based on mac type */ ret_val = em_get_auto_rd_done(hw); if (ret_val) return ret_val; break; + default: + /* Wait for EEPROM reload (it happens automatically) */ + msec_delay(5); + break; } /* Disable HW ARPs on ASF enabled adapters */ - if (hw->mac_type >= em_82540 && hw->mac_type <= em_82547_rev_2) { + if (hw->mac_type >= em_82540 && hw->mac_type <= em_82547_rev_2 && + hw->mac_type != em_icp_xxxx) { manc = E1000_READ_REG(hw, MANC); manc &= ~(E1000_MANC_ARP_EN); E1000_WRITE_REG(hw, MANC, manc); @@ -1193,9 +1219,15 @@ em_setup_link(struct em_hw *hw) uint32_t ctrl_ext; int32_t ret_val; uint16_t eeprom_data; + uint16_t eeprom_control2_reg_offset; DEBUGFUNC("em_setup_link"); + eeprom_control2_reg_offset = + (hw->mac_type != em_icp_xxxx) + ? EEPROM_INIT_CONTROL2_REG + : EEPROM_INIT_CONTROL3_ICP_xxxx(hw->icp_xxxx_port_num); + /* In the case of the phy reset being blocked, we already have a link. * We do not have to set it up again. */ if (em_check_phy_reset_block(hw)) @@ -1219,7 +1251,7 @@ em_setup_link(struct em_hw *hw) hw->fc = E1000_FC_FULL; break; default: - ret_val = em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, + ret_val = em_read_eeprom(hw, eeprom_control2_reg_offset, 1, &eeprom_data); if (ret_val) { DEBUGOUT("EEPROM Read Error\n"); @@ -1273,14 +1305,23 @@ em_setup_link(struct em_hw *hw) ret_val = em_detect_gig_phy(hw); if (ret_val) { DEBUGOUT("Error, did not detect valid phy.\n"); - return ret_val; + if (hw->mac_type == em_icp_xxxx) + return E1000_DEFER_INIT; + else + return ret_val; } DEBUGOUT1("Phy ID = %x \n", hw->phy_id); /* Call the necessary subroutine to configure the link. */ - ret_val = (hw->media_type == em_media_type_copper) ? - em_setup_copper_link(hw) : - em_setup_fiber_serdes_link(hw); + switch (hw->media_type) { + case em_media_type_copper: + case em_media_type_oem: + ret_val = em_setup_copper_link(hw); + break; + default: + ret_val = em_setup_fiber_serdes_link(hw); + break; + } /* Initialize the flow control address, type, and PAUSE timer * registers to their default values. This is done even if flow @@ -1849,10 +1890,23 @@ em_copper_link_mgp_setup(struct em_hw *hw) if (ret_val) return ret_val; + if (hw->phy_id == M88E1141_E_PHY_ID) { + phy_data |= 0x00000008; + ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + + ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX; + + } /* For BM PHY this bit is downshift enable */ - if (hw->phy_type != em_phy_bm) + else if (hw->phy_type != em_phy_bm) phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - + /* Options: * MDI/MDI-X = 0 (default) * 0 - Auto for all speeds @@ -1896,9 +1950,11 @@ em_copper_link_mgp_setup(struct em_hw *hw) if (ret_val) return ret_val; - if ((hw->phy_type == em_phy_m88) && + if (((hw->phy_type == em_phy_m88) && (hw->phy_revision < M88E1011_I_REV_4) && - (hw->phy_id != BME1000_E_PHY_ID)) { + (hw->phy_id != BME1000_E_PHY_ID)) || + (hw->phy_type == em_phy_oem)) { + /* Force TX_CLK in the Extended PHY Specific Control Register * to 25MHz clock. */ @@ -1906,6 +1962,11 @@ em_copper_link_mgp_setup(struct em_hw *hw) if (ret_val) return ret_val; + if (hw->phy_type == em_phy_oem) { + phy_data |= M88E1000_EPSCR_TX_TIME_CTRL; + phy_data |= M88E1000_EPSCR_RX_TIME_CTRL; + } + phy_data |= M88E1000_EPSCR_TX_CLK_25; if ((hw->phy_revision == E1000_REVISION_2) && @@ -1962,7 +2023,7 @@ em_copper_link_mgp_setup(struct em_hw *hw) * * hw - Struct containing variables accessed by shared code *********************************************************************/ -static int32_t +int32_t em_copper_link_autoneg(struct em_hw *hw) { int32_t ret_val; @@ -2033,13 +2094,14 @@ em_copper_link_autoneg(struct em_hw *hw) * * hw - Struct containing variables accessed by shared code ******************************************************************************/ -static int32_t +int32_t em_copper_link_postconfig(struct em_hw *hw) { int32_t ret_val; DEBUGFUNC("em_copper_link_postconfig"); - if (hw->mac_type >= em_82544) { + if (hw->mac_type >= em_82544 && + hw->mac_type != em_icp_xxxx) { em_config_collision_dist(hw); } else { ret_val = em_config_mac_to_phy(hw); @@ -2129,7 +2191,8 @@ em_setup_copper_link(struct em_hw *hw) if (ret_val) return ret_val; } else if (hw->phy_type == em_phy_m88 || - hw->phy_type == em_phy_bm) { + hw->phy_type == em_phy_bm || + hw->phy_type == em_phy_oem) { ret_val = em_copper_link_mgp_setup(hw); if (ret_val) return ret_val; @@ -2167,6 +2230,8 @@ em_setup_copper_link(struct em_hw *hw) if (ret_val) return ret_val; + hw->icp_xxxx_is_link_up = (phy_data & MII_SR_LINK_STATUS) != 0; + if (phy_data & MII_SR_LINK_STATUS) { /* Config the MAC and PHY after link is up */ ret_val = em_copper_link_postconfig(hw); @@ -2487,7 +2552,8 @@ em_phy_force_speed_duplex(struct em_hw *hw) if ((hw->phy_type == em_phy_m88) || (hw->phy_type == em_phy_gg82563) || - (hw->phy_type == em_phy_bm)) { + (hw->phy_type == em_phy_bm) || + (hw->phy_type == em_phy_oem)) { ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if (ret_val) return ret_val; @@ -2504,8 +2570,11 @@ em_phy_force_speed_duplex(struct em_hw *hw) /* Need to reset the PHY or these changes will be ignored */ mii_ctrl_reg |= MII_CR_RESET; + + } + /* Disable MDI-X support for 10/100 */ - } else if (hw->phy_type == em_phy_ife) { + else if (hw->phy_type == em_phy_ife) { ret_val = em_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data); if (ret_val) return ret_val; @@ -2578,6 +2647,7 @@ em_phy_force_speed_duplex(struct em_hw *hw) return ret_val; } } + /* This loop will early-out if the link condition has been met. */ for (i = PHY_FORCE_TIME; i > 0; i--) { if (mii_status_reg & MII_SR_LINK_STATUS) break; @@ -2596,7 +2666,8 @@ em_phy_force_speed_duplex(struct em_hw *hw) } if (hw->phy_type == em_phy_m88 || - hw->phy_type == em_phy_bm) { + hw->phy_type == em_phy_bm || + hw->phy_type == em_phy_oem) { /* Because we reset the PHY above, we need to re-force TX_CLK in the * Extended PHY Specific Control Register to 25MHz clock. This value * defaults back to a 2.5MHz clock when the PHY is reset. @@ -2617,7 +2688,11 @@ em_phy_force_speed_duplex(struct em_hw *hw) if (ret_val) return ret_val; - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + if ( hw->phy_id == M88E1141_E_PHY_ID) + phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX; + else + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + ret_val = em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); if (ret_val) return ret_val; @@ -2703,7 +2778,8 @@ em_config_mac_to_phy(struct em_hw *hw) /* 82544 or newer MAC, Auto Speed Detection takes care of * MAC speed/duplex configuration.*/ - if (hw->mac_type >= em_82544) + if (hw->mac_type >= em_82544 + && hw->mac_type != em_icp_xxxx) return E1000_SUCCESS; /* Read the Device Control Register and set the bits to Force Speed @@ -2837,7 +2913,9 @@ em_config_fc_after_link_up(struct em_hw *hw) if (((hw->media_type == em_media_type_fiber) && (hw->autoneg_failed)) || ((hw->media_type == em_media_type_internal_serdes) && (hw->autoneg_failed)) || - ((hw->media_type == em_media_type_copper) && (!hw->autoneg))) { + ((hw->media_type == em_media_type_copper) && (!hw->autoneg)) || + ((hw->media_type == em_media_type_oem) && (!hw->autoneg)) + ) { ret_val = em_force_mac_fc(hw); if (ret_val) { DEBUGOUT("Error forcing flow control settings\n"); @@ -2850,7 +2928,9 @@ em_config_fc_after_link_up(struct em_hw *hw) * has completed, and if so, how the PHY and link partner has * flow control configured. */ - if ((hw->media_type == em_media_type_copper) && hw->autoneg) { + if ((hw->media_type == em_media_type_copper || + (hw->media_type == em_media_type_oem)) && + hw->autoneg) { /* Read the MII Status Register and check to see if AutoNeg * has completed. We read this twice because this reg has * some "sticky" (latched) bits. @@ -3061,7 +3141,9 @@ em_check_for_link(struct em_hw *hw) * receive a Link Status Change interrupt or we have Rx Sequence * Errors. */ - if ((hw->media_type == em_media_type_copper) && hw->get_link_status) { + if ((hw->media_type == em_media_type_copper || + (hw->media_type == em_media_type_oem)) && + hw->get_link_status) { /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex * of the PHY. @@ -3074,6 +3156,8 @@ em_check_for_link(struct em_hw *hw) if (ret_val) return ret_val; + hw->icp_xxxx_is_link_up = (phy_data & MII_SR_LINK_STATUS) != 0; + if (phy_data & MII_SR_LINK_STATUS) { hw->get_link_status = FALSE; /* Check if there was DownShift, must be checked immediately after @@ -3121,7 +3205,7 @@ em_check_for_link(struct em_hw *hw) * speed/duplex on the MAC to the current PHY speed/duplex * settings. */ - if (hw->mac_type >= em_82544) + if (hw->mac_type >= em_82544 && hw->mac_type != em_icp_xxxx) em_config_collision_dist(hw); else { ret_val = em_config_mac_to_phy(hw); @@ -3672,6 +3756,12 @@ em_read_phy_reg_ex(struct em_hw *hw, uint32_t reg_addr, return -E1000_ERR_PARAM; } + if(hw->mac_type == em_icp_xxxx) { + *phy_data = gcu_miibus_readreg(hw, hw->icp_xxxx_port_num, + reg_addr); + return E1000_SUCCESS; + } + if (hw->mac_type > em_82543) { /* Set up Op-code, Phy Address, and register address in the MDI * Control register. The MAC will take care of interfacing with the @@ -3816,6 +3906,11 @@ em_write_phy_reg_ex(struct em_hw *hw, uint32_t reg_addr, return -E1000_ERR_PARAM; } + if(hw->mac_type == em_icp_xxxx) { + gcu_miibus_writereg(hw, hw->icp_xxxx_port_num, + reg_addr, phy_data); + return E1000_SUCCESS; + } if (hw->mac_type > em_82543) { /* Set up Op-code, Phy Address, register address, and data intended * for the PHY register in the MDI Control register. The MAC will take @@ -3946,7 +4041,7 @@ em_phy_hw_reset(struct em_hw *hw) DEBUGOUT("Resetting Phy...\n"); - if (hw->mac_type > em_82543) { + if (hw->mac_type > em_82543 && hw->mac_type != em_icp_xxxx ) { if ((hw->mac_type == em_80003es2lan) && (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { swfw = E1000_SWFW_PHY1_SM; @@ -3978,6 +4073,7 @@ em_phy_hw_reset(struct em_hw *hw) if (hw->mac_type >= em_82571) msec_delay_irq(10); em_swfw_sync_release(hw, swfw); + /* the M88E1141_E_PHY_ID might need reset here, but nothing proves it */ } else { /* Read the Extended Device Control Register, assert the PHY_RESET_DIR * bit to put the PHY into reset. Then, take it out of reset. @@ -4191,6 +4287,9 @@ em_match_gig_phy(struct em_hw *hw) if (hw->phy_id == IFE_C_E_PHY_ID) match = TRUE; if (hw->phy_id == BME1000_E_PHY_ID) match = TRUE; break; + case em_icp_xxxx: + if (hw->phy_id == M88E1141_E_PHY_ID) match = TRUE; + break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; @@ -4221,7 +4320,7 @@ em_detect_gig_phy(struct em_hw *hw) return E1000_SUCCESS; /* default phy address, most phys reside here, but not all (ICH10) */ - hw->phy_addr = 1; + hw->phy_addr = 0; /* The 82571 firmware may still be configuring the PHY. In this * case, we cannot access the PHY until the configuration is done. So @@ -4332,6 +4431,7 @@ em_init_eeprom_params(struct em_hw *hw) case em_82540: case em_82545: case em_82545_rev_3: + case em_icp_xxxx: case em_82546: case em_82546_rev_3: eeprom->type = em_eeprom_microwire; @@ -5086,9 +5186,14 @@ em_validate_eeprom_checksum(struct em_hw *hw) { uint16_t checksum = 0; uint16_t i, eeprom_data; + uint16_t checksum_reg; DEBUGFUNC("em_validate_eeprom_checksum"); + checksum_reg = hw->mac_type != em_icp_xxxx + ? EEPROM_CHECKSUM_REG + : EEPROM_CHECKSUM_REG_ICP_xxxx; + if (((hw->mac_type == em_82573) || (hw->mac_type == em_82574)) && (em_is_onboard_nvm_eeprom(hw) == FALSE)) { /* Check bit 4 of word 10h. If it is 0, firmware is done updating @@ -5124,7 +5229,7 @@ em_validate_eeprom_checksum(struct em_hw *hw) } } - for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { + for (i = 0; i < (checksum_reg + 1); i++) { if (em_read_eeprom(hw, i, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; @@ -5607,12 +5712,18 @@ em_read_mac_addr(struct em_hw * hw) { uint16_t offset; uint16_t eeprom_data, i; + uint16_t ia_base_addr = 0; DEBUGFUNC("em_read_mac_addr"); + if(hw->mac_type == em_icp_xxxx) { + ia_base_addr = (uint16_t) + EEPROM_IA_START_ICP_xxxx(hw->icp_xxxx_port_num); + } + for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) { offset = i >> 1; - if (em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { + if (em_read_eeprom(hw, offset + ia_base_addr, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -6019,7 +6130,7 @@ em_id_led_init(struct em_hw * hw) DEBUGFUNC("em_id_led_init"); - if (hw->mac_type < em_82540) { + if (hw->mac_type < em_82540 || hw->mac_type == em_icp_xxxx) { /* Nothing to do */ return E1000_SUCCESS; } @@ -6168,7 +6279,8 @@ em_clear_hw_cntrs(struct em_hw *hw) temp = E1000_READ_REG(hw, TSCTC); temp = E1000_READ_REG(hw, TSCTFC); - if (hw->mac_type <= em_82544) return; + if (hw->mac_type <= em_82544 + || hw->mac_type == em_icp_xxxx) return; temp = E1000_READ_REG(hw, MGTPRC); temp = E1000_READ_REG(hw, MGTPDC); @@ -6292,6 +6404,11 @@ em_get_bus_info(struct em_hw *hw) hw->bus_speed = em_bus_speed_unknown; hw->bus_width = em_bus_width_unknown; break; + case em_icp_xxxx: + hw->bus_type = em_bus_type_cpp; + hw->bus_speed = em_bus_speed_unknown; + hw->bus_width = em_bus_width_unknown; + break; case em_82571: case em_82572: case em_82573: @@ -6399,7 +6516,8 @@ em_get_cable_length(struct em_hw *hw, *min_length = *max_length = 0; /* Use old method for Phy older than IGP */ - if (hw->phy_type == em_phy_m88) { + if (hw->phy_type == em_phy_m88 || + hw->phy_type == em_phy_oem) { ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); @@ -6592,7 +6710,8 @@ em_check_downshift(struct em_hw *hw) hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0; } else if ((hw->phy_type == em_phy_m88) || - (hw->phy_type == em_phy_gg82563)) { + (hw->phy_type == em_phy_gg82563) || + (hw->phy_type == em_phy_oem)) { ret_val = em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); if (ret_val) diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h index 485e1cec2ce..4511dd2cd88 100644 --- a/sys/dev/pci/if_em_hw.h +++ b/sys/dev/pci/if_em_hw.h @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.h,v 1.34 2009/10/31 12:26:36 sobrado Exp $ */ +/* $OpenBSD: if_em_hw.h,v 1.35 2009/11/25 13:28:13 dms Exp $ */ /* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */ /* if_em_hw.h @@ -58,6 +58,7 @@ typedef enum { em_82540, em_82545, em_82545_rev_3, + em_icp_xxxx, em_82546, em_82546_rev_3, em_82541, @@ -91,6 +92,7 @@ typedef enum { em_media_type_copper = 0, em_media_type_fiber = 1, em_media_type_internal_serdes = 2, + em_media_type_oem = 3, em_num_media_types } em_media_type; @@ -112,6 +114,7 @@ typedef enum { em_bus_type_pci, em_bus_type_pcix, em_bus_type_pci_express, + em_bus_type_cpp, em_bus_type_reserved } em_bus_type; @@ -231,6 +234,7 @@ typedef enum { em_phy_igp_3, em_phy_ife, em_phy_bm, /* phy used in i82574L, ICH10 and some ICH9 */ + em_phy_oem, em_phy_undefined = 0xFF } em_phy_type; @@ -304,6 +308,7 @@ typedef enum { #define E1000_BLK_PHY_RESET 12 #define E1000_ERR_SWFW_SYNC 13 #define E1000_NOT_IMPLEMENTED 14 +#define E1000_DEFER_INIT 15 #define E1000_BYTE_SWAP_WORD(_value) ((((_value) & 0x00ff) << 8) | \ (((_value) & 0xff00) >> 8)) @@ -322,6 +327,8 @@ void em_config_collision_dist(struct em_hw *hw); int32_t em_check_for_link(struct em_hw *hw); int32_t em_get_speed_and_duplex(struct em_hw *hw, uint16_t *speed, uint16_t *duplex); int32_t em_force_mac_fc(struct em_hw *hw); +int32_t em_copper_link_autoneg(struct em_hw *hw); +int32_t em_copper_link_postconfig(struct em_hw *hw); /* PHY */ int32_t em_read_phy_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data); @@ -522,6 +529,9 @@ int32_t em_check_phy_reset_block(struct em_hw *hw); #define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 #define E1000_DEV_ID_82576_NS 0x150A #define E1000_DEV_ID_82574L 0x10D3 +#define E1000_DEV_ID_EP80579_LAN_1 0x5040 /* EP80579 LAN */ +#define E1000_DEV_ID_EP80579_LAN_2 0x5044 /* EP80579 LAN */ +#define E1000_DEV_ID_EP80579_LAN_3 0x5048 /* EP80579 LAN */ #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -1481,6 +1491,9 @@ struct em_hw { boolean_t mng_reg_access_disabled; boolean_t leave_av_bit_off; boolean_t kmrn_lock_loss_workaround_disabled; + boolean_t icp_xxxx_is_link_up; + uint32_t icp_xxxx_port_num; + struct gcu_softc * gcu; }; #define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ @@ -2954,6 +2967,10 @@ struct em_host_command_info { #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00 +/* M88E1141 specific */ +#define M88E1000_EPSCR_TX_TIME_CTRL 0x0002 /* Add Delay */ +#define M88E1000_EPSCR_RX_TIME_CTRL 0x0080 /* Add Delay */ + /* IGP01E1000 Specific Port Config Register - R/W */ #define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010 #define IGP01E1000_PSCFR_PRE_EN 0x0020 @@ -3180,6 +3197,7 @@ struct em_host_command_info { #define L1LXT971A_PHY_ID 0x001378E0 #define GG82563_E_PHY_ID 0x01410CA0 #define BME1000_E_PHY_ID 0x01410CB0 +#define M88E1141_E_PHY_ID 0x01410CD0 /* Bits... * 15-5: page @@ -3399,4 +3417,19 @@ union ich8_hws_flash_regacc { #define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds*/ #define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds*/ +/* ICP PCI Dev ID xxxx macros to calculate word offsets for IA, IPv4 and IPv6 */ +#define EEPROM_MGMT_CONTROL_ICP_xxxx(device_num) (((device_num) + 1) << 4) +#define EEPROM_INIT_CONTROL3_ICP_xxxx(device_num) ((((device_num) + 1) << 4) + 1) +#define EEPROM_IA_START_ICP_xxxx(device_num) ((((device_num) + 1) << 4) + 2) +#define EEPROM_IPV4_START_ICP_xxxx(device_num) ((((device_num) + 1) << 4) + 5) +#define EEPROM_IPV6_START_ICP_xxxx(device_num) ((((device_num) + 1) << 4) + 7) +#define EEPROM_CHECKSUM_REG_ICP_xxxx EEPROM_CHECKSUM_REG +#define PCI_CAP_ID_ST 0x09 +#define PCI_ST_SMIA_OFFSET 0x04 + +#define E1000_IMC1 0x008D8 /* Interrupt Mask Clear 1 - RW */ +#define E1000_IMC2 0x008F8 /* Interrupt Mask Clear 2 - RW */ +#define E1000_82542_IMC1 E1000_IMC1 +#define E1000_82542_IMC2 E1000_IMC2 + #endif /* _EM_HW_H_ */ diff --git a/sys/dev/pci/if_em_soc.c b/sys/dev/pci/if_em_soc.c new file mode 100644 index 00000000000..7932e9cacd2 --- /dev/null +++ b/sys/dev/pci/if_em_soc.c @@ -0,0 +1,136 @@ +/* $OpenBSD: if_em_soc.c,v 1.1 2009/11/25 13:28:13 dms Exp $ */ + +/* + * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <dev/pci/if_em.h> +#include <dev/pci/if_em_hw.h> +#include <dev/pci/if_em_soc.h> +#include <dev/pci/gcu.h> +#include <dev/pci/gcu_reg.h> + +void em_media_status(struct ifnet *, struct ifmediareq *); +int em_media_change(struct ifnet *); + +void * +em_lookup_gcu(struct device *self) +{ + struct device *dev; + + INIT_DEBUGOUT("em_lookup_gcu"); + TAILQ_FOREACH(dev, &alldevs, dv_list) { + if (strcmp(dev->dv_xname, "gcu0") == NULL) { + return dev; + } + } + return 0; +} + +int +em_attach_miibus(struct device *self) +{ + return 0; +} + +int +gcu_miibus_readreg(struct em_hw *hw, int phy, int reg) +{ + struct em_softc *sc = (struct em_softc *) + ((struct em_osdep *)hw->back)->dev; + struct gcu_softc *gcu = hw->gcu; + uint32_t data = 0; + uint32_t done = 0; + int i = 0; + + if (gcu == 0) + return 0; + + /* format the data to be written to MDIO_COMMAND_REG */ + data |= (reg << MDIO_COMMAND_PHY_REG_OFFSET); + data |= (phy << MDIO_COMMAND_PHY_ADDR_OFFSET); + data |= MDIO_COMMAND_GO_MASK; + + mtx_enter(&gcu->mdio_mtx); + bus_space_write_4(gcu->tag, gcu->handle, MDIO_COMMAND_REG, data); + + while (!done && (i++ < GCU_MAX_ATTEMPTS)) { + DELAY(GCU_CMD_DELAY); + data = bus_space_read_4(gcu->tag, gcu->handle, + MDIO_COMMAND_REG); + done = !((data & MDIO_COMMAND_GO_MASK) >> + MDIO_COMMAND_GO_OFFSET); + } + mtx_leave(&gcu->mdio_mtx); + + if (i >= GCU_MAX_ATTEMPTS) { + printf("%s: phy read timeout: phy %d, reg %d\n", + sc->sc_dv.dv_xname, phy, reg); + return (0); + } + + mtx_enter(&gcu->mdio_mtx); + data = bus_space_read_4(gcu->tag, gcu->handle, MDIO_STATUS_REG); + mtx_leave(&gcu->mdio_mtx); + + if((data & MDIO_STATUS_STATUS_MASK) != 0) { + printf("%s: unable to read phy %d reg %d\n", + sc->sc_dv.dv_xname, phy, reg); + return (0); + } + return (uint16_t) (data & MDIO_STATUS_READ_DATA_MASK); +} + +void +gcu_miibus_writereg(struct em_hw *hw, int phy, int reg, int val) +{ + struct em_softc *sc = (struct em_softc *) + ((struct em_osdep *)hw->back)->dev; + struct gcu_softc *gcu = hw->gcu; + uint32_t data, done = 0; + int i = 0; + + if (gcu == 0) + return; + + /* format the data to be written to the MDIO_COMMAND_REG */ + data = val; + data |= (reg << MDIO_COMMAND_PHY_REG_OFFSET); + data |= (phy << MDIO_COMMAND_PHY_ADDR_OFFSET); + data |= MDIO_COMMAND_OPER_MASK | MDIO_COMMAND_GO_MASK; + + mtx_enter(&gcu->mdio_mtx); + bus_space_write_4(gcu->tag, gcu->handle, MDIO_COMMAND_REG, data); + + while (!done && (i++ < GCU_MAX_ATTEMPTS)) { + DELAY(GCU_CMD_DELAY); + data = bus_space_read_4(gcu->tag, gcu->handle, + MDIO_COMMAND_REG); + done = !((data & MDIO_COMMAND_GO_MASK) >> + MDIO_COMMAND_GO_OFFSET); + } + mtx_leave(&gcu->mdio_mtx); + + if (i >= GCU_MAX_ATTEMPTS) { + printf("%s: phy read timeout: phy %d, reg %d\n", + sc->sc_dv.dv_xname, phy, reg); + return; + } +} + +void +gcu_miibus_statchg(struct device *dev) +{ +} diff --git a/sys/dev/pci/if_em_soc.h b/sys/dev/pci/if_em_soc.h new file mode 100644 index 00000000000..ddadf55130e --- /dev/null +++ b/sys/dev/pci/if_em_soc.h @@ -0,0 +1,28 @@ +/* $OpenBSD: if_em_soc.h,v 1.1 2009/11/25 13:28:13 dms Exp $ */ + +/* + * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +void *em_lookup_gcu(struct device *); +int em_attach_miibus(struct device *self); + +int gcu_miibus_readreg(struct em_hw *, int, int); +void gcu_miibus_writereg(struct em_hw *, int, int, int); +void gcu_miibus_statchg(struct device *); + +#define GCU_MAX_ATTEMPTS 64 +#define GCU_CMD_DELAY 50 /* microseconds */ |