Author: yongari
Date: Sat Dec 18 23:52:50 2010
New Revision: 216551
URL: http://svn.freebsd.org/changeset/base/216551

Log:
  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:
  head/sys/dev/jme/if_jme.c
  head/sys/dev/jme/if_jmereg.h
  head/sys/dev/jme/if_jmevar.h
  head/sys/dev/mii/jmphy.c
  head/sys/dev/mii/jmphyreg.h

Modified: head/sys/dev/jme/if_jme.c
==============================================================================
--- head/sys/dev/jme/if_jme.c   Sat Dec 18 23:26:38 2010        (r216550)
+++ head/sys/dev/jme/if_jme.c   Sat Dec 18 23:52:50 2010        (r216551)
@@ -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)
 {
@@ -446,6 +499,13 @@ jme_reg_macaddr(struct jme_softc *sc)
                device_printf(sc->jme_dev,
                    "Failed to retrieve Ethernet address.\n");
        } 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;
@@ -456,6 +516,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];
@@ -534,7 +630,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);
@@ -636,11 +732,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;
        }
 
@@ -648,14 +747,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);
        }
 
        /*
@@ -728,11 +833,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;
@@ -825,6 +936,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);
        }
 
@@ -1485,9 +1599,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;
        }
 
@@ -1519,8 +1635,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);
        }
 }
 
@@ -1558,6 +1673,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;
@@ -2210,6 +2327,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;
@@ -2588,13 +2712,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
@@ -2613,7 +2769,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;
@@ -2649,10 +2804,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.
@@ -2790,6 +2942,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));
@@ -3195,6 +3371,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: head/sys/dev/jme/if_jmereg.h
==============================================================================
--- head/sys/dev/jme/if_jmereg.h        Sat Dec 18 23:26:38 2010        
(r216550)
+++ head/sys/dev/jme/if_jmereg.h        Sat Dec 18 23:52:50 2010        
(r216551)
@@ -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: head/sys/dev/jme/if_jmevar.h
==============================================================================
--- head/sys/dev/jme/if_jmevar.h        Sat Dec 18 23:26:38 2010        
(r216550)
+++ head/sys/dev/jme/if_jmevar.h        Sat Dec 18 23:52:50 2010        
(r216551)
@@ -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: head/sys/dev/mii/jmphy.c
==============================================================================
--- head/sys/dev/mii/jmphy.c    Sat Dec 18 23:26:38 2010        (r216550)
+++ head/sys/dev/mii/jmphy.c    Sat Dec 18 23:52:50 2010        (r216551)
@@ -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: head/sys/dev/mii/jmphyreg.h
==============================================================================
--- head/sys/dev/mii/jmphyreg.h Sat Dec 18 23:26:38 2010        (r216550)
+++ head/sys/dev/mii/jmphyreg.h Sat Dec 18 23:52:50 2010        (r216551)
@@ -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_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to