diff options
author | yongari <yongari@FreeBSD.org> | 2010-12-18 23:52:50 +0000 |
---|---|---|
committer | yongari <yongari@FreeBSD.org> | 2010-12-18 23:52:50 +0000 |
commit | b52a1b882d10997e24ae7e5a9eebb4967b9cdf11 (patch) | |
tree | 5b530523b866e864753791f3f6a60d3de5cc22b6 /sys | |
parent | f652d40af333a97c256711fc5b849806fa38861b (diff) | |
download | FreeBSD-src-b52a1b882d10997e24ae7e5a9eebb4967b9cdf11.zip FreeBSD-src-b52a1b882d10997e24ae7e5a9eebb4967b9cdf11.tar.gz |
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
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/jme/if_jme.c | 255 | ||||
-rw-r--r-- | sys/dev/jme/if_jmereg.h | 105 | ||||
-rw-r--r-- | sys/dev/jme/if_jmevar.h | 31 | ||||
-rw-r--r-- | sys/dev/mii/jmphy.c | 39 | ||||
-rw-r--r-- | sys/dev/mii/jmphyreg.h | 9 |
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_ */ |