summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/jme/if_jme.c255
-rw-r--r--sys/dev/jme/if_jmereg.h105
-rw-r--r--sys/dev/jme/if_jmevar.h31
-rw-r--r--sys/dev/mii/jmphy.c39
-rw-r--r--sys/dev/mii/jmphyreg.h9
5 files changed, 403 insertions, 36 deletions
diff --git a/sys/dev/jme/if_jme.c b/sys/dev/jme/if_jme.c
index c24c522..0ef4260 100644
--- a/sys/dev/jme/if_jme.c
+++ b/sys/dev/jme/if_jme.c
@@ -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_softc *);
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)
{
diff --git a/sys/dev/jme/if_jmereg.h b/sys/dev/jme/if_jmereg.h
index c687098..f7dfb12 100644
--- a/sys/dev/jme/if_jmereg.h
+++ b/sys/dev/jme/if_jmereg.h
@@ -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
diff --git a/sys/dev/jme/if_jmevar.h b/sys/dev/jme/if_jmevar.h
index bee0ab1..3d6736d5 100644
--- a/sys/dev/jme/if_jmevar.h
+++ b/sys/dev/jme/if_jmevar.h
@@ -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;
diff --git a/sys/dev/mii/jmphy.c b/sys/dev/mii/jmphy.c
index 00611c4..3347a29 100644
--- a/sys/dev/mii/jmphy.c
+++ b/sys/dev/mii/jmphy.c
@@ -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
diff --git a/sys/dev/mii/jmphyreg.h b/sys/dev/mii/jmphyreg.h
index 743ae29..ec668ad 100644
--- a/sys/dev/mii/jmphyreg.h
+++ b/sys/dev/mii/jmphyreg.h
@@ -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_ */
OpenPOWER on IntegriCloud