diff options
author | Zhu Yi <yi.zhu@intel.com> | 2009-10-09 05:19:45 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-10-27 16:48:06 -0400 |
commit | 2f301227a1ede57504694e1f64839839f5737cac (patch) | |
tree | c148ca6c3409f5f8fed4455fba3a78fe31469135 /drivers/net/wireless/iwlwifi/iwl-sta.c | |
parent | ae751bab9f55c3152ebf713c89a4fb6f439c2575 (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.c | 62 |
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 c6633fec8216..dc74c16d36a8 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 | ||
100 | static void iwl_add_sta_callback(struct iwl_priv *priv, | 100 | static 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, | |||
132 | int iwl_send_add_sta(struct iwl_priv *priv, | 125 | int 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 | ||
325 | static void iwl_remove_sta_callback(struct iwl_priv *priv, | 318 | static 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, | |||
356 | static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, | 342 | static 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 | } |