diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 05a1674..64117f5 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -85,12 +85,14 @@ do {								\
 
 #define HOST_PORT_NUM		0
 #define SLIVER_SIZE		0x40
+#define CPSW_HW_STATS_LEN	36
 
 #define CPSW1_HOST_PORT_OFFSET	0x028
 #define CPSW1_SLAVE_OFFSET	0x050
 #define CPSW1_SLAVE_SIZE	0x040
 #define CPSW1_CPDMA_OFFSET	0x100
 #define CPSW1_STATERAM_OFFSET	0x200
+#define CPSW1_HW_STATS		0x400
 #define CPSW1_CPTS_OFFSET	0x500
 #define CPSW1_ALE_OFFSET	0x600
 #define CPSW1_SLIVER_OFFSET	0x700
@@ -99,6 +101,7 @@ do {								\
 #define CPSW2_SLAVE_OFFSET	0x200
 #define CPSW2_SLAVE_SIZE	0x100
 #define CPSW2_CPDMA_OFFSET	0x800
+#define CPSW2_HW_STATS		0x900
 #define CPSW2_STATERAM_OFFSET	0xa00
 #define CPSW2_CPTS_OFFSET	0xc00
 #define CPSW2_ALE_OFFSET	0xd00
@@ -332,6 +335,7 @@ struct cpsw_priv {
 	struct cpsw_platform_data	data;
 	struct cpsw_ss_regs __iomem	*regs;
 	struct cpsw_wr_regs __iomem	*wr_regs;
+	void __iomem			*hw_stats;
 	struct cpsw_host_regs __iomem	*host_port_regs;
 	u32				msg_enable;
 	u32				version;
@@ -723,6 +727,64 @@ static int cpsw_set_coalesce(struct net_device *ndev,
 	return 0;
 }
 
+static int cpsw_get_regs_len(struct net_device *ndev)
+{
+	int len;
+
+	len = CPSW_HW_STATS_LEN * sizeof(u32);
+	len += 2 * sizeof(struct cpdma_chan_stats);
+
+	return len;
+}
+
+static void cpsw_get_regs(struct net_device *ndev,
+			  struct ethtool_regs *regs, void *p)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+	struct cpdma_chan_stats	dma_stats;
+	u32 *reg = p;
+	int i;
+
+	/* update CPSW IP version */
+	regs->version = priv->version;
+
+	/* Packet Tx/Rx statistics */
+	for (i = 0; i < CPSW_HW_STATS_LEN; i++)
+		reg[i] = readl(((u32 *)priv->hw_stats) + i);
+
+	/* Rx DMA statistics */
+	cpdma_chan_get_stats(priv->rxch, &dma_stats);
+	reg[i++] = dma_stats.head_enqueue;
+	reg[i++] = dma_stats.tail_enqueue;
+	reg[i++] = dma_stats.pad_enqueue;
+	reg[i++] = dma_stats.misqueued;
+	reg[i++] = dma_stats.desc_alloc_fail;
+	reg[i++] = dma_stats.pad_alloc_fail;
+	reg[i++] = dma_stats.runt_receive_buff;
+	reg[i++] = dma_stats.runt_transmit_buff;
+	reg[i++] = dma_stats.empty_dequeue;
+	reg[i++] = dma_stats.busy_dequeue;
+	reg[i++] = dma_stats.good_dequeue;
+	reg[i++] = dma_stats.requeue;
+	reg[i++] = dma_stats.teardown_dequeue;
+
+	/* Tx DMA statistics */
+	cpdma_chan_get_stats(priv->txch, &dma_stats);
+	reg[i++] = dma_stats.head_enqueue;
+	reg[i++] = dma_stats.tail_enqueue;
+	reg[i++] = dma_stats.pad_enqueue;
+	reg[i++] = dma_stats.misqueued;
+	reg[i++] = dma_stats.desc_alloc_fail;
+	reg[i++] = dma_stats.pad_alloc_fail;
+	reg[i++] = dma_stats.runt_receive_buff;
+	reg[i++] = dma_stats.runt_transmit_buff;
+	reg[i++] = dma_stats.empty_dequeue;
+	reg[i++] = dma_stats.busy_dequeue;
+	reg[i++] = dma_stats.good_dequeue;
+	reg[i++] = dma_stats.requeue;
+	reg[i++] = dma_stats.teardown_dequeue;
+}
+
 static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)
 {
 	static char *leader = "........................................";
@@ -1344,9 +1406,10 @@ static void cpsw_get_drvinfo(struct net_device *ndev,
 {
 	struct cpsw_priv *priv = netdev_priv(ndev);
 
-	strlcpy(info->driver, "TI CPSW Driver v1.0", sizeof(info->driver));
+	strlcpy(info->driver, "cpsw", sizeof(info->driver));
 	strlcpy(info->version, "1.0", sizeof(info->version));
 	strlcpy(info->bus_info, priv->pdev->name, sizeof(info->bus_info));
+	info->regdump_len = cpsw_get_regs_len(ndev);
 }
 
 static u32 cpsw_get_msglevel(struct net_device *ndev)
@@ -1426,6 +1489,8 @@ static const struct ethtool_ops cpsw_ethtool_ops = {
 	.set_settings	= cpsw_set_settings,
 	.get_coalesce	= cpsw_get_coalesce,
 	.set_coalesce	= cpsw_set_coalesce,
+	.get_regs_len	= cpsw_get_regs_len,
+	.get_regs	= cpsw_get_regs,
 };
 
 static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
@@ -1623,6 +1688,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
 	priv_sl2->host_port = priv->host_port;
 	priv_sl2->host_port_regs = priv->host_port_regs;
 	priv_sl2->wr_regs = priv->wr_regs;
+	priv_sl2->hw_stats = priv->hw_stats;
 	priv_sl2->dma = priv->dma;
 	priv_sl2->txch = priv->txch;
 	priv_sl2->rxch = priv->rxch;
@@ -1780,7 +1846,8 @@ static int cpsw_probe(struct platform_device *pdev)
 	switch (priv->version) {
 	case CPSW_VERSION_1:
 		priv->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET;
-		priv->cpts->reg       = ss_regs + CPSW1_CPTS_OFFSET;
+		priv->hw_stats	     = ss_regs + CPSW1_HW_STATS;
+		priv->cpts->reg      = ss_regs + CPSW1_CPTS_OFFSET;
 		dma_params.dmaregs   = ss_regs + CPSW1_CPDMA_OFFSET;
 		dma_params.txhdp     = ss_regs + CPSW1_STATERAM_OFFSET;
 		ale_params.ale_regs  = ss_regs + CPSW1_ALE_OFFSET;
@@ -1791,7 +1858,8 @@ static int cpsw_probe(struct platform_device *pdev)
 		break;
 	case CPSW_VERSION_2:
 		priv->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET;
-		priv->cpts->reg       = ss_regs + CPSW2_CPTS_OFFSET;
+		priv->hw_stats	     = ss_regs + CPSW2_HW_STATS;
+		priv->cpts->reg      = ss_regs + CPSW2_CPTS_OFFSET;
 		dma_params.dmaregs   = ss_regs + CPSW2_CPDMA_OFFSET;
 		dma_params.txhdp     = ss_regs + CPSW2_STATERAM_OFFSET;
 		ale_params.ale_regs  = ss_regs + CPSW2_ALE_OFFSET;
