netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
To: Michael Chan <mchan@broadcom.com>
Cc: davem@davemloft.net, michaelc@cs.wisc.edu, anilgv@broadcom.com,
	netdev@vger.kernel.org, linux-scsi@vger.kernel.org,
	open-iscsi@googlegroups.com
Subject: Re: [PATCH 1/3] bnx2: Add support for CNIC driver.
Date: Wed, 21 May 2008 23:45:41 -0700	[thread overview]
Message-ID: <20080522064541.GA11933@linux.vnet.ibm.com> (raw)
In-Reply-To: <1211418386-18203-2-git-send-email-mchan@broadcom.com>

On Wed, May 21, 2008 at 06:06:24PM -0700, Michael Chan wrote:
> Add interface for a separate CNIC driver to drive additional rings
> and other resources for iSCSI.
> 
> A probe function is exported so that the CNIC driver can get
> information about bnx2 devices.  After calling the probe function,
> the CNIC driver can then register with the BNX2 driver before
> initializing the hardware for iSCSI.

Some RCU-related questions interspersed below, for example, how are
updates protected?

							Thanx, Paul

> Signed-off-by: Michael Chan <mchan@broadcom.com>
> ---
>  drivers/net/bnx2.c |  202 ++++++++++++++++++++++++++++++++++++++++++++++++++--
>  drivers/net/bnx2.h |   21 ++++++
>  2 files changed, 218 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
> index b32d227..ba12daf 100644
> --- a/drivers/net/bnx2.c
> +++ b/drivers/net/bnx2.c
> @@ -48,6 +48,11 @@
>  #include <linux/cache.h>
>  #include <linux/zlib.h>
> 
> +#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
> +#define BCM_CNIC	1
> +#include "cnic_drv.h"
> +#endif
> +
>  #include "bnx2.h"
>  #include "bnx2_fw.h"
>  #include "bnx2_fw2.h"
> @@ -302,6 +307,170 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
>  	spin_unlock_bh(&bp->indirect_lock);
>  }
> 
> +#ifdef BCM_CNIC
> +static int
> +bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
> +{
> +	struct bnx2 *bp = netdev_priv(dev);
> +	struct drv_ctl_io *io = &info->data.io;
> +
> +	switch (info->cmd) {
> +	case DRV_CTL_IO_WR_CMD:
> +		bnx2_reg_wr_ind(bp, io->offset, io->data);
> +		break;
> +	case DRV_CTL_IO_RD_CMD:
> +		io->data = bnx2_reg_rd_ind(bp, io->offset);
> +		break;
> +	case DRV_CTL_CTX_WR_CMD:
> +		bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
> +{
> +	struct cnic_ops *c_ops;
> +	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
> +	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
> +	int sb_id;
> +
> +	rcu_read_lock();
> +	c_ops = rcu_dereference(bp->cnic_ops);
> +	if (!c_ops)
> +		goto done;

Given that c_ops is unused below, what is happening here?  What prevents
bp->cnic_ops from becoming NULL immediately after we test it?  And if
it is OK for bp->cnic_ops to become NULL immediately after we test it,
why are we bothering to test it?

> +
> +	if (bp->flags & BNX2_FLAG_USING_MSIX) {
> +		cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
> +		bnapi->cnic_present = 0;
> +		sb_id = BNX2_CNIC_VEC;
> +		cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
> +	} else {
> +		cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
> +		bnapi->cnic_tag = bnapi->last_status_idx;
> +		bnapi->cnic_present = 1;
> +		sb_id = 0;
> +		cp->irq_arr[0].irq_flags &= !CNIC_IRQ_FL_MSIX;
> +	}
> +
> +	cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
> +	cp->irq_arr[0].status_blk = (void *) ((unsigned long) bp->status_blk +
> +		(BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
> +	cp->irq_arr[0].status_blk_num = sb_id;
> +	cp->num_irq = 1;
> +
> +done:
> +	rcu_read_unlock();
> +}
> +
> +static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
> +			      void *data)
> +{
> +	struct bnx2 *bp = netdev_priv(dev);
> +	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
> +
> +	if (ops == NULL)
> +		return -EINVAL;
> +
> +	if (!try_module_get(ops->cnic_owner))
> +		return -EBUSY;
> +
> +	bp->cnic_data = data;
> +	rcu_assign_pointer(bp->cnic_ops, ops);

What prevents multiple tasks from doing this assignment concurrently?

> +
> +	cp->num_irq = 0;
> +	cp->drv_state = CNIC_DRV_STATE_REGD;
> +
> +	bnx2_setup_cnic_irq_info(bp);
> +
> +	return 0;
> +}
> +
> +static int bnx2_unregister_cnic(struct net_device *dev)
> +{
> +	struct bnx2 *bp = netdev_priv(dev);
> +	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
> +	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
> +
> +	cp->drv_state = 0;
> +	module_put(bp->cnic_ops->cnic_owner);
> +	bnapi->cnic_present = 0;
> +	rcu_assign_pointer(bp->cnic_ops, NULL);

What prevents this from running concurrently with bnx2_register_cnic()?

> +	synchronize_rcu();

The caller is responsible for freeing up the old bp->cnic_ops structure?
Or is this structure statically allocated?

If so, is the idea to delay return until all prior calls through the
old ops structure have completed?

> +	return 0;
> +}
> +
> +struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
> +{
> +	struct bnx2 *bp = netdev_priv(dev);
> +	struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
> +
> +	cp->chip_id = bp->chip_id;
> +	cp->pdev = bp->pdev;
> +	cp->io_base = bp->regview;
> +	cp->drv_ctl = bnx2_drv_ctl;
> +	cp->drv_register_cnic = bnx2_register_cnic;
> +	cp->drv_unregister_cnic = bnx2_unregister_cnic;
> +
> +	return cp;
> +}
> +EXPORT_SYMBOL(bnx2_cnic_probe);
> +
> +static void
> +bnx2_cnic_stop(struct bnx2 *bp)
> +{
> +	struct cnic_ops *c_ops;
> +	struct cnic_ctl_info info;
> +
> +	rcu_read_lock();
> +	c_ops = rcu_dereference(bp->cnic_ops);
> +	if (c_ops) {
> +		info.cmd = CNIC_CTL_STOP_CMD;
> +		c_ops->cnic_ctl(bp->cnic_data, &info);
> +	}
> +	rcu_read_unlock();
> +}
> +
> +static void
> +bnx2_cnic_start(struct bnx2 *bp)
> +{
> +	struct cnic_ops *c_ops;
> +	struct cnic_ctl_info info;
> +
> +	rcu_read_lock();
> +	c_ops = rcu_dereference(bp->cnic_ops);
> +	if (c_ops) {
> +		if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
> +			struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
> +
> +			bnapi->cnic_tag = bnapi->last_status_idx;
> +		}
> +		info.cmd = CNIC_CTL_START_CMD;
> +		c_ops->cnic_ctl(bp->cnic_data, &info);
> +	}
> +	rcu_read_unlock();
> +}
> +
> +#else
> +
> +static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
> +{
> +}
> +
> +static void
> +bnx2_cnic_stop(struct bnx2 *bp)
> +{
> +}
> +
> +static void
> +bnx2_cnic_start(struct bnx2 *bp)
> +{
> +}
> +
> +#endif
> +
>  static int
>  bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
>  {
> @@ -475,6 +644,7 @@ bnx2_napi_enable(struct bnx2 *bp)
>  static void
>  bnx2_netif_stop(struct bnx2 *bp)
>  {
> +	bnx2_cnic_stop(bp);
>  	bnx2_disable_int_sync(bp);
>  	if (netif_running(bp->dev)) {
>  		bnx2_napi_disable(bp);
> @@ -491,6 +661,7 @@ bnx2_netif_start(struct bnx2 *bp)
>  			netif_wake_queue(bp->dev);
>  			bnx2_napi_enable(bp);
>  			bnx2_enable_int(bp);
> +			bnx2_cnic_start(bp);
>  		}
>  	}
>  }
> @@ -3007,6 +3178,9 @@ bnx2_has_work(struct bnx2_napi *bnapi)
>  	    (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
>  		return 1;
> 
> +	if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx))
> +		return 1;
> +
>  	return 0;
>  }
> 
> @@ -3059,6 +3233,20 @@ static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
>  	if (bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons)
>  		work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
> 
> +#ifdef BCM_CNIC
> +	if (bnapi->cnic_present) {
> +		struct cnic_ops *c_ops;
> +
> +		rcu_read_lock();
> +		c_ops = rcu_dereference(bp->cnic_ops);
> +		if (c_ops)
> +			bnapi->cnic_tag =
> +				c_ops->cnic_handler(bp->cnic_data,
> +						    bnapi->status_blk);
> +		rcu_read_unlock();
> +	}
> +#endif
> +
>  	return work_done;
>  }
> 
> @@ -3100,7 +3288,6 @@ static int bnx2_poll(struct napi_struct *napi, int budget)
>  			break;
>  		}
>  	}
> -
>  	return work_done;
>  }
> 
> @@ -5517,19 +5704,19 @@ static void
>  bnx2_enable_msix(struct bnx2 *bp)
>  {
>  	int i, rc;
> -	struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
> +	struct msix_entry msix_ent[BNX2_MAX_MSIX_CNIC_VEC];
> 
>  	bnx2_setup_msix_tbl(bp);
>  	REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
>  	REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
>  	REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
> 
> -	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
> +	for (i = 0; i < BNX2_MAX_MSIX_CNIC_VEC; i++) {
>  		msix_ent[i].entry = i;
>  		msix_ent[i].vector = 0;
>  	}
> 
> -	rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
> +	rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_CNIC_VEC);
>  	if (rc != 0)
>  		return;
> 
> @@ -5540,10 +5727,14 @@ bnx2_enable_msix(struct bnx2 *bp)
>  	strcat(bp->irq_tbl[BNX2_BASE_VEC].name, "-base");
>  	strcpy(bp->irq_tbl[BNX2_TX_VEC].name, bp->dev->name);
>  	strcat(bp->irq_tbl[BNX2_TX_VEC].name, "-tx");
> +#ifdef BCM_CNIC
> +	strcpy(bp->irq_tbl[BNX2_CNIC_VEC].name, bp->dev->name);
> +	strcat(bp->irq_tbl[BNX2_CNIC_VEC].name, "-cnic");
> +#endif
> 
>  	bp->irq_nvecs = BNX2_MAX_MSIX_VEC;
>  	bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
> -	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
> +	for (i = 0; i < BNX2_MAX_MSIX_CNIC_VEC; i++)
>  		bp->irq_tbl[i].vector = msix_ent[i].vector;
>  }
> 
> @@ -5571,6 +5762,7 @@ bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
>  			bp->irq_tbl[0].vector = bp->pdev->irq;
>  		}
>  	}
> +	bnx2_setup_cnic_irq_info(bp);
>  }
> 
>  /* Called with rtnl_lock */
> diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
> index 16020a1..a47ee60 100644
> --- a/drivers/net/bnx2.h
> +++ b/drivers/net/bnx2.h
> @@ -6562,6 +6562,15 @@ struct flash_spec {
>  #define BNX2_TX_VEC		1
>  #define BNX2_TX_INT_NUM	(BNX2_TX_VEC << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT)
> 
> +#ifdef BCM_CNIC
> +#define BNX2_MAX_MSIX_CNIC_VEC	(BNX2_MAX_MSIX_VEC + 1)
> +#define BNX2_CNIC_VEC		2
> +#define BNX2_CNIC_INT_NUM	\
> +	(BNX2_CNIC_VEC << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT)
> +#else
> +#define BNX2_MAX_MSIX_CNIC_VEC	BNX2_MAX_MSIX_VEC
> +#endif
> +
>  struct bnx2_irq {
>  	irq_handler_t	handler;
>  	u16		vector;
> @@ -6577,6 +6586,9 @@ struct bnx2_napi {
>  	u32 			last_status_idx;
>  	u32			int_num;
> 
> +	u32			cnic_tag;
> +	int			cnic_present;
> +
>  	u16			tx_cons;
>  	u16			hw_tx_cons;
> 
> @@ -6648,6 +6660,11 @@ struct bnx2 {
>  	int		tx_ring_size;
>  	u32		tx_wake_thresh;
> 
> +#ifdef BCM_CNIC
> +	struct cnic_ops		*cnic_ops;
> +	void			*cnic_data;
> +#endif
> +
>  	/* End of fields used in the performance code paths. */
> 
>  	char			*name;
> @@ -6813,6 +6830,10 @@ struct bnx2 {
> 
>  	struct bnx2_irq		irq_tbl[BNX2_MAX_MSIX_VEC];
>  	int			irq_nvecs;
> +
> +#ifdef BCM_CNIC
> +	struct cnic_eth_dev	cnic_eth_dev;
> +#endif
>  };
> 
>  #define REG_RD(bp, offset)					\
> -- 
> 1.5.5.GIT
> 
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2008-05-22  6:45 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-05-22  1:06 [PATCH 0/3] bnx2: Add iSCSI support Michael Chan
2008-05-22  1:06 ` [PATCH 2/3] cnic: Add CNIC driver Michael Chan
2008-05-22  7:44   ` Paul E. McKenney
2008-05-22 19:46     ` Michael Chan
2008-05-23  3:47       ` Paul E. McKenney
2008-05-23 20:09   ` Roland Dreier
2008-05-23 20:14   ` Roland Dreier
2008-05-24  0:42     ` Michael Chan
     [not found] ` <1211418386-18203-1-git-send-email-mchan-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2008-05-22  1:06   ` [PATCH 1/3] bnx2: Add support for " Michael Chan
2008-05-22  6:45     ` Paul E. McKenney [this message]
     [not found]       ` <20080522064541.GA11933-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2008-05-22 19:23         ` Michael Chan
2008-05-23  3:45           ` Paul E. McKenney
     [not found]             ` <20080523034522.GA8612-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2008-05-23  4:52               ` Michael Chan
2008-05-23  5:32                 ` Paul E. McKenney
     [not found]     ` <1211418386-18203-2-git-send-email-mchan-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2008-05-22 15:18       ` Konrad Rzeszutek
2008-05-22  1:06   ` [PATCH 3/3] bnx2i: Add bnx2i iSCSI driver Michael Chan
     [not found]     ` <1211418386-18203-4-git-send-email-mchan-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2008-05-22 15:15       ` Konrad Rzeszutek
2008-05-22 15:52         ` Ben Hutchings
2008-05-22 19:06         ` Anil Veerabhadrappa
2008-05-22 21:15     ` Christoph Hellwig
2008-05-22 22:59       ` Michael Chan
2008-05-23 20:23     ` Roland Dreier
2008-05-23 21:42       ` Anil Veerabhadrappa
2008-05-27 14:38         ` Roland Dreier
2008-05-27 19:17           ` Michael Chan
2008-05-27 18:21             ` Roland Dreier
2008-05-27 19:52           ` David Miller
2008-05-28  0:48             ` Michael Chan
2008-05-28  3:39               ` Jeff Garzik
2008-05-28  8:47                 ` Hannes Reinecke

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080522064541.GA11933@linux.vnet.ibm.com \
    --to=paulmck@linux.vnet.ibm.com \
    --cc=anilgv@broadcom.com \
    --cc=davem@davemloft.net \
    --cc=linux-scsi@vger.kernel.org \
    --cc=mchan@broadcom.com \
    --cc=michaelc@cs.wisc.edu \
    --cc=netdev@vger.kernel.org \
    --cc=open-iscsi@googlegroups.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).