diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2009-09-01 08:55:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-09-02 03:43:33 -0400 |
commit | 679563f47cd2547a0e091b5bd3ddf30027af6b08 (patch) | |
tree | efb6a8a9e6d080447b89014725bfcfad0b33a3e6 /drivers/net/tg3.c | |
parent | 4f125f42dd55390016e21f8b3960f99d02d1001f (diff) |
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>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r-- | drivers/net/tg3.c | 108 |
1 files changed, 81 insertions, 27 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7717eae1221d..12ead83bd06f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -160,6 +160,7 @@ MODULE_FIRMWARE(FIRMWARE_TG3); | |||
160 | MODULE_FIRMWARE(FIRMWARE_TG3TSO); | 160 | MODULE_FIRMWARE(FIRMWARE_TG3TSO); |
161 | MODULE_FIRMWARE(FIRMWARE_TG3TSO5); | 161 | MODULE_FIRMWARE(FIRMWARE_TG3TSO5); |
162 | 162 | ||
163 | #define TG3_RSS_MIN_NUM_MSIX_VECS 2 | ||
163 | 164 | ||
164 | static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ | 165 | static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ |
165 | module_param(tg3_debug, int, 0); | 166 | module_param(tg3_debug, int, 0); |
@@ -7767,7 +7768,7 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num) | |||
7767 | name[IFNAMSIZ-1] = 0; | 7768 | name[IFNAMSIZ-1] = 0; |
7768 | } | 7769 | } |
7769 | 7770 | ||
7770 | if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { | 7771 | if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { |
7771 | fn = tg3_msi; | 7772 | fn = tg3_msi; |
7772 | if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) | 7773 | if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) |
7773 | fn = tg3_msi_1shot; | 7774 | fn = tg3_msi_1shot; |
@@ -7928,34 +7929,81 @@ static int tg3_request_firmware(struct tg3 *tp) | |||
7928 | return 0; | 7929 | return 0; |
7929 | } | 7930 | } |
7930 | 7931 | ||
7932 | static bool tg3_enable_msix(struct tg3 *tp) | ||
7933 | { | ||
7934 | int i, rc, cpus = num_online_cpus(); | ||
7935 | struct msix_entry msix_ent[tp->irq_max]; | ||
7936 | |||
7937 | if (cpus == 1) | ||
7938 | /* Just fallback to the simpler MSI mode. */ | ||
7939 | return false; | ||
7940 | |||
7941 | /* | ||
7942 | * We want as many rx rings enabled as there are cpus. | ||
7943 | * The first MSIX vector only deals with link interrupts, etc, | ||
7944 | * so we add one to the number of vectors we are requesting. | ||
7945 | */ | ||
7946 | tp->irq_cnt = min_t(unsigned, cpus + 1, tp->irq_max); | ||
7947 | |||
7948 | for (i = 0; i < tp->irq_max; i++) { | ||
7949 | msix_ent[i].entry = i; | ||
7950 | msix_ent[i].vector = 0; | ||
7951 | } | ||
7952 | |||
7953 | rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt); | ||
7954 | if (rc != 0) { | ||
7955 | if (rc < TG3_RSS_MIN_NUM_MSIX_VECS) | ||
7956 | return false; | ||
7957 | if (pci_enable_msix(tp->pdev, msix_ent, rc)) | ||
7958 | return false; | ||
7959 | printk(KERN_NOTICE | ||
7960 | "%s: Requested %d MSI-X vectors, received %d\n", | ||
7961 | tp->dev->name, tp->irq_cnt, rc); | ||
7962 | tp->irq_cnt = rc; | ||
7963 | } | ||
7964 | |||
7965 | for (i = 0; i < tp->irq_max; i++) | ||
7966 | tp->napi[i].irq_vec = msix_ent[i].vector; | ||
7967 | |||
7968 | return true; | ||
7969 | } | ||
7970 | |||
7931 | static void tg3_ints_init(struct tg3 *tp) | 7971 | static void tg3_ints_init(struct tg3 *tp) |
7932 | { | 7972 | { |
7933 | if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) { | 7973 | if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI_OR_MSIX) && |
7974 | !(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { | ||
7934 | /* All MSI supporting chips should support tagged | 7975 | /* All MSI supporting chips should support tagged |
7935 | * status. Assert that this is the case. | 7976 | * status. Assert that this is the case. |
7936 | */ | 7977 | */ |
7937 | if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { | 7978 | printk(KERN_WARNING PFX "%s: MSI without TAGGED? " |
7938 | printk(KERN_WARNING PFX "%s: MSI without TAGGED? " | 7979 | "Not using MSI.\n", tp->dev->name); |
7939 | "Not using MSI.\n", tp->dev->name); | 7980 | goto defcfg; |
7940 | } else if (pci_enable_msi(tp->pdev) == 0) { | ||
7941 | u32 msi_mode; | ||
7942 | |||
7943 | msi_mode = tr32(MSGINT_MODE); | ||
7944 | tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); | ||
7945 | tp->tg3_flags2 |= TG3_FLG2_USING_MSI; | ||
7946 | } | ||
7947 | } | 7981 | } |
7948 | 7982 | ||
7949 | tp->irq_cnt = 1; | 7983 | if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) && tg3_enable_msix(tp)) |
7950 | tp->napi[0].irq_vec = tp->pdev->irq; | 7984 | tp->tg3_flags2 |= TG3_FLG2_USING_MSIX; |
7985 | else if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) && | ||
7986 | pci_enable_msi(tp->pdev) == 0) | ||
7987 | tp->tg3_flags2 |= TG3_FLG2_USING_MSI; | ||
7988 | |||
7989 | if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { | ||
7990 | u32 msi_mode = tr32(MSGINT_MODE); | ||
7991 | tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); | ||
7992 | } | ||
7993 | defcfg: | ||
7994 | if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { | ||
7995 | tp->irq_cnt = 1; | ||
7996 | tp->napi[0].irq_vec = tp->pdev->irq; | ||
7997 | } | ||
7951 | } | 7998 | } |
7952 | 7999 | ||
7953 | static void tg3_ints_fini(struct tg3 *tp) | 8000 | static void tg3_ints_fini(struct tg3 *tp) |
7954 | { | 8001 | { |
7955 | if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { | 8002 | if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) |
7956 | pci_disable_msi(tp->pdev); | 8003 | pci_disable_msix(tp->pdev); |
7957 | tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; | 8004 | else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) |
7958 | } | 8005 | pci_disable_msi(tp->pdev); |
8006 | tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX; | ||
7959 | } | 8007 | } |
7960 | 8008 | ||
7961 | static int tg3_open(struct net_device *dev) | 8009 | static int tg3_open(struct net_device *dev) |
@@ -7992,14 +8040,18 @@ static int tg3_open(struct net_device *dev) | |||
7992 | 8040 | ||
7993 | tg3_full_unlock(tp); | 8041 | tg3_full_unlock(tp); |
7994 | 8042 | ||
8043 | /* | ||
8044 | * Setup interrupts first so we know how | ||
8045 | * many NAPI resources to allocate | ||
8046 | */ | ||
8047 | tg3_ints_init(tp); | ||
8048 | |||
7995 | /* The placement of this call is tied | 8049 | /* The placement of this call is tied |
7996 | * to the setup and use of Host TX descriptors. | 8050 | * to the setup and use of Host TX descriptors. |
7997 | */ | 8051 | */ |
7998 | err = tg3_alloc_consistent(tp); | 8052 | err = tg3_alloc_consistent(tp); |
7999 | if (err) | 8053 | if (err) |
8000 | return err; | 8054 | goto err_out1; |
8001 | |||
8002 | tg3_ints_init(tp); | ||
8003 | 8055 | ||
8004 | napi_enable(&tp->napi[0].napi); | 8056 | napi_enable(&tp->napi[0].napi); |
8005 | 8057 | ||
@@ -8014,7 +8066,7 @@ static int tg3_open(struct net_device *dev) | |||
8014 | } | 8066 | } |
8015 | 8067 | ||
8016 | if (err) | 8068 | if (err) |
8017 | goto err_out1; | 8069 | goto err_out2; |
8018 | 8070 | ||
8019 | tg3_full_lock(tp, 0); | 8071 | tg3_full_lock(tp, 0); |
8020 | 8072 | ||
@@ -8043,7 +8095,7 @@ static int tg3_open(struct net_device *dev) | |||
8043 | tg3_full_unlock(tp); | 8095 | tg3_full_unlock(tp); |
8044 | 8096 | ||
8045 | if (err) | 8097 | if (err) |
8046 | goto err_out2; | 8098 | goto err_out3; |
8047 | 8099 | ||
8048 | if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { | 8100 | if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { |
8049 | err = tg3_test_msi(tp); | 8101 | err = tg3_test_msi(tp); |
@@ -8054,7 +8106,7 @@ static int tg3_open(struct net_device *dev) | |||
8054 | tg3_free_rings(tp); | 8106 | tg3_free_rings(tp); |
8055 | tg3_full_unlock(tp); | 8107 | tg3_full_unlock(tp); |
8056 | 8108 | ||
8057 | goto err_out1; | 8109 | goto err_out2; |
8058 | } | 8110 | } |
8059 | 8111 | ||
8060 | if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { | 8112 | if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { |
@@ -8081,16 +8133,18 @@ static int tg3_open(struct net_device *dev) | |||
8081 | 8133 | ||
8082 | return 0; | 8134 | return 0; |
8083 | 8135 | ||
8084 | err_out2: | 8136 | err_out3: |
8085 | for (i = tp->irq_cnt - 1; i >= 0; i--) { | 8137 | for (i = tp->irq_cnt - 1; i >= 0; i--) { |
8086 | struct tg3_napi *tnapi = &tp->napi[i]; | 8138 | struct tg3_napi *tnapi = &tp->napi[i]; |
8087 | free_irq(tnapi->irq_vec, tnapi); | 8139 | free_irq(tnapi->irq_vec, tnapi); |
8088 | } | 8140 | } |
8089 | 8141 | ||
8090 | err_out1: | 8142 | err_out2: |
8091 | napi_disable(&tp->napi[0].napi); | 8143 | napi_disable(&tp->napi[0].napi); |
8092 | tg3_ints_fini(tp); | ||
8093 | tg3_free_consistent(tp); | 8144 | tg3_free_consistent(tp); |
8145 | |||
8146 | err_out1: | ||
8147 | tg3_ints_fini(tp); | ||
8094 | return err; | 8148 | return err; |
8095 | } | 8149 | } |
8096 | 8150 | ||