net/enic: fix memory freeing
enic_alloc_consistent() allocated memory, but enic_free_consistent()
was an empty function, so allocated memory was never freed.
This commit adds a list and lock to the enic structure to keep track
of the memzones allocated in enic_alloc_consistent(), and
enic_free_consistent() uses that information to properly free memory.
Fixes: fefed3d1e6
("enic: new driver")
Signed-off-by: Nelson Escobar <neescoba@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
This commit is contained in:
parent
9d802d1cb9
commit
da5f560be9
@ -83,7 +83,7 @@ struct vnic_dev {
|
||||
struct vnic_intr_coal_timer_info intr_coal_timer_info;
|
||||
void *(*alloc_consistent)(void *priv, size_t size,
|
||||
dma_addr_t *dma_handle, u8 *name);
|
||||
void (*free_consistent)(struct rte_pci_device *hwdev,
|
||||
void (*free_consistent)(void *priv,
|
||||
size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle);
|
||||
};
|
||||
@ -101,7 +101,7 @@ void *vnic_dev_priv(struct vnic_dev *vdev)
|
||||
void vnic_register_cbacks(struct vnic_dev *vdev,
|
||||
void *(*alloc_consistent)(void *priv, size_t size,
|
||||
dma_addr_t *dma_handle, u8 *name),
|
||||
void (*free_consistent)(struct rte_pci_device *hwdev,
|
||||
void (*free_consistent)(void *priv,
|
||||
size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle))
|
||||
{
|
||||
@ -807,7 +807,7 @@ int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
|
||||
int vnic_dev_notify_unset(struct vnic_dev *vdev)
|
||||
{
|
||||
if (vdev->notify && !vnic_dev_in_reset(vdev)) {
|
||||
vdev->free_consistent(vdev->pdev,
|
||||
vdev->free_consistent(vdev->priv,
|
||||
sizeof(struct vnic_devcmd_notify),
|
||||
vdev->notify,
|
||||
vdev->notify_pa);
|
||||
@ -924,16 +924,16 @@ void vnic_dev_unregister(struct vnic_dev *vdev)
|
||||
{
|
||||
if (vdev) {
|
||||
if (vdev->notify)
|
||||
vdev->free_consistent(vdev->pdev,
|
||||
vdev->free_consistent(vdev->priv,
|
||||
sizeof(struct vnic_devcmd_notify),
|
||||
vdev->notify,
|
||||
vdev->notify_pa);
|
||||
if (vdev->stats)
|
||||
vdev->free_consistent(vdev->pdev,
|
||||
vdev->free_consistent(vdev->priv,
|
||||
sizeof(struct vnic_stats),
|
||||
vdev->stats, vdev->stats_pa);
|
||||
if (vdev->fw_info)
|
||||
vdev->free_consistent(vdev->pdev,
|
||||
vdev->free_consistent(vdev->priv,
|
||||
sizeof(struct vnic_devcmd_fw_info),
|
||||
vdev->fw_info, vdev->fw_info_pa);
|
||||
kfree(vdev);
|
||||
@ -1041,7 +1041,7 @@ int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
|
||||
|
||||
ret = vnic_dev_cmd(vdev, CMD_ADD_FILTER, &a0, &a1, wait);
|
||||
*entry = (u16)a0;
|
||||
vdev->free_consistent(vdev->pdev, tlv_size, tlv_va, tlv_pa);
|
||||
vdev->free_consistent(vdev->priv, tlv_size, tlv_va, tlv_pa);
|
||||
} else if (cmd == CLSF_DEL) {
|
||||
a0 = *entry;
|
||||
ret = vnic_dev_cmd(vdev, CMD_DEL_FILTER, &a0, &a1, wait);
|
||||
|
@ -102,7 +102,7 @@ unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev,
|
||||
void vnic_register_cbacks(struct vnic_dev *vdev,
|
||||
void *(*alloc_consistent)(void *priv, size_t size,
|
||||
dma_addr_t *dma_handle, u8 *name),
|
||||
void (*free_consistent)(struct rte_pci_device *hwdev,
|
||||
void (*free_consistent)(void *priv,
|
||||
size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle));
|
||||
void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
|
||||
|
@ -46,6 +46,8 @@
|
||||
#include "vnic_rss.h"
|
||||
#include "enic_res.h"
|
||||
#include "cq_enet_desc.h"
|
||||
#include <sys/queue.h>
|
||||
#include <rte_spinlock.h>
|
||||
|
||||
#define DRV_NAME "enic_pmd"
|
||||
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Poll-mode Driver"
|
||||
@ -98,6 +100,11 @@ struct enic_soft_stats {
|
||||
rte_atomic64_t rx_packet_errors;
|
||||
};
|
||||
|
||||
struct enic_memzone_entry {
|
||||
const struct rte_memzone *rz;
|
||||
LIST_ENTRY(enic_memzone_entry) entries;
|
||||
};
|
||||
|
||||
/* Per-instance private data structure */
|
||||
struct enic {
|
||||
struct enic *next;
|
||||
@ -143,6 +150,11 @@ struct enic {
|
||||
|
||||
/* software counters */
|
||||
struct enic_soft_stats soft_stats;
|
||||
|
||||
/* linked list storing memory allocations */
|
||||
LIST_HEAD(enic_memzone_list, enic_memzone_entry) memzone_list;
|
||||
rte_spinlock_t memzone_list_lock;
|
||||
|
||||
};
|
||||
|
||||
static inline unsigned int enic_sop_rq(unsigned int rq)
|
||||
|
@ -340,12 +340,14 @@ enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
|
||||
}
|
||||
|
||||
static void *
|
||||
enic_alloc_consistent(__rte_unused void *priv, size_t size,
|
||||
enic_alloc_consistent(void *priv, size_t size,
|
||||
dma_addr_t *dma_handle, u8 *name)
|
||||
{
|
||||
void *vaddr;
|
||||
const struct rte_memzone *rz;
|
||||
*dma_handle = 0;
|
||||
struct enic *enic = (struct enic *)priv;
|
||||
struct enic_memzone_entry *mze;
|
||||
|
||||
rz = rte_memzone_reserve_aligned((const char *)name,
|
||||
size, SOCKET_ID_ANY, 0, ENIC_ALIGN);
|
||||
@ -358,16 +360,49 @@ enic_alloc_consistent(__rte_unused void *priv, size_t size,
|
||||
vaddr = rz->addr;
|
||||
*dma_handle = (dma_addr_t)rz->phys_addr;
|
||||
|
||||
mze = rte_malloc("enic memzone entry",
|
||||
sizeof(struct enic_memzone_entry), 0);
|
||||
|
||||
if (!mze) {
|
||||
pr_err("%s : Failed to allocate memory for memzone list\n",
|
||||
__func__);
|
||||
rte_memzone_free(rz);
|
||||
}
|
||||
|
||||
mze->rz = rz;
|
||||
|
||||
rte_spinlock_lock(&enic->memzone_list_lock);
|
||||
LIST_INSERT_HEAD(&enic->memzone_list, mze, entries);
|
||||
rte_spinlock_unlock(&enic->memzone_list_lock);
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static void
|
||||
enic_free_consistent(__rte_unused struct rte_pci_device *hwdev,
|
||||
__rte_unused size_t size,
|
||||
__rte_unused void *vaddr,
|
||||
__rte_unused dma_addr_t dma_handle)
|
||||
enic_free_consistent(void *priv,
|
||||
__rte_unused size_t size,
|
||||
void *vaddr,
|
||||
dma_addr_t dma_handle)
|
||||
{
|
||||
/* Nothing to be done */
|
||||
struct enic_memzone_entry *mze;
|
||||
struct enic *enic = (struct enic *)priv;
|
||||
|
||||
rte_spinlock_lock(&enic->memzone_list_lock);
|
||||
LIST_FOREACH(mze, &enic->memzone_list, entries) {
|
||||
if (mze->rz->addr == vaddr &&
|
||||
mze->rz->phys_addr == dma_handle)
|
||||
break;
|
||||
}
|
||||
if (mze == NULL) {
|
||||
rte_spinlock_unlock(&enic->memzone_list_lock);
|
||||
dev_warning(enic,
|
||||
"Tried to free memory, but couldn't find it in the memzone list\n");
|
||||
return;
|
||||
}
|
||||
LIST_REMOVE(mze, entries);
|
||||
rte_spinlock_unlock(&enic->memzone_list_lock);
|
||||
rte_memzone_free(mze->rz);
|
||||
rte_free(mze);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -843,7 +878,7 @@ static int enic_set_rsskey(struct enic *enic)
|
||||
rss_key_buf_pa,
|
||||
sizeof(union vnic_rss_key));
|
||||
|
||||
enic_free_consistent(enic->pdev, sizeof(union vnic_rss_key),
|
||||
enic_free_consistent(enic, sizeof(union vnic_rss_key),
|
||||
rss_key_buf_va, rss_key_buf_pa);
|
||||
|
||||
return err;
|
||||
@ -870,7 +905,7 @@ static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
|
||||
rss_cpu_buf_pa,
|
||||
sizeof(union vnic_rss_cpu));
|
||||
|
||||
enic_free_consistent(enic->pdev, sizeof(union vnic_rss_cpu),
|
||||
enic_free_consistent(enic, sizeof(union vnic_rss_cpu),
|
||||
rss_cpu_buf_va, rss_cpu_buf_pa);
|
||||
|
||||
return err;
|
||||
@ -1056,6 +1091,9 @@ int enic_probe(struct enic *enic)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
LIST_INIT(&enic->memzone_list);
|
||||
rte_spinlock_init(&enic->memzone_list_lock);
|
||||
|
||||
vnic_register_cbacks(enic->vdev,
|
||||
enic_alloc_consistent,
|
||||
enic_free_consistent);
|
||||
|
Loading…
Reference in New Issue
Block a user