Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Jan 2011 19:04:18 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r217955 - in stable/7/sys/dev: jme mii
Message-ID:  <201101271904.p0RJ4IlZ030193@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Thu Jan 27 19:04:17 2011
New Revision: 217955
URL: http://svn.freebsd.org/changeset/base/217955

Log:
  MFC r216551:
    Add support for JMicron JMC251/JMC261  Gigabit/Fast ethernet
    controller with Card Read Host Controller. These controllers are
    multi-function devices and have the same ethernet core of
    JMC250/JMC260. Starting from REVFM 5(chip full mask revision)
    controllers have the following features.
     o eFuse support
     o PCD(Packet Completion Deferring)
     o More advanced PHY power saving
  
    Because these controllers started to use eFuse, station address
    modified by driver is permanent as if it was written to EEPROM. If
    you have to change station address please save your controller
    default address to safe place before reprogramming it. There is no
    way to restore factory default station address.
  
    Many thanks to JMicron for continuing to support FreeBSD.
  
    HW donated by:	JMicron

Modified:
  stable/7/sys/dev/jme/if_jme.c
  stable/7/sys/dev/jme/if_jmereg.h
  stable/7/sys/dev/jme/if_jmevar.h
  stable/7/sys/dev/mii/jmphy.c
  stable/7/sys/dev/mii/jmphyreg.h
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/dev/jme/if_jme.c
==============================================================================
--- stable/7/sys/dev/jme/if_jme.c	Thu Jan 27 19:02:28 2011	(r217954)
+++ stable/7/sys/dev/jme/if_jme.c	Thu Jan 27 19:04:17 2011	(r217955)
@@ -97,9 +97,9 @@ static struct jme_dev {
 	const char	*jme_name;
 } jme_devs[] = {
 	{ VENDORID_JMICRON, DEVICEID_JMC250,
-	    "JMicron Inc, JMC250 Gigabit Ethernet" },
+	    "JMicron Inc, JMC25x Gigabit Ethernet" },
 	{ VENDORID_JMICRON, DEVICEID_JMC260,
-	    "JMicron Inc, JMC260 Fast Ethernet" },
+	    "JMicron Inc, JMC26x Fast Ethernet" },
 };
 
 static int jme_miibus_readreg(device_t, int, int);
