@@ -131,7 +131,7 @@ static int p54p_upload_firmware(struct i
static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
int ring_index, struct p54p_desc *ring, u32 ring_limit,
- struct sk_buff **rx_buf)
+ struct sk_buff **rx_buf, u32 index)
{
struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control;
@@ -139,7 +139,11 @@ static void p54p_refill_rx_ring(struct i
idx = le32_to_cpu(ring_control->host_idx[ring_index]);
limit = idx;
- limit -= le32_to_cpu(ring_control->device_idx[ring_index]);
+/*
+ * Use last processed index instead of device_idx
+ * so we don't corrupt our ring
+ */
+ limit -= le32_to_cpu(index);
limit = ring_limit - limit;
i = idx % ring_limit;
@@ -181,9 +185,26 @@ static void p54p_check_rx_ring(struct ie
struct p54p_ring_control *ring_control = priv->ring_control;
struct p54p_desc *desc;
u32 idx, i;
+ int ret;
+ idx = le32_to_cpu(ring_control->device_idx[ring_index]);
i = (*index) % ring_limit;
- (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
+ if(unlikely((idx - (*index)) > ring_limit ||
+ (le32_to_cpu(ring_control->host_idx[ring_index]) - (*index)) > ring_limit)) {
+ printk(KERN_DEBUG "%s: devidx jumped *index=%d devidx=%d hostidx=%d ring_limit=%d\n",
+ __func__,(*index),idx,ring_control->host_idx[ring_index],ring_limit);
+/*
+ * Do nothing things are really wrong - device index has jumped got corrupted
+ * - wait for it to stabilize
+ * So far device idx exactly 0xFF (255) bytes less than what it should be.
+ * only seen to happen on very fast wireless and packet floods and/or iperf test
+ * In testing this error only encountered once - so next time around the
+ * device index is correct.
+ * if to continue would soft lockup/hang in while loop in p54p_refill_rx_ring
+ */
+ return;
+ }
+ (*index) = idx;
idx %= ring_limit;
while (i != idx) {
u16 len;
@@ -197,25 +218,40 @@ static void p54p_check_rx_ring(struct ie
i %= ring_limit;
continue;
}
+ if(unlikely(len == (desc->host_addr & 0xffff)
+ && (desc->flags == ((desc->host_addr & 0xffff0000) >> 16))) ) {
+/* device has put device dma in desc len/flag location - will crash in skb_put
+ * desc->len and desc->flags contain the host_addr -
+ * trap before skb_put and discard
+ * ViewSonic V210 and wireless card GENTEK WL-850 , IT8152 PCI bridge
+ * happens occasionally - no clear reason or frequency.
+ *
+ */
+ printk(KERN_DEBUG "%s: rx_ring len/flags has address - skipping!\n",__func__);
+ skb_trim(skb,0);
+ desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
+ desc->flags=0;
+
+ } else {
+
skb_put(skb, len);
- if (p54_rx(dev, skb)) {
- pci_unmap_single(priv->pdev,
+ ret=p54_rx(dev,skb);
+ pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
priv->common.rx_mtu + 32,
PCI_DMA_FROMDEVICE);
- rx_buf[i] = NULL;
- desc->host_addr = 0;
- } else {
- skb_trim(skb, 0);
- desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
- }
+ if(ret==0)
+ dev_kfree_skb(skb);
+ rx_buf[i] = NULL;
+ desc->host_addr = 0;
+ } /* end of desc->len skb corrupt crash test */
i++;
i %= ring_limit;
}
- p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf);
+ p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf, (*index));
}
/* caller must hold priv->lock */
@@ -428,10 +464,10 @@ static int p54p_open(struct ieee80211_hw
priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data,
- ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data);
+ ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data, 0);
p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
- ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt);
+ ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt, 0);
P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
P54P_READ(ring_control_base);
@@ -550,9 +586,26 @@ static int __devinit p54p_probe(struct p
}
err = p54p_open(dev);
- if (err)
- goto err_free_common;
+ if (err) {
+
+ printk(KERN_DEBUG "%s: p54p_open failed - trying again\n",__func__);
+ msleep(10);
+ err = p54p_open(dev);
+ if (err)
+ goto err_free_common;
+ }
err = p54_read_eeprom(dev);
+ if (err)
+ {
+ printk(KERN_DEBUG "%s: p54_read_eeprom failed - trying again\n",__func__);
+ p54p_stop(dev);
+ err = p54p_open(dev);
+ if (err)
+ goto err_free_common;
+ msleep(10);
+ err = p54_read_eeprom(dev);
+
+ }
p54p_stop(dev);
if (err)
goto err_free_common;