From patchwork Sun Oct 11 14:28:55 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quintin Pitts X-Patchwork-Id: 53004 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n9BEZvnm027076 for ; Sun, 11 Oct 2009 14:35:58 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755848AbZJKO3h (ORCPT ); Sun, 11 Oct 2009 10:29:37 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755832AbZJKO3h (ORCPT ); Sun, 11 Oct 2009 10:29:37 -0400 Received: from mail-gx0-f212.google.com ([209.85.217.212]:62550 "EHLO mail-gx0-f212.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755273AbZJKO3g (ORCPT ); Sun, 11 Oct 2009 10:29:36 -0400 Received: by gxk4 with SMTP id 4so9325044gxk.8 for ; Sun, 11 Oct 2009 07:28:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from :user-agent:mime-version:to:cc:subject:content-type :content-transfer-encoding; bh=Tl+aBDzkki9prVxuOAPI9Ngn3KWtnIN0cP9esw8Tprk=; b=QIkQiER1ajw4rlWNZoj0C083dw60YYvGs/+qIqlCaLc9f91t2A87VeVIN0DWY2PEEA Ce7F7LcWGzEa4eNj5J7yvuuaT52Kh0I/qdt1WXzKXQK+x1k2y0Kt6uU+RVc9dgNvDNVh pT/7G7RspxId2aG7JeHI9cVyI6cm/vQUXTCIs= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:cc:subject :content-type:content-transfer-encoding; b=bYKlGXB5RVw+KpuynTXhhtgHFb8dciMzIs297Mg0Zs+A5Fbqh9hcj0uQwibtgI5UI9 JGRjWecVxsG+lCxkt/uPNALH66pIk7lBk1xXrUJKlrulOMJYV3M8Tm3f2HJk9LyiuK0V lqUkMudCtnLCxWmuBVQv5uj3GPFHLgtgpxo0s= Received: by 10.101.134.23 with SMTP id l23mr4755894ann.112.1255271337992; Sun, 11 Oct 2009 07:28:57 -0700 (PDT) Received: from qdiehard4.qpitts.net (76-242-69-2.lightspeed.dllstx.sbcglobal.net [76.242.69.2]) by mx.google.com with ESMTPS id 22sm1603791yxe.3.2009.10.11.07.28.56 (version=TLSv1/SSLv3 cipher=RC4-MD5); Sun, 11 Oct 2009 07:28:57 -0700 (PDT) Message-ID: <4AD1EBA7.904@gmail.com> Date: Sun, 11 Oct 2009 09:28:55 -0500 From: Quintin Pitts User-Agent: Thunderbird 2.0.0.21 (X11/20090302) MIME-Version: 1.0 To: John Linville CC: linux-wireless , Christian Lamparter Subject: [RFC] p54pci: skb_over_panic, soft lockup, stall under flood Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org --- a/drivers/net/wireless/p54/p54pci.c 2009-09-29 23:13:58.000000000 -0500 +++ b/drivers/net/wireless/p54/p54pci.c 2009-10-09 08:15:58.000000000 -0500 @@ -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;