Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fbfb8031 authored by Shannon Nelson's avatar Shannon Nelson Committed by David S. Miller
Browse files

ionic: Add hardware init and device commands



The ionic device has a small set of PCI registers, including a
device control and data space, and a large set of message
commands.

Also adds new DEVLINK_INFO_VERSION_GENERIC tags for
ASIC_ID, ASIC_REV, and FW.

Signed-off-by: default avatarShannon Nelson <snelson@pensando.io>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent df69ba43
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -3,4 +3,5 @@

obj-$(CONFIG_IONIC) := ionic.o

ionic-y := ionic_main.o ionic_bus_pci.o ionic_devlink.o
ionic-y := ionic_main.o ionic_bus_pci.o ionic_devlink.o ionic_dev.o \
	   ionic_debugfs.o
+18 −0
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@
#ifndef _IONIC_H_
#define _IONIC_H_

#include "ionic_if.h"
#include "ionic_dev.h"
#include "ionic_devlink.h"

#define IONIC_DRV_NAME		"ionic"
@@ -19,9 +21,25 @@
#define IONIC_SUBDEV_ID_NAPLES_100_4	0x4001
#define IONIC_SUBDEV_ID_NAPLES_100_8	0x4002

#define DEVCMD_TIMEOUT  10

struct ionic {
	struct pci_dev *pdev;
	struct device *dev;
	struct ionic_dev idev;
	struct mutex dev_cmd_lock;	/* lock for dev_cmd operations */
	struct dentry *dentry;
	struct ionic_dev_bar bars[IONIC_BARS_MAX];
	unsigned int num_bars;
	struct ionic_identity ident;
};

int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
int ionic_set_dma_mask(struct ionic *ionic);
int ionic_setup(struct ionic *ionic);

int ionic_identify(struct ionic *ionic);
int ionic_init(struct ionic *ionic);
int ionic_reset(struct ionic *ionic);

#endif /* _IONIC_H_ */
+1 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#ifndef _IONIC_BUS_H_
#define _IONIC_BUS_H_

const char *ionic_bus_info(struct ionic *ionic);
int ionic_bus_register_driver(void);
void ionic_bus_unregister_driver(void);

+141 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

#include "ionic.h"
#include "ionic_bus.h"
#include "ionic_debugfs.h"

/* Supported devices */
static const struct pci_device_id ionic_id_table[] = {
@@ -17,10 +18,68 @@ static const struct pci_device_id ionic_id_table[] = {
};
MODULE_DEVICE_TABLE(pci, ionic_id_table);

const char *ionic_bus_info(struct ionic *ionic)
{
	return pci_name(ionic->pdev);
}

static int ionic_map_bars(struct ionic *ionic)
{
	struct pci_dev *pdev = ionic->pdev;
	struct device *dev = ionic->dev;
	struct ionic_dev_bar *bars;
	unsigned int i, j;

	bars = ionic->bars;
	ionic->num_bars = 0;

	for (i = 0, j = 0; i < IONIC_BARS_MAX; i++) {
		if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
			continue;
		bars[j].len = pci_resource_len(pdev, i);

		/* only map the whole bar 0 */
		if (j > 0) {
			bars[j].vaddr = NULL;
		} else {
			bars[j].vaddr = pci_iomap(pdev, i, bars[j].len);
			if (!bars[j].vaddr) {
				dev_err(dev,
					"Cannot memory-map BAR %d, aborting\n",
					i);
				return -ENODEV;
			}
		}

		bars[j].bus_addr = pci_resource_start(pdev, i);
		bars[j].res_index = i;
		ionic->num_bars++;
		j++;
	}

	return 0;
}

static void ionic_unmap_bars(struct ionic *ionic)
{
	struct ionic_dev_bar *bars = ionic->bars;
	unsigned int i;

	for (i = 0; i < IONIC_BARS_MAX; i++) {
		if (bars[i].vaddr) {
			iounmap(bars[i].vaddr);
			bars[i].bus_addr = 0;
			bars[i].vaddr = NULL;
			bars[i].len = 0;
		}
	}
}

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

	ionic = ionic_devlink_alloc(dev);
	if (!ionic)
@@ -29,14 +88,96 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	ionic->pdev = pdev;
	ionic->dev = dev;
	pci_set_drvdata(pdev, ionic);
	mutex_init(&ionic->dev_cmd_lock);

	/* Query system for DMA addressing limitation for the device. */
	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN));
	if (err) {
		dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting.  err=%d\n",
			err);
		goto err_out_clear_drvdata;
	}

	ionic_debugfs_add_dev(ionic);

	/* Setup PCI device */
	err = pci_enable_device_mem(pdev);
	if (err) {
		dev_err(dev, "Cannot enable PCI device: %d, aborting\n", err);
		goto err_out_debugfs_del_dev;
	}

	err = pci_request_regions(pdev, IONIC_DRV_NAME);
	if (err) {
		dev_err(dev, "Cannot request PCI regions: %d, aborting\n", err);
		goto err_out_pci_disable_device;
	}

	pci_set_master(pdev);

	err = ionic_map_bars(ionic);
	if (err)
		goto err_out_pci_clear_master;

	/* Configure the device */
	err = ionic_setup(ionic);
	if (err) {
		dev_err(dev, "Cannot setup device: %d, aborting\n", err);
		goto err_out_unmap_bars;
	}

	err = ionic_identify(ionic);
	if (err) {
		dev_err(dev, "Cannot identify device: %d, aborting\n", err);
		goto err_out_teardown;
	}

	err = ionic_init(ionic);
	if (err) {
		dev_err(dev, "Cannot init device: %d, aborting\n", err);
		goto err_out_teardown;
	}

	err = ionic_devlink_register(ionic);
	if (err)
		dev_err(dev, "Cannot register devlink: %d\n", err);

	return 0;

