forked from Minki/linux
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:
parent
4f125f42dd
commit
679563f47c
@ -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;
|
||||
|
||||
msi_mode = tr32(MSGINT_MODE);
|
||||
tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
|
||||
tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
|
||||
}
|
||||
printk(KERN_WARNING PFX "%s: MSI without TAGGED? "
|
||||
"Not using MSI.\n", tp->dev->name);
|
||||
goto defcfg;
|
||||
}
|
||||
|
||||
tp->irq_cnt = 1;
|
||||
tp->napi[0].irq_vec = tp->pdev->irq;
|
||||
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) {
|
||||
pci_disable_msi(tp->pdev);
|
||||
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_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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user