diff options
author | Sathya Perla <sathyap@serverengines.com> | 2009-06-17 20:05:54 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-19 03:18:40 -0400 |
commit | 6ac7b687cb3acc437a586794949a43f5249956bb (patch) | |
tree | 249aa952dfafa22a8c299dc344df1aa7aeea8364 | |
parent | 5fb379ee67a7ec55ff65b467b472f3d69b60ba16 (diff) |
be2net: Use MCC queue for cmds that may be called in BH context
Currenlty multicast_set and promiscuous_config cmds -- that may be called in BH context --
use the blocking MCC mbox to post cmds.
An mbox cmd is protected via a spin_lock(cmd_lock) and not spin_lock_bh() as it is undesirable
to disable BHs while a blocking mbox cmd is in progress (and take long to finish.)
This can lockup a cmd in progress in process context.
So, these two cmds in BH context must use the MCC queue to post cmds.
Signed-off-by: Sathya Perla <sathyap@serverengines.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/benet/be_cmds.c | 69 |
1 files changed, 52 insertions, 17 deletions
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index f1ec191f0c0d..e4ad5e67fde7 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c | |||
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | #include "be.h" | 18 | #include "be.h" |
19 | 19 | ||
20 | void be_mcc_notify(struct be_ctrl_info *ctrl) | 20 | static void be_mcc_notify(struct be_ctrl_info *ctrl) |
21 | { | 21 | { |
22 | struct be_queue_info *mccq = &ctrl->mcc_obj.q; | 22 | struct be_queue_info *mccq = &ctrl->mcc_obj.q; |
23 | u32 val = 0; | 23 | u32 val = 0; |
@@ -101,6 +101,28 @@ void be_process_mcc(struct be_ctrl_info *ctrl) | |||
101 | spin_unlock_bh(&ctrl->mcc_cq_lock); | 101 | spin_unlock_bh(&ctrl->mcc_cq_lock); |
102 | } | 102 | } |
103 | 103 | ||
104 | /* Wait till no more pending mcc requests are present */ | ||
105 | static void be_mcc_wait_compl(struct be_ctrl_info *ctrl) | ||
106 | { | ||
107 | #define mcc_timeout 50000 /* 5s timeout */ | ||
108 | int i; | ||
109 | for (i = 0; i < mcc_timeout; i++) { | ||
110 | be_process_mcc(ctrl); | ||
111 | if (atomic_read(&ctrl->mcc_obj.q.used) == 0) | ||
112 | break; | ||
113 | udelay(100); | ||
114 | } | ||
115 | if (i == mcc_timeout) | ||
116 | printk(KERN_WARNING DRV_NAME "mcc poll timed out\n"); | ||
117 | } | ||
118 | |||
119 | /* Notify MCC requests and wait for completion */ | ||
120 | static void be_mcc_notify_wait(struct be_ctrl_info *ctrl) | ||
121 | { | ||
122 | be_mcc_notify(ctrl); | ||
123 | be_mcc_wait_compl(ctrl); | ||
124 | } | ||
125 | |||
104 | static int be_mbox_db_ready_wait(void __iomem *db) | 126 | static int be_mbox_db_ready_wait(void __iomem *db) |
105 | { | 127 | { |
106 | int cnt = 0, wait = 5; | 128 | int cnt = 0, wait = 5; |
@@ -872,14 +894,18 @@ int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array, | |||
872 | return status; | 894 | return status; |
873 | } | 895 | } |
874 | 896 | ||
897 | /* Use MCC for this command as it may be called in BH context */ | ||
875 | int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) | 898 | int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) |
876 | { | 899 | { |
877 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | 900 | struct be_mcc_wrb *wrb; |
878 | struct be_cmd_req_promiscuous_config *req = embedded_payload(wrb); | 901 | struct be_cmd_req_promiscuous_config *req; |
879 | int status; | ||
880 | 902 | ||
881 | spin_lock(&ctrl->mbox_lock); | 903 | spin_lock_bh(&ctrl->mcc_lock); |
882 | memset(wrb, 0, sizeof(*wrb)); | 904 | |
905 | wrb = wrb_from_mcc(&ctrl->mcc_obj.q); | ||
906 | BUG_ON(!wrb); | ||
907 | |||
908 | req = embedded_payload(wrb); | ||
883 | 909 | ||
884 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | 910 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); |
885 | 911 | ||
@@ -891,21 +917,29 @@ int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en) | |||
891 | else | 917 | else |
892 | req->port0_promiscuous = en; | 918 | req->port0_promiscuous = en; |
893 | 919 | ||
894 | status = be_mbox_db_ring(ctrl); | 920 | be_mcc_notify_wait(ctrl); |
895 | 921 | ||
896 | spin_unlock(&ctrl->mbox_lock); | 922 | spin_unlock_bh(&ctrl->mcc_lock); |
897 | return status; | 923 | return 0; |
898 | } | 924 | } |
899 | 925 | ||
926 | /* | ||
927 | * Use MCC for this command as it may be called in BH context | ||
928 | * (mc == NULL) => multicast promiscous | ||
929 | */ | ||
900 | int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id, u8 *mac_table, | 930 | int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id, u8 *mac_table, |
901 | u32 num, bool promiscuous) | 931 | u32 num, bool promiscuous) |
902 | { | 932 | { |
903 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | 933 | #define BE_MAX_MC 32 /* set mcast promisc if > 32 */ |
904 | struct be_cmd_req_mcast_mac_config *req = embedded_payload(wrb); | 934 | struct be_mcc_wrb *wrb; |
905 | int status; | 935 | struct be_cmd_req_mcast_mac_config *req; |
906 | 936 | ||
907 | spin_lock(&ctrl->mbox_lock); | 937 | spin_lock_bh(&ctrl->mcc_lock); |
908 | memset(wrb, 0, sizeof(*wrb)); | 938 | |
939 | wrb = wrb_from_mcc(&ctrl->mcc_obj.q); | ||
940 | BUG_ON(!wrb); | ||
941 | |||
942 | req = embedded_payload(wrb); | ||
909 | 943 | ||
910 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | 944 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); |
911 | 945 | ||
@@ -920,10 +954,11 @@ int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id, u8 *mac_table, | |||
920 | memcpy(req->mac, mac_table, ETH_ALEN * num); | 954 | memcpy(req->mac, mac_table, ETH_ALEN * num); |
921 | } | 955 | } |
922 | 956 | ||
923 | status = be_mbox_db_ring(ctrl); | 957 | be_mcc_notify_wait(ctrl); |
924 | 958 | ||
925 | spin_unlock(&ctrl->mbox_lock); | 959 | spin_unlock_bh(&ctrl->mcc_lock); |
926 | return status; | 960 | |
961 | return 0; | ||
927 | } | 962 | } |
928 | 963 | ||
929 | int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) | 964 | int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc) |