@@ -110,7 +110,9 @@ static int jme_mediachange(struct ifnet 
 static int jme_probe(device_t);
 static int jme_eeprom_read_byte(struct jme_softc *, uint8_t, uint8_t *);
 static int jme_eeprom_macaddr(struct jme_softc *);
+static int jme_efuse_macaddr(struct jme_softc *);
 static void jme_reg_macaddr(struct jme_softc *);
+static void jme_set_macaddr(struct jme_softc *, uint8_t *);
 static void jme_map_intr_vector(struct jme_softc *);
 static int jme_attach(device_t);
 static int jme_detach(device_t);
@@ -152,6 +154,8 @@ static void jme_set_filter(struct jme_so
 static void jme_stats_clear(struct jme_softc *);
 static void jme_stats_save(struct jme_softc *);
 static void jme_stats_update(struct jme_softc *);
+static void jme_phy_down(struct jme_softc *);
+static void jme_phy_up(struct jme_softc *);
 static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
 static int sysctl_hw_jme_tx_coal_to(SYSCTL_HANDLER_ARGS);
 static int sysctl_hw_jme_tx_coal_pkt(SYSCTL_HANDLER_ARGS);
@@ -432,6 +436,55 @@ jme_eeprom_macaddr(struct jme_softc *sc)
 	return (ENOENT);
 }
 
+static int
+jme_efuse_macaddr(struct jme_softc *sc)
+{
+	uint32_t reg;
+	int i;
+
+	reg = pci_read_config(sc->jme_dev, JME_EFUSE_CTL1, 4);
+	if ((reg & (EFUSE_CTL1_AUTOLOAD_ERR | EFUSE_CTL1_AUTOLAOD_DONE)) !=
+	    EFUSE_CTL1_AUTOLAOD_DONE)
+		return (ENOENT);
+	/* Reset eFuse controller. */
+	reg = pci_read_config(sc->jme_dev, JME_EFUSE_CTL2, 4);
+	reg |= EFUSE_CTL2_RESET;
+	pci_write_config(sc->jme_dev, JME_EFUSE_CTL2, reg, 4);
+	reg = pci_read_config(sc->jme_dev, JME_EFUSE_CTL2, 4);
+	reg &= ~EFUSE_CTL2_RESET;
+	pci_write_config(sc->jme_dev, JME_EFUSE_CTL2, reg, 4);
+
+	/* Have eFuse reload station address to MAC controller. */
+	reg = pci_read_config(sc->jme_dev, JME_EFUSE_CTL1, 4);
+	reg &= ~EFUSE_CTL1_CMD_MASK;
+	reg |= EFUSE_CTL1_CMD_AUTOLOAD | EFUSE_CTL1_EXECUTE;
+	pci_write_config(sc->jme_dev, JME_EFUSE_CTL1, reg, 4);
+
+	/*
+	 * Verify completion of eFuse autload command.  It should be
+	 * completed within 108us.
+	 */
+	DELAY(110);
+	for (i = 10; i > 0; i--) {
+		reg = pci_read_config(sc->jme_dev, JME_EFUSE_CTL1, 4);
+		if ((reg & (EFUSE_CTL1_AUTOLOAD_ERR |
+		    EFUSE_CTL1_AUTOLAOD_DONE)) != EFUSE_CTL1_AUTOLAOD_DONE) {
+			DELAY(20);
+			continue;
+		}
+		if ((reg & EFUSE_CTL1_EXECUTE) == 0)
+			break;
+		/* Station address loading is still in progress. */
+		DELAY(20);
+	}
+	if (i == 0) {
+		device_printf(sc->jme_dev, "eFuse autoload timed out.\n");
+		return (ETIMEDOUT);
+	}
+
+	return (0);
+}
+
 static void
 jme_reg_macaddr(struct jme_softc *sc)
 {
@@ -454,6 +507,13 @@ jme_reg_macaddr(struct jme_softc *sc)
 		sc->jme_eaddr[4] = (par0 >> 8) & 0xff;
 		sc->jme_eaddr[5] = par0 & 0xff;
 	} else {
+		/*
+		 * For controllers that use eFuse, the station address
+		 * could also be extracted from JME_PCI_PAR0 and
+		 * JME_PCI_PAR1 registers in PCI configuration space.
+		 * Each register holds exactly half of station address(24bits)
+		 * so use JME_PAR0, JME_PAR1 registers instead.
+		 */
 		sc->jme_eaddr[0] = (par0 >> 0) & 0xFF;
 		sc->jme_eaddr[1] = (par0 >> 8) & 0xFF;
 		sc->jme_eaddr[2] = (par0 >> 16) & 0xFF;
@@ -464,6 +524,42 @@ jme_reg_macaddr(struct jme_softc *sc)
 }
 
 static void
+jme_set_macaddr(struct jme_softc *sc, uint8_t *eaddr)
+{
+	uint32_t val;
+	int i;
+
+	if ((sc->jme_flags & JME_FLAG_EFUSE) != 0) {
+		/*
+		 * Avoid reprogramming station address if the address
+		 * is the same as previous one.  Note, reprogrammed
+		 * station address is permanent as if it was written
+		 * to EEPROM. So if station address was changed by
+		 * admistrator it's possible to lose factory configured
+		 * address when driver fails to restore its address.
+		 * (e.g. reboot or system crash)
+		 */
+		if (bcmp(eaddr, sc->jme_eaddr, ETHER_ADDR_LEN) != 0) {
+			for (i = 0; i < ETHER_ADDR_LEN; i++) {
+				val = JME_EFUSE_EEPROM_FUNC0 <<
+				    JME_EFUSE_EEPROM_FUNC_SHIFT;
+				val |= JME_EFUSE_EEPROM_PAGE_BAR1 <<
+				    JME_EFUSE_EEPROM_PAGE_SHIFT;
+				val |= (JME_PAR0 + i) <<
+				    JME_EFUSE_EEPROM_ADDR_SHIFT;
+				val |= eaddr[i] << JME_EFUSE_EEPROM_DATA_SHIFT;
+				pci_write_config(sc->jme_dev, JME_EFUSE_EEPROM,
+				    val | JME_EFUSE_EEPROM_WRITE, 4);
+			}
+		}
+	} else {
+		CSR_WRITE_4(sc, JME_PAR0,
+		    eaddr[3] << 24 | eaddr[2] << 16 | eaddr[1] << 8 | eaddr[0]);
+		CSR_WRITE_4(sc, JME_PAR1, eaddr[5] << 8 | eaddr[4]);
+	}
+}
+
+static void
 jme_map_intr_vector(struct jme_softc *sc)
 {
 	uint32_t map[MSINUM_NUM_INTR_SOURCE / JME_MSI_MESSAGES];
@@ -542,7 +638,7 @@ jme_attach(device_t dev)
 	struct mii_data *mii;
 	uint32_t reg;
 	uint16_t burst;
-	int error, i, msic, msixc, pmc;
+	int error, i, mii_flags, msic, msixc, pmc;
 
 	error = 0;
 	sc = device_get_softc(dev);
@@ -644,11 +740,14 @@ jme_attach(device_t dev)
 		goto fail;
 	}
 
+	/* Identify controller features and bugs. */
 	if (CHIPMODE_REVFM(sc->jme_chip_rev) >= 2) {
 		if ((sc->jme_rev & DEVICEID_JMC2XX_MASK) == DEVICEID_JMC260 &&
 		    CHIPMODE_REVFM(sc->jme_chip_rev) == 2)
 			sc->jme_flags |= JME_FLAG_DMA32BIT;
-		sc->jme_flags |= JME_FLAG_TXCLK;
+		if (CHIPMODE_REVFM(sc->jme_chip_rev) >= 5)
+			sc->jme_flags |= JME_FLAG_EFUSE | JME_FLAG_PCCPCD;
+		sc->jme_flags |= JME_FLAG_TXCLK | JME_FLAG_RXCLK;
 		sc->jme_flags |= JME_FLAG_HWMIB;
 	}
 
@@ -656,14 +755,20 @@ jme_attach(device_t dev)
 	jme_reset(sc);
 
 	/* Get station address. */
-	reg = CSR_READ_4(sc, JME_SMBCSR);
-	if ((reg & SMBCSR_EEPROM_PRESENT) != 0)
-		error = jme_eeprom_macaddr(sc);
-	if (error != 0 || (reg & SMBCSR_EEPROM_PRESENT) == 0) {
-		if (error != 0 && (bootverbose))
+	if ((sc->jme_flags & JME_FLAG_EFUSE) != 0) {
+		error = jme_efuse_macaddr(sc);
+		if (error == 0)
+			jme_reg_macaddr(sc);
+	} else {
+		error = ENOENT;
+		reg = CSR_READ_4(sc, JME_SMBCSR);
+		if ((reg & SMBCSR_EEPROM_PRESENT) != 0)
+			error = jme_eeprom_macaddr(sc);
+		if (error != 0 && bootverbose)
 			device_printf(sc->jme_dev,
 			    "ethernet hardware address not found in EEPROM.\n");
-		jme_reg_macaddr(sc);
+		if (error != 0)
+			jme_reg_macaddr(sc);
 	}
 
 	/*
@@ -736,11 +841,17 @@ jme_attach(device_t dev)
 	}
 	ifp->if_capenable = ifp->if_capabilities;
 
+	/* Wakeup PHY. */
+	jme_phy_up(sc);
+	mii_flags = MIIF_DOPAUSE;
+	/* Ask PHY calibration to PHY driver. */
+	if (CHIPMODE_REVFM(sc->jme_chip_rev) >= 5)
+		mii_flags |= MIIF_MACPRIV0;
 	/* Set up MII bus. */
 	error = mii_attach(dev, &sc->jme_miibus, ifp, jme_mediachange,
 	    jme_mediastatus, BMSR_DEFCAPMASK,
 	    sc->jme_flags & JME_FLAG_FPGA ? MII_PHY_ANY : sc->jme_phyaddr,
-	    MII_OFFSET_ANY, MIIF_DOPAUSE);
+	    MII_OFFSET_ANY, mii_flags);
 	if (error != 0) {
 		device_printf(dev, "attaching PHYs failed\n");
 		goto fail;
@@ -833,6 +944,9 @@ jme_detach(device_t dev)
 		taskqueue_drain(sc->jme_tq, &sc->jme_int_task);
 		taskqueue_drain(sc->jme_tq, &sc->jme_tx_task);
 		taskqueue_drain(taskqueue_swi, &sc->jme_link_task);
+		/* Restore possibly modified station address. */
+		if ((sc->jme_flags & JME_FLAG_EFUSE) != 0)
+			jme_set_macaddr(sc, sc->jme_eaddr);
 		ether_ifdetach(ifp);
 	}
 
@@ -1493,9 +1607,11 @@ jme_setwol(struct jme_softc *sc)
 			CSR_WRITE_4(sc, JME_GHC, CSR_READ_4(sc, JME_GHC) &
 			    ~(GHC_TX_OFFLD_CLK_100 | GHC_TX_MAC_CLK_100 |
 			    GHC_TX_OFFLD_CLK_1000 | GHC_TX_MAC_CLK_1000));
+		if ((sc->jme_flags & JME_FLAG_RXCLK) != 0)
+			CSR_WRITE_4(sc, JME_GPREG1,
+			    CSR_READ_4(sc, JME_GPREG1) | GPREG1_RX_MAC_CLK_DIS);
 		/* No PME capability, PHY power down. */
-		jme_miibus_writereg(sc->jme_dev, sc->jme_phyaddr,
-		    MII_BMCR, BMCR_PDOWN);
+		jme_phy_down(sc);
 		return;
 	}
 
