Skip to content

Commit

Permalink
ionic: support sr-iov operations
Browse files Browse the repository at this point in the history
Add the netdev ops for managing VFs.  Since most of the
management work happens in the NIC firmware, the driver becomes
mostly a pass-through for the network stack commands that want
to control and configure the VFs.

We also tweak ionic_station_set() a little to allow for
the VFs that start off with a zero'd mac address.

Signed-off-by: Shannon Nelson <snelson@pensando.io>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Shannon Nelson authored and David S. Miller committed Jan 5, 2020
1 parent 3d462ce commit fbb3980
Show file tree
Hide file tree
Showing 6 changed files with 438 additions and 8 deletions.
17 changes: 16 additions & 1 deletion drivers/net/ethernet/pensando/ionic/ionic.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct ionic_lif;

#define IONIC_DRV_NAME "ionic"
#define IONIC_DRV_DESCRIPTION "Pensando Ethernet NIC Driver"
#define IONIC_DRV_VERSION "0.18.0-k"
#define IONIC_DRV_VERSION "0.20.0-k"

#define PCI_VENDOR_ID_PENSANDO 0x1dd8

Expand All @@ -25,6 +25,18 @@ struct ionic_lif;

#define DEVCMD_TIMEOUT 10

struct ionic_vf {
u16 index;
u8 macaddr[6];
__le32 maxrate;
__le16 vlanid;
u8 spoofchk;
u8 trusted;
u8 linkstate;
dma_addr_t stats_pa;
struct ionic_lif_stats stats;
};

struct ionic {
struct pci_dev *pdev;
struct device *dev;
Expand All @@ -46,6 +58,9 @@ struct ionic {
DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX);
struct work_struct nb_work;
struct notifier_block nb;
struct rw_semaphore vf_op_lock; /* lock for VF operations */
struct ionic_vf *vfs;
int num_vfs;
struct timer_list watchdog_timer;
int watchdog_period;
};
Expand Down
113 changes: 113 additions & 0 deletions drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,112 @@ void ionic_bus_unmap_dbpage(struct ionic *ionic, void __iomem *page)
iounmap(page);
}

static void ionic_vf_dealloc_locked(struct ionic *ionic)
{
struct ionic_vf *v;
dma_addr_t dma = 0;
int i;

if (!ionic->vfs)
return;

for (i = ionic->num_vfs - 1; i >= 0; i--) {
v = &ionic->vfs[i];

if (v->stats_pa) {
(void)ionic_set_vf_config(ionic, i,
IONIC_VF_ATTR_STATSADDR,
(u8 *)&dma);
dma_unmap_single(ionic->dev, v->stats_pa,
sizeof(v->stats), DMA_FROM_DEVICE);
v->stats_pa = 0;
}
}

kfree(ionic->vfs);
ionic->vfs = NULL;
ionic->num_vfs = 0;
}

static void ionic_vf_dealloc(struct ionic *ionic)
{
down_write(&ionic->vf_op_lock);
ionic_vf_dealloc_locked(ionic);
up_write(&ionic->vf_op_lock);
}

static int ionic_vf_alloc(struct ionic *ionic, int num_vfs)
{
struct ionic_vf *v;
int err = 0;
int i;

down_write(&ionic->vf_op_lock);

ionic->vfs = kcalloc(num_vfs, sizeof(struct ionic_vf), GFP_KERNEL);
if (!ionic->vfs) {
err = -ENOMEM;
goto out;
}

for (i = 0; i < num_vfs; i++) {
v = &ionic->vfs[i];
v->stats_pa = dma_map_single(ionic->dev, &v->stats,
sizeof(v->stats), DMA_FROM_DEVICE);
if (dma_mapping_error(ionic->dev, v->stats_pa)) {
v->stats_pa = 0;
err = -ENODEV;
goto out;
}

/* ignore failures from older FW, we just won't get stats */
(void)ionic_set_vf_config(ionic, i, IONIC_VF_ATTR_STATSADDR,
(u8 *)&v->stats_pa);
ionic->num_vfs++;
}

out:
if (err)
ionic_vf_dealloc_locked(ionic);
up_write(&ionic->vf_op_lock);
return err;
}

static int ionic_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
struct ionic *ionic = pci_get_drvdata(pdev);
struct device *dev = ionic->dev;
int ret = 0;

if (num_vfs > 0) {
ret = pci_enable_sriov(pdev, num_vfs);
if (ret) {
dev_err(dev, "Cannot enable SRIOV: %d\n", ret);
goto out;
}

ret = ionic_vf_alloc(ionic, num_vfs);
if (ret) {
dev_err(dev, "Cannot alloc VFs: %d\n", ret);
pci_disable_sriov(pdev);
goto out;
}

ret = num_vfs;
} else {
pci_disable_sriov(pdev);
ionic_vf_dealloc(ionic);
}

out:
return ret;
}

