diff options
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_ */ |