lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <879ae2c3f79d5212253811518769cdaa4bf8b9c7.camel@mellanox.com>
Date:   Wed, 24 Jul 2019 23:21:17 +0000
From:   Saeed Mahameed <saeedm@...lanox.com>
To:     "snelson@...sando.io" <snelson@...sando.io>,
        "netdev@...r.kernel.org" <netdev@...r.kernel.org>,
        "davem@...emloft.net" <davem@...emloft.net>
Subject: Re: [PATCH v4 net-next 08/19] ionic: Add notifyq support

On Mon, 2019-07-22 at 14:40 -0700, Shannon Nelson wrote:
> The AdminQ is fine for sending messages and requests to the NIC,
> but we also need to have events published from the NIC to the
> driver.  The NotifyQ handles this for us, using the same interrupt
> as AdminQ.
> 
> Signed-off-by: Shannon Nelson <snelson@...sando.io>
> ---
>  .../ethernet/pensando/ionic/ionic_debugfs.c   |  16 ++
>  .../net/ethernet/pensando/ionic/ionic_lif.c   | 181
> +++++++++++++++++-
>  .../net/ethernet/pensando/ionic/ionic_lif.h   |   4 +
>  3 files changed, 200 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c
> b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c
> index 9af15c69b2a6..1d05b23de303 100644
> --- a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c
> @@ -126,6 +126,7 @@ int ionic_debugfs_add_qcq(struct lif *lif, struct
> qcq *qcq)
>  	struct debugfs_blob_wrapper *desc_blob;
>  	struct device *dev = lif->ionic->dev;
>  	struct intr *intr = &qcq->intr;
> +	struct dentry *stats_dentry;
>  	struct queue *q = &qcq->q;
>  	struct cq *cq = &qcq->cq;
>  
> @@ -219,6 +220,21 @@ int ionic_debugfs_add_qcq(struct lif *lif,
> struct qcq *qcq)
>  					intr_ctrl_regset);
>  	}
>  
> +	if (qcq->flags & QCQ_F_NOTIFYQ) {
> +		stats_dentry = debugfs_create_dir("notifyblock",
> qcq_dentry);
> +		if (IS_ERR_OR_NULL(stats_dentry))
> +			return PTR_ERR(stats_dentry);
> +
> +		debugfs_create_u64("eid", 0400, stats_dentry,
> +				   (u64 *)&lif->info->status.eid);
> +		debugfs_create_u16("link_status", 0400, stats_dentry,
> +				   (u16 *)&lif->info-
> >status.link_status);
> +		debugfs_create_u32("link_speed", 0400, stats_dentry,
> +				   (u32 *)&lif->info-
> >status.link_speed);
> +		debugfs_create_u16("link_down_count", 0400,
> stats_dentry,
> +				   (u16 *)&lif->info-
> >status.link_down_count);
> +	}
> +

you never write to these lif->info->status.xyz ..
and link state and speed are/should be available  in "ethtool <ifname>"
so this looks redundant to me. you can also use ethtool -S to report
linkdown count.