err_out_teardown:
	ionic_dev_teardown(ionic);
err_out_unmap_bars:
	ionic_unmap_bars(ionic);
	pci_release_regions(pdev);
err_out_pci_clear_master:
	pci_clear_master(pdev);
err_out_pci_disable_device:
	pci_disable_device(pdev);
err_out_debugfs_del_dev:
	ionic_debugfs_del_dev(ionic);
err_out_clear_drvdata:
	mutex_destroy(&ionic->dev_cmd_lock);
	ionic_devlink_free(ionic);

	return err;
}

static void ionic_remove(struct pci_dev *pdev)
{
	struct ionic *ionic = pci_get_drvdata(pdev);

	if (!ionic)
		return;

	ionic_devlink_unregister(ionic);
	ionic_reset(ionic);
	ionic_dev_teardown(ionic);
	ionic_unmap_bars(ionic);
	pci_release_regions(pdev);
	pci_clear_master(pdev);
	pci_disable_device(pdev);
	ionic_debugfs_del_dev(ionic);
	mutex_destroy(&ionic->dev_cmd_lock);
	ionic_devlink_free(ionic);
}

+61 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */

#include <linux/netdevice.h>

#include "ionic.h"
#include "ionic_bus.h"
#include "ionic_debugfs.h"

#ifdef CONFIG_DEBUG_FS

static struct dentry *ionic_dir;

void ionic_debugfs_create(void)
{
	ionic_dir = debugfs_create_dir(IONIC_DRV_NAME, NULL);
}

void ionic_debugfs_destroy(void)
{
	debugfs_remove_recursive(ionic_dir);
}

void ionic_debugfs_add_dev(struct ionic *ionic)
{
	ionic->dentry = debugfs_create_dir(ionic_bus_info(ionic), ionic_dir);
}

void ionic_debugfs_del_dev(struct ionic *ionic)
{
	debugfs_remove_recursive(ionic->dentry);
	ionic->dentry = NULL;
}

static int identity_show(struct seq_file *seq, void *v)
{
	struct ionic *ionic = seq->private;
	struct ionic_identity *ident;

	ident = &ionic->ident;

	seq_printf(seq, "nlifs:            %d\n", ident->dev.nlifs);
	seq_printf(seq, "nintrs:           %d\n", ident->dev.nintrs);
	seq_printf(seq, "ndbpgs_per_lif:   %d\n", ident->dev.ndbpgs_per_lif);
	seq_printf(seq, "intr_coal_mult:   %d\n", ident->dev.intr_coal_mult);
	seq_printf(seq, "intr_coal_div:    %d\n", ident->dev.intr_coal_div);

	seq_printf(seq, "max_ucast_filters:  %d\n", ident->lif.eth.max_ucast_filters);
	seq_printf(seq, "max_mcast_filters:  %d\n", ident->lif.eth.max_mcast_filters);

	return 0;
}
DEFINE_SHOW_ATTRIBUTE(identity);

void ionic_debugfs_add_ident(struct ionic *ionic)
{
	debugfs_create_file("identity", 0400, ionic->dentry,
			    ionic, &identity_fops) ? 0 : -EOPNOTSUPP;
}

#endif
Loading