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

Commit 679563f4 authored by Matt Carlson's avatar Matt Carlson Committed by David S. Miller
Browse files

tg3: Add MSI-X support



This patch adds MSI-X support.

Signed-off-by: default avatarMatt Carlson <mcarlson@broadcom.com>
Reviewed-by: default avatarBenjamin Li <benli@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4f125f42
Loading
Loading
Loading
Loading
+81 −27
Original line number Diff line number Diff line
@@ -160,6 +160,7 @@ MODULE_FIRMWARE(FIRMWARE_TG3);
MODULE_FIRMWARE(FIRMWARE_TG3TSO);
MODULE_FIRMWARE(FIRMWARE_TG3TSO5);

#define TG3_RSS_MIN_NUM_MSIX_VECS	2

static int tg3_debug = -1;	/* -1 == use TG3_DEF_MSG_ENABLE as value */
module_param(tg3_debug, int, 0);
@@ -7767,7 +7768,7 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num)
		name[IFNAMSIZ-1] = 0;
	}

	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) {
		fn = tg3_msi;
		if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
			fn = tg3_msi_1shot;
@@ -7928,34 +7929,81 @@ static int tg3_request_firmware(struct tg3 *tp)
	return 0;
}

static bool tg3_enable_msix(struct tg3 *tp)
{
	int i, rc, cpus = num_online_cpus();
	struct msix_entry msix_ent[tp->irq_max];

	if (cpus == 1)
		/* Just fallback to the simpler MSI mode. */
		return false;

	/*
	 * We want as many rx rings enabled as there are cpus.
	 * The first MSIX vector only deals with link interrupts, etc,
	 * so we add one to the number of vectors we are requesting.
	 */
	tp->irq_cnt = min_t(unsigned, cpus + 1, tp->irq_max);

	for (i = 0; i < tp->irq_max; i++) {
		msix_ent[i].entry  = i;
		msix_ent[i].vector = 0;
	}

	rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt);
	if (rc != 0) {
		if (rc < TG3_RSS_MIN_NUM_MSIX_VECS)
			return false;
		if (pci_enable_msix(tp->pdev, msix_ent, rc))
			return false;
		printk(KERN_NOTICE
		       "%s: Requested %d MSI-X vectors, received %d\n",
		       tp->dev->name, tp->irq_cnt, rc);
		tp->irq_cnt = rc;
	}

	for (i = 0; i < tp->irq_max; i++)
		tp->napi[i].irq_vec = msix_ent[i].vector;

	return true;
}

static void tg3_ints_init(struct tg3 *tp)
{
	if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) {
	if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI_OR_MSIX) &&
	    !(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
		/* All MSI supporting chips should support tagged
		 * status.  Assert that this is the case.
		 */
		if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
		printk(KERN_WARNING PFX "%s: MSI without TAGGED? "
		       "Not using MSI.\n", tp->dev->name);
		} else if (pci_enable_msi(tp->pdev) == 0) {
			u32 msi_mode;
		goto defcfg;
	}

			msi_mode = tr32(MSGINT_MODE);
			tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
	if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) && tg3_enable_msix(tp))
		tp->tg3_flags2 |= TG3_FLG2_USING_MSIX;
	else if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) &&
		 pci_enable_msi(tp->pdev) == 0)
		tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
		}
	}

	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) {
		u32 msi_mode = tr32(MSGINT_MODE);
		tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
	}
defcfg:
	if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) {
		tp->irq_cnt = 1;
		tp->napi[0].irq_vec = tp->pdev->irq;
	}
}

static void tg3_ints_fini(struct tg3 *tp)
{
		if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
	if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX)
		pci_disable_msix(tp->pdev);
	else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
		pci_disable_msi(tp->pdev);
			tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
		}
	tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX;
}

static int tg3_open(struct net_device *dev)
@@ -7992,14 +8040,18 @@ static int tg3_open(struct net_device *dev)

	tg3_full_unlock(tp);

	/*
	 * Setup interrupts first so we know how
	 * many NAPI resources to allocate
	 */
	tg3_ints_init(tp);

	/* The placement of this call is tied
	 * to the setup and use of Host TX descriptors.
	 */
	err = tg3_alloc_consistent(tp);
	if (err)
		return err;

	tg3_ints_init(tp);
		goto err_out1;

	napi_enable(&tp->napi[0].napi);

@@ -8014,7 +8066,7 @@ static int tg3_open(struct net_device *dev)
	}

	if (err)
		goto err_out1;
		goto err_out2;

	tg3_full_lock(tp, 0);

@@ -8043,7 +8095,7 @@ static int tg3_open(struct net_device *dev)
	tg3_full_unlock(tp);

	if (err)
		goto err_out2;
		goto err_out3;

	if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
		err = tg3_test_msi(tp);
@@ -8054,7 +8106,7 @@ static int tg3_open(struct net_device *dev)
			tg3_free_rings(tp);
			tg3_full_unlock(tp);

			goto err_out1;
			goto err_out2;
		}

		if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
@@ -8081,16 +8133,18 @@ static int tg3_open(struct net_device *dev)

	return 0;

err_out2:
err_out3:
	for (i = tp->irq_cnt - 1; i >= 0; i--) {
		struct tg3_napi *tnapi = &tp->napi[i];
		free_irq(tnapi->irq_vec, tnapi);
	}

err_out1:
err_out2:
	napi_disable(&tp->napi[0].napi);
	tg3_ints_fini(tp);
	tg3_free_consistent(tp);

err_out1:
	tg3_ints_fini(tp);
	return err;
}

+6 −0
Original line number Diff line number Diff line
@@ -2621,6 +2621,9 @@ struct tg3 {
#define TG3_FLAG_NVRAM			0x00002000
#define TG3_FLAG_NVRAM_BUFFERED		0x00004000
#define TG3_FLAG_SUPPORT_MSI		0x00008000
#define TG3_FLAG_SUPPORT_MSIX		0x00010000
#define TG3_FLAG_SUPPORT_MSI_OR_MSIX	(TG3_FLAG_SUPPORT_MSI | \
					 TG3_FLAG_SUPPORT_MSIX)
#define TG3_FLAG_PCIX_MODE		0x00020000
#define TG3_FLAG_PCI_HIGH_SPEED		0x00040000
#define TG3_FLAG_PCI_32BIT		0x00080000
@@ -2659,6 +2662,9 @@ struct tg3 {
#define TG3_FLG2_5750_PLUS		0x00080000
#define TG3_FLG2_PROTECTED_NVRAM	0x00100000
#define TG3_FLG2_USING_MSI		0x00200000
#define TG3_FLG2_USING_MSIX		0x00400000
#define TG3_FLG2_USING_MSI_OR_MSIX	(TG3_FLG2_USING_MSI | \
					TG3_FLG2_USING_MSIX)
#define TG3_FLG2_MII_SERDES		0x00800000
#define TG3_FLG2_ANY_SERDES		(TG3_FLG2_PHY_SERDES |	\
					TG3_FLG2_MII_SERDES)