tg3: Add MSI-X support

This patch adds MSI-X support.

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Matt Carlson 2009-09-01 12:55:46 +00:00 committed by David S. Miller
parent 4f125f42dd
commit 679563f47c
2 changed files with 87 additions and 27 deletions

View file

@ -160,6 +160,7 @@ MODULE_FIRMWARE(FIRMWARE_TG3);
MODULE_FIRMWARE(FIRMWARE_TG3TSO); MODULE_FIRMWARE(FIRMWARE_TG3TSO);
MODULE_FIRMWARE(FIRMWARE_TG3TSO5); 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 */ static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */
module_param(tg3_debug, int, 0); 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; 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; fn = tg3_msi;
if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
fn = tg3_msi_1shot; fn = tg3_msi_1shot;
@ -7928,34 +7929,81 @@ static int tg3_request_firmware(struct tg3 *tp)
return 0; 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) 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 /* All MSI supporting chips should support tagged
* status. Assert that this is the case. * status. Assert that this is the case.
*/ */
if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
printk(KERN_WARNING PFX "%s: MSI without TAGGED? " printk(KERN_WARNING PFX "%s: MSI without TAGGED? "
"Not using MSI.\n", tp->dev->name); "Not using MSI.\n", tp->dev->name);
} else if (pci_enable_msi(tp->pdev) == 0) { goto defcfg;
u32 msi_mode; }
msi_mode = tr32(MSGINT_MODE); if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) && tg3_enable_msix(tp))
tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); 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; 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->irq_cnt = 1;
tp->napi[0].irq_vec = tp->pdev->irq; tp->napi[0].irq_vec = tp->pdev->irq;
}
} }
static void tg3_ints_fini(struct tg3 *tp) 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); 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) static int tg3_open(struct net_device *dev)
@ -7992,14 +8040,18 @@ static int tg3_open(struct net_device *dev)
tg3_full_unlock(tp); 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 /* The placement of this call is tied
* to the setup and use of Host TX descriptors. * to the setup and use of Host TX descriptors.
*/ */
err = tg3_alloc_consistent(tp); err = tg3_alloc_consistent(tp);
if (err) if (err)
return err; goto err_out1;
tg3_ints_init(tp);
napi_enable(&tp->napi[0].napi); napi_enable(&tp->napi[0].napi);
@ -8014,7 +8066,7 @@ static int tg3_open(struct net_device *dev)
} }
if (err) if (err)
goto err_out1; goto err_out2;
tg3_full_lock(tp, 0); tg3_full_lock(tp, 0);
@ -8043,7 +8095,7 @@ static int tg3_open(struct net_device *dev)
tg3_full_unlock(tp); tg3_full_unlock(tp);
if (err) if (err)
goto err_out2; goto err_out3;
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
err = tg3_test_msi(tp); err = tg3_test_msi(tp);
@ -8054,7 +8106,7 @@ static int tg3_open(struct net_device *dev)
tg3_free_rings(tp); tg3_free_rings(tp);
tg3_full_unlock(tp); tg3_full_unlock(tp);
goto err_out1; goto err_out2;
} }
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
@ -8081,16 +8133,18 @@ static int tg3_open(struct net_device *dev)
return 0; return 0;
err_out2: err_out3:
for (i = tp->irq_cnt - 1; i >= 0; i--) { for (i = tp->irq_cnt - 1; i >= 0; i--) {
struct tg3_napi *tnapi = &tp->napi[i]; struct tg3_napi *tnapi = &tp->napi[i];
free_irq(tnapi->irq_vec, tnapi); free_irq(tnapi->irq_vec, tnapi);
} }
err_out1: err_out2:
napi_disable(&tp->napi[0].napi); napi_disable(&tp->napi[0].napi);
tg3_ints_fini(tp);
tg3_free_consistent(tp); tg3_free_consistent(tp);
err_out1:
tg3_ints_fini(tp);
return err; return err;
} }

View file

@ -2621,6 +2621,9 @@ struct tg3 {
#define TG3_FLAG_NVRAM 0x00002000 #define TG3_FLAG_NVRAM 0x00002000
#define TG3_FLAG_NVRAM_BUFFERED 0x00004000 #define TG3_FLAG_NVRAM_BUFFERED 0x00004000
#define TG3_FLAG_SUPPORT_MSI 0x00008000 #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_PCIX_MODE 0x00020000
#define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000
#define TG3_FLAG_PCI_32BIT 0x00080000 #define TG3_FLAG_PCI_32BIT 0x00080000
@ -2659,6 +2662,9 @@ struct tg3 {
#define TG3_FLG2_5750_PLUS 0x00080000 #define TG3_FLG2_5750_PLUS 0x00080000
#define TG3_FLG2_PROTECTED_NVRAM 0x00100000 #define TG3_FLG2_PROTECTED_NVRAM 0x00100000
#define TG3_FLG2_USING_MSI 0x00200000 #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_MII_SERDES 0x00800000
#define TG3_FLG2_ANY_SERDES (TG3_FLG2_PHY_SERDES | \ #define TG3_FLG2_ANY_SERDES (TG3_FLG2_PHY_SERDES | \
TG3_FLG2_MII_SERDES) TG3_FLG2_MII_SERDES)