|
@@ -137,9 +137,6 @@ static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
|
|
|
[TSU_POST3] = 0x0078,
|
|
|
[TSU_POST4] = 0x007c,
|
|
|
[TSU_ADRH0] = 0x0100,
|
|
|
- [TSU_ADRL0] = 0x0104,
|
|
|
- [TSU_ADRH31] = 0x01f8,
|
|
|
- [TSU_ADRL31] = 0x01fc,
|
|
|
|
|
|
[TXNLCR0] = 0x0080,
|
|
|
[TXALCR0] = 0x0084,
|
|
@@ -206,9 +203,6 @@ static const u16 sh_eth_offset_fast_rz[SH_ETH_MAX_REGISTER_OFFSET] = {
|
|
|
[TSU_ADSBSY] = 0x0060,
|
|
|
[TSU_TEN] = 0x0064,
|
|
|
[TSU_ADRH0] = 0x0100,
|
|
|
- [TSU_ADRL0] = 0x0104,
|
|
|
- [TSU_ADRH31] = 0x01f8,
|
|
|
- [TSU_ADRL31] = 0x01fc,
|
|
|
|
|
|
[TXNLCR0] = 0x0080,
|
|
|
[TXALCR0] = 0x0084,
|
|
@@ -405,8 +399,6 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
|
|
|
[FWALCR1] = 0x00b4,
|
|
|
|
|
|
[TSU_ADRH0] = 0x0100,
|
|
|
- [TSU_ADRL0] = 0x0104,
|
|
|
- [TSU_ADRL31] = 0x01fc,
|
|
|
};
|
|
|
|
|
|
static void sh_eth_rcv_snd_disable(struct net_device *ndev);
|
|
@@ -601,6 +593,7 @@ static struct sh_eth_cpu_data sh7757_data = {
|
|
|
.no_ade = 1,
|
|
|
.rpadir = 1,
|
|
|
.rpadir_value = 2 << 16,
|
|
|
+ .rtrate = 1,
|
|
|
};
|
|
|
|
|
|
#define SH_GIGA_ETH_BASE 0xfee00000UL
|
|
@@ -1945,6 +1938,192 @@ error_exit:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/* If it is ever necessary to increase SH_ETH_REG_DUMP_MAX_REGS, the
|
|
|
+ * version must be bumped as well. Just adding registers up to that
|
|
|
+ * limit is fine, as long as the existing register indices don't
|
|
|
+ * change.
|
|
|
+ */
|
|
|
+#define SH_ETH_REG_DUMP_VERSION 1
|
|
|
+#define SH_ETH_REG_DUMP_MAX_REGS 256
|
|
|
+
|
|
|
+static size_t __sh_eth_get_regs(struct net_device *ndev, u32 *buf)
|
|
|
+{
|
|
|
+ struct sh_eth_private *mdp = netdev_priv(ndev);
|
|
|
+ struct sh_eth_cpu_data *cd = mdp->cd;
|
|
|
+ u32 *valid_map;
|
|
|
+ size_t len;
|
|
|
+
|
|
|
+ BUILD_BUG_ON(SH_ETH_MAX_REGISTER_OFFSET > SH_ETH_REG_DUMP_MAX_REGS);
|
|
|
+
|
|
|
+ /* Dump starts with a bitmap that tells ethtool which
|
|
|
+ * registers are defined for this chip.
|
|
|
+ */
|
|
|
+ len = DIV_ROUND_UP(SH_ETH_REG_DUMP_MAX_REGS, 32);
|
|
|
+ if (buf) {
|
|
|
+ valid_map = buf;
|
|
|
+ buf += len;
|
|
|
+ } else {
|
|
|
+ valid_map = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Add a register to the dump, if it has a defined offset.
|
|
|
+ * This automatically skips most undefined registers, but for
|
|
|
+ * some it is also necessary to check a capability flag in
|
|
|
+ * struct sh_eth_cpu_data.
|
|
|
+ */
|
|
|
+#define mark_reg_valid(reg) valid_map[reg / 32] |= 1U << (reg % 32)
|
|
|
+#define add_reg_from(reg, read_expr) do { \
|
|
|
+ if (mdp->reg_offset[reg] != SH_ETH_OFFSET_INVALID) { \
|
|
|
+ if (buf) { \
|
|
|
+ mark_reg_valid(reg); \
|
|
|
+ *buf++ = read_expr; \
|
|
|
+ } \
|
|
|
+ ++len; \
|
|
|
+ } \
|
|
|
+ } while (0)
|
|
|
+#define add_reg(reg) add_reg_from(reg, sh_eth_read(ndev, reg))
|
|
|
+#define add_tsu_reg(reg) add_reg_from(reg, sh_eth_tsu_read(mdp, reg))
|
|
|
+
|
|
|
+ add_reg(EDSR);
|
|
|
+ add_reg(EDMR);
|
|
|
+ add_reg(EDTRR);
|
|
|
+ add_reg(EDRRR);
|
|
|
+ add_reg(EESR);
|
|
|
+ add_reg(EESIPR);
|
|
|
+ add_reg(TDLAR);
|
|
|
+ add_reg(TDFAR);
|
|
|
+ add_reg(TDFXR);
|
|
|
+ add_reg(TDFFR);
|
|
|
+ add_reg(RDLAR);
|
|
|
+ add_reg(RDFAR);
|
|
|
+ add_reg(RDFXR);
|
|
|
+ add_reg(RDFFR);
|
|
|
+ add_reg(TRSCER);
|
|
|
+ add_reg(RMFCR);
|
|
|
+ add_reg(TFTR);
|
|
|
+ add_reg(FDR);
|
|
|
+ add_reg(RMCR);
|
|
|
+ add_reg(TFUCR);
|
|
|
+ add_reg(RFOCR);
|
|
|
+ if (cd->rmiimode)
|
|
|
+ add_reg(RMIIMODE);
|
|
|
+ add_reg(FCFTR);
|
|
|
+ if (cd->rpadir)
|
|
|
+ add_reg(RPADIR);
|
|
|
+ if (!cd->no_trimd)
|
|
|
+ add_reg(TRIMD);
|
|
|
+ add_reg(ECMR);
|
|
|
+ add_reg(ECSR);
|
|
|
+ add_reg(ECSIPR);
|
|
|
+ add_reg(PIR);
|
|
|
+ if (!cd->no_psr)
|
|
|
+ add_reg(PSR);
|
|
|
+ add_reg(RDMLR);
|
|
|
+ add_reg(RFLR);
|
|
|
+ add_reg(IPGR);
|
|
|
+ if (cd->apr)
|
|
|
+ add_reg(APR);
|
|
|
+ if (cd->mpr)
|
|
|
+ add_reg(MPR);
|
|
|
+ add_reg(RFCR);
|
|
|
+ add_reg(RFCF);
|
|
|
+ if (cd->tpauser)
|
|
|
+ add_reg(TPAUSER);
|
|
|
+ add_reg(TPAUSECR);
|
|
|
+ add_reg(GECMR);
|
|
|
+ if (cd->bculr)
|
|
|
+ add_reg(BCULR);
|
|
|
+ add_reg(MAHR);
|
|
|
+ add_reg(MALR);
|
|
|
+ add_reg(TROCR);
|
|
|
+ add_reg(CDCR);
|
|
|
+ add_reg(LCCR);
|
|
|
+ add_reg(CNDCR);
|
|
|
+ add_reg(CEFCR);
|
|
|
+ add_reg(FRECR);
|
|
|
+ add_reg(TSFRCR);
|
|
|
+ add_reg(TLFRCR);
|
|
|
+ add_reg(CERCR);
|
|
|
+ add_reg(CEECR);
|
|
|
+ add_reg(MAFCR);
|
|
|
+ if (cd->rtrate)
|
|
|
+ add_reg(RTRATE);
|
|
|
+ if (cd->hw_crc)
|
|
|
+ add_reg(CSMR);
|
|
|
+ if (cd->select_mii)
|
|
|
+ add_reg(RMII_MII);
|
|
|
+ add_reg(ARSTR);
|
|
|
+ if (cd->tsu) {
|
|
|
+ add_tsu_reg(TSU_CTRST);
|
|
|
+ add_tsu_reg(TSU_FWEN0);
|
|
|
+ add_tsu_reg(TSU_FWEN1);
|
|
|
+ add_tsu_reg(TSU_FCM);
|
|
|
+ add_tsu_reg(TSU_BSYSL0);
|
|
|
+ add_tsu_reg(TSU_BSYSL1);
|
|
|
+ add_tsu_reg(TSU_PRISL0);
|
|
|
+ add_tsu_reg(TSU_PRISL1);
|
|
|
+ add_tsu_reg(TSU_FWSL0);
|
|
|
+ add_tsu_reg(TSU_FWSL1);
|
|
|
+ add_tsu_reg(TSU_FWSLC);
|
|
|
+ add_tsu_reg(TSU_QTAG0);
|
|
|
+ add_tsu_reg(TSU_QTAG1);
|
|
|
+ add_tsu_reg(TSU_QTAGM0);
|
|
|
+ add_tsu_reg(TSU_QTAGM1);
|
|
|
+ add_tsu_reg(TSU_FWSR);
|
|
|
+ add_tsu_reg(TSU_FWINMK);
|
|
|
+ add_tsu_reg(TSU_ADQT0);
|
|
|
+ add_tsu_reg(TSU_ADQT1);
|
|
|
+ add_tsu_reg(TSU_VTAG0);
|
|
|
+ add_tsu_reg(TSU_VTAG1);
|
|
|
+ add_tsu_reg(TSU_ADSBSY);
|
|
|
+ add_tsu_reg(TSU_TEN);
|
|
|
+ add_tsu_reg(TSU_POST1);
|
|
|
+ add_tsu_reg(TSU_POST2);
|
|
|
+ add_tsu_reg(TSU_POST3);
|
|
|
+ add_tsu_reg(TSU_POST4);
|
|
|
+ if (mdp->reg_offset[TSU_ADRH0] != SH_ETH_OFFSET_INVALID) {
|
|
|
+ /* This is the start of a table, not just a single
|
|
|
+ * register.
|
|
|
+ */
|
|
|
+ if (buf) {
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ mark_reg_valid(TSU_ADRH0);
|
|
|
+ for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES * 2; i++)
|
|
|
+ *buf++ = ioread32(
|
|
|
+ mdp->tsu_addr +
|
|
|
+ mdp->reg_offset[TSU_ADRH0] +
|
|
|
+ i * 4);
|
|
|
+ }
|
|
|
+ len += SH_ETH_TSU_CAM_ENTRIES * 2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+#undef mark_reg_valid
|
|
|
+#undef add_reg_from
|
|
|
+#undef add_reg
|
|
|
+#undef add_tsu_reg
|
|
|
+
|
|
|
+ return len * 4;
|
|
|
+}
|
|
|
+
|
|
|
+static int sh_eth_get_regs_len(struct net_device *ndev)
|
|
|
+{
|
|
|
+ return __sh_eth_get_regs(ndev, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+static void sh_eth_get_regs(struct net_device *ndev, struct ethtool_regs *regs,
|
|
|
+ void *buf)
|
|
|
+{
|
|
|
+ struct sh_eth_private *mdp = netdev_priv(ndev);
|
|
|
+
|
|
|
+ regs->version = SH_ETH_REG_DUMP_VERSION;
|
|
|
+
|
|
|
+ pm_runtime_get_sync(&mdp->pdev->dev);
|
|
|
+ __sh_eth_get_regs(ndev, buf);
|
|
|
+ pm_runtime_put_sync(&mdp->pdev->dev);
|
|
|
+}
|
|
|
+
|
|
|
static int sh_eth_nway_reset(struct net_device *ndev)
|
|
|
{
|
|
|
struct sh_eth_private *mdp = netdev_priv(ndev);
|
|
@@ -2090,6 +2269,8 @@ static int sh_eth_set_ringparam(struct net_device *ndev,
|
|
|
static const struct ethtool_ops sh_eth_ethtool_ops = {
|
|
|
.get_settings = sh_eth_get_settings,
|
|
|
.set_settings = sh_eth_set_settings,
|
|
|
+ .get_regs_len = sh_eth_get_regs_len,
|
|
|
+ .get_regs = sh_eth_get_regs,
|
|
|
.nway_reset = sh_eth_nway_reset,
|
|
|
.get_msglevel = sh_eth_get_msglevel,
|
|
|
.set_msglevel = sh_eth_set_msglevel,
|