diff options
author | Christian Lamparter <chunkeey@web.de> | 2008-10-14 22:07:16 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-10-31 19:00:33 -0400 |
commit | b92f30d65aeb0502e2ed8beb80c8465578b40002 (patch) | |
tree | 7d2669d864df5368377dcad11c1bbf4be266eff5 /drivers/net/wireless/p54/p54pci.c | |
parent | 9de5776ff33a006b864341a6ec8d31f1a3c628cf (diff) |
p54: fix memory management
We have to be careful if multiple "control frames" are passed in a very short intervals to
the device's firmware. As p54_assign_address always put them into same memory location.
To guarantee that this won't happen anymore, we have to treat control frames like normal
data frames in the devices own memory management.
Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54/p54pci.c')
-rw-r--r-- | drivers/net/wireless/p54/p54pci.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index bba2c90e533f..1bb9584f0355 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c | |||
@@ -235,7 +235,7 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, | |||
235 | 235 | ||
236 | while (i != idx) { | 236 | while (i != idx) { |
237 | desc = &ring[i]; | 237 | desc = &ring[i]; |
238 | kfree(tx_buf[i]); | 238 | p54_free_skb(dev, tx_buf[i]); |
239 | tx_buf[i] = NULL; | 239 | tx_buf[i] = NULL; |
240 | 240 | ||
241 | pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), | 241 | pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), |
@@ -306,8 +306,8 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) | |||
306 | return reg ? IRQ_HANDLED : IRQ_NONE; | 306 | return reg ? IRQ_HANDLED : IRQ_NONE; |
307 | } | 307 | } |
308 | 308 | ||
309 | static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, | 309 | static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, |
310 | size_t len, int free_on_tx) | 310 | int free_on_tx) |
311 | { | 311 | { |
312 | struct p54p_priv *priv = dev->priv; | 312 | struct p54p_priv *priv = dev->priv; |
313 | struct p54p_ring_control *ring_control = priv->ring_control; | 313 | struct p54p_ring_control *ring_control = priv->ring_control; |
@@ -322,18 +322,19 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, | |||
322 | idx = le32_to_cpu(ring_control->host_idx[1]); | 322 | idx = le32_to_cpu(ring_control->host_idx[1]); |
323 | i = idx % ARRAY_SIZE(ring_control->tx_data); | 323 | i = idx % ARRAY_SIZE(ring_control->tx_data); |
324 | 324 | ||
325 | mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE); | 325 | mapping = pci_map_single(priv->pdev, skb->data, skb->len, |
326 | PCI_DMA_TODEVICE); | ||
326 | desc = &ring_control->tx_data[i]; | 327 | desc = &ring_control->tx_data[i]; |
327 | desc->host_addr = cpu_to_le32(mapping); | 328 | desc->host_addr = cpu_to_le32(mapping); |
328 | desc->device_addr = data->req_id; | 329 | desc->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; |
329 | desc->len = cpu_to_le16(len); | 330 | desc->len = cpu_to_le16(skb->len); |
330 | desc->flags = 0; | 331 | desc->flags = 0; |
331 | 332 | ||
332 | wmb(); | 333 | wmb(); |
333 | ring_control->host_idx[1] = cpu_to_le32(idx + 1); | 334 | ring_control->host_idx[1] = cpu_to_le32(idx + 1); |
334 | 335 | ||
335 | if (free_on_tx) | 336 | if (free_on_tx) |
336 | priv->tx_buf_data[i] = data; | 337 | priv->tx_buf_data[i] = skb; |
337 | 338 | ||
338 | spin_unlock_irqrestore(&priv->lock, flags); | 339 | spin_unlock_irqrestore(&priv->lock, flags); |
339 | 340 | ||
@@ -342,8 +343,10 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, | |||
342 | 343 | ||
343 | /* FIXME: unlikely to happen because the device usually runs out of | 344 | /* FIXME: unlikely to happen because the device usually runs out of |
344 | memory before we fill the ring up, but we can make it impossible */ | 345 | memory before we fill the ring up, but we can make it impossible */ |
345 | if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) | 346 | if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) { |
347 | p54_free_skb(dev, skb); | ||
346 | printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); | 348 | printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); |
349 | } | ||
347 | } | 350 | } |
348 | 351 | ||
349 | static void p54p_stop(struct ieee80211_hw *dev) | 352 | static void p54p_stop(struct ieee80211_hw *dev) |
@@ -393,7 +396,7 @@ static void p54p_stop(struct ieee80211_hw *dev) | |||
393 | le16_to_cpu(desc->len), | 396 | le16_to_cpu(desc->len), |
394 | PCI_DMA_TODEVICE); | 397 | PCI_DMA_TODEVICE); |
395 | 398 | ||
396 | kfree(priv->tx_buf_data[i]); | 399 | p54_free_skb(dev, priv->tx_buf_data[i]); |
397 | priv->tx_buf_data[i] = NULL; | 400 | priv->tx_buf_data[i] = NULL; |
398 | } | 401 | } |
399 | 402 | ||
@@ -405,7 +408,7 @@ static void p54p_stop(struct ieee80211_hw *dev) | |||
405 | le16_to_cpu(desc->len), | 408 | le16_to_cpu(desc->len), |
406 | PCI_DMA_TODEVICE); | 409 | PCI_DMA_TODEVICE); |
407 | 410 | ||
408 | kfree(priv->tx_buf_mgmt[i]); | 411 | p54_free_skb(dev, priv->tx_buf_mgmt[i]); |
409 | priv->tx_buf_mgmt[i] = NULL; | 412 | priv->tx_buf_mgmt[i] = NULL; |
410 | } | 413 | } |
411 | 414 | ||