@@ -1527,8 +1643,7 @@ jme_setwol(struct jme_softc *sc)
 	pci_write_config(sc->jme_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
 	if ((ifp->if_capenable & IFCAP_WOL) == 0) {
 		/* No WOL, PHY power down. */
-		jme_miibus_writereg(sc->jme_dev, sc->jme_phyaddr,
-		    MII_BMCR, BMCR_PDOWN);
+		jme_phy_down(sc);
 	}
 }
 
@@ -1566,6 +1681,8 @@ jme_resume(device_t dev)
 		pci_write_config(sc->jme_dev,
 		    pmc + PCIR_POWER_STATUS, pmstat, 2);
 	}
+	/* Wakeup PHY. */
+	jme_phy_up(sc);
 	ifp = sc->jme_ifp;
 	if ((ifp->if_flags & IFF_UP) != 0) {
 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
@@ -2218,6 +2335,13 @@ jme_link_task(void *arg, int pending)
 		CSR_WRITE_4(sc, JME_RXCSR, sc->jme_rxcsr | RXCSR_RX_ENB |
 		    RXCSR_RXQ_START);
 		CSR_WRITE_4(sc, JME_TXCSR, sc->jme_txcsr | TXCSR_TX_ENB);
+		/* Lastly enable TX/RX clock. */
+		if ((sc->jme_flags & JME_FLAG_TXCLK) != 0)
+			CSR_WRITE_4(sc, JME_GHC,
+			    CSR_READ_4(sc, JME_GHC) & ~GHC_TX_MAC_CLK_DIS);
+		if ((sc->jme_flags & JME_FLAG_RXCLK) != 0)
+			CSR_WRITE_4(sc, JME_GPREG1,
+			    CSR_READ_4(sc, JME_GPREG1) & ~GPREG1_RX_MAC_CLK_DIS);
 	}
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -2596,13 +2720,45 @@ jme_tick(void *arg)
 static void
 jme_reset(struct jme_softc *sc)
 {
+	uint32_t ghc, gpreg;
 
 	/* Stop receiver, transmitter. */
 	jme_stop_rx(sc);
 	jme_stop_tx(sc);
+
+	/* Reset controller. */
 	CSR_WRITE_4(sc, JME_GHC, GHC_RESET);
+	CSR_READ_4(sc, JME_GHC);
+	DELAY(10);
+	/*
+	 * Workaround Rx FIFO overruns seen under certain conditions.
+	 * Explicitly synchorize TX/RX clock.  TX/RX clock should be
+	 * enabled only after enabling TX/RX MACs.
+	 */
+	if ((sc->jme_flags & (JME_FLAG_TXCLK | JME_FLAG_RXCLK)) != 0) {
+		/* Disable TX clock. */
+		CSR_WRITE_4(sc, JME_GHC, GHC_RESET | GHC_TX_MAC_CLK_DIS);
+		/* Disable RX clock. */
+		gpreg = CSR_READ_4(sc, JME_GPREG1);
+		CSR_WRITE_4(sc, JME_GPREG1, gpreg | GPREG1_RX_MAC_CLK_DIS);
+		gpreg = CSR_READ_4(sc, JME_GPREG1);
+		/* De-assert RESET but still disable TX clock. */
+		CSR_WRITE_4(sc, JME_GHC, GHC_TX_MAC_CLK_DIS);
+		ghc = CSR_READ_4(sc, JME_GHC);
+
+		/* Enable TX clock. */
+		CSR_WRITE_4(sc, JME_GHC, ghc & ~GHC_TX_MAC_CLK_DIS);
+		/* Enable RX clock. */
+		CSR_WRITE_4(sc, JME_GPREG1, gpreg & ~GPREG1_RX_MAC_CLK_DIS);
+		CSR_READ_4(sc, JME_GPREG1);
+
+		/* Disable TX/RX clock again. */
+		CSR_WRITE_4(sc, JME_GHC, GHC_TX_MAC_CLK_DIS);
+		CSR_WRITE_4(sc, JME_GPREG1, gpreg | GPREG1_RX_MAC_CLK_DIS);
+	} else
+		CSR_WRITE_4(sc, JME_GHC, 0);
+	CSR_READ_4(sc, JME_GHC);
 	DELAY(10);
-	CSR_WRITE_4(sc, JME_GHC, 0);
 }
 
 static void
