Blame SOURCES/0001-net-enic-allocate-stats-DMA-buffer-upfront-during-pr.patch

a6040a
From 8d782f3f89e1dcd0c8af1c3c93501d7a06159d66 Mon Sep 17 00:00:00 2001
a6040a
From: Hyong Youb Kim <hyonkim@cisco.com>
a6040a
Date: Wed, 7 Mar 2018 18:46:58 -0800
a6040a
Subject: [PATCH] net/enic: allocate stats DMA buffer upfront during probe
a6040a
a6040a
The driver provides a DMA buffer to the firmware when it requests port
a6040a
stats. The NIC then fills that buffer with latest stats. Currently,
a6040a
the driver allocates the DMA buffer the first time it requests stats
a6040a
and saves it for later use. This can lead to crashes when
a6040a
primary/secondary processes are involved. For example, the following
a6040a
sequence crashes the secondary process.
a6040a
a6040a
1. Start a primary app that does not call rte_eth_stats_get()
a6040a
2. dpdk-procinfo -- --stats
a6040a
a6040a
dpdk-procinfo crashes while trying to allocate the stats DMA buffer
a6040a
because the alloc function pointer (vdev.alloc_consistent) is valid
a6040a
only in the primary process, not in the secondary process.
a6040a
a6040a
Overwriting the alloc function pointer in the secondary process is not
a6040a
an option, as it will simply make the pointer invalid in the primary
a6040a
process. Instead, allocate the DMA buffer during probe so that only
a6040a
the primary process does both allocate and free. This allows the
a6040a
secondary process to dump stats as well.
a6040a
a6040a
Fixes: 9913fbb91df0 ("enic/base: common code")
a6040a
Cc: stable@dpdk.org
a6040a
a6040a
Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
a6040a
Reviewed-by: John Daley <johndale@cisco.com>
a6040a
---
a6040a
 drivers/net/enic/base/vnic_dev.c | 24 ++++++++++++++----------
a6040a
 drivers/net/enic/base/vnic_dev.h |  1 +
a6040a
 drivers/net/enic/enic_main.c     |  9 +++++++++
a6040a
 3 files changed, 24 insertions(+), 10 deletions(-)
a6040a
a6040a
diff --git a/drivers/net/enic/base/vnic_dev.c b/drivers/net/enic/base/vnic_dev.c
a6040a
index 05b595eb8..1f8d222fc 100644
a6040a
--- a/drivers/net/enic/base/vnic_dev.c
a6040a
+++ b/drivers/net/enic/base/vnic_dev.c
a6040a
@@ -587,17 +587,9 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
a6040a
 {
a6040a
 	u64 a0, a1;
a6040a
 	int wait = 1000;
a6040a
-	static u32 instance;
a6040a
-	char name[NAME_MAX];
a6040a
 
a6040a
-	if (!vdev->stats) {
a6040a
-		snprintf((char *)name, sizeof(name),
a6040a
-			"vnic_stats-%u", instance++);
a6040a
-		vdev->stats = vdev->alloc_consistent(vdev->priv,
a6040a
-			sizeof(struct vnic_stats), &vdev->stats_pa, (u8 *)name);
a6040a
-		if (!vdev->stats)
a6040a
-			return -ENOMEM;
a6040a
-	}
a6040a
+	if (!vdev->stats)
a6040a
+		return -ENOMEM;
a6040a
 
a6040a
 	*stats = vdev->stats;
a6040a
 	a0 = vdev->stats_pa;
a6040a
@@ -922,6 +914,18 @@ u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev)
a6040a
 	return vdev->intr_coal_timer_info.max_usec;
a6040a
 }
a6040a
 
a6040a
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev)
a6040a
+{
a6040a
+	char name[NAME_MAX];
a6040a
+	static u32 instance;
a6040a
+
a6040a
+	snprintf((char *)name, sizeof(name), "vnic_stats-%u", instance++);
a6040a
+	vdev->stats = vdev->alloc_consistent(vdev->priv,
a6040a
+					     sizeof(struct vnic_stats),
a6040a
+					     &vdev->stats_pa, (u8 *)name);
a6040a
+	return vdev->stats == NULL ? -ENOMEM : 0;
a6040a
+}
a6040a
+
a6040a
 void vnic_dev_unregister(struct vnic_dev *vdev)
a6040a
 {
a6040a
 	if (vdev) {
a6040a
diff --git a/drivers/net/enic/base/vnic_dev.h b/drivers/net/enic/base/vnic_dev.h
a6040a
index 8c0992063..7e5736b4d 100644
a6040a
--- a/drivers/net/enic/base/vnic_dev.h
a6040a
+++ b/drivers/net/enic/base/vnic_dev.h
a6040a
@@ -165,6 +165,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
a6040a
 	void *priv, struct rte_pci_device *pdev, struct vnic_dev_bar *bar,
a6040a
 	unsigned int num_bars);
a6040a
 struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev);
a6040a
+int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev);
a6040a
 int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback);
a6040a
 int vnic_dev_get_size(void);
a6040a
 int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op);
a6040a
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
a6040a
index c3796c543..235ef5940 100644
a6040a
--- a/drivers/net/enic/enic_main.c
a6040a
+++ b/drivers/net/enic/enic_main.c
a6040a
@@ -1478,6 +1478,15 @@ int enic_probe(struct enic *enic)
a6040a
 		enic_alloc_consistent,
a6040a
 		enic_free_consistent);
a6040a
 
a6040a
+	/*
a6040a
+	 * Allocate the consistent memory for stats upfront so both primary and
a6040a
+	 * secondary processes can dump stats.
a6040a
+	 */
a6040a
+	err = vnic_dev_alloc_stats_mem(enic->vdev);
a6040a
+	if (err) {
a6040a
+		dev_err(enic, "Failed to allocate cmd memory, aborting\n");
a6040a
+		goto err_out_unregister;
a6040a
+	}
a6040a
 	/* Issue device open to get device in known state */
a6040a
 	err = enic_dev_open(enic);
a6040a
 	if (err) {
a6040a
-- 
a6040a
2.14.3
a6040a