aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-sta.c
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2009-10-09 05:19:45 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-10-27 16:48:06 -0400
commit2f301227a1ede57504694e1f64839839f5737cac (patch)
treec148ca6c3409f5f8fed4455fba3a78fe31469135 /drivers/net/wireless/iwlwifi/iwl-sta.c
parentae751bab9f55c3152ebf713c89a4fb6f439c2575 (diff)
iwlwifi: use paged Rx
This switches the iwlwifi driver to use paged skb from linear skb for Rx buffer. So that it relieves some Rx buffer allocation pressure for the memory subsystem. Currently iwlwifi (4K for 3945) requests 8K bytes for Rx buffer. Due to the trailing skb_shared_info in the skb->data, alloc_skb() will do the next order allocation, which is 16K bytes. This is suboptimal and more likely to fail when the system is under memory usage pressure. Switching to paged Rx skb lets us allocate the RXB directly by alloc_pages(), so that only order 1 allocation is required. It also adjusts the area spin_lock (with IRQ disabled) protected in the tasklet because tasklet guarentees to run only on one CPU and the new unprotected code can be preempted by the IRQ handler. This saves us from spawning another workqueue to make skb_linearize/__pskb_pull_tail happy (which cannot be called in hard irq context). Finally, mac80211 doesn't support paged Rx yet. So we linearize the skb for all the management frames and software decryption or defragmentation required data frames before handed to mac80211. For all the other frames, we __pskb_pull_tail 64 bytes in the linear area of the skb for mac80211 to handle them properly. Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c62
1 files changed, 24 insertions, 38 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index c6633fec821..dc74c16d36a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -99,32 +99,25 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
99 99
100static void iwl_add_sta_callback(struct iwl_priv *priv, 100static void iwl_add_sta_callback(struct iwl_priv *priv,
101 struct iwl_device_cmd *cmd, 101 struct iwl_device_cmd *cmd,
102 struct sk_buff *skb) 102 struct iwl_rx_packet *pkt)
103{ 103{
104 struct iwl_rx_packet *res = NULL;
105 struct iwl_addsta_cmd *addsta = 104 struct iwl_addsta_cmd *addsta =
106 (struct iwl_addsta_cmd *)cmd->cmd.payload; 105 (struct iwl_addsta_cmd *)cmd->cmd.payload;
107 u8 sta_id = addsta->sta.sta_id; 106 u8 sta_id = addsta->sta.sta_id;
108 107
109 if (!skb) { 108 if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
110 IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
111 return;
112 }
113
114 res = (struct iwl_rx_packet *)skb->data;
115 if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
116 IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", 109 IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
117 res->hdr.flags); 110 pkt->hdr.flags);
118 return; 111 return;
119 } 112 }
120 113
121 switch (res->u.add_sta.status) { 114 switch (pkt->u.add_sta.status) {
122 case ADD_STA_SUCCESS_MSK: 115 case ADD_STA_SUCCESS_MSK:
123 iwl_sta_ucode_activate(priv, sta_id); 116 iwl_sta_ucode_activate(priv, sta_id);
124 /* fall through */ 117 /* fall through */
125 default: 118 default:
126 IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", 119 IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
127 res->u.add_sta.status); 120 pkt->u.add_sta.status);
128 break; 121 break;
129 } 122 }
130} 123}
@@ -132,7 +125,7 @@ static void iwl_add_sta_callback(struct iwl_priv *priv,
132int iwl_send_add_sta(struct iwl_priv *priv, 125int iwl_send_add_sta(struct iwl_priv *priv,
133 struct iwl_addsta_cmd *sta, u8 flags) 126 struct iwl_addsta_cmd *sta, u8 flags)
134{ 127{
135 struct iwl_rx_packet *res = NULL; 128 struct iwl_rx_packet *pkt = NULL;
136 int ret = 0; 129 int ret = 0;
137 u8 data[sizeof(*sta)]; 130 u8 data[sizeof(*sta)];
138 struct iwl_host_cmd cmd = { 131 struct iwl_host_cmd cmd = {
@@ -152,15 +145,15 @@ int iwl_send_add_sta(struct iwl_priv *priv,
152 if (ret || (flags & CMD_ASYNC)) 145 if (ret || (flags & CMD_ASYNC))
153 return ret; 146 return ret;
154 147
155 res = (struct iwl_rx_packet *)cmd.reply_skb->data; 148 pkt = (struct iwl_rx_packet *)cmd.reply_page;
156 if (res->hdr.flags & IWL_CMD_FAILED_MSK) { 149 if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
157 IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", 150 IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
158 res->hdr.flags); 151 pkt->hdr.flags);
159 ret = -EIO; 152 ret = -EIO;
160 } 153 }
161 154
162 if (ret == 0) { 155 if (ret == 0) {
163 switch (res->u.add_sta.status) { 156 switch (pkt->u.add_sta.status) {
164 case ADD_STA_SUCCESS_MSK: 157 case ADD_STA_SUCCESS_MSK:
165 iwl_sta_ucode_activate(priv, sta->sta.sta_id); 158 iwl_sta_ucode_activate(priv, sta->sta.sta_id);
166 IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); 159 IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
@@ -172,8 +165,8 @@ int iwl_send_add_sta(struct iwl_priv *priv,
172 } 165 }
173 } 166 }
174 167
175 priv->alloc_rxb_skb--; 168 priv->alloc_rxb_page--;
176 dev_kfree_skb_any(cmd.reply_skb); 169 free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
177 170
178 return ret; 171 return ret;
179} 172}
@@ -324,26 +317,19 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
324 317
325static void iwl_remove_sta_callback(struct iwl_priv *priv, 318static void iwl_remove_sta_callback(struct iwl_priv *priv,
326 struct iwl_device_cmd *cmd, 319 struct iwl_device_cmd *cmd,
327 struct sk_buff *skb) 320 struct iwl_rx_packet *pkt)
328{ 321{
329 struct iwl_rx_packet *res = NULL;
330 struct iwl_rem_sta_cmd *rm_sta = 322 struct iwl_rem_sta_cmd *rm_sta =
331 (struct iwl_rem_sta_cmd *)cmd->cmd.payload; 323 (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
332 const char *addr = rm_sta->addr; 324 const char *addr = rm_sta->addr;
333 325
334 if (!skb) { 326 if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
335 IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
336 return;
337 }
338
339 res = (struct iwl_rx_packet *)skb->data;
340 if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
341 IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", 327 IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
342 res->hdr.flags); 328 pkt->hdr.flags);
343 return; 329 return;
344 } 330 }
345 331
346 switch (res->u.rem_sta.status) { 332 switch (pkt->u.rem_sta.status) {
347 case REM_STA_SUCCESS_MSK: 333 case REM_STA_SUCCESS_MSK:
348 iwl_sta_ucode_deactivate(priv, addr); 334 iwl_sta_ucode_deactivate(priv, addr);
349 break; 335 break;
@@ -356,7 +342,7 @@ static void iwl_remove_sta_callback(struct iwl_priv *priv,
356static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, 342static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
357 u8 flags) 343 u8 flags)
358{ 344{
359 struct iwl_rx_packet *res = NULL; 345 struct iwl_rx_packet *pkt;
360 int ret; 346 int ret;
361 347
362 struct iwl_rem_sta_cmd rm_sta_cmd; 348 struct iwl_rem_sta_cmd rm_sta_cmd;
@@ -381,15 +367,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
381 if (ret || (flags & CMD_ASYNC)) 367 if (ret || (flags & CMD_ASYNC))
382 return ret; 368 return ret;
383 369
384 res = (struct iwl_rx_packet *)cmd.reply_skb->data; 370 pkt = (struct iwl_rx_packet *)cmd.reply_page;
385 if (res->hdr.flags & IWL_CMD_FAILED_MSK) { 371 if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
386 IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", 372 IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
387 res->hdr.flags); 373 pkt->hdr.flags);
388 ret = -EIO; 374 ret = -EIO;
389 } 375 }
390 376
391 if (!ret) { 377 if (!ret) {
392 switch (res->u.rem_sta.status) { 378 switch (pkt->u.rem_sta.status) {
393 case REM_STA_SUCCESS_MSK: 379 case REM_STA_SUCCESS_MSK:
394 iwl_sta_ucode_deactivate(priv, addr); 380 iwl_sta_ucode_deactivate(priv, addr);
395 IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); 381 IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
@@ -401,8 +387,8 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
401 } 387 }
402 } 388 }
403 389
404 priv->alloc_rxb_skb--; 390 priv->alloc_rxb_page--;
405 dev_kfree_skb_any(cmd.reply_skb); 391 free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
406 392
407 return ret; 393 return ret;
408} 394}