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>
This commit is contained in:
Christian Lamparter
2008-10-15 04:07:16 +02:00
committed by John W. Linville
parent 9de5776ff3
commit b92f30d65a
4 changed files with 229 additions and 163 deletions

View File

@@ -235,7 +235,7 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
while (i != idx) {
desc = &ring[i];
kfree(tx_buf[i]);
p54_free_skb(dev, tx_buf[i]);
tx_buf[i] = NULL;
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)
return reg ? IRQ_HANDLED : IRQ_NONE;
}
static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
size_t len, int free_on_tx)
static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
int free_on_tx)
{
struct p54p_priv *priv = dev->priv;
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,
idx = le32_to_cpu(ring_control->host_idx[1]);
i = idx % ARRAY_SIZE(ring_control->tx_data);
mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE);
mapping = pci_map_single(priv->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE);
desc = &ring_control->tx_data[i];
desc->host_addr = cpu_to_le32(mapping);
desc->device_addr = data->req_id;
desc->len = cpu_to_le16(len);
desc->device_addr = ((struct p54_control_hdr *)skb->data)->req_id;
desc->len = cpu_to_le16(skb->len);
desc->flags = 0;
wmb();
ring_control->host_idx[1] = cpu_to_le32(idx + 1);
if (free_on_tx)
priv->tx_buf_data[i] = data;
priv->tx_buf_data[i] = skb;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -342,8 +343,10 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
/* FIXME: unlikely to happen because the device usually runs out of
memory before we fill the ring up, but we can make it impossible */
if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2)
if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) {
p54_free_skb(dev, skb);
printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy));
}
}
static void p54p_stop(struct ieee80211_hw *dev)
@@ -393,7 +396,7 @@ static void p54p_stop(struct ieee80211_hw *dev)
le16_to_cpu(desc->len),
PCI_DMA_TODEVICE);
kfree(priv->tx_buf_data[i]);
p54_free_skb(dev, priv->tx_buf_data[i]);
priv->tx_buf_data[i] = NULL;
}
@@ -405,7 +408,7 @@ static void p54p_stop(struct ieee80211_hw *dev)
le16_to_cpu(desc->len),
PCI_DMA_TODEVICE);
kfree(priv->tx_buf_mgmt[i]);
p54_free_skb(dev, priv->tx_buf_mgmt[i]);
priv->tx_buf_mgmt[i] = NULL;
}