|
|
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 |
|