diff options
Diffstat (limited to 'sys/dev/jme/if_jme.c')
-rw-r--r-- | sys/dev/jme/if_jme.c | 324 |
1 files changed, 268 insertions, 56 deletions
diff --git a/sys/dev/jme/if_jme.c b/sys/dev/jme/if_jme.c index 8a8e931..0fd5b8c 100644 --- a/sys/dev/jme/if_jme.c +++ b/sys/dev/jme/if_jme.c @@ -64,7 +64,6 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> -#include <machine/atomic.h> #include <machine/bus.h> #include <machine/in_cksum.h> @@ -98,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); @@ -111,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); @@ -125,8 +126,8 @@ static void jme_setwol(struct jme_softc *); static int jme_suspend(device_t); static int jme_resume(device_t); static int jme_encap(struct jme_softc *, struct mbuf **); -static void jme_tx_task(void *, int); static void jme_start(struct ifnet *); +static void jme_start_locked(struct ifnet *); static void jme_watchdog(struct jme_softc *); static int jme_ioctl(struct ifnet *, u_long, caddr_t); static void jme_mac_config(struct jme_softc *); @@ -153,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); @@ -433,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) { @@ -447,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; @@ -457,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]; @@ -535,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); @@ -637,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; } @@ -649,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); } /* @@ -676,7 +780,7 @@ jme_attach(device_t dev) /* Set max allowable DMA size. */ if (pci_find_extcap(dev, PCIY_EXPRESS, &i) == 0) { sc->jme_flags |= JME_FLAG_PCIE; - burst = pci_read_config(dev, i + 0x08, 2); + burst = pci_read_config(dev, i + PCIR_EXPRESS_DEVICE_CTL, 2); if (bootverbose) { device_printf(dev, "Read request size : %d bytes.\n", 128 << ((burst >> 12) & 0x07)); @@ -729,10 +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_phyaddr, MII_OFFSET_ANY, - MIIF_DOPAUSE); + jme_mediastatus, BMSR_DEFCAPMASK, + sc->jme_flags & JME_FLAG_FPGA ? MII_PHY_ANY : sc->jme_phyaddr, + MII_OFFSET_ANY, mii_flags); if (error != 0) { device_printf(dev, "attaching PHYs failed\n"); goto fail; @@ -771,7 +882,6 @@ jme_attach(device_t dev) ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); /* Create local taskq. */ - TASK_INIT(&sc->jme_tx_task, 1, jme_tx_task, ifp); sc->jme_tq = taskqueue_create_fast("jme_taskq", M_WAITOK, taskqueue_thread_enqueue, &sc->jme_tq); if (sc->jme_tq == NULL) { @@ -823,8 +933,10 @@ jme_detach(device_t dev) JME_UNLOCK(sc); callout_drain(&sc->jme_tick_ch); 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); } @@ -854,10 +966,12 @@ jme_detach(device_t dev) } } - bus_release_resources(dev, sc->jme_irq_spec, sc->jme_irq); + if (sc->jme_irq[0] != NULL) + bus_release_resources(dev, sc->jme_irq_spec, sc->jme_irq); if ((sc->jme_flags & (JME_FLAG_MSIX | JME_FLAG_MSI)) != 0) pci_release_msi(dev); - bus_release_resources(dev, sc->jme_res_spec, sc->jme_res); + if (sc->jme_res[0] != NULL) + bus_release_resources(dev, sc->jme_res_spec, sc->jme_res); mtx_destroy(&sc->jme_mtx); return (0); @@ -1483,9 +1597,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; } @@ -1517,8 +1633,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); } } @@ -1556,6 +1671,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; @@ -1753,16 +1870,18 @@ jme_encap(struct jme_softc *sc, struct mbuf **m_head) } static void -jme_tx_task(void *arg, int pending) +jme_start(struct ifnet *ifp) { - struct ifnet *ifp; + struct jme_softc *sc; - ifp = (struct ifnet *)arg; - jme_start(ifp); + sc = ifp->if_softc; + JME_LOCK(sc); + jme_start_locked(ifp); + JME_UNLOCK(sc); } static void -jme_start(struct ifnet *ifp) +jme_start_locked(struct ifnet *ifp) { struct jme_softc *sc; struct mbuf *m_head; @@ -1770,16 +1889,14 @@ jme_start(struct ifnet *ifp) sc = ifp->if_softc; - JME_LOCK(sc); + JME_LOCK_ASSERT(sc); if (sc->jme_cdata.jme_tx_cnt >= JME_TX_DESC_HIWAT) jme_txeof(sc); if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != - IFF_DRV_RUNNING || (sc->jme_flags & JME_FLAG_LINK) == 0) { - JME_UNLOCK(sc); + IFF_DRV_RUNNING || (sc->jme_flags & JME_FLAG_LINK) == 0) return; - } for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); @@ -1818,8 +1935,6 @@ jme_start(struct ifnet *ifp) /* Set a timeout in case the chip goes out to lunch. */ sc->jme_watchdog_timer = JME_TX_TIMEOUT; } - - JME_UNLOCK(sc); } static void @@ -1845,7 +1960,7 @@ jme_watchdog(struct jme_softc *sc) if_printf(sc->jme_ifp, "watchdog timeout (missed Tx interrupts) -- recovering\n"); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - taskqueue_enqueue(sc->jme_tq, &sc->jme_tx_task); + jme_start_locked(ifp); return; } @@ -1854,7 +1969,7 @@ jme_watchdog(struct jme_softc *sc) ifp->if_drv_flags &= ~IFF_DRV_RUNNING; jme_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - taskqueue_enqueue(sc->jme_tq, &sc->jme_tx_task); + jme_start_locked(ifp); } static int @@ -2148,10 +2263,8 @@ jme_link_task(void *arg, int pending) /* XXX Drain all queued tasks. */ JME_UNLOCK(sc); taskqueue_drain(sc->jme_tq, &sc->jme_int_task); - taskqueue_drain(sc->jme_tq, &sc->jme_tx_task); JME_LOCK(sc); - jme_rxintr(sc, JME_RX_RING_CNT); if (sc->jme_cdata.jme_rxhead != NULL) m_freem(sc->jme_cdata.jme_rxhead); JME_RXCHAIN_RESET(sc); @@ -2178,10 +2291,10 @@ jme_link_task(void *arg, int pending) /* * Reuse configured Rx descriptors and reset - * procuder/consumer index. + * producer/consumer index. */ sc->jme_cdata.jme_rx_cons = 0; - atomic_set_int(&sc->jme_morework, 0); + sc->jme_morework = 0; jme_init_tx_ring(sc); /* Initialize shadow status block. */ jme_init_ssb(sc); @@ -2208,6 +2321,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; @@ -2250,11 +2370,11 @@ jme_int_task(void *arg, int pending) sc = (struct jme_softc *)arg; ifp = sc->jme_ifp; + JME_LOCK(sc); status = CSR_READ_4(sc, JME_INTR_STATUS); - more = atomic_readandclear_int(&sc->jme_morework); - if (more != 0) { + if (sc->jme_morework != 0) { + sc->jme_morework = 0; status |= INTR_RXQ_COAL | INTR_RXQ_COAL_TO; - more = 0; } if ((status & JME_INTRS) == 0 || status == 0xFFFFFFFF) goto done; @@ -2270,7 +2390,7 @@ jme_int_task(void *arg, int pending) if ((status & (INTR_RXQ_COAL | INTR_RXQ_COAL_TO)) != 0) { more = jme_rxintr(sc, sc->jme_process_limit); if (more != 0) - atomic_set_int(&sc->jme_morework, 1); + sc->jme_morework = 1; } if ((status & INTR_RXQ_DESC_EMPTY) != 0) { /* @@ -2285,19 +2405,18 @@ jme_int_task(void *arg, int pending) CSR_WRITE_4(sc, JME_RXCSR, sc->jme_rxcsr | RXCSR_RX_ENB | RXCSR_RXQ_START); } - /* - * Reclaiming Tx buffers are deferred to make jme(4) run - * without locks held. - */ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - taskqueue_enqueue(sc->jme_tq, &sc->jme_tx_task); + jme_start_locked(ifp); } if (more != 0 || (CSR_READ_4(sc, JME_INTR_STATUS) & JME_INTRS) != 0) { taskqueue_enqueue(sc->jme_tq, &sc->jme_int_task); + JME_UNLOCK(sc); return; } done: + JME_UNLOCK(sc); + /* Reenable interrupts. */ CSR_WRITE_4(sc, JME_INTR_MASK_SET, JME_INTRS); } @@ -2399,6 +2518,8 @@ jme_rxeof(struct jme_softc *sc) uint32_t flags, status; int cons, count, nsegs; + JME_LOCK_ASSERT(sc); + ifp = sc->jme_ifp; cons = sc->jme_cdata.jme_rx_cons; @@ -2510,7 +2631,9 @@ jme_rxeof(struct jme_softc *sc) ifp->if_ipackets++; /* Pass it on. */ + JME_UNLOCK(sc); (*ifp->if_input)(ifp, m); + JME_LOCK(sc); /* Reset mbuf chains. */ JME_RXCHAIN_RESET(sc); @@ -2587,13 +2710,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 @@ -2612,7 +2767,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; @@ -2648,10 +2802,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. @@ -2789,6 +2940,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)); @@ -2980,7 +3155,7 @@ jme_init_rx_ring(struct jme_softc *sc) sc->jme_cdata.jme_rx_cons = 0; JME_RXCHAIN_RESET(sc); - atomic_set_int(&sc->jme_morework, 0); + sc->jme_morework = 0; rd = &sc->jme_rdata; bzero(rd->jme_rx_ring, JME_RX_RING_SIZE); @@ -3194,6 +3369,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) { |