static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
struct ionic *ionic;
int num_vfs;
int err;

ionic = ionic_devlink_alloc(dev);
Expand Down Expand Up @@ -206,6 +308,15 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_lifs;
}

init_rwsem(&ionic->vf_op_lock);
num_vfs = pci_num_vf(pdev);
if (num_vfs) {
dev_info(dev, "%d VFs found already enabled\n", num_vfs);
err = ionic_vf_alloc(ionic, num_vfs);
if (err)
dev_err(dev, "Cannot enable existing VFs: %d\n", err);
}

err = ionic_lifs_register(ionic);
if (err) {
dev_err(dev, "Cannot register LIFs: %d, aborting\n", err);
Expand All @@ -223,6 +334,7 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_deregister_lifs:
ionic_lifs_unregister(ionic);
err_out_deinit_lifs:
ionic_vf_dealloc(ionic);
ionic_lifs_deinit(ionic);
err_out_free_lifs:
ionic_lifs_free(ionic);
Expand Down Expand Up @@ -279,6 +391,7 @@ static struct pci_driver ionic_driver = {
.id_table = ionic_id_table,
.probe = ionic_probe,
.remove = ionic_remove,
.sriov_configure = ionic_sriov_configure,
};

int ionic_bus_register_driver(void)
Expand Down
58 changes: 58 additions & 0 deletions drivers/net/ethernet/pensando/ionic/ionic_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,64 @@ void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type)
ionic_dev_cmd_go(idev, &cmd);
}

/* VF commands */
int ionic_set_vf_config(struct ionic *ionic, int vf, u8 attr, u8 *data)
{
union ionic_dev_cmd cmd = {
.vf_setattr.opcode = IONIC_CMD_VF_SETATTR,
.vf_setattr.attr = attr,
.vf_setattr.vf_index = vf,
};
int err;

switch (attr) {
case IONIC_VF_ATTR_SPOOFCHK:
cmd.vf_setattr.spoofchk = *data;
dev_dbg(ionic->dev, "%s: vf %d spoof %d\n",
__func__, vf, *data);
break;
case IONIC_VF_ATTR_TRUST:
cmd.vf_setattr.trust = *data;
dev_dbg(ionic->dev, "%s: vf %d trust %d\n",
__func__, vf, *data);
break;
case IONIC_VF_ATTR_LINKSTATE:
cmd.vf_setattr.linkstate = *data;
dev_dbg(ionic->dev, "%s: vf %d linkstate %d\n",
__func__, vf, *data);
break;
case IONIC_VF_ATTR_MAC:
ether_addr_copy(cmd.vf_setattr.macaddr, data);
dev_dbg(ionic->dev, "%s: vf %d macaddr %pM\n",
__func__, vf, data);
break;
case IONIC_VF_ATTR_VLAN:
cmd.vf_setattr.vlanid = cpu_to_le16(*(u16 *)data);
dev_dbg(ionic->dev, "%s: vf %d vlan %d\n",
__func__, vf, *(u16 *)data);
break;
case IONIC_VF_ATTR_RATE:
cmd.vf_setattr.maxrate = cpu_to_le32(*(u32 *)data);
dev_dbg(ionic->dev, "%s: vf %d maxrate %d\n",
__func__, vf, *(u32 *)data);
break;
case IONIC_VF_ATTR_STATSADDR:
cmd.vf_setattr.stats_pa = cpu_to_le64(*(u64 *)data);
dev_dbg(ionic->dev, "%s: vf %d stats_pa 0x%08llx\n",
__func__, vf, *(u64 *)data);
break;
default:
return -EINVAL;
}

mutex_lock(&ionic->dev_cmd_lock);
ionic_dev_cmd_go(&ionic->idev, &cmd);
err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
mutex_unlock(&ionic->dev_cmd_lock);

return err;
}

/* LIF commands */
void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver)
{
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/ethernet/pensando/ionic/ionic_dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ static_assert(sizeof(struct ionic_rxq_desc) == 16);
static_assert(sizeof(struct ionic_rxq_sg_desc) == 128);
static_assert(sizeof(struct ionic_rxq_comp) == 16);

/* SR/IOV */
static_assert(sizeof(struct ionic_vf_setattr_cmd) == 64);
static_assert(sizeof(struct ionic_vf_setattr_comp) == 16);
static_assert(sizeof(struct ionic_vf_getattr_cmd) == 64);
static_assert(sizeof(struct ionic_vf_getattr_comp) == 16);

struct ionic_devinfo {
u8 asic_type;
u8 asic_rev;
Expand Down Expand Up @@ -275,6 +281,7 @@ 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_pause(struct ionic_dev *idev, u8 pause_type);

int ionic_set_vf_config(struct ionic *ionic, int vf, u8 attr, u8 *data);
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);
Expand Down
Loading

0 comments on commit fbb3980

Please sign in to comment.