+static int
+jme_get_regs_len(struct net_device *netdev)
+{
+ return 0x400;
+}
+
+static void
+mmapio_memcpy(struct jme_adapter *jme, __u32 *p, __u32 reg, int len)
+{
+ int i;
+
+ for(i = 0 ; i < len ; i += 4)
+ p[i >> 2] = jread32(jme, reg + i);
+
+}
+
+static void
+jme_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
+{
+ struct jme_adapter *jme = netdev_priv(netdev);
+ __u32 *p32 = (__u32*)p;
+
+ memset(p, 0, 0x400);
+
+ regs->version = 1;
+ mmapio_memcpy(jme, p32, JME_MAC, JME_MAC_LEN);
+
+ p32 += 0x100 >> 2;
+ mmapio_memcpy(jme, p32, JME_PHY, JME_PHY_LEN);
+
+ p32 += 0x100 >> 2;
+ mmapio_memcpy(jme, p32, JME_MISC, JME_MISC_LEN);
+
+ p32 += 0x100 >> 2;
+ mmapio_memcpy(jme, p32, JME_RSS, JME_RSS_LEN);
+
+}
+
+static int
+jme_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd)
+{
+ struct jme_adapter *jme = netdev_priv(netdev);
+
+ ecmd->use_adaptive_rx_coalesce = true;
+ ecmd->tx_coalesce_usecs = PCC_TX_TO;
+ ecmd->tx_max_coalesced_frames = PCC_TX_CNT;
+
+ switch(jme->dpi.cur) {
+ case PCC_P1:
+ ecmd->rx_coalesce_usecs = PCC_P1_TO;
+ ecmd->rx_max_coalesced_frames = PCC_P1_CNT;
+ break;
+ case PCC_P2:
+ ecmd->rx_coalesce_usecs = PCC_P2_TO;
+ ecmd->rx_max_coalesced_frames = PCC_P2_CNT;
+ break;
+ case PCC_P3:
+ ecmd->rx_coalesce_usecs = PCC_P3_TO;
+ ecmd->rx_max_coalesced_frames = PCC_P3_CNT;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * It's not actually for coalesce.
+ * It changes internell FIFO related setting for testing.
+ */
+static int
+jme_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd)
+{
+ struct jme_adapter *jme = netdev_priv(netdev);
+
+ if(ecmd->use_adaptive_rx_coalesce &&
+ ecmd->use_adaptive_tx_coalesce &&
+ ecmd->rx_coalesce_usecs == 250 &&
+ (ecmd->rx_max_coalesced_frames_low == 16 ||
+ ecmd->rx_max_coalesced_frames_low == 32 ||
+ ecmd->rx_max_coalesced_frames_low == 64 ||
+ ecmd->rx_max_coalesced_frames_low == 128)) {
+ jme->reg_rxcs &= ~RXCS_FIFOTHNP;
+ switch(ecmd->rx_max_coalesced_frames_low) {
+ case 16:
+ jme->reg_rxcs |= RXCS_FIFOTHNP_16QW;
+ break;
+ case 32:
+ jme->reg_rxcs |= RXCS_FIFOTHNP_32QW;
+ break;
+ case 64:
+ jme->reg_rxcs |= RXCS_FIFOTHNP_64QW;
+ break;
+ case 128:
+ default:
+ jme->reg_rxcs |= RXCS_FIFOTHNP_128QW;
+ }
+ jme_restart_rx_engine(jme);
+ }
+ else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void
+jme_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *ecmd)
+{
+ struct jme_adapter *jme = netdev_priv(netdev);
+ unsigned long flags;
+ __u32 val;
+
+ ecmd->tx_pause = (jme->reg_txpfc & TXPFC_PF_EN) != 0;
+ ecmd->rx_pause = (jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0;
+
+ spin_lock_irqsave(&jme->phy_lock, flags);
+ val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE);
+ spin_unlock_irqrestore(&jme->phy_lock, flags);
+ ecmd->autoneg = (val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0;
+}
+
+static int
+jme_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *ecmd)
+{
+ struct jme_adapter *jme = netdev_priv(netdev);
+ unsigned long flags;
+ __u32 val;
+
+ if( ((jme->reg_txpfc & TXPFC_PF_EN) != 0) !=
+ (ecmd->tx_pause != 0)) {
+
+ if(ecmd->tx_pause)
+ jme->reg_txpfc |= TXPFC_PF_EN;
+ else
+ jme->reg_txpfc &= ~TXPFC_PF_EN;
+
+ jwrite32(jme, JME_TXPFC, jme->reg_txpfc);
+ }
+
+ spin_lock_irqsave(&jme->rxmcs_lock, flags);
+ if( ((jme->reg_rxmcs & RXMCS_FLOWCTRL) != 0) !=
+ (ecmd->rx_pause != 0)) {
+
+ if(ecmd->rx_pause)
+ jme->reg_rxmcs |= RXMCS_FLOWCTRL;
+ else
+ jme->reg_rxmcs &= ~RXMCS_FLOWCTRL;
+
+ jwrite32(jme, JME_RXMCS, jme->reg_rxmcs);
+ }
+ spin_unlock_irqrestore(&jme->rxmcs_lock, flags);
+
+ spin_lock_irqsave(&jme->phy_lock, flags);
+ val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE);
+ if( ((val & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) != 0) !=
+ (ecmd->autoneg != 0)) {
+
+ if(ecmd->autoneg)
+ val |= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+ else
+ val &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+
+ jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_ADVERTISE, val);
+ }
+ spin_unlock_irqrestore(&jme->phy_lock, flags);
+
+ return 0;
+}
+