mirror of https://gitee.com/openkylin/linux.git
ionic: Add basic lif support
The LIF is the Logical Interface, which represents the external connections. The NIC can multiplex many LIFs to a single port, but in most setups, LIF0 is the primary control for the port. Signed-off-by: Shannon Nelson <snelson@pensando.io> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
04436595c4
commit
1a58e19646
|
@ -4,4 +4,4 @@
|
||||||
obj-$(CONFIG_IONIC) := ionic.o
|
obj-$(CONFIG_IONIC) := ionic.o
|
||||||
|
|
||||||
ionic-y := ionic_main.o ionic_bus_pci.o ionic_devlink.o ionic_dev.o \
|
ionic-y := ionic_main.o ionic_bus_pci.o ionic_devlink.o ionic_dev.o \
|
||||||
ionic_debugfs.o
|
ionic_debugfs.o ionic_lif.o
|
||||||
|
|
|
@ -32,6 +32,13 @@ struct ionic {
|
||||||
struct ionic_dev_bar bars[IONIC_BARS_MAX];
|
struct ionic_dev_bar bars[IONIC_BARS_MAX];
|
||||||
unsigned int num_bars;
|
unsigned int num_bars;
|
||||||
struct ionic_identity ident;
|
struct ionic_identity ident;
|
||||||
|
struct list_head lifs;
|
||||||
|
unsigned int nnqs_per_lif;
|
||||||
|
unsigned int neqs_per_lif;
|
||||||
|
unsigned int ntxqs_per_lif;
|
||||||
|
unsigned int nrxqs_per_lif;
|
||||||
|
DECLARE_BITMAP(lifbits, IONIC_LIFS_MAX);
|
||||||
|
unsigned int nintrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
|
int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#define _IONIC_BUS_H_
|
#define _IONIC_BUS_H_
|
||||||
|
|
||||||
const char *ionic_bus_info(struct ionic *ionic);
|
const char *ionic_bus_info(struct ionic *ionic);
|
||||||
|
int ionic_bus_alloc_irq_vectors(struct ionic *ionic, unsigned int nintrs);
|
||||||
|
void ionic_bus_free_irq_vectors(struct ionic *ionic);
|
||||||
int ionic_bus_register_driver(void);
|
int ionic_bus_register_driver(void);
|
||||||
void ionic_bus_unregister_driver(void);
|
void ionic_bus_unregister_driver(void);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "ionic.h"
|
#include "ionic.h"
|
||||||
#include "ionic_bus.h"
|
#include "ionic_bus.h"
|
||||||
|
#include "ionic_lif.h"
|
||||||
#include "ionic_debugfs.h"
|
#include "ionic_debugfs.h"
|
||||||
|
|
||||||
/* Supported devices */
|
/* Supported devices */
|
||||||
|
@ -23,6 +24,17 @@ const char *ionic_bus_info(struct ionic *ionic)
|
||||||
return pci_name(ionic->pdev);
|
return pci_name(ionic->pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ionic_bus_alloc_irq_vectors(struct ionic *ionic, unsigned int nintrs)
|
||||||
|
{
|
||||||
|
return pci_alloc_irq_vectors(ionic->pdev, nintrs, nintrs,
|
||||||
|
PCI_IRQ_MSIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ionic_bus_free_irq_vectors(struct ionic *ionic)
|
||||||
|
{
|
||||||
|
pci_free_irq_vectors(ionic->pdev);
|
||||||
|
}
|
||||||
|
|
||||||
static int ionic_map_bars(struct ionic *ionic)
|
static int ionic_map_bars(struct ionic *ionic)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = ionic->pdev;
|
struct pci_dev *pdev = ionic->pdev;
|
||||||
|
@ -151,12 +163,44 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
goto err_out_reset;
|
goto err_out_reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Configure LIFs */
|
||||||
|
err = ionic_lif_identify(ionic, IONIC_LIF_TYPE_CLASSIC,
|
||||||
|
&ionic->ident.lif);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Cannot identify LIFs: %d, aborting\n", err);
|
||||||
|
goto err_out_port_reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ionic_lifs_size(ionic);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Cannot size LIFs: %d, aborting\n", err);
|
||||||
|
goto err_out_port_reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ionic_lifs_alloc(ionic);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Cannot allocate LIFs: %d, aborting\n", err);
|
||||||
|
goto err_out_free_irqs;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ionic_lifs_init(ionic);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Cannot init LIFs: %d, aborting\n", err);
|
||||||
|
goto err_out_free_lifs;
|
||||||
|
}
|
||||||
|
|
||||||
err = ionic_devlink_register(ionic);
|
err = ionic_devlink_register(ionic);
|
||||||
if (err)
|
if (err)
|
||||||
dev_err(dev, "Cannot register devlink: %d\n", err);
|
dev_err(dev, "Cannot register devlink: %d\n", err);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_out_free_lifs:
|
||||||
|
ionic_lifs_free(ionic);
|
||||||
|
err_out_free_irqs:
|
||||||
|
ionic_bus_free_irq_vectors(ionic);
|
||||||
|
err_out_port_reset:
|
||||||
|
ionic_port_reset(ionic);
|
||||||
err_out_reset:
|
err_out_reset:
|
||||||
ionic_reset(ionic);
|
ionic_reset(ionic);
|
||||||
err_out_teardown:
|
err_out_teardown:
|
||||||
|
@ -185,6 +229,9 @@ static void ionic_remove(struct pci_dev *pdev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ionic_devlink_unregister(ionic);
|
ionic_devlink_unregister(ionic);
|
||||||
|
ionic_lifs_deinit(ionic);
|
||||||
|
ionic_lifs_free(ionic);
|
||||||
|
ionic_bus_free_irq_vectors(ionic);
|
||||||
ionic_port_reset(ionic);
|
ionic_port_reset(ionic);
|
||||||
ionic_reset(ionic);
|
ionic_reset(ionic);
|
||||||
ionic_dev_teardown(ionic);
|
ionic_dev_teardown(ionic);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
|
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
|
||||||
|
|
||||||
|
#include <linux/pci.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
|
|
||||||
#include "ionic.h"
|
#include "ionic.h"
|
||||||
#include "ionic_bus.h"
|
#include "ionic_bus.h"
|
||||||
|
#include "ionic_lif.h"
|
||||||
#include "ionic_debugfs.h"
|
#include "ionic_debugfs.h"
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
@ -58,4 +60,38 @@ void ionic_debugfs_add_ident(struct ionic *ionic)
|
||||||
ionic, &identity_fops) ? 0 : -EOPNOTSUPP;
|
ionic, &identity_fops) ? 0 : -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ionic_debugfs_add_sizes(struct ionic *ionic)
|
||||||
|
{
|
||||||
|
debugfs_create_u32("nlifs", 0400, ionic->dentry,
|
||||||
|
(u32 *)&ionic->ident.dev.nlifs);
|
||||||
|
debugfs_create_u32("nintrs", 0400, ionic->dentry, &ionic->nintrs);
|
||||||
|
|
||||||
|
debugfs_create_u32("ntxqs_per_lif", 0400, ionic->dentry,
|
||||||
|
(u32 *)&ionic->ident.lif.eth.config.queue_count[IONIC_QTYPE_TXQ]);
|
||||||
|
debugfs_create_u32("nrxqs_per_lif", 0400, ionic->dentry,
|
||||||
|
(u32 *)&ionic->ident.lif.eth.config.queue_count[IONIC_QTYPE_RXQ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int netdev_show(struct seq_file *seq, void *v)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = seq->private;
|
||||||
|
|
||||||
|
seq_printf(seq, "%s\n", netdev->name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DEFINE_SHOW_ATTRIBUTE(netdev);
|
||||||
|
|
||||||
|
void ionic_debugfs_add_lif(struct ionic_lif *lif)
|
||||||
|
{
|
||||||
|
lif->dentry = debugfs_create_dir(lif->name, lif->ionic->dentry);
|
||||||
|
debugfs_create_file("netdev", 0400, lif->dentry,
|
||||||
|
lif->netdev, &netdev_fops);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ionic_debugfs_del_lif(struct ionic_lif *lif)
|
||||||
|
{
|
||||||
|
debugfs_remove_recursive(lif->dentry);
|
||||||
|
lif->dentry = NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,12 +13,18 @@ void ionic_debugfs_destroy(void);
|
||||||
void ionic_debugfs_add_dev(struct ionic *ionic);
|
void ionic_debugfs_add_dev(struct ionic *ionic);
|
||||||
void ionic_debugfs_del_dev(struct ionic *ionic);
|
void ionic_debugfs_del_dev(struct ionic *ionic);
|
||||||
void ionic_debugfs_add_ident(struct ionic *ionic);
|
void ionic_debugfs_add_ident(struct ionic *ionic);
|
||||||
|
void ionic_debugfs_add_sizes(struct ionic *ionic);
|
||||||
|
void ionic_debugfs_add_lif(struct ionic_lif *lif);
|
||||||
|
void ionic_debugfs_del_lif(struct ionic_lif *lif);
|
||||||
#else
|
#else
|
||||||
static inline void ionic_debugfs_create(void) { }
|
static inline void ionic_debugfs_create(void) { }
|
||||||
static inline void ionic_debugfs_destroy(void) { }
|
static inline void ionic_debugfs_destroy(void) { }
|
||||||
static inline void ionic_debugfs_add_dev(struct ionic *ionic) { }
|
static inline void ionic_debugfs_add_dev(struct ionic *ionic) { }
|
||||||
static inline void ionic_debugfs_del_dev(struct ionic *ionic) { }
|
static inline void ionic_debugfs_del_dev(struct ionic *ionic) { }
|
||||||
static inline void ionic_debugfs_add_ident(struct ionic *ionic) { }
|
static inline void ionic_debugfs_add_ident(struct ionic *ionic) { }
|
||||||
|
static inline void ionic_debugfs_add_sizes(struct ionic *ionic) { }
|
||||||
|
static inline void ionic_debugfs_add_lif(struct ionic_lif *lif) { }
|
||||||
|
static inline void ionic_debugfs_del_lif(struct ionic_lif *lif) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _IONIC_DEBUGFS_H_ */
|
#endif /* _IONIC_DEBUGFS_H_ */
|
||||||
|
|
|
@ -226,3 +226,37 @@ void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type)
|
||||||
|
|
||||||
ionic_dev_cmd_go(idev, &cmd);
|
ionic_dev_cmd_go(idev, &cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* LIF commands */
|
||||||
|
void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver)
|
||||||
|
{
|
||||||
|
union ionic_dev_cmd cmd = {
|
||||||
|
.lif_identify.opcode = IONIC_CMD_LIF_IDENTIFY,
|
||||||
|
.lif_identify.type = type,
|
||||||
|
.lif_identify.ver = ver,
|
||||||
|
};
|
||||||
|
|
||||||
|
ionic_dev_cmd_go(idev, &cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index,
|
||||||
|
dma_addr_t info_pa)
|
||||||
|
{
|
||||||
|
union ionic_dev_cmd cmd = {
|
||||||
|
.lif_init.opcode = IONIC_CMD_LIF_INIT,
|
||||||
|
.lif_init.index = cpu_to_le16(lif_index),
|
||||||
|
.lif_init.info_pa = cpu_to_le64(info_pa),
|
||||||
|
};
|
||||||
|
|
||||||
|
ionic_dev_cmd_go(idev, &cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index)
|
||||||
|
{
|
||||||
|
union ionic_dev_cmd cmd = {
|
||||||
|
.lif_init.opcode = IONIC_CMD_LIF_RESET,
|
||||||
|
.lif_init.index = cpu_to_le16(lif_index),
|
||||||
|
};
|
||||||
|
|
||||||
|
ionic_dev_cmd_go(idev, &cmd);
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "ionic_if.h"
|
#include "ionic_if.h"
|
||||||
#include "ionic_regs.h"
|
#include "ionic_regs.h"
|
||||||
|
|
||||||
|
#define IONIC_LIFS_MAX 1024
|
||||||
|
|
||||||
struct ionic_dev_bar {
|
struct ionic_dev_bar {
|
||||||
void __iomem *vaddr;
|
void __iomem *vaddr;
|
||||||
phys_addr_t bus_addr;
|
phys_addr_t bus_addr;
|
||||||
|
@ -148,4 +150,9 @@ void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable);
|
||||||
void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type);
|
void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type);
|
||||||
void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type);
|
void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type);
|
||||||
|
|
||||||
|
void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver);
|
||||||
|
void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index,
|
||||||
|
dma_addr_t addr);
|
||||||
|
void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index);
|
||||||
|
|
||||||
#endif /* _IONIC_DEV_H_ */
|
#endif /* _IONIC_DEV_H_ */
|
||||||
|
|
|
@ -0,0 +1,291 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
|
||||||
|
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/cpumask.h>
|
||||||
|
|
||||||
|
#include "ionic.h"
|
||||||
|
#include "ionic_bus.h"
|
||||||
|
#include "ionic_lif.h"
|
||||||
|
#include "ionic_debugfs.h"
|
||||||
|
|
||||||
|
static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index)
|
||||||
|
{
|
||||||
|
struct device *dev = ionic->dev;
|
||||||
|
struct net_device *netdev;
|
||||||
|
struct ionic_lif *lif;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
netdev = alloc_etherdev_mqs(sizeof(*lif),
|
||||||
|
ionic->ntxqs_per_lif, ionic->ntxqs_per_lif);
|
||||||
|
if (!netdev) {
|
||||||
|
dev_err(dev, "Cannot allocate netdev, aborting\n");
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_NETDEV_DEV(netdev, dev);
|
||||||
|
|
||||||
|
lif = netdev_priv(netdev);
|
||||||
|
lif->netdev = netdev;
|
||||||
|
|
||||||
|
lif->neqs = ionic->neqs_per_lif;
|
||||||
|
lif->nxqs = ionic->ntxqs_per_lif;
|
||||||
|
|
||||||
|
lif->ionic = ionic;
|
||||||
|
lif->index = index;
|
||||||
|
|
||||||
|
snprintf(lif->name, sizeof(lif->name), "lif%u", index);
|
||||||
|
|
||||||
|
/* allocate lif info */
|
||||||
|
lif->info_sz = ALIGN(sizeof(*lif->info), PAGE_SIZE);
|
||||||
|
lif->info = dma_alloc_coherent(dev, lif->info_sz,
|
||||||
|
&lif->info_pa, GFP_KERNEL);
|
||||||
|
if (!lif->info) {
|
||||||
|
dev_err(dev, "Failed to allocate lif info, aborting\n");
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto err_out_free_netdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&lif->list, &ionic->lifs);
|
||||||
|
|
||||||
|
return lif;
|
||||||
|
|
||||||
|
err_out_free_netdev:
|
||||||
|
free_netdev(lif->netdev);
|
||||||
|
lif = NULL;
|
||||||
|
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ionic_lifs_alloc(struct ionic *ionic)
|
||||||
|
{
|
||||||
|
struct ionic_lif *lif;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&ionic->lifs);
|
||||||
|
|
||||||
|
/* only build the first lif, others are for later features */
|
||||||
|
set_bit(0, ionic->lifbits);
|
||||||
|
lif = ionic_lif_alloc(ionic, 0);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(lif);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ionic_lif_reset(struct ionic_lif *lif)
|
||||||
|
{
|
||||||
|
struct ionic_dev *idev = &lif->ionic->idev;
|
||||||
|
|
||||||
|
mutex_lock(&lif->ionic->dev_cmd_lock);
|
||||||
|
ionic_dev_cmd_lif_reset(idev, lif->index);
|
||||||
|
ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
|
||||||
|
mutex_unlock(&lif->ionic->dev_cmd_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ionic_lif_free(struct ionic_lif *lif)
|
||||||
|
{
|
||||||
|
struct device *dev = lif->ionic->dev;
|
||||||
|
|
||||||
|
ionic_lif_reset(lif);
|
||||||
|
|
||||||
|
/* free lif info */
|
||||||
|
dma_free_coherent(dev, lif->info_sz, lif->info, lif->info_pa);
|
||||||
|
lif->info = NULL;
|
||||||
|
lif->info_pa = 0;
|
||||||
|
|
||||||
|
/* free netdev & lif */
|
||||||
|
ionic_debugfs_del_lif(lif);
|
||||||
|
list_del(&lif->list);
|
||||||
|
free_netdev(lif->netdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ionic_lifs_free(struct ionic *ionic)
|
||||||
|
{
|
||||||
|
struct list_head *cur, *tmp;
|
||||||
|
struct ionic_lif *lif;
|
||||||
|
|
||||||
|
list_for_each_safe(cur, tmp, &ionic->lifs) {
|
||||||
|
lif = list_entry(cur, struct ionic_lif, list);
|
||||||
|
|
||||||
|
ionic_lif_free(lif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ionic_lif_deinit(struct ionic_lif *lif)
|
||||||
|
{
|
||||||
|
if (!test_bit(IONIC_LIF_INITED, lif->state))
|
||||||
|
return;
|
||||||
|
|
||||||
|
clear_bit(IONIC_LIF_INITED, lif->state);
|
||||||
|
|
||||||
|
ionic_lif_reset(lif);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ionic_lifs_deinit(struct ionic *ionic)
|
||||||
|
{
|
||||||
|
struct list_head *cur, *tmp;
|
||||||
|
struct ionic_lif *lif;
|
||||||
|
|
||||||
|
list_for_each_safe(cur, tmp, &ionic->lifs) {
|
||||||
|
lif = list_entry(cur, struct ionic_lif, list);
|
||||||
|
ionic_lif_deinit(lif);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ionic_lif_init(struct ionic_lif *lif)
|
||||||
|
{
|
||||||
|
struct ionic_dev *idev = &lif->ionic->idev;
|
||||||
|
struct ionic_lif_init_comp comp;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
ionic_debugfs_add_lif(lif);
|
||||||
|
|
||||||
|
mutex_lock(&lif->ionic->dev_cmd_lock);
|
||||||
|
ionic_dev_cmd_lif_init(idev, lif->index, lif->info_pa);
|
||||||
|
err = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
|
||||||
|
ionic_dev_cmd_comp(idev, (union ionic_dev_cmd_comp *)&comp);
|
||||||
|
mutex_unlock(&lif->ionic->dev_cmd_lock);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
lif->hw_index = le16_to_cpu(comp.hw_index);
|
||||||
|
|
||||||
|
set_bit(IONIC_LIF_INITED, lif->state);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ionic_lifs_init(struct ionic *ionic)
|
||||||
|
{
|
||||||
|
struct list_head *cur, *tmp;
|
||||||
|
struct ionic_lif *lif;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
list_for_each_safe(cur, tmp, &ionic->lifs) {
|
||||||
|
lif = list_entry(cur, struct ionic_lif, list);
|
||||||
|
err = ionic_lif_init(lif);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ionic_lif_identify(struct ionic *ionic, u8 lif_type,
|
||||||
|
union ionic_lif_identity *lid)
|
||||||
|
{
|
||||||
|
struct ionic_dev *idev = &ionic->idev;
|
||||||
|
size_t sz;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
sz = min(sizeof(*lid), sizeof(idev->dev_cmd_regs->data));
|
||||||
|
|
||||||
|
mutex_lock(&ionic->dev_cmd_lock);
|
||||||
|
ionic_dev_cmd_lif_identify(idev, lif_type, IONIC_IDENTITY_VERSION_1);
|
||||||
|
err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
|
||||||
|
memcpy_fromio(lid, &idev->dev_cmd_regs->data, sz);
|
||||||
|
mutex_unlock(&ionic->dev_cmd_lock);
|
||||||
|
if (err)
|
||||||
|
return (err);
|
||||||
|
|
||||||
|
dev_dbg(ionic->dev, "capabilities 0x%llx\n",
|
||||||
|
le64_to_cpu(lid->capabilities));
|
||||||
|
|
||||||
|
dev_dbg(ionic->dev, "eth.max_ucast_filters %d\n",
|
||||||
|
le32_to_cpu(lid->eth.max_ucast_filters));
|
||||||
|
dev_dbg(ionic->dev, "eth.max_mcast_filters %d\n",
|
||||||
|
le32_to_cpu(lid->eth.max_mcast_filters));
|
||||||
|
dev_dbg(ionic->dev, "eth.features 0x%llx\n",
|
||||||
|
le64_to_cpu(lid->eth.config.features));
|
||||||
|
dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_ADMINQ] %d\n",
|
||||||
|
le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_ADMINQ]));
|
||||||
|
dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_NOTIFYQ] %d\n",
|
||||||
|
le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_NOTIFYQ]));
|
||||||
|
dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_RXQ] %d\n",
|
||||||
|
le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_RXQ]));
|
||||||
|
dev_dbg(ionic->dev, "eth.queue_count[IONIC_QTYPE_TXQ] %d\n",
|
||||||
|
le32_to_cpu(lid->eth.config.queue_count[IONIC_QTYPE_TXQ]));
|
||||||
|
dev_dbg(ionic->dev, "eth.config.name %s\n", lid->eth.config.name);
|
||||||
|
dev_dbg(ionic->dev, "eth.config.mac %pM\n", lid->eth.config.mac);
|
||||||
|
dev_dbg(ionic->dev, "eth.config.mtu %d\n",
|
||||||
|
le32_to_cpu(lid->eth.config.mtu));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ionic_lifs_size(struct ionic *ionic)
|
||||||
|
{
|
||||||
|
struct ionic_identity *ident = &ionic->ident;
|
||||||
|
unsigned int nintrs, dev_nintrs;
|
||||||
|
union ionic_lif_config *lc;
|
||||||
|
unsigned int ntxqs_per_lif;
|
||||||
|
unsigned int nrxqs_per_lif;
|
||||||
|
unsigned int neqs_per_lif;
|
||||||
|
unsigned int nnqs_per_lif;
|
||||||
|
unsigned int nxqs, neqs;
|
||||||
|
unsigned int min_intrs;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
lc = &ident->lif.eth.config;
|
||||||
|
dev_nintrs = le32_to_cpu(ident->dev.nintrs);
|
||||||
|
neqs_per_lif = le32_to_cpu(ident->lif.rdma.eq_qtype.qid_count);
|
||||||
|
nnqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_NOTIFYQ]);
|
||||||
|
ntxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_TXQ]);
|
||||||
|
nrxqs_per_lif = le32_to_cpu(lc->queue_count[IONIC_QTYPE_RXQ]);
|
||||||
|
|
||||||
|
nxqs = min(ntxqs_per_lif, nrxqs_per_lif);
|
||||||
|
nxqs = min(nxqs, num_online_cpus());
|
||||||
|
neqs = min(neqs_per_lif, num_online_cpus());
|
||||||
|
|
||||||
|
try_again:
|
||||||
|
/* interrupt usage:
|
||||||
|
* 1 for master lif adminq/notifyq
|
||||||
|
* 1 for each CPU for master lif TxRx queue pairs
|
||||||
|
* whatever's left is for RDMA queues
|
||||||
|
*/
|
||||||
|
nintrs = 1 + nxqs + neqs;
|
||||||
|
min_intrs = 2; /* adminq + 1 TxRx queue pair */
|
||||||
|
|
||||||
|
if (nintrs > dev_nintrs)
|
||||||
|
goto try_fewer;
|
||||||
|
|
||||||
|
err = ionic_bus_alloc_irq_vectors(ionic, nintrs);
|
||||||
|
if (err < 0 && err != -ENOSPC) {
|
||||||
|
dev_err(ionic->dev, "Can't get intrs from OS: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err == -ENOSPC)
|
||||||
|
goto try_fewer;
|
||||||
|
|
||||||
|
if (err != nintrs) {
|
||||||
|
ionic_bus_free_irq_vectors(ionic);
|
||||||
|
goto try_fewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
ionic->nnqs_per_lif = nnqs_per_lif;
|
||||||
|
ionic->neqs_per_lif = neqs;
|
||||||
|
ionic->ntxqs_per_lif = nxqs;
|
||||||
|
ionic->nrxqs_per_lif = nxqs;
|
||||||
|
ionic->nintrs = nintrs;
|
||||||
|
|
||||||
|
ionic_debugfs_add_sizes(ionic);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
try_fewer:
|
||||||
|
if (nnqs_per_lif > 1) {
|
||||||
|
nnqs_per_lif >>= 1;
|
||||||
|
goto try_again;
|
||||||
|
}
|
||||||
|
if (neqs > 1) {
|
||||||
|
neqs >>= 1;
|
||||||
|
goto try_again;
|
||||||
|
}
|
||||||
|
if (nxqs > 1) {
|
||||||
|
nxqs >>= 1;
|
||||||
|
goto try_again;
|
||||||
|
}
|
||||||
|
dev_err(ionic->dev, "Can't get minimum %d intrs from OS\n", min_intrs);
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
|
||||||
|
|
||||||
|
#ifndef _IONIC_LIF_H_
|
||||||
|
#define _IONIC_LIF_H_
|
||||||
|
|
||||||
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
enum ionic_lif_state_flags {
|
||||||
|
IONIC_LIF_INITED,
|
||||||
|
|
||||||
|
/* leave this as last */
|
||||||
|
IONIC_LIF_STATE_SIZE
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IONIC_LIF_NAME_MAX_SZ 32
|
||||||
|
struct ionic_lif {
|
||||||
|
char name[IONIC_LIF_NAME_MAX_SZ];
|
||||||
|
struct list_head list;
|
||||||
|
struct net_device *netdev;
|
||||||
|
DECLARE_BITMAP(state, IONIC_LIF_STATE_SIZE);
|
||||||
|
struct ionic *ionic;
|
||||||
|
bool registered;
|
||||||
|
unsigned int index;
|
||||||
|
unsigned int hw_index;
|
||||||
|
unsigned int neqs;
|
||||||
|
unsigned int nxqs;
|
||||||
|
|
||||||
|
struct ionic_lif_info *info;
|
||||||
|
dma_addr_t info_pa;
|
||||||
|
u32 info_sz;
|
||||||
|
|
||||||
|
struct dentry *dentry;
|
||||||
|
u32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
int ionic_lifs_alloc(struct ionic *ionic);
|
||||||
|
void ionic_lifs_free(struct ionic *ionic);
|
||||||
|
void ionic_lifs_deinit(struct ionic *ionic);
|
||||||
|
int ionic_lifs_init(struct ionic *ionic);
|
||||||
|
int ionic_lif_identify(struct ionic *ionic, u8 lif_type,
|
||||||
|
union ionic_lif_identity *lif_ident);
|
||||||
|
int ionic_lifs_size(struct ionic *ionic);
|
||||||
|
|
||||||
|
#endif /* _IONIC_LIF_H_ */
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "ionic.h"
|
#include "ionic.h"
|
||||||
#include "ionic_bus.h"
|
#include "ionic_bus.h"
|
||||||
|
#include "ionic_lif.h"
|
||||||
#include "ionic_debugfs.h"
|
#include "ionic_debugfs.h"
|
||||||
|
|
||||||
MODULE_DESCRIPTION(IONIC_DRV_DESCRIPTION);
|
MODULE_DESCRIPTION(IONIC_DRV_DESCRIPTION);
|
||||||
|
|
Loading…
Reference in New Issue