@@ -2621,7 +2777,6 @@ jme_init_locked(struct jme_softc *sc)
 {
 	struct ifnet *ifp;
 	struct mii_data *mii;
-	uint8_t eaddr[ETHER_ADDR_LEN];
 	bus_addr_t paddr;
 	uint32_t reg;
 	int error;
@@ -2657,10 +2812,7 @@ jme_init_locked(struct jme_softc *sc)
 	jme_init_ssb(sc);
 
 	/* Reprogram the station address. */
-	bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN);
-	CSR_WRITE_4(sc, JME_PAR0,
-	    eaddr[3] << 24 | eaddr[2] << 16 | eaddr[1] << 8 | eaddr[0]);
-	CSR_WRITE_4(sc, JME_PAR1, eaddr[5] << 8 | eaddr[4]);
+	jme_set_macaddr(sc, IF_LLADDR(sc->jme_ifp));
 
 	/*
 	 * Configure Tx queue.
@@ -2798,6 +2950,30 @@ jme_init_locked(struct jme_softc *sc)
 	    PCCRX_COAL_PKT_MASK;
 	CSR_WRITE_4(sc, JME_PCCRX0, reg);
 
+	/*
+	 * Configure PCD(Packet Completion Deferring).  It seems PCD
+	 * generates an interrupt when the time interval between two
+	 * back-to-back incoming/outgoing packet is long enough for
+	 * it to reach its timer value 0. The arrival of new packets
+	 * after timer has started causes the PCD timer to restart.
+	 * Unfortunately, it's not clear how PCD is useful at this
+	 * moment, so just use the same of PCC parameters.
+	 */
+	if ((sc->jme_flags & JME_FLAG_PCCPCD) != 0) {
+		sc->jme_rx_pcd_to = sc->jme_rx_coal_to;
+		if (sc->jme_rx_coal_to > PCDRX_TO_MAX)
+			sc->jme_rx_pcd_to = PCDRX_TO_MAX;
+		sc->jme_tx_pcd_to = sc->jme_tx_coal_to;
+		if (sc->jme_tx_coal_to > PCDTX_TO_MAX)
+			sc->jme_tx_pcd_to = PCDTX_TO_MAX;
+		reg = sc->jme_rx_pcd_to << PCDRX0_TO_THROTTLE_SHIFT;
+		reg |= sc->jme_rx_pcd_to << PCDRX0_TO_SHIFT;
+		CSR_WRITE_4(sc, PCDRX_REG(0), reg);
+		reg = sc->jme_tx_pcd_to << PCDTX_TO_THROTTLE_SHIFT;
+		reg |= sc->jme_tx_pcd_to << PCDTX_TO_SHIFT;
+		CSR_WRITE_4(sc, JME_PCDTX, reg);
+	}
+
 	/* Configure shadow status block but don't enable posting. */
 	paddr = sc->jme_rdata.jme_ssb_block_paddr;
 	CSR_WRITE_4(sc, JME_SHBASE_ADDR_HI, JME_ADDR_HI(paddr));
