This patch follows Eric Dumazet's commit7b70176421
for Atheros atl1c driver to fix one exactly same bug in alx driver, that the network link will be lost in 1-5 minutes after the device is up. My laptop Lenovo Y580 with Atheros AR8161 ethernet device hit the same problem with kernel 4.4, and it will be cured by Jarod Wilson's commitc406700c
for alx driver which get merged in 4.5. But there are still some alx devices can't function well even with Jarod's patch, while this patch could make them work fine. More details on https://bugzilla.kernel.org/show_bug.cgi?id=70761 The debug shows the issue is very likely to be related with the RX DMA address, specifically 0x...f80, if RX buffer get 0x...f80 several times, their will be RX overflow error and device will stop working. For kernel 4.5.0 with Jarod's patch which works fine with my AR8161/Lennov Y580, if I made some change to the __netdev_alloc_skb --> __alloc_page_frag() to make the allocated buffer can get an address with 0x...f80, then the same error happens. If I make it to 0x...f40 or 0x....fc0, everything will be still fine. So I tend to believe that the 0x..f80 address cause the silicon to behave abnormally. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=70761 Cc: Eric Dumazet <edumazet@google.com> Cc: Johannes Berg <johannes@sipsolutions.net> Cc: Jarod Wilson <jarod@redhat.com> Signed-off-by: Feng Tang <feng.tang@intel.com> Tested-by: Ole Lukoie <olelukoie@mail.ru> Signed-off-by: David S. Miller <davem@davemloft.net>
122 lines
3.0 KiB
C
122 lines
3.0 KiB
C
/*
|
|
* Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
|
|
*
|
|
* This file is free software: you may copy, redistribute and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation, either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This file is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* This file incorporates work covered by the following copyright and
|
|
* permission notice:
|
|
*
|
|
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifndef _ALX_H_
|
|
#define _ALX_H_
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/spinlock.h>
|
|
#include "hw.h"
|
|
|
|
#define ALX_WATCHDOG_TIME (5 * HZ)
|
|
|
|
struct alx_buffer {
|
|
struct sk_buff *skb;
|
|
DEFINE_DMA_UNMAP_ADDR(dma);
|
|
DEFINE_DMA_UNMAP_LEN(size);
|
|
};
|
|
|
|
struct alx_rx_queue {
|
|
struct alx_rrd *rrd;
|
|
dma_addr_t rrd_dma;
|
|
|
|
struct alx_rfd *rfd;
|
|
dma_addr_t rfd_dma;
|
|
|
|
struct alx_buffer *bufs;
|
|
|
|
u16 write_idx, read_idx;
|
|
u16 rrd_read_idx;
|
|
};
|
|
#define ALX_RX_ALLOC_THRESH 32
|
|
|
|
struct alx_tx_queue {
|
|
struct alx_txd *tpd;
|
|
dma_addr_t tpd_dma;
|
|
struct alx_buffer *bufs;
|
|
u16 write_idx, read_idx;
|
|
};
|
|
|
|
#define ALX_DEFAULT_TX_WORK 128
|
|
|
|
enum alx_device_quirks {
|
|
ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG = BIT(0),
|
|
};
|
|
|
|
struct alx_priv {
|
|
struct net_device *dev;
|
|
|
|
struct alx_hw hw;
|
|
|
|
/* all descriptor memory */
|
|
struct {
|
|
dma_addr_t dma;
|
|
void *virt;
|
|
unsigned int size;
|
|
} descmem;
|
|
|
|
/* protect int_mask updates */
|
|
spinlock_t irq_lock;
|
|
u32 int_mask;
|
|
|
|
unsigned int tx_ringsz;
|
|
unsigned int rx_ringsz;
|
|
unsigned int rxbuf_size;
|
|
|
|
struct page *rx_page;
|
|
unsigned int rx_page_offset;
|
|
unsigned int rx_frag_size;
|
|
|
|
struct napi_struct napi;
|
|
struct alx_tx_queue txq;
|
|
struct alx_rx_queue rxq;
|
|
|
|
struct work_struct link_check_wk;
|
|
struct work_struct reset_wk;
|
|
|
|
u16 msg_enable;
|
|
|
|
bool msi;
|
|
|
|
/* protects hw.stats */
|
|
spinlock_t stats_lock;
|
|
};
|
|
|
|
extern const struct ethtool_ops alx_ethtool_ops;
|
|
extern const char alx_drv_name[];
|
|
|
|
#endif
|