diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index a7cb74a..c14f99f 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -18,6 +18,8 @@
 #include <linux/spinlock.h>
 #include <linux/hashtable.h>
 #include <linux/crc32.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/sort.h>
 #include <linux/random.h>
 #include <linux/netdevice.h>
@@ -43,6 +45,8 @@
 
 static const char rocker_driver_name[] = "rocker";
 
+static struct dentry *rocker_dbg_root;
+
 static const struct pci_device_id rocker_pci_id_table[] = {
 	{PCI_VDEVICE(REDHAT, PCI_DEVICE_ID_REDHAT_ROCKER), 0},
 	{0, }
@@ -238,6 +242,7 @@ struct rocker {
 	struct {
 		u64 id;
 	} hw;
+	struct dentry *dbg_dir;
 	spinlock_t cmd_ring_lock;		/* for cmd ring accesses */
 	struct rocker_dma_ring_info cmd_ring;
 	struct rocker_dma_ring_info event_ring;
@@ -2363,22 +2368,351 @@ static int rocker_cmd_group_tbl_del(const struct rocker_port *rocker_port,
  * Flow, group, FDB, internal VLAN and neigh tables
  ***************************************************/
 
+static int dbg_of_dpa_flow_tbl_read(struct seq_file *file, void *data)
+{
+	struct rocker *rocker = file->private;
+	struct rocker_flow_tbl_entry *entry;
+	unsigned long flags;
+	int bkt;
+
+	char *tbl_id_to_str(enum rocker_of_dpa_table_id tbl_id)
+	{
+		switch (tbl_id) {
+		case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT:
+			return "ig_port";
+		case ROCKER_OF_DPA_TABLE_ID_VLAN:
+			return "vlan";
+		case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC:
+			return "term_mac";
+		case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING:
+			return "ucast_routing";
+		case ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING:
+			return "mcast_routing";
+		case ROCKER_OF_DPA_TABLE_ID_BRIDGING:
+			return "bridge";
+		case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY:
+			return "acl";
+		}
+		return "unknown";
+	}
+
+	spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
+
+	hash_for_each(rocker->flow_tbl, bkt, entry, entry) {
+		struct rocker_flow_tbl_key *key = &entry->key;
+
+		seq_printf(file, "cmd %d cookie %llx\tpriority %-3d tbl %-15s",
+			   entry->cmd, entry->cookie,
+			   key->priority,
+			   tbl_id_to_str(key->tbl_id));
+		switch (key->tbl_id) {
+		case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT:
+			seq_printf(file, "in_pport %d",
+				   key->ig_port.in_pport);
+			if (key->ig_port.in_pport_mask != 0xffffffff)
+				seq_printf(file, "/0x%08x",
+					   key->ig_port.in_pport_mask);
+			seq_printf(file, " goto_tbl %s\n",
+				   tbl_id_to_str(key->ig_port.goto_tbl));
+			break;
+		case ROCKER_OF_DPA_TABLE_ID_VLAN:
+			seq_printf(file, "in_pport %d vlan_id %d",
+				   key->vlan.in_pport,
+				   be16_to_cpu(key->vlan.vlan_id));
+			if (key->vlan.vlan_id_mask != 0xffff)
+				seq_printf(file, "/0x%04x",
+					   be16_to_cpu(key->vlan.vlan_id_mask));
+			seq_printf(file, " goto_tbl %s untagged %d new_vlan_id %d\n",
+				   tbl_id_to_str(key->vlan.goto_tbl),
+				   key->vlan.untagged,
+				   be16_to_cpu(key->vlan.new_vlan_id));
+			break;
+		case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC:
+			seq_printf(file, "in_pport %d",
+				   key->term_mac.in_pport);
+			if (key->term_mac.in_pport_mask != 0xffffffff)
+				seq_printf(file, "/0x%08x",
+					   key->term_mac.in_pport_mask);
+			seq_printf(file, " eth_type 0x%04x %pM",
+				   be16_to_cpu(key->term_mac.eth_type),
+				   key->term_mac.eth_dst);
+			if (!is_broadcast_ether_addr(
+			    key->term_mac.eth_dst_mask))
+				seq_printf(file, "/%pM",
+					   key->term_mac.eth_dst_mask);
+			seq_printf(file, " vlan_id %d",
+				   be16_to_cpu(key->term_mac.vlan_id));
+			if (key->term_mac.vlan_id_mask != 0xffff)
+				seq_printf(file, "/0x%04x",
+					   be16_to_cpu(
+					   key->term_mac.vlan_id_mask));
+			seq_printf(file, " goto_tbl %s copy_to_cpu %d\n",
+				   tbl_id_to_str(key->term_mac.goto_tbl),
+				   key->term_mac.copy_to_cpu);
+			break;
+		case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING:
+			seq_printf(file, "eth_type 0x%04x %pI4",
+				   be16_to_cpu(key->ucast_routing.eth_type),
+				   &key->ucast_routing.dst4);
+			if (key->ucast_routing.dst4_mask != 0xffffffff)
+				seq_printf(file, "/%pI4",
+					   &key->ucast_routing.dst4_mask);
+			seq_printf(file, " goto_tbl %s group_id 0x%08x\n",
+				   tbl_id_to_str(key->ucast_routing.goto_tbl),
+				   key->ucast_routing.group_id);
+			break;
+		case ROCKER_OF_DPA_TABLE_ID_BRIDGING:
+			if (key->bridge.has_eth_dst) {
+				seq_printf(file, "%pM",
+					   key->bridge.eth_dst);
+				if (key->bridge.has_eth_dst_mask)
+					seq_printf(file, "/%pM ",
+						   key->bridge.eth_dst_mask);
+				else
+					seq_puts(file, " ");
+			}
+			seq_printf(file, "vlan_id %d tunnel_id %d goto_tbl %s group_id 0x%08x copy_to_cpu %d\n",
+				   be16_to_cpu(key->bridge.vlan_id),
+				   key->bridge.tunnel_id,
+				   tbl_id_to_str(key->bridge.goto_tbl),
+				   key->bridge.group_id,
+				   key->bridge.copy_to_cpu);
+			break;
+		case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY:
+			seq_printf(file, "in_pport %d",
+				   key->acl.in_pport);
+			if (key->acl.in_pport_mask != 0xffffffff)
+				seq_printf(file, "/0x%08x",
+					   key->acl.in_pport_mask);
+			if (!is_zero_ether_addr(key->acl.eth_src)) {
+				seq_printf(file, " %pM",
+					   key->acl.eth_src);
+				if (!is_broadcast_ether_addr(
+				    key->acl.eth_src_mask))
+					seq_printf(file, "/%pM",
+						   key->acl.eth_src_mask);
+			}
+			if (!is_zero_ether_addr(key->acl.eth_dst)) {
+				seq_printf(file, " %pM",
+					   key->acl.eth_dst);
+				if (!is_broadcast_ether_addr(
+				    key->acl.eth_dst_mask))
+					seq_printf(file, "/%pM",
+						   key->acl.eth_dst_mask);
+			}
+			seq_printf(file, " eth_type 0x%04x",
+				   be16_to_cpu(key->acl.eth_type));
+			seq_printf(file, " vlan_id %d",
+				   be16_to_cpu(key->acl.vlan_id));
+			if (key->acl.vlan_id_mask != 0xffff)
+				seq_printf(file, "/0x%04x",
+					   be16_to_cpu(key->acl.vlan_id_mask));
+			seq_printf(file, " ip proto %d", key->acl.ip_proto);
+			if (key->acl.ip_proto_mask != 0xff)
+				seq_printf(file, "/%d", key->acl.ip_proto_mask);
+			seq_printf(file, " ip tos %d", key->acl.ip_tos);
+			if (key->acl.ip_tos_mask != 0xff)
+				seq_printf(file, "/%d", key->acl.ip_tos_mask);
+			seq_printf(file, " group_id 0x%08x\n",
+				   key->acl.group_id);
+			break;
+		default:
+			seq_puts(file, "\n");
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
+
+	return 0;
+}
+
+static int dbg_of_dpa_group_tbl_read(struct seq_file *file, void *data)
+{
+	struct rocker *rocker = file->private;
+	struct rocker_group_tbl_entry *entry;
+	unsigned long flags;
+	u32 *group_id;
+	int bkt;
+	int i;
+
+	spin_lock_irqsave(&rocker->group_tbl_lock, flags);
+
+	hash_for_each(rocker->group_tbl, bkt, entry, entry) {
+		seq_printf(file, "cmd %d group_id 0x%08x",
+			   entry->cmd, entry->group_id);
+		switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
+		case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
+			seq_printf(file, " (L2 interface vlan %d port %d)",
+				   ROCKER_GROUP_VLAN_GET(entry->group_id),
+				   ROCKER_GROUP_PORT_GET(entry->group_id));
+			seq_printf(file, " pop_vlan %d",
+				   entry->l2_interface.pop_vlan);
+			break;
+		case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
+			seq_printf(file, " (L2 rewrite index %d)",
+				   ROCKER_GROUP_INDEX_LONG_GET(
+				   entry->group_id));
+			if (!is_zero_ether_addr(entry->l2_rewrite.eth_src))
+				seq_printf(file, " src %pM",
+					   entry->l2_rewrite.eth_src);
+			if (!is_zero_ether_addr(entry->l2_rewrite.eth_dst))
+				seq_printf(file, " dst %pM",
+					   entry->l2_rewrite.eth_dst);
+			if (entry->l2_rewrite.vlan_id)
+				seq_printf(file, " vlan %d",
+					   be16_to_cpu(
+					   entry->l2_rewrite.vlan_id));
+			seq_printf(file, " group_id 0x%08x",
+				   entry->l2_rewrite.group_id);
+			break;
+		case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
+			seq_printf(file, " (L2 flood vlan %d index %d)",
+				   ROCKER_GROUP_VLAN_GET(entry->group_id),
+				   ROCKER_GROUP_INDEX_GET(entry->group_id));
+			break;
+		case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
+			seq_printf(file, " (L2 multicast vlan %d index %d)",
+				   ROCKER_GROUP_VLAN_GET(entry->group_id),
+				   ROCKER_GROUP_INDEX_GET(entry->group_id));
+			break;
+		case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
+			seq_printf(file, " (L3 unicast index %d)",
+				   ROCKER_GROUP_INDEX_LONG_GET(
+				   entry->group_id));
+			if (!is_zero_ether_addr(entry->l3_unicast.eth_src))
+				seq_printf(file, " src %pM",
+					   entry->l3_unicast.eth_src);
+			if (!is_zero_ether_addr(entry->l3_unicast.eth_dst))
+				seq_printf(file, " dst %pM",
+					   entry->l3_unicast.eth_dst);
+			if (entry->l3_unicast.vlan_id)
+				seq_printf(file, " vlan %d",
+					   be16_to_cpu(
+					   entry->l3_unicast.vlan_id));
+			seq_printf(file, " ttl_check %d",
+				   entry->l3_unicast.ttl_check);
+			seq_printf(file, " group_id 0x%08x",
+				   entry->l3_unicast.group_id);
+			break;
+		}
+		for (i = 0, group_id = entry->group_ids;
+		     i < entry->group_count;
+		     i++, group_id++)
+			seq_printf(file, "%s0x%08x%s",
+				   i == 0 ? " {" : " ",
+				   *group_id,
+				   i + 1 == entry->group_count ? "}" : "");
+		seq_puts(file, "\n");
+	}
+
+	spin_unlock_irqrestore(&rocker->group_tbl_lock, flags);
+
+	return 0;
+}
+
+static int dbg_fdb_tbl_read(struct seq_file *file, void *data)
+{
+	struct rocker *rocker = file->private;
+	struct rocker_fdb_tbl_entry *entry;
+	unsigned long flags;
+	int bkt;
+
+	spin_lock_irqsave(&rocker->fdb_tbl_lock, flags);
+
+	hash_for_each(rocker->fdb_tbl, bkt, entry, entry)
+		seq_printf(file, "learned %d pport %d addr %pM vlan %d\n",
+			   entry->learned, entry->key.pport,
+			   entry->key.addr, be16_to_cpu(entry->key.vlan_id));
+
+	spin_unlock_irqrestore(&rocker->fdb_tbl_lock, flags);
+
+	return 0;
+}
+
+static int dbg_internal_vlan_tbl_read(struct seq_file *file, void *data)
+{
+	struct rocker *rocker = file->private;
+	struct rocker_internal_vlan_tbl_entry *entry;
+	unsigned long flags;
+	int bkt;
+
+	spin_lock_irqsave(&rocker->internal_vlan_tbl_lock, flags);
+
+	hash_for_each(rocker->internal_vlan_tbl, bkt, entry, entry)
+		seq_printf(file, "ifindex %d ref_count %d vlan %d\n",
+			   entry->ifindex, entry->ref_count,
+			   be16_to_cpu(entry->vlan_id));
+
+	spin_unlock_irqrestore(&rocker->internal_vlan_tbl_lock, flags);
+
+	return 0;
+}
+
+static int dbg_neigh_tbl_read(struct seq_file *file, void *data)
+{
+	struct rocker *rocker = file->private;
+	struct rocker_neigh_tbl_entry *entry;
+	unsigned long flags;
+	int bkt;
+
+	spin_lock_irqsave(&rocker->neigh_tbl_lock, flags);
+
+	hash_for_each(rocker->neigh_tbl, bkt, entry, entry)
+		seq_printf(file, "%pI4 dev %s ref_count %d index %d dst %pM ttl_check %d\n",
+			   &entry->ip_addr, entry->dev->name, entry->ref_count,
+			   entry->index, entry->eth_dst, entry->ttl_check);
+
+	spin_unlock_irqrestore(&rocker->neigh_tbl_lock, flags);
+
+	return 0;
+}
+
+#define ROCKER_DBG_TBL(name) \
+	static int dbg_##name##_open(struct inode *inode, struct file *f) \
+	{                                                                 \
+		struct rocker *rocker = inode->i_private;                 \
+		return single_open(f, dbg_##name##_read, rocker);         \
+	}                                                                 \
+	static const struct file_operations dbg_##name##_ops = {          \
+		.owner = THIS_MODULE,                                     \
+		.open = dbg_##name##_open,                                \
+		.release = single_release,                                \
+		.read = seq_read,                                         \
+		.llseek = seq_lseek                                       \
+	}
+
+ROCKER_DBG_TBL(of_dpa_flow_tbl);
+ROCKER_DBG_TBL(of_dpa_group_tbl);
+ROCKER_DBG_TBL(fdb_tbl);
+ROCKER_DBG_TBL(internal_vlan_tbl);
+ROCKER_DBG_TBL(neigh_tbl);
+
 static int rocker_init_tbls(struct rocker *rocker)
 {
+#define ROCKER_CREATE_DBG_FILE(name)                                      \
+	debugfs_create_file(#name, S_IRUGO, rocker->dbg_dir, rocker,      \
+			    &dbg_##name##_ops)
+
 	hash_init(rocker->flow_tbl);
 	spin_lock_init(&rocker->flow_tbl_lock);
+	ROCKER_CREATE_DBG_FILE(of_dpa_flow_tbl);
 
 	hash_init(rocker->group_tbl);
 	spin_lock_init(&rocker->group_tbl_lock);
+	ROCKER_CREATE_DBG_FILE(of_dpa_group_tbl);
 
 	hash_init(rocker->fdb_tbl);
 	spin_lock_init(&rocker->fdb_tbl_lock);
+	ROCKER_CREATE_DBG_FILE(fdb_tbl);
 
 	hash_init(rocker->internal_vlan_tbl);
 	spin_lock_init(&rocker->internal_vlan_tbl_lock);
+	ROCKER_CREATE_DBG_FILE(internal_vlan_tbl);
 
 	hash_init(rocker->neigh_tbl);
 	spin_lock_init(&rocker->neigh_tbl_lock);
+	ROCKER_CREATE_DBG_FILE(neigh_tbl);
 
 	return 0;
 }
@@ -5090,6 +5424,23 @@ static void rocker_msix_fini(const struct rocker *rocker)
 	kfree(rocker->msix_entries);
 }
 
+static int rocker_probe_debugfs_init(struct rocker *rocker)
+{
+	char dbg_dir_name[sizeof(rocker->hw.id) * 2 + 1];
+
+	sprintf(dbg_dir_name, "%*phN", (int)sizeof(rocker->hw.id),
+		&rocker->hw.id);
+	rocker->dbg_dir = debugfs_create_dir(dbg_dir_name, rocker_dbg_root);
+	if (!rocker->dbg_dir)
+		return -ENOMEM;
+	return 0;
+}
+
+static void rocker_probe_debugfs_fini(struct rocker *rocker)
+{
+	debugfs_remove_recursive(rocker->dbg_dir);
+}
+
 static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct rocker *rocker;
@@ -5182,6 +5533,12 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	rocker->hw.id = rocker_read64(rocker, SWITCH_ID);
 
+	err = rocker_probe_debugfs_init(rocker);
+	if (err) {
+		dev_err(&pdev->dev, "cannot init debugfs\n");
+		goto err_dbg_dir;
+	}
+
 	err = rocker_init_tbls(rocker);
 	if (err) {
 		dev_err(&pdev->dev, "cannot init rocker tables\n");
@@ -5202,6 +5559,8 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 err_probe_ports:
 	rocker_free_tbls(rocker);
 err_init_tbls:
+	rocker_probe_debugfs_fini(rocker);
+err_dbg_dir:
 	free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
 err_request_event_irq:
 	free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD), rocker);
@@ -5228,6 +5587,7 @@ static void rocker_remove(struct pci_dev *pdev)
 	struct rocker *rocker = pci_get_drvdata(pdev);
 
 	rocker_free_tbls(rocker);
+	rocker_probe_debugfs_fini(rocker);
 	rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);
 	rocker_remove_ports(rocker);
 	free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
@@ -5426,18 +5786,36 @@ static struct notifier_block rocker_netevent_nb __read_mostly = {
  * Module init and exit
  ***********************/
 
+static int rocker_debugfs_init(void)
+{
+	rocker_dbg_root = debugfs_create_dir(rocker_driver_name, NULL);
+	if (!rocker_dbg_root)
+		return -ENOMEM;
+	return 0;
+}
+
+static void rocker_debugfs_fini(void)
+{
+	debugfs_remove_recursive(rocker_dbg_root);
+}
+
 static int __init rocker_module_init(void)
 {
 	int err;
 
 	register_netdevice_notifier(&rocker_netdevice_nb);
 	register_netevent_notifier(&rocker_netevent_nb);
+	err = rocker_debugfs_init();
+	if (err)
+		goto err_debugfs;
 	err = pci_register_driver(&rocker_pci_driver);
 	if (err)
 		goto err_pci_register_driver;
 	return 0;
 
 err_pci_register_driver:
+	rocker_debugfs_fini();
+err_debugfs:
 	unregister_netevent_notifier(&rocker_netevent_nb);
 	unregister_netdevice_notifier(&rocker_netdevice_nb);
 	return err;
@@ -5445,6 +5823,7 @@ err_pci_register_driver:
 
 static void __exit rocker_module_exit(void)
 {
+	rocker_debugfs_fini();
 	unregister_netevent_notifier(&rocker_netevent_nb);
 	unregister_netdevice_notifier(&rocker_netdevice_nb);
 	pci_unregister_driver(&rocker_pci_driver);
diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h
index 12490b2..0eacc53 100644
--- a/drivers/net/ethernet/rocker/rocker.h
+++ b/drivers/net/ethernet/rocker/rocker.h
@@ -419,7 +419,7 @@ enum rocker_of_dpa_overlay_type {
 #define ROCKER_GROUP_TYPE_SET(type) \
 	(((type) << ROCKER_GROUP_TYPE_SHIFT) & ROCKER_GROUP_TYPE_MASK)
 #define ROCKER_GROUP_VLAN_GET(group_id) \
-	(((group_id) & ROCKER_GROUP_VLAN_ID_MASK) >> ROCKER_GROUP_VLAN_ID_SHIFT)
+	(((group_id) & ROCKER_GROUP_VLAN_MASK) >> ROCKER_GROUP_VLAN_SHIFT)
 #define ROCKER_GROUP_VLAN_SET(vlan_id) \
 	(((vlan_id) << ROCKER_GROUP_VLAN_SHIFT) & ROCKER_GROUP_VLAN_MASK)
 #define ROCKER_GROUP_PORT_GET(group_id) \