@@ -3203,6 +3379,43 @@ jme_stats_update(struct jme_softc *sc)
 	stat->tx_bad_frames += ostat->tx_bad_frames;
 }
 
+static void
+jme_phy_down(struct jme_softc *sc)
+{
+	uint32_t reg;
+
+	jme_miibus_writereg(sc->jme_dev, sc->jme_phyaddr, MII_BMCR, BMCR_PDOWN);
+	if (CHIPMODE_REVFM(sc->jme_chip_rev) >= 5) {
+		reg = CSR_READ_4(sc, JME_PHYPOWDN);
+		reg |= 0x0000000F;
+		CSR_WRITE_4(sc, JME_PHYPOWDN, reg);
+		reg = pci_read_config(sc->jme_dev, JME_PCI_PE1, 4);
+		reg &= ~PE1_GIGA_PDOWN_MASK;
+		reg |= PE1_GIGA_PDOWN_D3;
+		pci_write_config(sc->jme_dev, JME_PCI_PE1, reg, 4);
+	}
+}
+
+static void
+jme_phy_up(struct jme_softc *sc)
+{
+	uint32_t reg;
+	uint16_t bmcr;
+
+	bmcr = jme_miibus_readreg(sc->jme_dev, sc->jme_phyaddr, MII_BMCR);
+	bmcr &= ~BMCR_PDOWN;
+	jme_miibus_writereg(sc->jme_dev, sc->jme_phyaddr, MII_BMCR, bmcr);
+	if (CHIPMODE_REVFM(sc->jme_chip_rev) >= 5) {
+		reg = CSR_READ_4(sc, JME_PHYPOWDN);
+		reg &= ~0x0000000F;
+		CSR_WRITE_4(sc, JME_PHYPOWDN, reg);
+		reg = pci_read_config(sc->jme_dev, JME_PCI_PE1, 4);
+		reg &= ~PE1_GIGA_PDOWN_MASK;
+		reg |= PE1_GIGA_PDOWN_DIS;
+		pci_write_config(sc->jme_dev, JME_PCI_PE1, reg, 4);
+	}
+}
+
 static int
 sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
 {

Modified: stable/7/sys/dev/jme/if_jmereg.h
==============================================================================
--- stable/7/sys/dev/jme/if_jmereg.h	Thu Jan 27 19:02:28 2011	(r217954)
+++ stable/7/sys/dev/jme/if_jmereg.h	Thu Jan 27 19:04:17 2011	(r217955)
@@ -63,6 +63,10 @@
 
 #define	JME_PCI_DBG		0x9C
 
+#define	JME_PCI_PAR0		0xA4	/* JMC25x/JMC26x REVFM >= 5 */
+
+#define	JME_PCI_PAR1		0xA8	/* JMC25x/JMC26x REVFM >= 5 */
+
 #define	JME_PCI_SPI		0xB0
 
 #define	SPI_ENB			0x00000010
@@ -71,6 +75,21 @@
 #define	SPI_SCK_CTRL		0x00000002
 #define	SPI_CS_N_CTRL		0x00000001
 
+#define	JME_EFUSE_CTL1		0xB8
+#define	EFUSE_CTL1_DATA_MASK	0xF0000000
+#define	EFUSE_CTL1_EXECUTE	0x08000000
+#define	EFUSE_CTL1_CMD_AUTOLOAD	0x02000000
+#define	EFUSE_CTL1_CMD_READ	0x04000000
+#define	EFUSE_CTL1_CMD_BLOW	0x06000000
+#define	EFUSE_CTL1_CMD_MASK	0x06000000
+#define	EFUSE_CTL1_AUTOLOAD_ERR	0x00010000
+#define	EFUSE_CTL1_BYTE_SEL_MASK	0x0000FF00
+#define	EFUSE_CTL1_BIT_SEL_MASK	0x00000070
+#define	EFUSE_CTL1_AUTOLAOD_DONE	0x00000001
+
+#define	JME_EFUSE_CTL2		0xBC
+#define	EFUSE_CTL2_RESET	0x00008000
+
 #define	JME_PCI_PHYCFG0		0xC0
 
 #define	JME_PCI_PHYCFG1		0xC4
@@ -86,7 +105,7 @@
 /* PCIe link error/status. */
 #define	JME_PCI_LES		0xD8
 
-/* propeietary register 0. */
+/* Proprietary register 0. */
 #define	JME_PCI_PE0		0xE0
 #define	PE0_SPI_EXIST		0x00200000
 #define	PE0_PME_D0		0x00100000
@@ -115,7 +134,31 @@
 #define	PE0_PM_AUXC_MASK	0x00000007
 #define	PE0_PM_AUXC_DEF		0x00000007
 
+/* Proprietary register 1. */
 #define	JME_PCI_PE1		0xE4
+#define	PE1_GIGA_PDOWN_MASK	0x0000C000
+#define	PE1_GIGA_PDOWN_DIS	0x00000000
+#define	PE1_GIGA_PDOWN_D3	0x00004000
+#define	PE1_GIGA_PDOWN_PCIE_SHUTDOWN	0x00008000
+#define	PE1_GIGA_PDOWN_PCIE_IDDQ	0x0000C000
+
+#define	JME_EFUSE_EEPROM	0xE8
+#define	JME_EFUSE_EEPROM_WRITE	0x80000000
+#define	JME_EFUSE_EEPROM_FUNC_MASK	0x70000000
+#define	JME_EFUSE_EEPROM_PAGE_MASK	0x0F000000
+#define	JME_EFUSE_EEPROM_ADDR_MASK	0x00FF0000
+#define	JME_EFUSE_EEPROM_DATA_MASK	0x0000FF00
+#define	JME_EFUSE_EEPROM_SMBSTAT_MASK	0x000000FF
+#define	JME_EFUSE_EEPROM_FUNC_SHIFT	28       
+#define	JME_EFUSE_EEPROM_PAGE_SHIFT	24
+#define	JME_EFUSE_EEPROM_ADDR_SHIFT	16
+#define	JME_EFUSE_EEPROM_DATA_SHIFT	8
+#define	JME_EFUSE_EEPROM_SMBSTAT_SHIFT	0
+
+#define	JME_EFUSE_EEPROM_FUNC0		0
+#define	JME_EFUSE_EEPROM_PAGE_BAR0	0
+#define	JME_EFUSE_EEPROM_PAGE_BAR1	1
+#define	JME_EFUSE_EEPROM_PAGE_BAR2	2
 
 #define	JME_PCI_PHYTEST		0xF8
 
@@ -312,7 +355,7 @@
 #define	RXMAC_PAD_10BYTES	0x00000002
 #define	RXMAC_CSUM_ENB		0x00000001
 
-/* Rx unicast MAC address. */
+/* Rx unicast MAC address. Read-only on JMC25x/JMC26x REVFM >= 5 */
 #define	JME_PAR0		0x0038
 #define	JME_PAR1		0x003C
 
@@ -455,6 +498,7 @@
 #define	JME_GIGARCHI		0x041C
 #define	JME_GIGARDLO		0x0420
 #define	JME_GIGARDHI		0x0424
+#define	JME_PHYPOWDN		0x0424	/* JMC250/JMC260 REVFM >= 5 */
 
 /* BIST status and control. */
 #define	JME_GIGACSR		0x0428
@@ -627,6 +671,7 @@
 
 /* General purpose register 1. */
 #define	JME_GPREG1		0x080C
+#define	GPREG1_RX_MAC_CLK_DIS	0x04000000	/* JMC250/JMC260 REVFM >= 2 */
 #define	GPREG1_RSS_IPV6_10_100	0x00000040	/* JMC250 A2 */
 #define	GPREG1_HDPX_FIX		0x00000020	/* JMC250 A2 */
 #define	GPREG1_INTDLY_UNIT_16US	0x00000018	/* JMC250 A1, A2 */
@@ -816,6 +861,53 @@
 #define	SHBASE_POST_FORCE	0x00000002
 #define	SHBASE_POST_ENB		0x00000001
 
+#define	JME_PCDRX_BASE		0x0850
+#define	JME_PCDRX_END		0x0857
+#define	PCDRX_REG(x)		(JME_PCDRX_BASE + (((x) / 2) * 4))
+#define	PCDRX1_TO_THROTTLE_MASK	0xFF000000
+#define	PCDRX1_TO_MASK		0x00FF0000
+#define	PCDRX0_TO_THROTTLE_MASK	0x0000FF00
+#define	PCDRX0_TO_MASK		0x000000FF
+#define	PCDRX1_TO_THROTTLE_SHIFT	24
+#define	PCDRX1_TO_SHIFT		16
+#define	PCDRX0_TO_THROTTLE_SHIFT	8
+#define	PCDRX0_TO_SHIFT		0
+#define	PCDRX_TO_MIN		1
+#define	PCDRX_TO_MAX		255
+
+#define	JME_PCDTX		0x0858
+#define	PCDTX_TO_THROTTLE_MASK	0x0000FF00
+#define	PCDTX_TO_MASK		0x000000FF
+#define	PCDTX_TO_THROTTLE_SHIFT	8
+#define	PCDTX_TO_SHIFT		0
+#define	PCDTX_TO_MIN		1
+#define	PCDTX_TO_MAX		255
+
+#define	JME_PCCPCD_STAT		0x085C
+#define	PCCPCD_STAT_RX3_MASK	0xFF000000
+#define	PCCPCD_STAT_RX2_MASK	0x00FF0000
+#define	PCCPCD_STAT_RX1_MASK	0x0000FF00
+#define	PCCPCD_STAT_RX0_MASK	0x000000FF
+#define	PCCPCD_STAT_RX3_SHIFT	24
+#define	PCCPCD_STAT_RX2_SHIFT	16
+#define	PCCPCD_STAT_RX1_SHIFT	8
+#define	PCCPCD_STAT_RX0_SHIFT	0
+
+/* TX data throughput in KB. */
+#define	JME_TX_THROUGHPUT	0x0860
+#define	TX_THROUGHPUT_MASK	0x000FFFFF
+
+/* RX data throughput in KB. */
+#define	JME_RX_THROUGHPUT	0x0864
+#define	RX_THROUGHPUT_MASK	0x000FFFFF
+
+#define	JME_LPI_CTL		0x086C
+#define	LPI_STAT_ANC_ANF	0x00000010
+#define	LPI_STAT_AN_TIMEOUT	0x00000008
+#define	LPI_STAT_RX_LPI		0x00000004
+#define	LPI_INT_ENB		0x00000002
+#define	LPI_REQ			0x00000001
+
 /* Timer 1 and 2. */
 #define	JME_TIMER1		0x0870
 #define	JME_TIMER2		0x0874
@@ -824,6 +916,15 @@
 #define	TIMER_CNT_SHIFT		0
 #define	TIMER_UNIT		1024	/* 1024us */
 
+/* Timer 3. */
+#define	JME_TIMER3		0x0878
+#define	TIMER3_TIMEOUT		0x00010000
+#define	TIMER3_TIMEOUT_COUNT_MASK	0x0000FF00	/* 130ms unit */
+#define	TIMER3_TIMEOUT_VAL_MASK		0x000000E0
+#define	TIMER3_ENB		0x00000001
+#define	TIMER3_TIMEOUT_COUNT_SHIFT	8
+#define	TIMER3_TIMEOUT_VALUE_SHIFT	1
+
 /* Aggresive power mode control. */
 #define	JME_APMC		0x087C
 #define	APMC_PCIE_SDOWN_STAT	0x80000000

Modified: stable/7/sys/dev/jme/if_jmevar.h
==============================================================================
--- stable/7/sys/dev/jme/if_jmevar.h	Thu Jan 27 19:02:28 2011	(r217954)
+++ stable/7/sys/dev/jme/if_jmevar.h	Thu Jan 27 19:04:17 2011	(r217955)
@@ -185,19 +185,22 @@ struct jme_softc {
 	uint32_t		jme_tx_dma_size;
 	uint32_t		jme_rx_dma_size;
 	int			jme_flags;
-#define	JME_FLAG_FPGA		0x0001
-#define	JME_FLAG_PCIE		0x0002
-#define	JME_FLAG_PCIX		0x0003
-#define	JME_FLAG_MSI		0x0004
-#define	JME_FLAG_MSIX		0x0010
-#define	JME_FLAG_PMCAP		0x0020
-#define	JME_FLAG_FASTETH	0x0040
-#define	JME_FLAG_NOJUMBO	0x0080
-#define	JME_FLAG_TXCLK		0x0100
-#define	JME_FLAG_DMA32BIT	0x0200
-#define	JME_FLAG_HWMIB		0x0400
-#define	JME_FLAG_DETACH		0x4000
-#define	JME_FLAG_LINK		0x8000
+#define	JME_FLAG_FPGA		0x00000001
+#define	JME_FLAG_PCIE		0x00000002
+#define	JME_FLAG_PCIX		0x00000004
+#define	JME_FLAG_MSI		0x00000008
+#define	JME_FLAG_MSIX		0x00000010
+#define	JME_FLAG_PMCAP		0x00000020
+#define	JME_FLAG_FASTETH	0x00000040
+#define	JME_FLAG_NOJUMBO	0x00000080
+#define	JME_FLAG_RXCLK		0x00000100
+#define	JME_FLAG_TXCLK		0x00000200
+#define	JME_FLAG_DMA32BIT	0x00000400
+#define	JME_FLAG_HWMIB		0x00000800
+#define	JME_FLAG_EFUSE		0x00001000
+#define	JME_FLAG_PCCPCD		0x00002000
+#define	JME_FLAG_DETACH		0x40000000
+#define	JME_FLAG_LINK		0x80000000
 
 	struct jme_hw_stats	jme_ostats;
 	struct jme_hw_stats	jme_stats;
@@ -210,8 +213,10 @@ struct jme_softc {
 	uint32_t		jme_rxcsr;
 	int			jme_process_limit;
 	int			jme_tx_coal_to;
+	int			jme_tx_pcd_to;
 	int			jme_tx_coal_pkt;
 	int			jme_rx_coal_to;
+	int			jme_rx_pcd_to;
 	int			jme_rx_coal_pkt;
 	volatile int		jme_morework;
 

Modified: stable/7/sys/dev/mii/jmphy.c
==============================================================================
--- stable/7/sys/dev/mii/jmphy.c	Thu Jan 27 19:02:28 2011	(r217954)
+++ stable/7/sys/dev/mii/jmphy.c	Thu Jan 27 19:04:17 2011	(r217955)
@@ -104,6 +104,7 @@ jmphy_attach(device_t dev)
 	struct mii_softc *sc;
 	struct mii_attach_args *ma;
 	struct mii_data *mii;
+	struct ifnet *ifp;
 
 	jsc = device_get_softc(dev);
 	sc = &jsc->mii_sc;
@@ -118,6 +119,10 @@ jmphy_attach(device_t dev)
 	sc->mii_service = jmphy_service;
 	sc->mii_pdata = mii;
 
+	ifp = sc->mii_pdata->mii_ifp;
+	if (strcmp(ifp->if_dname, "jme") == 0 &&
+	    (sc->mii_flags & MIIF_MACPRIV0) != 0)
+		sc->mii_flags |= MIIF_PHYPRIV0;
 	jsc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
 	jsc->mii_model = MII_MODEL(ma->mii_id2);
 	jsc->mii_rev = MII_REV(ma->mii_id2);
@@ -265,6 +270,7 @@ static void
 jmphy_reset(struct mii_softc *sc)
 {
 	struct jmphy_softc *jsc;
+	uint16_t t2cr, val;
 	int i;
 
 	jsc = (struct jmphy_softc *)sc;
@@ -279,6 +285,39 @@ jmphy_reset(struct mii_softc *sc)
 		if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0)
 			break;
 	}
+	/* Perform vendor recommended PHY calibration. */
+	if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) {
+		/* Select PHY test mode 1. */
+		t2cr = PHY_READ(sc, MII_100T2CR);
+		t2cr &= ~GTCR_TEST_MASK;
+		t2cr |= 0x2000;
+		PHY_WRITE(sc, MII_100T2CR, t2cr);
+		/* Apply calibration patch. */
+		PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_READ |
+		    JMPHY_EXT_COMM_2);
+		val = PHY_READ(sc, JMPHY_SPEC_DATA);
+		val &= ~0x0002;
+		val |= 0x0010 | 0x0001;
+		PHY_WRITE(sc, JMPHY_SPEC_DATA, val);
+		PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_WRITE |
+		    JMPHY_EXT_COMM_2);
+
+		/* XXX 20ms to complete recalibration. */
+		DELAY(20 * 1000);
+
+		PHY_READ(sc, MII_100T2CR);
+		PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_READ |
+		    JMPHY_EXT_COMM_2);
+		val = PHY_READ(sc, JMPHY_SPEC_DATA);
+		val &= ~(0x0001 | 0x0002 | 0x0010);
+		PHY_WRITE(sc, JMPHY_SPEC_DATA, val);
+		PHY_WRITE(sc, JMPHY_SPEC_ADDR, JMPHY_SPEC_ADDR_WRITE |
+		    JMPHY_EXT_COMM_2);
+		/* Disable PHY test mode. */
+		PHY_READ(sc, MII_100T2CR);
+		t2cr &= ~GTCR_TEST_MASK;
+		PHY_WRITE(sc, MII_100T2CR, t2cr);
+	}
 }
 
 static uint16_t

Modified: stable/7/sys/dev/mii/jmphyreg.h
==============================================================================
--- stable/7/sys/dev/mii/jmphyreg.h	Thu Jan 27 19:02:28 2011	(r217954)
+++ stable/7/sys/dev/mii/jmphyreg.h	Thu Jan 27 19:04:17 2011	(r217955)
@@ -105,4 +105,13 @@
 #define	JMPHY_TMCTL			0x1A
 #define	JMPHY_TMCTL_SLEEP_ENB		0x1000
 
+/* PHY specific configuration register. */
+#define	JMPHY_SPEC_ADDR			0x1E
+#define	JMPHY_SPEC_ADDR_READ		0x4000
+#define	JMPHY_SPEC_ADDR_WRITE		0x8000
+
+#define	JMPHY_SPEC_DATA			0x1F
+
+#define	JMPHY_EXT_COMM_2		0x32
+
 #endif	/* _DEV_MII_JMPHYREG_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101271904.p0RJ4IlZ030193>