diff options
author | Brice Goglin <brice@myri.com> | 2008-05-08 20:22:16 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-05-30 22:11:47 -0400 |
commit | 981813d8e0a16946f511f4eda17bb4ee4fa2769c (patch) | |
tree | 177ad13be780a25ee8cc5052b2aa266243d12fe6 /drivers/net | |
parent | 0dcffac1a329be69bab0ac604bf7283737108e68 (diff) |
myri10ge: add Direct Cache Access support
Add I/O AT DCA (Direct Cache Access) support.
Signed-off-by: Brice Goglin <brice@myri.com>
Signed-off-by: Andrew Gallatin <gallatin@myri.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/myri10ge/myri10ge.c | 146 |
1 files changed, 145 insertions, 1 deletions
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index eddcee326f06..93007d38df57 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/if_ether.h> | 49 | #include <linux/if_ether.h> |
50 | #include <linux/if_vlan.h> | 50 | #include <linux/if_vlan.h> |
51 | #include <linux/inet_lro.h> | 51 | #include <linux/inet_lro.h> |
52 | #include <linux/dca.h> | ||
52 | #include <linux/ip.h> | 53 | #include <linux/ip.h> |
53 | #include <linux/inet.h> | 54 | #include <linux/inet.h> |
54 | #include <linux/in.h> | 55 | #include <linux/in.h> |
@@ -185,6 +186,11 @@ struct myri10ge_slice_state { | |||
185 | dma_addr_t fw_stats_bus; | 186 | dma_addr_t fw_stats_bus; |
186 | int watchdog_tx_done; | 187 | int watchdog_tx_done; |
187 | int watchdog_tx_req; | 188 | int watchdog_tx_req; |
189 | #ifdef CONFIG_DCA | ||
190 | int cached_dca_tag; | ||
191 | int cpu; | ||
192 | __be32 __iomem *dca_tag; | ||
193 | #endif | ||
188 | char irq_desc[32]; | 194 | char irq_desc[32]; |
189 | }; | 195 | }; |
190 | 196 | ||
@@ -212,6 +218,9 @@ struct myri10ge_priv { | |||
212 | int msi_enabled; | 218 | int msi_enabled; |
213 | int msix_enabled; | 219 | int msix_enabled; |
214 | struct msix_entry *msix_vectors; | 220 | struct msix_entry *msix_vectors; |
221 | #ifdef CONFIG_DCA | ||
222 | int dca_enabled; | ||
223 | #endif | ||
215 | u32 link_state; | 224 | u32 link_state; |
216 | unsigned int rdma_tags_available; | 225 | unsigned int rdma_tags_available; |
217 | int intr_coal_delay; | 226 | int intr_coal_delay; |
@@ -335,6 +344,10 @@ static int myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; | |||
335 | module_param(myri10ge_rss_hash, int, S_IRUGO); | 344 | module_param(myri10ge_rss_hash, int, S_IRUGO); |
336 | MODULE_PARM_DESC(myri10ge_rss_hash, "Type of RSS hashing to do"); | 345 | MODULE_PARM_DESC(myri10ge_rss_hash, "Type of RSS hashing to do"); |
337 | 346 | ||
347 | static int myri10ge_dca = 1; | ||
348 | module_param(myri10ge_dca, int, S_IRUGO); | ||
349 | MODULE_PARM_DESC(myri10ge_dca, "Enable DCA if possible"); | ||
350 | |||
338 | #define MYRI10GE_FW_OFFSET 1024*1024 | 351 | #define MYRI10GE_FW_OFFSET 1024*1024 |
339 | #define MYRI10GE_HIGHPART_TO_U32(X) \ | 352 | #define MYRI10GE_HIGHPART_TO_U32(X) \ |
340 | (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0) | 353 | (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0) |
@@ -878,6 +891,9 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) | |||
878 | struct myri10ge_slice_state *ss; | 891 | struct myri10ge_slice_state *ss; |
879 | int i, status; | 892 | int i, status; |
880 | size_t bytes; | 893 | size_t bytes; |
894 | #ifdef CONFIG_DCA | ||
895 | unsigned long dca_tag_off; | ||
896 | #endif | ||
881 | 897 | ||
882 | /* try to send a reset command to the card to see if it | 898 | /* try to send a reset command to the card to see if it |
883 | * is alive */ | 899 | * is alive */ |
@@ -970,6 +986,20 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) | |||
970 | } | 986 | } |
971 | put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); | 987 | put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); |
972 | 988 | ||
989 | #ifdef CONFIG_DCA | ||
990 | status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_DCA_OFFSET, &cmd, 0); | ||
991 | dca_tag_off = cmd.data0; | ||
992 | for (i = 0; i < mgp->num_slices; i++) { | ||
993 | ss = &mgp->ss[i]; | ||
994 | if (status == 0) { | ||
995 | ss->dca_tag = (__iomem __be32 *) | ||
996 | (mgp->sram + dca_tag_off + 4 * i); | ||
997 | } else { | ||
998 | ss->dca_tag = NULL; | ||
999 | } | ||
1000 | } | ||
1001 | #endif /* CONFIG_DCA */ | ||
1002 | |||
973 | /* reset mcp/driver shared state back to 0 */ | 1003 | /* reset mcp/driver shared state back to 0 */ |
974 | 1004 | ||
975 | mgp->link_changes = 0; | 1005 | mgp->link_changes = 0; |
@@ -995,6 +1025,77 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) | |||
995 | return status; | 1025 | return status; |
996 | } | 1026 | } |
997 | 1027 | ||
1028 | #ifdef CONFIG_DCA | ||
1029 | static void | ||
1030 | myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag) | ||
1031 | { | ||
1032 | ss->cpu = cpu; | ||
1033 | ss->cached_dca_tag = tag; | ||
1034 | put_be32(htonl(tag), ss->dca_tag); | ||
1035 | } | ||
1036 | |||
1037 | static inline void myri10ge_update_dca(struct myri10ge_slice_state *ss) | ||
1038 | { | ||
1039 | int cpu = get_cpu(); | ||
1040 | int tag; | ||
1041 | |||
1042 | if (cpu != ss->cpu) { | ||
1043 | tag = dca_get_tag(cpu); | ||
1044 | if (ss->cached_dca_tag != tag) | ||
1045 | myri10ge_write_dca(ss, cpu, tag); | ||
1046 | } | ||
1047 | put_cpu(); | ||
1048 | } | ||
1049 | |||
1050 | static void myri10ge_setup_dca(struct myri10ge_priv *mgp) | ||
1051 | { | ||
1052 | int err, i; | ||
1053 | struct pci_dev *pdev = mgp->pdev; | ||
1054 | |||
1055 | if (mgp->ss[0].dca_tag == NULL || mgp->dca_enabled) | ||
1056 | return; | ||
1057 | if (!myri10ge_dca) { | ||
1058 | dev_err(&pdev->dev, "dca disabled by administrator\n"); | ||
1059 | return; | ||
1060 | } | ||
1061 | err = dca_add_requester(&pdev->dev); | ||
1062 | if (err) { | ||
1063 | dev_err(&pdev->dev, | ||
1064 | "dca_add_requester() failed, err=%d\n", err); | ||
1065 | return; | ||
1066 | } | ||
1067 | mgp->dca_enabled = 1; | ||
1068 | for (i = 0; i < mgp->num_slices; i++) | ||
1069 | myri10ge_write_dca(&mgp->ss[i], -1, 0); | ||
1070 | } | ||
1071 | |||
1072 | static void myri10ge_teardown_dca(struct myri10ge_priv *mgp) | ||
1073 | { | ||
1074 | struct pci_dev *pdev = mgp->pdev; | ||
1075 | int err; | ||
1076 | |||
1077 | if (!mgp->dca_enabled) | ||
1078 | return; | ||
1079 | mgp->dca_enabled = 0; | ||
1080 | err = dca_remove_requester(&pdev->dev); | ||
1081 | } | ||
1082 | |||
1083 | static int myri10ge_notify_dca_device(struct device *dev, void *data) | ||
1084 | { | ||
1085 | struct myri10ge_priv *mgp; | ||
1086 | unsigned long event; | ||
1087 | |||
1088 | mgp = dev_get_drvdata(dev); | ||
1089 | event = *(unsigned long *)data; | ||
1090 | |||
1091 | if (event == DCA_PROVIDER_ADD) | ||
1092 | myri10ge_setup_dca(mgp); | ||
1093 | else if (event == DCA_PROVIDER_REMOVE) | ||
1094 | myri10ge_teardown_dca(mgp); | ||
1095 | return 0; | ||
1096 | } | ||
1097 | #endif /* CONFIG_DCA */ | ||
1098 | |||
998 | static inline void | 1099 | static inline void |
999 | myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst, | 1100 | myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst, |
1000 | struct mcp_kreq_ether_recv *src) | 1101 | struct mcp_kreq_ether_recv *src) |
@@ -1362,6 +1463,11 @@ static int myri10ge_poll(struct napi_struct *napi, int budget) | |||
1362 | struct net_device *netdev = ss->mgp->dev; | 1463 | struct net_device *netdev = ss->mgp->dev; |
1363 | int work_done; | 1464 | int work_done; |
1364 | 1465 | ||
1466 | #ifdef CONFIG_DCA | ||
1467 | if (ss->mgp->dca_enabled) | ||
1468 | myri10ge_update_dca(ss); | ||
1469 | #endif | ||
1470 | |||
1365 | /* process as many rx events as NAPI will allow */ | 1471 | /* process as many rx events as NAPI will allow */ |
1366 | work_done = myri10ge_clean_rx_done(ss, budget); | 1472 | work_done = myri10ge_clean_rx_done(ss, budget); |
1367 | 1473 | ||
@@ -1586,6 +1692,9 @@ static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = { | |||
1586 | "tx_boundary", "WC", "irq", "MSI", "MSIX", | 1692 | "tx_boundary", "WC", "irq", "MSI", "MSIX", |
1587 | "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs", | 1693 | "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs", |
1588 | "serial_number", "watchdog_resets", | 1694 | "serial_number", "watchdog_resets", |
1695 | #ifdef CONFIG_DCA | ||
1696 | "dca_capable", "dca_enabled", | ||
1697 | #endif | ||
1589 | "link_changes", "link_up", "dropped_link_overflow", | 1698 | "link_changes", "link_up", "dropped_link_overflow", |
1590 | "dropped_link_error_or_filtered", | 1699 | "dropped_link_error_or_filtered", |
1591 | "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32", | 1700 | "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32", |
@@ -1662,6 +1771,10 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, | |||
1662 | data[i++] = (unsigned int)mgp->read_write_dma; | 1771 | data[i++] = (unsigned int)mgp->read_write_dma; |
1663 | data[i++] = (unsigned int)mgp->serial_number; | 1772 | data[i++] = (unsigned int)mgp->serial_number; |
1664 | data[i++] = (unsigned int)mgp->watchdog_resets; | 1773 | data[i++] = (unsigned int)mgp->watchdog_resets; |
1774 | #ifdef CONFIG_DCA | ||
1775 | data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL); | ||
1776 | data[i++] = (unsigned int)(mgp->dca_enabled); | ||
1777 | #endif | ||
1665 | data[i++] = (unsigned int)mgp->link_changes; | 1778 | data[i++] = (unsigned int)mgp->link_changes; |
1666 | 1779 | ||
1667 | /* firmware stats are useful only in the first slice */ | 1780 | /* firmware stats are useful only in the first slice */ |
@@ -3687,7 +3800,9 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3687 | dev_err(&pdev->dev, "failed reset\n"); | 3800 | dev_err(&pdev->dev, "failed reset\n"); |
3688 | goto abort_with_slices; | 3801 | goto abort_with_slices; |
3689 | } | 3802 | } |
3690 | 3803 | #ifdef CONFIG_DCA | |
3804 | myri10ge_setup_dca(mgp); | ||
3805 | #endif | ||
3691 | pci_set_drvdata(pdev, mgp); | 3806 | pci_set_drvdata(pdev, mgp); |
3692 | if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU) | 3807 | if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU) |
3693 | myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; | 3808 | myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; |
@@ -3788,6 +3903,9 @@ static void myri10ge_remove(struct pci_dev *pdev) | |||
3788 | netdev = mgp->dev; | 3903 | netdev = mgp->dev; |
3789 | unregister_netdev(netdev); | 3904 | unregister_netdev(netdev); |
3790 | 3905 | ||
3906 | #ifdef CONFIG_DCA | ||
3907 | myri10ge_teardown_dca(mgp); | ||
3908 | #endif | ||
3791 | myri10ge_dummy_rdma(mgp, 0); | 3909 | myri10ge_dummy_rdma(mgp, 0); |
3792 | 3910 | ||
3793 | /* avoid a memory leak */ | 3911 | /* avoid a memory leak */ |
@@ -3830,6 +3948,26 @@ static struct pci_driver myri10ge_driver = { | |||
3830 | #endif | 3948 | #endif |
3831 | }; | 3949 | }; |
3832 | 3950 | ||
3951 | #ifdef CONFIG_DCA | ||
3952 | static int | ||
3953 | myri10ge_notify_dca(struct notifier_block *nb, unsigned long event, void *p) | ||
3954 | { | ||
3955 | int err = driver_for_each_device(&myri10ge_driver.driver, | ||
3956 | NULL, &event, | ||
3957 | myri10ge_notify_dca_device); | ||
3958 | |||
3959 | if (err) | ||
3960 | return NOTIFY_BAD; | ||
3961 | return NOTIFY_DONE; | ||
3962 | } | ||
3963 | |||
3964 | static struct notifier_block myri10ge_dca_notifier = { | ||
3965 | .notifier_call = myri10ge_notify_dca, | ||
3966 | .next = NULL, | ||
3967 | .priority = 0, | ||
3968 | }; | ||
3969 | #endif /* CONFIG_DCA */ | ||
3970 | |||
3833 | static __init int myri10ge_init_module(void) | 3971 | static __init int myri10ge_init_module(void) |
3834 | { | 3972 | { |
3835 | printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name, | 3973 | printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name, |
@@ -3842,6 +3980,9 @@ static __init int myri10ge_init_module(void) | |||
3842 | myri10ge_driver.name, myri10ge_rss_hash); | 3980 | myri10ge_driver.name, myri10ge_rss_hash); |
3843 | myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; | 3981 | myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; |
3844 | } | 3982 | } |
3983 | #ifdef CONFIG_DCA | ||
3984 | dca_register_notify(&myri10ge_dca_notifier); | ||
3985 | #endif | ||
3845 | 3986 | ||
3846 | return pci_register_driver(&myri10ge_driver); | 3987 | return pci_register_driver(&myri10ge_driver); |
3847 | } | 3988 | } |
@@ -3850,6 +3991,9 @@ module_init(myri10ge_init_module); | |||
3850 | 3991 | ||
3851 | static __exit void myri10ge_cleanup_module(void) | 3992 | static __exit void myri10ge_cleanup_module(void) |
3852 | { | 3993 | { |
3994 | #ifdef CONFIG_DCA | ||
3995 | dca_unregister_notify(&myri10ge_dca_notifier); | ||
3996 | #endif | ||
3853 | pci_unregister_driver(&myri10ge_driver); | 3997 | pci_unregister_driver(&myri10ge_driver); |
3854 | } | 3998 | } |
3855 | 3999 | ||