>  	return 0;
>  }
>  
> diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
> b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
> index 19c046502a26..01f9665611d4 100644
> --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
> @@ -12,6 +12,8 @@
>  #include "ionic_lif.h"
>  #include "ionic_debugfs.h"
>  
> +static int ionic_notifyq_clean(struct lif *lif, int budget);
> +
>  static bool ionic_adminq_service(struct cq *cq, struct cq_info
> *cq_info)
>  {
>  	struct admin_comp *comp = cq_info->cq_desc;
> @@ -26,7 +28,90 @@ static bool ionic_adminq_service(struct cq *cq,
> struct cq_info *cq_info)
>  
>  static int ionic_adminq_napi(struct napi_struct *napi, int budget)
>  {
> -	return ionic_napi(napi, budget, ionic_adminq_service, NULL,
> NULL);
> +	struct lif *lif = napi_to_cq(napi)->lif;
> +	int n_work = 0;
> +	int a_work = 0;
> +
> +	if (likely(lif->notifyqcq && lif->notifyqcq->flags &
> QCQ_F_INITED))
> +		n_work = ionic_notifyq_clean(lif, budget);
> +	a_work = ionic_napi(napi, budget, ionic_adminq_service, NULL,
> NULL);
> +
> +	return max(n_work, a_work);
> +}
> +
> +static bool ionic_notifyq_service(struct cq *cq, struct cq_info
> *cq_info)
> +{
> +	union notifyq_comp *comp = cq_info->cq_desc;
> +	struct net_device *netdev;
> +	struct queue *q;
> +	struct lif *lif;
> +	u64 eid;
> +
> +	q = cq->bound_q;
> +	lif = q->info[0].cb_arg;
> +	netdev = lif->netdev;
> +	eid = le64_to_cpu(comp->event.eid);
> +
> +	/* Have we run out of new completions to process? */
> +	if (eid <= lif->last_eid)
> +		return false;
> +
> +	lif->last_eid = eid;
> +
> +	dev_dbg(lif->ionic->dev, "notifyq event:\n");
> +	dynamic_hex_dump("event ", DUMP_PREFIX_OFFSET, 16, 1,
> +			 comp, sizeof(*comp), true);
> +
> +	switch (le16_to_cpu(comp->event.ecode)) {
> +	case EVENT_OPCODE_LINK_CHANGE:
> +		netdev_info(netdev, "Notifyq EVENT_OPCODE_LINK_CHANGE
> eid=%lld\n",
> +			    eid);
> +		netdev_info(netdev,
> +			    "  link_status=%d link_speed=%d\n",
> +			    le16_to_cpu(comp->link_change.link_status),
> +			    le32_to_cpu(comp->link_change.link_speed));
> +		break;
> +	case EVENT_OPCODE_RESET:
> +		netdev_info(netdev, "Notifyq EVENT_OPCODE_RESET
> eid=%lld\n",
> +			    eid);
> +		netdev_info(netdev, "  reset_code=%d state=%d\n",
> +			    comp->reset.reset_code,
> +			    comp->reset.state);
> +		break;
> +	case EVENT_OPCODE_LOG:
> +		netdev_info(netdev, "Notifyq EVENT_OPCODE_LOG
> eid=%lld\n", eid);
> +		print_hex_dump(KERN_INFO, "notifyq ",
> DUMP_PREFIX_OFFSET, 16, 1,
> +			       comp->log.data, sizeof(comp->log.data),
> true);

So your device can generate log buffer dump into the kernel log .. 
I am not sure how acceptable this is, maybe trace buffer is more
appropriate for this.

> +		break;
> +	default:
> +		netdev_warn(netdev, "Notifyq unknown event ecode=%d
> eid=%lld\n",
> +			    comp->event.ecode, eid);
> +		break;
> +	}
> +
> +	return true;
> +}
> +
> +static int ionic_notifyq_clean(struct lif *lif, int budget)
> +{
> +	struct ionic_dev *idev = &lif->ionic->idev;
> +	struct cq *cq = &lif->notifyqcq->cq;
> +	u32 work_done;
> +
> +	work_done = ionic_cq_service(cq, budget, ionic_notifyq_service,
> +				     NULL, NULL);
> +	if (work_done)
> +		ionic_intr_credits(idev->intr_ctrl, cq->bound_intr-
> >index,
> +				   work_done,
> IONIC_INTR_CRED_RESET_COALESCE);
> +
> +	/* If we ran out of budget, there are more events
> +	 * to process and napi will reschedule us soon
> +	 */
> +	if (work_done == budget)
> +		goto return_to_napi;
> +
> +return_to_napi:
> +	return work_done;
>  }
>  
>  static irqreturn_t ionic_isr(int irq, void *data)
> @@ -62,6 +147,17 @@ static void ionic_intr_free(struct lif *lif, int
> index)
>  		clear_bit(index, lif->ionic->intrs);
>  }
>  
> +static void ionic_link_qcq_interrupts(struct qcq *src_qcq, struct
> qcq *n_qcq)
> +{
> +	if (WARN_ON(n_qcq->flags & QCQ_F_INTR)) {
> +		ionic_intr_free(n_qcq->cq.lif, n_qcq->intr.index);
> +		n_qcq->flags &= ~QCQ_F_INTR;
> +	}
> +
> +	n_qcq->intr.vector = src_qcq->intr.vector;
> +	n_qcq->intr.index = src_qcq->intr.index;
> +}
> +
>  static int ionic_qcq_alloc(struct lif *lif, unsigned int type,
>  			   unsigned int index,
>  			   const char *name, unsigned int flags,
> @@ -236,11 +332,36 @@ static int ionic_qcqs_alloc(struct lif *lif)
>  	if (err)
>  		return err;
>  
> +	if (lif->ionic->nnqs_per_lif) {
> +		flags = QCQ_F_NOTIFYQ;
> +		err = ionic_qcq_alloc(lif, IONIC_QTYPE_NOTIFYQ, 0,
> "notifyq",
> +				      flags, IONIC_NOTIFYQ_LENGTH,
> +				      sizeof(struct notifyq_cmd),
> +				      sizeof(union notifyq_comp),
> +				      0, lif->kern_pid, &lif-
> >notifyqcq);
> +		if (err)
> +			goto err_out_free_adminqcq;
> +
> +		/* Let the notifyq ride on the adminq interrupt */
> +		ionic_link_qcq_interrupts(lif->adminqcq, lif-
> >notifyqcq);
> +	}
> +
>  	return 0;
> +
> +err_out_free_adminqcq:
> +	ionic_qcq_free(lif, lif->adminqcq);
> +	lif->adminqcq = NULL;
> +
> +	return err;
>  }
>  
>  static void ionic_qcqs_free(struct lif *lif)
>  {
> +	if (lif->notifyqcq) {
> +		ionic_qcq_free(lif, lif->notifyqcq);
> +		lif->notifyqcq = NULL;
> +	}
> +
>  	if (lif->adminqcq) {
>  		ionic_qcq_free(lif, lif->adminqcq);
>  		lif->adminqcq = NULL;
> @@ -400,6 +521,7 @@ static void ionic_lif_deinit(struct lif *lif)
>  	clear_bit(LIF_INITED, lif->state);
>  
>  	napi_disable(&lif->adminqcq->napi);
> +	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
>  	ionic_lif_qcq_deinit(lif, lif->adminqcq);
>  
>  	ionic_lif_reset(lif);
> @@ -484,6 +606,55 @@ static int ionic_lif_adminq_init(struct lif
> *lif)
>  	return 0;
>  }
>  
> +static int ionic_lif_notifyq_init(struct lif *lif)
> +{
> +	struct device *dev = lif->ionic->dev;
> +	struct qcq *qcq = lif->notifyqcq;
> +	struct queue *q = &qcq->q;
> +	int err;
> +
> +	struct ionic_admin_ctx ctx = {
> +		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
> +		.cmd.q_init = {
> +			.opcode = CMD_OPCODE_Q_INIT,
> +			.lif_index = cpu_to_le16(lif->index),
> +			.type = q->type,
> +			.index = cpu_to_le32(q->index),
> +			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
> +					     IONIC_QINIT_F_ENA),
> +			.intr_index = cpu_to_le16(lif->adminqcq-
> >intr.index),
> +			.pid = cpu_to_le16(q->pid),
> +			.ring_size = ilog2(q->num_descs),
> +			.ring_base = cpu_to_le64(q->base_pa),
> +		}
> +	};
> +
> +	dev_dbg(dev, "notifyq_init.pid %d\n", ctx.cmd.q_init.pid);
> +	dev_dbg(dev, "notifyq_init.index %d\n", ctx.cmd.q_init.index);
> +	dev_dbg(dev, "notifyq_init.ring_base 0x%llx\n",
> ctx.cmd.q_init.ring_base);
> +	dev_dbg(dev, "notifyq_init.ring_size %d\n",
> ctx.cmd.q_init.ring_size);
> +
> +	err = ionic_adminq_post_wait(lif, &ctx);
> +	if (err)
> +		return err;
> +
> +	q->hw_type = ctx.comp.q_init.hw_type;
> +	q->hw_index = le32_to_cpu(ctx.comp.q_init.hw_index);
> +	q->dbval = IONIC_DBELL_QID(q->hw_index);
> +
> +	dev_dbg(dev, "notifyq->hw_type %d\n", q->hw_type);
> +	dev_dbg(dev, "notifyq->hw_index %d\n", q->hw_index);
> +
> +	/* preset the callback info */
> +	q->info[0].cb_arg = lif;
> +
> +	qcq->flags |= QCQ_F_INITED;
> +
> +	ionic_debugfs_add_qcq(lif, qcq);
> +
> +	return 0;
> +}
> +
>  static int ionic_lif_init(struct lif *lif)
>  {
>  	struct ionic_dev *idev = &lif->ionic->idev;
> @@ -534,10 +705,18 @@ static int ionic_lif_init(struct lif *lif)
>  	if (err)
>  		goto err_out_adminq_deinit;
>  
> +	if (lif->ionic->nnqs_per_lif) {
> +		err = ionic_lif_notifyq_init(lif);
> +		if (err)
> +			goto err_out_notifyq_deinit;
> +	}
> +
>  	set_bit(LIF_INITED, lif->state);
>  
>  	return 0;
>  
> +err_out_notifyq_deinit:
> +	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
>  err_out_adminq_deinit:
>  	ionic_lif_qcq_deinit(lif, lif->adminqcq);
>  	ionic_lif_reset(lif);
> diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
> b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
> index 28ab92b43a64..80eec0778f40 100644
> --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
> @@ -7,6 +7,7 @@
>  #include <linux/pci.h>
>  
>  #define IONIC_ADMINQ_LENGTH	16	/* must be a power of two */
> +#define IONIC_NOTIFYQ_LENGTH	64	/* must be a power of two */
>  
>  #define GET_NAPI_CNTR_IDX(work_done)	(work_done)
>  #define MAX_NUM_NAPI_CNTR	(NAPI_POLL_WEIGHT + 1)
> @@ -26,6 +27,7 @@ struct rx_stats {
>  #define QCQ_F_INITED		BIT(0)
>  #define QCQ_F_SG		BIT(1)
>  #define QCQ_F_INTR		BIT(2)
> +#define QCQ_F_NOTIFYQ		BIT(5)
>  
>  struct napi_stats {
>  	u64 poll_count;
> @@ -78,6 +80,8 @@ struct lif {
>  	u64 __iomem *kern_dbpage;
>  	spinlock_t adminq_lock;		/* lock for AdminQ operations
> */
>  	struct qcq *adminqcq;
> +	struct qcq *notifyqcq;
> +	u64 last_eid;
>  	unsigned int neqs;
>  	unsigned int nxqs;
>  

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