Merge tag 'v3.10' into drm-intel-fixes
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 18 Jul 2013 10:03:29 +0000 (12:03 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 18 Jul 2013 10:03:29 +0000 (12:03 +0200)
Backmerge Linux 3.10 to get at

commit 19b2dbde5732170a03bd82cc8bd442cf88d856f7
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Wed Jun 12 10:15:12 2013 +0100

    drm/i915: Restore fences after resume and GPU resets

That commit is not in my current -fixes pile since that's based on my
-next queue for 3.11. And the above mentioned fix was merged really
late into 3.10 (and blew up, bad me) so was on a diverging branch.

Option B would have been to rebase my current pile of fixes onto
Dave's drm-fixes branch. But since some of the patches here are a bit
tricky I've decided not to void all the testing by moving over the
entire merge window.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
133 files changed:
Documentation/networking/ip-sysctl.txt
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/include/asm/cputype.h
arch/arm/include/asm/glue-proc.h
arch/arm/include/asm/smp_plat.h
arch/arm/kernel/devtree.c
arch/arm/kernel/setup.c
arch/arm/mm/nommu.c
arch/arm/mm/proc-fa526.S
arch/arm/mm/proc-macros.S
arch/arm/mm/proc-v7.S
arch/mn10300/include/asm/uaccess.h
arch/mn10300/kernel/setup.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/platforms/pseries/eeh_cache.c
arch/powerpc/platforms/pseries/eeh_pe.c
arch/x86/kernel/kprobes/core.c
crypto/algboss.c
crypto/api.c
crypto/internal.h
drivers/acpi/dock.c
drivers/acpi/internal.h
drivers/acpi/scan.c
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/libata.h
drivers/block/rbd.c
drivers/bluetooth/btmrvl_main.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/gpio/gpio-omap.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/qxl/qxl_ioctl.c
drivers/mfd/tps6586x.c
drivers/net/bonding/bond_main.c
drivers/net/can/usb/usb_8dev.c
drivers/net/ethernet/atheros/Kconfig
drivers/net/ethernet/atheros/Makefile
drivers/net/ethernet/atheros/alx/Makefile [new file with mode: 0644]
drivers/net/ethernet/atheros/alx/alx.h [new file with mode: 0644]
drivers/net/ethernet/atheros/alx/ethtool.c [new file with mode: 0644]
drivers/net/ethernet/atheros/alx/hw.c [new file with mode: 0644]
drivers/net/ethernet/atheros/alx/hw.h [new file with mode: 0644]
drivers/net/ethernet/atheros/alx/main.c [new file with mode: 0644]
drivers/net/ethernet/atheros/alx/reg.h [new file with mode: 0644]
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/pxa168_eth.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/octeon/octeon_mgmt.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/renesas/sh_eth.h
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/macvtap.c
drivers/net/tun.c
drivers/net/usb/qmi_wwan.c
drivers/net/vxlan.c
drivers/net/wan/dlci.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/iwlegacy/3945-rs.c
drivers/net/wireless/iwlegacy/4965-rs.c
drivers/net/wireless/iwlwifi/dvm/rs.c
drivers/net/wireless/iwlwifi/dvm/rxon.c
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/pci.h
drivers/pci/setup-bus.c
drivers/regulator/tps6586x-regulator.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe_ctlr.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mr.c
drivers/scsi/qla2xxx/qla_nx.c
fs/exec.c
fs/ubifs/dir.c
include/acpi/acpi_drivers.h
include/linux/if_vlan.h
include/linux/netdevice.h
include/linux/skbuff.h
include/uapi/linux/Kbuild
kernel/events/hw_breakpoint.c
kernel/ptrace.c
kernel/time/tick-broadcast.c
net/bluetooth/hci_core.c
net/bluetooth/l2cap_core.c
net/bridge/br_multicast.c
net/core/dev.c
net/core/dev_ioctl.c
net/core/ethtool.c
net/core/skbuff.c
net/core/sock.c
net/ipv4/gre.c
net/ipv4/netfilter/ipt_ULOG.c
net/ipv4/tcp_ipv4.c
net/ipv6/addrconf.c
net/ipv6/ip6_output.c
net/ipv6/ndisc.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/key/af_key.c
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rate.c
net/mac80211/util.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/nf_conntrack_labels.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_nat_sip.c
net/netfilter/xt_TCPMSS.c
net/netfilter/xt_TCPOPTSTRIP.c
net/wireless/nl80211.c

index f98ca63..3458d63 100644 (file)
@@ -420,10 +420,10 @@ tcp_synack_retries - INTEGER
        for a passive TCP connection will happen after 63seconds.
 
 tcp_syncookies - BOOLEAN
-       Only valid when the kernel was compiled with CONFIG_SYNCOOKIES
+       Only valid when the kernel was compiled with CONFIG_SYN_COOKIES
        Send out syncookies when the syn backlog queue of a socket
        overflows. This is to prevent against the common 'SYN flood attack'
-       Default: FALSE
+       Default: 1
 
        Note, that syncookies is fallback facility.
        It MUST NOT be used to help highly loaded servers to stand
index 437dd12..79daefa 100644 (file)
@@ -3222,7 +3222,7 @@ F:        lib/fault-inject.c
 
 FCOE SUBSYSTEM (libfc, libfcoe, fcoe)
 M:     Robert Love <robert.w.love@intel.com>
-L:     devel@open-fcoe.org
+L:     fcoe-devel@open-fcoe.org
 W:     www.Open-FCoE.org
 S:     Supported
 F:     drivers/scsi/libfc/
index 0142c93..e5e3ba0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 10
 SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
 NAME = Unicycling Gorilla
 
 # *DOCUMENTATION*
index 2651b1d..136f263 100644 (file)
@@ -1087,6 +1087,20 @@ if !MMU
 source "arch/arm/Kconfig-nommu"
 endif
 
+config PJ4B_ERRATA_4742
+       bool "PJ4B Errata 4742: IDLE Wake Up Commands can Cause the CPU Core to Cease Operation"
+       depends on CPU_PJ4B && MACH_ARMADA_370
+       default y
+       help
+         When coming out of either a Wait for Interrupt (WFI) or a Wait for
+         Event (WFE) IDLE states, a specific timing sensitivity exists between
+         the retiring WFI/WFE instructions and the newly issued subsequent
+         instructions.  This sensitivity can result in a CPU hang scenario.
+         Workaround:
+         The software must insert either a Data Synchronization Barrier (DSB)
+         or Data Memory Barrier (DMB) command immediately after the WFI/WFE
+         instruction
+
 config ARM_ERRATA_326103
        bool "ARM errata: FSR write bit incorrect on a SWP to read-only memory"
        depends on CPU_V6
index 7652712..dba62cb 100644 (file)
@@ -32,6 +32,8 @@
 
 #define MPIDR_HWID_BITMASK 0xFFFFFF
 
+#define MPIDR_INVALID (~MPIDR_HWID_BITMASK)
+
 #define MPIDR_LEVEL_BITS 8
 #define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1)
 
index ac1dd54..8017e94 100644 (file)
 # endif
 #endif
 
+#ifdef CONFIG_CPU_PJ4B
+# ifdef CPU_NAME
+#  undef  MULTI_CPU
+#  define MULTI_CPU
+# else
+#  define CPU_NAME cpu_pj4b
+# endif
+#endif
+
 #ifndef MULTI_CPU
 #define cpu_proc_init                  __glue(CPU_NAME,_proc_init)
 #define cpu_proc_fin                   __glue(CPU_NAME,_proc_fin)
index aaa61b6..e789832 100644 (file)
@@ -49,7 +49,7 @@ static inline int cache_ops_need_broadcast(void)
 /*
  * Logical CPU mapping.
  */
-extern int __cpu_logical_map[];
+extern u32 __cpu_logical_map[];
 #define cpu_logical_map(cpu)   __cpu_logical_map[cpu]
 /*
  * Retrieve logical cpu index corresponding to a given MPIDR[23:0]
index 5af04f6..5859c8b 100644 (file)
@@ -82,7 +82,7 @@ void __init arm_dt_init_cpu_maps(void)
        u32 i, j, cpuidx = 1;
        u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
 
-       u32 tmp_map[NR_CPUS] = { [0 ... NR_CPUS-1] = UINT_MAX };
+       u32 tmp_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID };
        bool bootcpu_valid = false;
        cpus = of_find_node_by_path("/cpus");
 
@@ -92,6 +92,9 @@ void __init arm_dt_init_cpu_maps(void)
        for_each_child_of_node(cpus, cpu) {
                u32 hwid;
 
+               if (of_node_cmp(cpu->type, "cpu"))
+                       continue;
+
                pr_debug(" * %s...\n", cpu->full_name);
                /*
                 * A device tree containing CPU nodes with missing "reg"
@@ -149,9 +152,10 @@ void __init arm_dt_init_cpu_maps(void)
                tmp_map[i] = hwid;
        }
 
-       if (WARN(!bootcpu_valid, "DT missing boot CPU MPIDR[23:0], "
-                                "fall back to default cpu_logical_map\n"))
+       if (!bootcpu_valid) {
+               pr_warn("DT missing boot CPU MPIDR[23:0], fall back to default cpu_logical_map\n");
                return;
+       }
 
        /*
         * Since the boot CPU node contains proper data, and all nodes have
index 1522c7a..b4b1d39 100644 (file)
@@ -444,7 +444,7 @@ void notrace cpu_init(void)
            : "r14");
 }
 
-int __cpu_logical_map[NR_CPUS];
+u32 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = MPIDR_INVALID };
 
 void __init smp_setup_processor_id(void)
 {
index d51225f..eb5293a 100644 (file)
@@ -57,6 +57,12 @@ void flush_dcache_page(struct page *page)
 }
 EXPORT_SYMBOL(flush_dcache_page);
 
+void flush_kernel_dcache_page(struct page *page)
+{
+       __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
+}
+EXPORT_SYMBOL(flush_kernel_dcache_page);
+
 void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
                       unsigned long uaddr, void *dst, const void *src,
                       unsigned long len)
index d217e97..aaeb6c1 100644 (file)
@@ -81,7 +81,6 @@ ENDPROC(cpu_fa526_reset)
  */
        .align  4
 ENTRY(cpu_fa526_do_idle)
-       mcr     p15, 0, r0, c7, c0, 4           @ Wait for interrupt
        mov     pc, lr
 
 
index f9a0aa7..e3c48a3 100644 (file)
@@ -333,3 +333,8 @@ ENTRY(\name\()_tlb_fns)
        .endif
        .size   \name\()_tlb_fns, . - \name\()_tlb_fns
 .endm
+
+.macro globl_equ x, y
+       .globl  \x
+       .equ    \x, \y
+.endm
index 4c8c9c1..e35fec3 100644 (file)
@@ -140,6 +140,29 @@ ENTRY(cpu_v7_do_resume)
 ENDPROC(cpu_v7_do_resume)
 #endif
 
+#ifdef CONFIG_CPU_PJ4B
+       globl_equ       cpu_pj4b_switch_mm,     cpu_v7_switch_mm
+       globl_equ       cpu_pj4b_set_pte_ext,   cpu_v7_set_pte_ext
+       globl_equ       cpu_pj4b_proc_init,     cpu_v7_proc_init
+       globl_equ       cpu_pj4b_proc_fin,      cpu_v7_proc_fin
+       globl_equ       cpu_pj4b_reset,         cpu_v7_reset
+#ifdef CONFIG_PJ4B_ERRATA_4742
+ENTRY(cpu_pj4b_do_idle)
+       dsb                                     @ WFI may enter a low-power mode
+       wfi
+       dsb                                     @barrier
+       mov     pc, lr
+ENDPROC(cpu_pj4b_do_idle)
+#else
+       globl_equ       cpu_pj4b_do_idle,       cpu_v7_do_idle
+#endif
+       globl_equ       cpu_pj4b_dcache_clean_area,     cpu_v7_dcache_clean_area
+       globl_equ       cpu_pj4b_do_suspend,    cpu_v7_do_suspend
+       globl_equ       cpu_pj4b_do_resume,     cpu_v7_do_resume
+       globl_equ       cpu_pj4b_suspend_size,  cpu_v7_suspend_size
+
+#endif
+
        __CPUINIT
 
 /*
@@ -350,6 +373,9 @@ __v7_setup_stack:
 
        @ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
        define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
+#ifdef CONFIG_CPU_PJ4B
+       define_processor_functions pj4b, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
+#endif
 
        .section ".rodata"
 
@@ -362,7 +388,7 @@ __v7_setup_stack:
        /*
         * Standard v7 proc info content
         */
-.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0
+.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0, proc_fns = v7_processor_functions
        ALT_SMP(.long   PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
                        PMD_SECT_AF | PMD_FLAGS_SMP | \mm_mmuflags)
        ALT_UP(.long    PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
@@ -375,7 +401,7 @@ __v7_setup_stack:
        .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | \
                HWCAP_EDSP | HWCAP_TLS | \hwcaps
        .long   cpu_v7_name
-       .long   v7_processor_functions
+       .long   \proc_fns
        .long   v7wbi_tlb_fns
        .long   v6_user_fns
        .long   v7_cache_fns
@@ -407,12 +433,14 @@ __v7_ca9mp_proc_info:
        /*
         * Marvell PJ4B processor.
         */
+#ifdef CONFIG_CPU_PJ4B
        .type   __v7_pj4b_proc_info, #object
 __v7_pj4b_proc_info:
        .long   0x560f5800
        .long   0xff0fff00
-       __v7_proc __v7_pj4b_setup
+       __v7_proc __v7_pj4b_setup, proc_fns = pj4b_processor_functions
        .size   __v7_pj4b_proc_info, . - __v7_pj4b_proc_info
+#endif
 
        /*
         * ARM Ltd. Cortex A7 processor.
index 780560b..d7966e0 100644 (file)
@@ -161,7 +161,7 @@ struct __large_struct { unsigned long buf[100]; };
 
 #define __get_user_check(x, ptr, size)                                 \
 ({                                                                     \
-       const __typeof__(ptr) __guc_ptr = (ptr);                        \
+       const __typeof__(*(ptr))* __guc_ptr = (ptr);                    \
        int _e;                                                         \
        if (likely(__access_ok((unsigned long) __guc_ptr, (size))))     \
                _e = __get_user_nocheck((x), __guc_ptr, (size));        \
index 33c3bd1..ebac9c1 100644 (file)
@@ -38,6 +38,7 @@ struct mn10300_cpuinfo boot_cpu_data;
 /* For PCI or other memory-mapped resources */
 unsigned long pci_mem_start = 0x18000000;
 
+static char __initdata cmd_line[COMMAND_LINE_SIZE];
 char redboot_command_line[COMMAND_LINE_SIZE] =
        "console=ttyS0,115200 root=/dev/mtdblock3 rw";
 
@@ -74,45 +75,19 @@ static const char *const mn10300_cputypes[] = {
 };
 
 /*
- *
+ * Pick out the memory size.  We look for mem=size,
+ * where size is "size[KkMm]"
  */
-static void __init parse_mem_cmdline(char **cmdline_p)
+static int __init early_mem(char *p)
 {
-       char *from, *to, c;
-
-       /* save unparsed command line copy for /proc/cmdline */
-       strcpy(boot_command_line, redboot_command_line);
-
-       /* see if there's an explicit memory size option */
-       from = redboot_command_line;
-       to = redboot_command_line;
-       c = ' ';
-
-       for (;;) {
-               if (c == ' ' && !memcmp(from, "mem=", 4)) {
-                       if (to != redboot_command_line)
-                               to--;
-                       memory_size = memparse(from + 4, &from);
-               }
-
-               c = *(from++);
-               if (!c)
-                       break;
-
-               *(to++) = c;
-       }
-
-       *to = '\0';
-       *cmdline_p = redboot_command_line;
+       memory_size = memparse(p, &p);
 
        if (memory_size == 0)
                panic("Memory size not known\n");
 
-       memory_end = (unsigned long) CONFIG_KERNEL_RAM_BASE_ADDRESS +
-               memory_size;
-       if (memory_end > phys_memory_end)
-               memory_end = phys_memory_end;
+       return 0;
 }
+early_param("mem", early_mem);
 
 /*
  * architecture specific setup
@@ -125,7 +100,20 @@ void __init setup_arch(char **cmdline_p)
        cpu_init();
        unit_setup();
        smp_init_cpus();
-       parse_mem_cmdline(cmdline_p);
+
+       /* save unparsed command line copy for /proc/cmdline */
+       strlcpy(boot_command_line, redboot_command_line, COMMAND_LINE_SIZE);
+
+       /* populate cmd_line too for later use, preserving boot_command_line */
+       strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
+       *cmdline_p = cmd_line;
+
+       parse_early_param();
+
+       memory_end = (unsigned long) CONFIG_KERNEL_RAM_BASE_ADDRESS +
+               memory_size;
+       if (memory_end > phys_memory_end)
+               memory_end = phys_memory_end;
 
        init_mm.start_code = (unsigned long)&_text;
        init_mm.end_code = (unsigned long) &_etext;
index eabeec9..f46914a 100644 (file)
@@ -994,7 +994,7 @@ void pcibios_setup_bus_self(struct pci_bus *bus)
                ppc_md.pci_dma_bus_setup(bus);
 }
 
-void pcibios_setup_device(struct pci_dev *dev)
+static void pcibios_setup_device(struct pci_dev *dev)
 {
        /* Fixup NUMA node as it may not be setup yet by the generic
         * code and is needed by the DMA init
@@ -1015,6 +1015,17 @@ void pcibios_setup_device(struct pci_dev *dev)
                ppc_md.pci_irq_fixup(dev);
 }
 
+int pcibios_add_device(struct pci_dev *dev)
+{
+       /*
+        * We can only call pcibios_setup_device() after bus setup is complete,
+        * since some of the platform specific DMA setup code depends on it.
+        */
+       if (dev->bus->is_added)
+               pcibios_setup_device(dev);
+       return 0;
+}
+
 void pcibios_setup_bus_devices(struct pci_bus *bus)
 {
        struct pci_dev *dev;
@@ -1469,10 +1480,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
                if (ppc_md.pcibios_enable_device_hook(dev))
                        return -EINVAL;
 
-       /* avoid pcie irq fix up impact on cardbus */
-       if (dev->hdr_type != PCI_HEADER_TYPE_CARDBUS)
-               pcibios_setup_device(dev);
-
        return pci_enable_resources(dev, mask);
 }
 
index 5a4c879..5ce3ba7 100644 (file)
@@ -294,8 +294,6 @@ void __init eeh_addr_cache_build(void)
        spin_lock_init(&pci_io_addr_cache_root.piar_lock);
 
        for_each_pci_dev(dev) {
-               eeh_addr_cache_insert_dev(dev);
-
                dn = pci_device_to_OF_node(dev);
                if (!dn)
                        continue;
@@ -308,6 +306,8 @@ void __init eeh_addr_cache_build(void)
                dev->dev.archdata.edev = edev;
                edev->pdev = dev;
 
+               eeh_addr_cache_insert_dev(dev);
+
                eeh_sysfs_add_device(dev);
        }
 
index fe43d1a..9d4a9e8 100644 (file)
@@ -639,7 +639,8 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
 
        if (pe->type & EEH_PE_PHB) {
                bus = pe->phb->bus;
-       } else if (pe->type & EEH_PE_BUS) {
+       } else if (pe->type & EEH_PE_BUS ||
+                  pe->type & EEH_PE_DEVICE) {
                edev = list_first_entry(&pe->edevs, struct eeh_dev, list);
                pdev = eeh_dev_to_pci_dev(edev);
                if (pdev)
index 9895a9a..211bce4 100644 (file)
@@ -365,10 +365,14 @@ int __kprobes __copy_instruction(u8 *dest, u8 *src)
        return insn.length;
 }
 
-static void __kprobes arch_copy_kprobe(struct kprobe *p)
+static int __kprobes arch_copy_kprobe(struct kprobe *p)
 {
+       int ret;
+
        /* Copy an instruction with recovering if other optprobe modifies it.*/
-       __copy_instruction(p->ainsn.insn, p->addr);
+       ret = __copy_instruction(p->ainsn.insn, p->addr);
+       if (!ret)
+               return -EINVAL;
 
        /*
         * __copy_instruction can modify the displacement of the instruction,
@@ -384,6 +388,8 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p)
 
        /* Also, displacement change doesn't affect the first byte */
        p->opcode = p->ainsn.insn[0];
+
+       return 0;
 }
 
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
@@ -397,8 +403,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
        p->ainsn.insn = get_insn_slot();
        if (!p->ainsn.insn)
                return -ENOMEM;
-       arch_copy_kprobe(p);
-       return 0;
+
+       return arch_copy_kprobe(p);
 }
 
 void __kprobes arch_arm_kprobe(struct kprobe *p)
index 769219b..76fc0b2 100644 (file)
@@ -45,10 +45,9 @@ struct cryptomgr_param {
                } nu32;
        } attrs[CRYPTO_MAX_ATTRS];
 
-       char larval[CRYPTO_MAX_ALG_NAME];
        char template[CRYPTO_MAX_ALG_NAME];
 
-       struct completion *completion;
+       struct crypto_larval *larval;
 
        u32 otype;
        u32 omask;
@@ -87,7 +86,8 @@ static int cryptomgr_probe(void *data)
        crypto_tmpl_put(tmpl);
 
 out:
-       complete_all(param->completion);
+       complete_all(&param->larval->completion);
+       crypto_alg_put(&param->larval->alg);
        kfree(param);
        module_put_and_exit(0);
 }
@@ -187,18 +187,19 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval)
        param->otype = larval->alg.cra_flags;
        param->omask = larval->mask;
 
-       memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
-
-       param->completion = &larval->completion;
+       crypto_alg_get(&larval->alg);
+       param->larval = larval;
 
        thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe");
        if (IS_ERR(thread))
-               goto err_free_param;
+               goto err_put_larval;
 
        wait_for_completion_interruptible(&larval->completion);
 
        return NOTIFY_STOP;
 
+err_put_larval:
+       crypto_alg_put(&larval->alg);
 err_free_param:
        kfree(param);
 err_put_module:
index 033a714..3b61803 100644 (file)
@@ -34,12 +34,6 @@ EXPORT_SYMBOL_GPL(crypto_alg_sem);
 BLOCKING_NOTIFIER_HEAD(crypto_chain);
 EXPORT_SYMBOL_GPL(crypto_chain);
 
-static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
-{
-       atomic_inc(&alg->cra_refcnt);
-       return alg;
-}
-
 struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
 {
        return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
index 9ebedae..bd39bfc 100644 (file)
@@ -103,6 +103,12 @@ int crypto_register_notifier(struct notifier_block *nb);
 int crypto_unregister_notifier(struct notifier_block *nb);
 int crypto_probing_notify(unsigned long val, void *v);
 
+static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
+{
+       atomic_inc(&alg->cra_refcnt);
+       return alg;
+}
+
 static inline void crypto_alg_put(struct crypto_alg *alg)
 {
        if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
index ec117c6..14de9f4 100644 (file)
@@ -66,20 +66,21 @@ struct dock_station {
        spinlock_t dd_lock;
        struct mutex hp_lock;
        struct list_head dependent_devices;
-       struct list_head hotplug_devices;
 
        struct list_head sibling;
        struct platform_device *dock_device;
 };
 static LIST_HEAD(dock_stations);
 static int dock_station_count;
+static DEFINE_MUTEX(hotplug_lock);
 
 struct dock_dependent_device {
        struct list_head list;
-       struct list_head hotplug_list;
        acpi_handle handle;
-       const struct acpi_dock_ops *ops;
-       void *context;
+       const struct acpi_dock_ops *hp_ops;
+       void *hp_context;
+       unsigned int hp_refcount;
+       void (*hp_release)(void *);
 };
 
 #define DOCK_DOCKING   0x00000001
@@ -111,7 +112,6 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
 
        dd->handle = handle;
        INIT_LIST_HEAD(&dd->list);
-       INIT_LIST_HEAD(&dd->hotplug_list);
 
        spin_lock(&ds->dd_lock);
        list_add_tail(&dd->list, &ds->dependent_devices);
@@ -121,35 +121,90 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
 }
 
 /**
- * dock_add_hotplug_device - associate a hotplug handler with the dock station
- * @ds: The dock station
- * @dd: The dependent device struct
- *
- * Add the dependent device to the dock's hotplug device list
+ * dock_init_hotplug - Initialize a hotplug device on a docking station.
+ * @dd: Dock-dependent device.
+ * @ops: Dock operations to attach to the dependent device.
+ * @context: Data to pass to the @ops callbacks and @release.
+ * @init: Optional initialization routine to run after setting up context.
+ * @release: Optional release routine to run on removal.
  */
-static void
-dock_add_hotplug_device(struct dock_station *ds,
-                       struct dock_dependent_device *dd)
+static int dock_init_hotplug(struct dock_dependent_device *dd,
+                            const struct acpi_dock_ops *ops, void *context,
+                            void (*init)(void *), void (*release)(void *))
 {
-       mutex_lock(&ds->hp_lock);
-       list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
-       mutex_unlock(&ds->hp_lock);
+       int ret = 0;
+
+       mutex_lock(&hotplug_lock);
+
+       if (dd->hp_context) {
+               ret = -EEXIST;
+       } else {
+               dd->hp_refcount = 1;
+               dd->hp_ops = ops;
+               dd->hp_context = context;
+               dd->hp_release = release;
+       }
+
+       if (!WARN_ON(ret) && init)
+               init(context);
+
+       mutex_unlock(&hotplug_lock);
+       return ret;
 }
 
 /**
- * dock_del_hotplug_device - remove a hotplug handler from the dock station
- * @ds: The dock station
- * @dd: the dependent device struct
+ * dock_release_hotplug - Decrement hotplug reference counter of dock device.
+ * @dd: Dock-dependent device.
  *
- * Delete the dependent device from the dock's hotplug device list
+ * Decrement the reference counter of @dd and if 0, detach its hotplug
+ * operations from it, reset its context pointer and run the optional release
+ * routine if present.
  */
-static void
-dock_del_hotplug_device(struct dock_station *ds,
-                       struct dock_dependent_device *dd)
+static void dock_release_hotplug(struct dock_dependent_device *dd)
 {
-       mutex_lock(&ds->hp_lock);
-       list_del(&dd->hotplug_list);
-       mutex_unlock(&ds->hp_lock);
+       void (*release)(void *) = NULL;
+       void *context = NULL;
+
+       mutex_lock(&hotplug_lock);
+
+       if (dd->hp_context && !--dd->hp_refcount) {
+               dd->hp_ops = NULL;
+               context = dd->hp_context;
+               dd->hp_context = NULL;
+               release = dd->hp_release;
+               dd->hp_release = NULL;
+       }
+
+       if (release && context)
+               release(context);
+
+       mutex_unlock(&hotplug_lock);
+}
+
+static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
+                              bool uevent)
+{
+       acpi_notify_handler cb = NULL;
+       bool run = false;
+
+       mutex_lock(&hotplug_lock);
+
+       if (dd->hp_context) {
+               run = true;
+               dd->hp_refcount++;
+               if (dd->hp_ops)
+                       cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler;
+       }
+
+       mutex_unlock(&hotplug_lock);
+
+       if (!run)
+               return;
+
+       if (cb)
+               cb(dd->handle, event, dd->hp_context);
+
+       dock_release_hotplug(dd);
 }
 
 /**
@@ -360,9 +415,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
        /*
         * First call driver specific hotplug functions
         */
-       list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
-               if (dd->ops && dd->ops->handler)
-                       dd->ops->handler(dd->handle, event, dd->context);
+       list_for_each_entry(dd, &ds->dependent_devices, list)
+               dock_hotplug_event(dd, event, false);
 
        /*
         * Now make sure that an acpi_device is created for each
@@ -398,9 +452,8 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
        if (num == DOCK_EVENT)
                kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 
-       list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
-               if (dd->ops && dd->ops->uevent)
-                       dd->ops->uevent(dd->handle, event, dd->context);
+       list_for_each_entry(dd, &ds->dependent_devices, list)
+               dock_hotplug_event(dd, event, true);
 
        if (num != DOCK_EVENT)
                kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
@@ -570,19 +623,24 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier);
  * @handle: the handle of the device
  * @ops: handlers to call after docking
  * @context: device specific data
+ * @init: Optional initialization routine to run after registration
+ * @release: Optional release routine to run on unregistration
  *
  * If a driver would like to perform a hotplug operation after a dock
  * event, they can register an acpi_notifiy_handler to be called by
  * the dock driver after _DCK is executed.
  */
-int
-register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops,
-                            void *context)
+int register_hotplug_dock_device(acpi_handle handle,
+                                const struct acpi_dock_ops *ops, void *context,
+                                void (*init)(void *), void (*release)(void *))
 {
        struct dock_dependent_device *dd;
        struct dock_station *dock_station;
        int ret = -EINVAL;
 
+       if (WARN_ON(!context))
+               return -EINVAL;
+
        if (!dock_station_count)
                return -ENODEV;
 
@@ -597,12 +655,8 @@ register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops
                 * ops
                 */
                dd = find_dock_dependent_device(dock_station, handle);
-               if (dd) {
-                       dd->ops = ops;
-                       dd->context = context;
-                       dock_add_hotplug_device(dock_station, dd);
+               if (dd && !dock_init_hotplug(dd, ops, context, init, release))
                        ret = 0;
-               }
        }
 
        return ret;
@@ -624,7 +678,7 @@ void unregister_hotplug_dock_device(acpi_handle handle)
        list_for_each_entry(dock_station, &dock_stations, sibling) {
                dd = find_dock_dependent_device(dock_station, handle);
                if (dd)
-                       dock_del_hotplug_device(dock_station, dd);
+                       dock_release_hotplug(dd);
        }
 }
 EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
@@ -953,7 +1007,6 @@ static int __init dock_add(acpi_handle handle)
        mutex_init(&dock_station->hp_lock);
        spin_lock_init(&dock_station->dd_lock);
        INIT_LIST_HEAD(&dock_station->sibling);
-       INIT_LIST_HEAD(&dock_station->hotplug_devices);
        ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
        INIT_LIST_HEAD(&dock_station->dependent_devices);
 
@@ -994,30 +1047,6 @@ err_unregister:
 }
 
 /**
- * dock_remove - free up resources related to the dock station
- */
-static int dock_remove(struct dock_station *ds)
-{
-       struct dock_dependent_device *dd, *tmp;
-       struct platform_device *dock_device = ds->dock_device;
-
-       if (!dock_station_count)
-               return 0;
-
-       /* remove dependent devices */
-       list_for_each_entry_safe(dd, tmp, &ds->dependent_devices, list)
-               kfree(dd);
-
-       list_del(&ds->sibling);
-
-       /* cleanup sysfs */
-       sysfs_remove_group(&dock_device->dev.kobj, &dock_attribute_group);
-       platform_device_unregister(dock_device);
-
-       return 0;
-}
-
-/**
  * find_dock_and_bay - look for dock stations and bays
  * @handle: acpi handle of a device
  * @lvl: unused
@@ -1035,7 +1064,7 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
-static int __init dock_init(void)
+int __init acpi_dock_init(void)
 {
        if (acpi_disabled)
                return 0;
@@ -1054,19 +1083,3 @@ static int __init dock_init(void)
                ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
        return 0;
 }
-
-static void __exit dock_exit(void)
-{
-       struct dock_station *tmp, *dock_station;
-
-       unregister_acpi_bus_notifier(&dock_acpi_notifier);
-       list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling)
-               dock_remove(dock_station);
-}
-
-/*
- * Must be called before drivers of devices in dock, otherwise we can't know
- * which devices are in a dock
- */
-subsys_initcall(dock_init);
-module_exit(dock_exit);
index 297cbf4..c610a76 100644 (file)
@@ -40,6 +40,11 @@ void acpi_container_init(void);
 #else
 static inline void acpi_container_init(void) {}
 #endif
+#ifdef CONFIG_ACPI_DOCK
+void acpi_dock_init(void);
+#else
+static inline void acpi_dock_init(void) {}
+#endif
 #ifdef CONFIG_ACPI_HOTPLUG_MEMORY
 void acpi_memory_hotplug_init(void);
 #else
index b14ac46..27da630 100644 (file)
@@ -2042,6 +2042,7 @@ int __init acpi_scan_init(void)
        acpi_lpss_init();
        acpi_container_init();
        acpi_memory_hotplug_init();
+       acpi_dock_init();
 
        mutex_lock(&acpi_scan_lock);
        /*
index 87f2f39..cf4e702 100644 (file)
@@ -156,8 +156,10 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
 
        spin_unlock_irqrestore(ap->lock, flags);
 
-       if (wait)
+       if (wait) {
                ata_port_wait_eh(ap);
+               flush_work(&ap->hotplug_task.work);
+       }
 }
 
 static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
@@ -214,6 +216,39 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
        .uevent = ata_acpi_ap_uevent,
 };
 
+void ata_acpi_hotplug_init(struct ata_host *host)
+{
+       int i;
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+               acpi_handle handle;
+               struct ata_device *dev;
+
+               if (!ap)
+                       continue;
+
+               handle = ata_ap_acpi_handle(ap);
+               if (handle) {
+                       /* we might be on a docking station */
+                       register_hotplug_dock_device(handle,
+                                                    &ata_acpi_ap_dock_ops, ap,
+                                                    NULL, NULL);
+               }
+
+               ata_for_each_dev(dev, &ap->link, ALL) {
+                       handle = ata_dev_acpi_handle(dev);
+                       if (!handle)
+                               continue;
+
+                       /* we might be on a docking station */
+                       register_hotplug_dock_device(handle,
+                                                    &ata_acpi_dev_dock_ops,
+                                                    dev, NULL, NULL);
+               }
+       }
+}
+
 /**
  * ata_acpi_dissociate - dissociate ATA host from ACPI objects
  * @host: target ATA host
index f218427..adf002a 100644 (file)
@@ -6148,6 +6148,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        if (rc)
                goto err_tadd;
 
+       ata_acpi_hotplug_init(host);
+
        /* set cable, sata_spd_limit and report */
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
index c949dd3..577d902 100644 (file)
@@ -122,6 +122,7 @@ extern int ata_acpi_register(void);
 extern void ata_acpi_unregister(void);
 extern void ata_acpi_bind(struct ata_device *dev);
 extern void ata_acpi_unbind(struct ata_device *dev);
+extern void ata_acpi_hotplug_init(struct ata_host *host);
 #else
 static inline void ata_acpi_dissociate(struct ata_host *host) { }
 static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
@@ -134,6 +135,7 @@ static inline int ata_acpi_register(void) { return 0; }
 static inline void ata_acpi_unregister(void) { }
 static inline void ata_acpi_bind(struct ata_device *dev) { }
 static inline void ata_acpi_unbind(struct ata_device *dev) { }
+static inline void ata_acpi_hotplug_init(struct ata_host *host) {}
 #endif
 
 /* libata-scsi.c */
index 49394e3..aff789d 100644 (file)
@@ -2252,13 +2252,17 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
                                        obj_request->pages, length,
                                        offset & ~PAGE_MASK, false, false);
 
+               /*
+                * set obj_request->img_request before formatting
+                * the osd_request so that it gets the right snapc
+                */
+               rbd_img_obj_request_add(img_request, obj_request);
                if (write_request)
                        rbd_osd_req_format_write(obj_request);
                else
                        rbd_osd_req_format_read(obj_request);
 
                obj_request->img_offset = img_offset;
-               rbd_img_obj_request_add(img_request, obj_request);
 
                img_offset += length;
                resid -= length;
@@ -4243,6 +4247,10 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
 
        down_write(&rbd_dev->header_rwsem);
 
+       ret = rbd_dev_v2_image_size(rbd_dev);
+       if (ret)
+               goto out;
+
        if (first_time) {
                ret = rbd_dev_v2_header_onetime(rbd_dev);
                if (ret)
@@ -4276,10 +4284,6 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
                                        "is EXPERIMENTAL!");
        }
 
-       ret = rbd_dev_v2_image_size(rbd_dev);
-       if (ret)
-               goto out;
-
        if (rbd_dev->spec->snap_id == CEPH_NOSNAP)
                if (rbd_dev->mapping.size != rbd_dev->header.image_size)
                        rbd_dev->mapping.size = rbd_dev->header.image_size;
index 3a4343b..9a9f518 100644 (file)
@@ -498,6 +498,10 @@ static int btmrvl_service_main_thread(void *data)
                add_wait_queue(&thread->wait_q, &wait);
 
                set_current_state(TASK_INTERRUPTIBLE);
+               if (kthread_should_stop()) {
+                       BT_DBG("main_thread: break from main thread");
+                       break;
+               }
 
                if (adapter->wakeup_tries ||
                                ((!adapter->int_count) &&
@@ -513,11 +517,6 @@ static int btmrvl_service_main_thread(void *data)
 
                BT_DBG("main_thread woke up");
 
-               if (kthread_should_stop()) {
-                       BT_DBG("main_thread: break from main thread");
-                       break;
-               }
-
                spin_lock_irqsave(&priv->driver_lock, flags);
                if (adapter->int_count) {
                        adapter->int_count = 0;
index 4b9bb5d..93eb5cb 100644 (file)
@@ -47,6 +47,8 @@ static struct od_ops od_ops;
 static struct cpufreq_governor cpufreq_gov_ondemand;
 #endif
 
+static unsigned int default_powersave_bias;
+
 static void ondemand_powersave_bias_init_cpu(int cpu)
 {
        struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
@@ -543,7 +545,7 @@ static int od_init(struct dbs_data *dbs_data)
 
        tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
        tuners->ignore_nice = 0;
-       tuners->powersave_bias = 0;
+       tuners->powersave_bias = default_powersave_bias;
        tuners->io_is_busy = should_io_be_busy();
 
        dbs_data->tuners = tuners;
@@ -585,6 +587,7 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
        unsigned int cpu;
        cpumask_t done;
 
+       default_powersave_bias = powersave_bias;
        cpumask_clear(&done);
 
        get_online_cpus();
@@ -593,11 +596,17 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
                        continue;
 
                policy = per_cpu(od_cpu_dbs_info, cpu).cdbs.cur_policy;
-               dbs_data = policy->governor_data;
-               od_tuners = dbs_data->tuners;
-               od_tuners->powersave_bias = powersave_bias;
+               if (!policy)
+                       continue;
 
                cpumask_or(&done, &done, policy->cpus);
+
+               if (policy->governor != &cpufreq_gov_ondemand)
+                       continue;
+
+               dbs_data = policy->governor_data;
+               od_tuners = dbs_data->tuners;
+               od_tuners->powersave_bias = default_powersave_bias;
        }
        put_online_cpus();
 }
index d3f7d2d..4a43036 100644 (file)
@@ -1094,6 +1094,9 @@ static int omap_gpio_probe(struct platform_device *pdev)
        const struct omap_gpio_platform_data *pdata;
        struct resource *res;
        struct gpio_bank *bank;
+#ifdef CONFIG_ARCH_OMAP1
+       int irq_base;
+#endif
 
        match = of_match_device(of_match_ptr(omap_gpio_match), dev);
 
@@ -1135,11 +1138,28 @@ static int omap_gpio_probe(struct platform_device *pdev)
                                pdata->get_context_loss_count;
        }
 
+#ifdef CONFIG_ARCH_OMAP1
+       /*
+        * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
+        * irq_alloc_descs() and irq_domain_add_legacy() and just use a
+        * linear IRQ domain mapping for all OMAP platforms.
+        */
+       irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
+       if (irq_base < 0) {
+               dev_err(dev, "Couldn't allocate IRQ numbers\n");
+               return -ENODEV;
+       }
 
+       bank->domain = irq_domain_add_legacy(node, bank->width, irq_base,
+                                            0, &irq_domain_simple_ops, NULL);
+#else
        bank->domain = irq_domain_add_linear(node, bank->width,
                                             &irq_domain_simple_ops, NULL);
-       if (!bank->domain)
+#endif
+       if (!bank->domain) {
+               dev_err(dev, "Couldn't register an IRQ domain\n");
                return -ENODEV;
+       }
 
        if (bank->regs->set_dataout && bank->regs->clr_dataout)
                bank->set_dataout = _set_gpio_dataout_reg;
index cc1d605..a416645 100644 (file)
@@ -1806,6 +1806,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
 struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
                                struct drm_gem_object *gem_obj, int flags);
 
+void i915_gem_restore_fences(struct drm_device *dev);
+
 /* i915_gem_context.c */
 void i915_gem_context_init(struct drm_device *dev);
 void i915_gem_context_fini(struct drm_device *dev);
index 06d66e0..97afd26 100644 (file)
@@ -2251,25 +2251,15 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
        }
 }
 
-static void i915_gem_reset_fences(struct drm_device *dev)
+void i915_gem_restore_fences(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
-
-               if (reg->obj)
-                       i915_gem_object_fence_lost(reg->obj);
-
-               i915_gem_write_fence(dev, i, NULL);
-
-               reg->pin_count = 0;
-               reg->obj = NULL;
-               INIT_LIST_HEAD(&reg->lru_list);
+               i915_gem_write_fence(dev, i, reg->obj);
        }
-
-       INIT_LIST_HEAD(&dev_priv->mm.fence_list);
 }
 
 void i915_gem_reset(struct drm_device *dev)
@@ -2292,8 +2282,7 @@ void i915_gem_reset(struct drm_device *dev)
                obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
        }
 
-       /* The fence registers are invalidated so clear them out */
-       i915_gem_reset_fences(dev);
+       i915_gem_restore_fences(dev);
 }
 
 /**
@@ -4003,8 +3992,6 @@ i915_gem_idle(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_gem_evict_everything(dev);
 
-       i915_gem_reset_fences(dev);
-
        /* Hack!  Don't let anybody do execbuf while we don't control the chip.
         * We need to replace this with a semaphore, or something.
         * And not confound mm.suspended!
@@ -4340,7 +4327,8 @@ i915_gem_load(struct drm_device *dev)
                dev_priv->num_fence_regs = 8;
 
        /* Initialize fence registers to zero */
-       i915_gem_reset_fences(dev);
+       INIT_LIST_HEAD(&dev_priv->mm.fence_list);
+       i915_gem_restore_fences(dev);
 
        i915_gem_detect_bit_6_swizzle(dev);
        init_waitqueue_head(&dev_priv->pending_flip_queue);
index 88b9a66..70db618 100644 (file)
@@ -394,6 +394,7 @@ int i915_restore_state(struct drm_device *dev)
 
        mutex_lock(&dev->struct_mutex);
 
+       i915_gem_restore_fences(dev);
        i915_restore_display(dev);
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
index a4b71b2..a30f294 100644 (file)
@@ -171,6 +171,11 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
                if (user_cmd.command_size > PAGE_SIZE - sizeof(union qxl_release_info))
                        return -EINVAL;
 
+               if (!access_ok(VERIFY_READ,
+                              (void *)(unsigned long)user_cmd.command,
+                              user_cmd.command_size))
+                       return -EFAULT;
+
                ret = qxl_alloc_release_reserved(qdev,
                                                 sizeof(union qxl_release_info) +
                                                 user_cmd.command_size,
index 721b918..4b93ed4 100644 (file)
@@ -107,7 +107,7 @@ static struct mfd_cell tps6586x_cell[] = {
                .name = "tps6586x-gpio",
        },
        {
-               .name = "tps6586x-pmic",
+               .name = "tps6586x-regulator",
        },
        {
                .name = "tps6586x-rtc",
index 02d9ae7..f975696 100644 (file)
@@ -2413,7 +2413,8 @@ static void bond_miimon_commit(struct bonding *bond)
 
                        pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex.\n",
                                bond->dev->name, slave->dev->name,
-                               slave->speed, slave->duplex ? "full" : "half");
+                               slave->speed == SPEED_UNKNOWN ? 0 : slave->speed,
+                               slave->duplex ? "full" : "half");
 
                        /* notify ad that the link status has changed */
                        if (bond->params.mode == BOND_MODE_8023AD)
index 6e15ef0..cbd388e 100644 (file)
@@ -977,7 +977,7 @@ static int usb_8dev_probe(struct usb_interface *intf,
        err = usb_8dev_cmd_version(priv, &version);
        if (err) {
                netdev_err(netdev, "can't get firmware version\n");
-               goto cleanup_cmd_msg_buffer;
+               goto cleanup_unregister_candev;
        } else {
                netdev_info(netdev,
                         "firmware: %d.%d, hardware: %d.%d\n",
@@ -989,6 +989,9 @@ static int usb_8dev_probe(struct usb_interface *intf,
 
        return 0;
 
+cleanup_unregister_candev:
+       unregister_netdev(priv->netdev);
+
 cleanup_cmd_msg_buffer:
        kfree(priv->cmd_msg_buffer);
 
index 36d6abd..ad6aa1e 100644 (file)
@@ -67,4 +67,22 @@ config ATL1C
          To compile this driver as a module, choose M here.  The module
          will be called atl1c.
 
+config ALX
+       tristate "Qualcomm Atheros AR816x/AR817x support"
+       depends on PCI
+       select CRC32
+       select NET_CORE
+       select MDIO
+       help
+         This driver supports the Qualcomm Atheros L1F ethernet adapter,
+         i.e. the following chipsets:
+
+         1969:1091 - AR8161 Gigabit Ethernet
+         1969:1090 - AR8162 Fast Ethernet
+         1969:10A1 - AR8171 Gigabit Ethernet
+         1969:10A0 - AR8172 Fast Ethernet
+
+         To compile this driver as a module, choose M here.  The module
+         will be called alx.
+
 endif # NET_VENDOR_ATHEROS
index e7e76fb..5cf1c65 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_ATL1) += atlx/
 obj-$(CONFIG_ATL2) += atlx/
 obj-$(CONFIG_ATL1E) += atl1e/
 obj-$(CONFIG_ATL1C) += atl1c/
+obj-$(CONFIG_ALX) += alx/
diff --git a/drivers/net/ethernet/atheros/alx/Makefile b/drivers/net/ethernet/atheros/alx/Makefile
new file mode 100644 (file)
index 0000000..5901fa4
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_ALX) += alx.o
+alx-objs := main.o ethtool.o hw.o
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h
new file mode 100644 (file)
index 0000000..50b3ae2
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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;
+               int size;
+       } descmem;
+
+       /* protect int_mask updates */
+       spinlock_t irq_lock;
+       u32 int_mask;
+
+       int tx_ringsz;
+       int rx_ringsz;
+       int rxbuf_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;
+};
+
+extern const struct ethtool_ops alx_ethtool_ops;
+extern const char alx_drv_name[];
+
+#endif
diff --git a/drivers/net/ethernet/atheros/alx/ethtool.c b/drivers/net/ethernet/atheros/alx/ethtool.c
new file mode 100644 (file)
index 0000000..6fa2aec
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+#include <linux/pci.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mdio.h>
+#include <linux/interrupt.h>
+#include <asm/byteorder.h>
+
+#include "alx.h"
+#include "reg.h"
+#include "hw.h"
+
+
+static int alx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+
+       ecmd->supported = SUPPORTED_10baseT_Half |
+                         SUPPORTED_10baseT_Full |
+                         SUPPORTED_100baseT_Half |
+                         SUPPORTED_100baseT_Full |
+                         SUPPORTED_Autoneg |
+                         SUPPORTED_TP |
+                         SUPPORTED_Pause;
+       if (alx_hw_giga(hw))
+               ecmd->supported |= SUPPORTED_1000baseT_Full;
+
+       ecmd->advertising = ADVERTISED_TP;
+       if (hw->adv_cfg & ADVERTISED_Autoneg)
+               ecmd->advertising |= hw->adv_cfg;
+
+       ecmd->port = PORT_TP;
+       ecmd->phy_address = 0;
+       if (hw->adv_cfg & ADVERTISED_Autoneg)
+               ecmd->autoneg = AUTONEG_ENABLE;
+       else
+               ecmd->autoneg = AUTONEG_DISABLE;
+       ecmd->transceiver = XCVR_INTERNAL;
+
+       if (hw->flowctrl & ALX_FC_ANEG && hw->adv_cfg & ADVERTISED_Autoneg) {
+               if (hw->flowctrl & ALX_FC_RX) {
+                       ecmd->advertising |= ADVERTISED_Pause;
+
+                       if (!(hw->flowctrl & ALX_FC_TX))
+                               ecmd->advertising |= ADVERTISED_Asym_Pause;
+               } else if (hw->flowctrl & ALX_FC_TX) {
+                       ecmd->advertising |= ADVERTISED_Asym_Pause;
+               }
+       }
+
+       if (hw->link_speed != SPEED_UNKNOWN) {
+               ethtool_cmd_speed_set(ecmd,
+                                     hw->link_speed - hw->link_speed % 10);
+               ecmd->duplex = hw->link_speed % 10;
+       } else {
+               ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
+               ecmd->duplex = DUPLEX_UNKNOWN;
+       }
+
+       return 0;
+}
+
+static int alx_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+       u32 adv_cfg;
+
+       ASSERT_RTNL();
+
+       if (ecmd->autoneg == AUTONEG_ENABLE) {
+               if (ecmd->advertising & ADVERTISED_1000baseT_Half)
+                       return -EINVAL;
+               adv_cfg = ecmd->advertising | ADVERTISED_Autoneg;
+       } else {
+               int speed = ethtool_cmd_speed(ecmd);
+
+               switch (speed + ecmd->duplex) {
+               case SPEED_10 + DUPLEX_HALF:
+                       adv_cfg = ADVERTISED_10baseT_Half;
+                       break;
+               case SPEED_10 + DUPLEX_FULL:
+                       adv_cfg = ADVERTISED_10baseT_Full;
+                       break;
+               case SPEED_100 + DUPLEX_HALF:
+                       adv_cfg = ADVERTISED_100baseT_Half;
+                       break;
+               case SPEED_100 + DUPLEX_FULL:
+                       adv_cfg = ADVERTISED_100baseT_Full;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       hw->adv_cfg = adv_cfg;
+       return alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl);
+}
+
+static void alx_get_pauseparam(struct net_device *netdev,
+                              struct ethtool_pauseparam *pause)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+
+       if (hw->flowctrl & ALX_FC_ANEG &&
+           hw->adv_cfg & ADVERTISED_Autoneg)
+               pause->autoneg = AUTONEG_ENABLE;
+       else
+               pause->autoneg = AUTONEG_DISABLE;
+
+       if (hw->flowctrl & ALX_FC_TX)
+               pause->tx_pause = 1;
+       else
+               pause->tx_pause = 0;
+
+       if (hw->flowctrl & ALX_FC_RX)
+               pause->rx_pause = 1;
+       else
+               pause->rx_pause = 0;
+}
+
+
+static int alx_set_pauseparam(struct net_device *netdev,
+                             struct ethtool_pauseparam *pause)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+       int err = 0;
+       bool reconfig_phy = false;
+       u8 fc = 0;
+
+       if (pause->tx_pause)
+               fc |= ALX_FC_TX;
+       if (pause->rx_pause)
+               fc |= ALX_FC_RX;
+       if (pause->autoneg)
+               fc |= ALX_FC_ANEG;
+
+       ASSERT_RTNL();
+
+       /* restart auto-neg for auto-mode */
+       if (hw->adv_cfg & ADVERTISED_Autoneg) {
+               if (!((fc ^ hw->flowctrl) & ALX_FC_ANEG))
+                       reconfig_phy = true;
+               if (fc & hw->flowctrl & ALX_FC_ANEG &&
+                   (fc ^ hw->flowctrl) & (ALX_FC_RX | ALX_FC_TX))
+                       reconfig_phy = true;
+       }
+
+       if (reconfig_phy) {
+               err = alx_setup_speed_duplex(hw, hw->adv_cfg, fc);
+               return err;
+       }
+
+       /* flow control on mac */
+       if ((fc ^ hw->flowctrl) & (ALX_FC_RX | ALX_FC_TX))
+               alx_cfg_mac_flowcontrol(hw, fc);
+
+       hw->flowctrl = fc;
+
+       return 0;
+}
+
+static u32 alx_get_msglevel(struct net_device *netdev)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+
+       return alx->msg_enable;
+}
+
+static void alx_set_msglevel(struct net_device *netdev, u32 data)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+
+       alx->msg_enable = data;
+}
+
+static void alx_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+
+       wol->supported = WAKE_MAGIC | WAKE_PHY;
+       wol->wolopts = 0;
+
+       if (hw->sleep_ctrl & ALX_SLEEP_WOL_MAGIC)
+               wol->wolopts |= WAKE_MAGIC;
+       if (hw->sleep_ctrl & ALX_SLEEP_WOL_PHY)
+               wol->wolopts |= WAKE_PHY;
+}
+
+static int alx_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+
+       if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
+                           WAKE_UCAST | WAKE_BCAST | WAKE_MCAST))
+               return -EOPNOTSUPP;
+
+       hw->sleep_ctrl = 0;
+
+       if (wol->wolopts & WAKE_MAGIC)
+               hw->sleep_ctrl |= ALX_SLEEP_WOL_MAGIC;
+       if (wol->wolopts & WAKE_PHY)
+               hw->sleep_ctrl |= ALX_SLEEP_WOL_PHY;
+
+       device_set_wakeup_enable(&alx->hw.pdev->dev, hw->sleep_ctrl);
+
+       return 0;
+}
+
+static void alx_get_drvinfo(struct net_device *netdev,
+                           struct ethtool_drvinfo *drvinfo)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+
+       strlcpy(drvinfo->driver, alx_drv_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->bus_info, pci_name(alx->hw.pdev),
+               sizeof(drvinfo->bus_info));
+}
+
+const struct ethtool_ops alx_ethtool_ops = {
+       .get_settings   = alx_get_settings,
+       .set_settings   = alx_set_settings,
+       .get_pauseparam = alx_get_pauseparam,
+       .set_pauseparam = alx_set_pauseparam,
+       .get_drvinfo    = alx_get_drvinfo,
+       .get_msglevel   = alx_get_msglevel,
+       .set_msglevel   = alx_set_msglevel,
+       .get_wol        = alx_get_wol,
+       .set_wol        = alx_set_wol,
+       .get_link       = ethtool_op_get_link,
+};
diff --git a/drivers/net/ethernet/atheros/alx/hw.c b/drivers/net/ethernet/atheros/alx/hw.c
new file mode 100644 (file)
index 0000000..220a16a
--- /dev/null
@@ -0,0 +1,1226 @@
+/*
+ * 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.
+ */
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/mdio.h>
+#include "reg.h"
+#include "hw.h"
+
+static inline bool alx_is_rev_a(u8 rev)
+{
+       return rev == ALX_REV_A0 || rev == ALX_REV_A1;
+}
+
+static int alx_wait_mdio_idle(struct alx_hw *hw)
+{
+       u32 val;
+       int i;
+
+       for (i = 0; i < ALX_MDIO_MAX_AC_TO; i++) {
+               val = alx_read_mem32(hw, ALX_MDIO);
+               if (!(val & ALX_MDIO_BUSY))
+                       return 0;
+               udelay(10);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int alx_read_phy_core(struct alx_hw *hw, bool ext, u8 dev,
+                            u16 reg, u16 *phy_data)
+{
+       u32 val, clk_sel;
+       int err;
+
+       *phy_data = 0;
+
+       /* use slow clock when it's in hibernation status */
+       clk_sel = hw->link_speed != SPEED_UNKNOWN ?
+                       ALX_MDIO_CLK_SEL_25MD4 :
+                       ALX_MDIO_CLK_SEL_25MD128;
+
+       if (ext) {
+               val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT |
+                     reg << ALX_MDIO_EXTN_REG_SHIFT;
+               alx_write_mem32(hw, ALX_MDIO_EXTN, val);
+
+               val = ALX_MDIO_SPRES_PRMBL | ALX_MDIO_START |
+                     ALX_MDIO_MODE_EXT | ALX_MDIO_OP_READ |
+                     clk_sel << ALX_MDIO_CLK_SEL_SHIFT;
+       } else {
+               val = ALX_MDIO_SPRES_PRMBL |
+                     clk_sel << ALX_MDIO_CLK_SEL_SHIFT |
+                     reg << ALX_MDIO_REG_SHIFT |
+                     ALX_MDIO_START | ALX_MDIO_OP_READ;
+       }
+       alx_write_mem32(hw, ALX_MDIO, val);
+
+       err = alx_wait_mdio_idle(hw);
+       if (err)
+               return err;
+       val = alx_read_mem32(hw, ALX_MDIO);
+       *phy_data = ALX_GET_FIELD(val, ALX_MDIO_DATA);
+       return 0;
+}
+
+static int alx_write_phy_core(struct alx_hw *hw, bool ext, u8 dev,
+                             u16 reg, u16 phy_data)
+{
+       u32 val, clk_sel;
+
+       /* use slow clock when it's in hibernation status */
+       clk_sel = hw->link_speed != SPEED_UNKNOWN ?
+                       ALX_MDIO_CLK_SEL_25MD4 :
+                       ALX_MDIO_CLK_SEL_25MD128;
+
+       if (ext) {
+               val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT |
+                     reg << ALX_MDIO_EXTN_REG_SHIFT;
+               alx_write_mem32(hw, ALX_MDIO_EXTN, val);
+
+               val = ALX_MDIO_SPRES_PRMBL |
+                     clk_sel << ALX_MDIO_CLK_SEL_SHIFT |
+                     phy_data << ALX_MDIO_DATA_SHIFT |
+                     ALX_MDIO_START | ALX_MDIO_MODE_EXT;
+       } else {
+               val = ALX_MDIO_SPRES_PRMBL |
+                     clk_sel << ALX_MDIO_CLK_SEL_SHIFT |
+                     reg << ALX_MDIO_REG_SHIFT |
+                     phy_data << ALX_MDIO_DATA_SHIFT |
+                     ALX_MDIO_START;
+       }
+       alx_write_mem32(hw, ALX_MDIO, val);
+
+       return alx_wait_mdio_idle(hw);
+}
+
+static int __alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data)
+{
+       return alx_read_phy_core(hw, false, 0, reg, phy_data);
+}
+
+static int __alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data)
+{
+       return alx_write_phy_core(hw, false, 0, reg, phy_data);
+}
+
+static int __alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata)
+{
+       return alx_read_phy_core(hw, true, dev, reg, pdata);
+}
+
+static int __alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data)
+{
+       return alx_write_phy_core(hw, true, dev, reg, data);
+}
+
+static int __alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata)
+{
+       int err;
+
+       err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg);
+       if (err)
+               return err;
+
+       return __alx_read_phy_reg(hw, ALX_MII_DBG_DATA, pdata);
+}
+
+static int __alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data)
+{
+       int err;
+
+       err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg);
+       if (err)
+               return err;
+
+       return __alx_write_phy_reg(hw, ALX_MII_DBG_DATA, data);
+}
+
+int alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data)
+{
+       int err;
+
+       spin_lock(&hw->mdio_lock);
+       err = __alx_read_phy_reg(hw, reg, phy_data);
+       spin_unlock(&hw->mdio_lock);
+
+       return err;
+}
+
+int alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data)
+{
+       int err;
+
+       spin_lock(&hw->mdio_lock);
+       err = __alx_write_phy_reg(hw, reg, phy_data);
+       spin_unlock(&hw->mdio_lock);
+
+       return err;
+}
+
+int alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata)
+{
+       int err;
+
+       spin_lock(&hw->mdio_lock);
+       err = __alx_read_phy_ext(hw, dev, reg, pdata);
+       spin_unlock(&hw->mdio_lock);
+
+       return err;
+}
+
+int alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data)
+{
+       int err;
+
+       spin_lock(&hw->mdio_lock);
+       err = __alx_write_phy_ext(hw, dev, reg, data);
+       spin_unlock(&hw->mdio_lock);
+
+       return err;
+}
+
+static int alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata)
+{
+       int err;
+
+       spin_lock(&hw->mdio_lock);
+       err = __alx_read_phy_dbg(hw, reg, pdata);
+       spin_unlock(&hw->mdio_lock);
+
+       return err;
+}
+
+static int alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data)
+{
+       int err;
+
+       spin_lock(&hw->mdio_lock);
+       err = __alx_write_phy_dbg(hw, reg, data);
+       spin_unlock(&hw->mdio_lock);
+
+       return err;
+}
+
+static u16 alx_get_phy_config(struct alx_hw *hw)
+{
+       u32 val;
+       u16 phy_val;
+
+       val = alx_read_mem32(hw, ALX_PHY_CTRL);
+       /* phy in reset */
+       if ((val & ALX_PHY_CTRL_DSPRST_OUT) == 0)
+               return ALX_DRV_PHY_UNKNOWN;
+
+       val = alx_read_mem32(hw, ALX_DRV);
+       val = ALX_GET_FIELD(val, ALX_DRV_PHY);
+       if (ALX_DRV_PHY_UNKNOWN == val)
+               return ALX_DRV_PHY_UNKNOWN;
+
+       alx_read_phy_reg(hw, ALX_MII_DBG_ADDR, &phy_val);
+       if (ALX_PHY_INITED == phy_val)
+               return val;
+
+       return ALX_DRV_PHY_UNKNOWN;
+}
+
+static bool alx_wait_reg(struct alx_hw *hw, u32 reg, u32 wait, u32 *val)
+{
+       u32 read;
+       int i;
+
+       for (i = 0; i < ALX_SLD_MAX_TO; i++) {
+               read = alx_read_mem32(hw, reg);
+               if ((read & wait) == 0) {
+                       if (val)
+                               *val = read;
+                       return true;
+               }
+               mdelay(1);
+       }
+
+       return false;
+}
+
+static bool alx_read_macaddr(struct alx_hw *hw, u8 *addr)
+{
+       u32 mac0, mac1;
+
+       mac0 = alx_read_mem32(hw, ALX_STAD0);
+       mac1 = alx_read_mem32(hw, ALX_STAD1);
+
+       /* addr should be big-endian */
+       *(__be32 *)(addr + 2) = cpu_to_be32(mac0);
+       *(__be16 *)addr = cpu_to_be16(mac1);
+
+       return is_valid_ether_addr(addr);
+}
+
+int alx_get_perm_macaddr(struct alx_hw *hw, u8 *addr)
+{
+       u32 val;
+
+       /* try to get it from register first */
+       if (alx_read_macaddr(hw, addr))
+               return 0;
+
+       /* try to load from efuse */
+       if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_STAT | ALX_SLD_START, &val))
+               return -EIO;
+       alx_write_mem32(hw, ALX_SLD, val | ALX_SLD_START);
+       if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_START, NULL))
+               return -EIO;
+       if (alx_read_macaddr(hw, addr))
+               return 0;
+
+       /* try to load from flash/eeprom (if present) */
+       val = alx_read_mem32(hw, ALX_EFLD);
+       if (val & (ALX_EFLD_F_EXIST | ALX_EFLD_E_EXIST)) {
+               if (!alx_wait_reg(hw, ALX_EFLD,
+                                 ALX_EFLD_STAT | ALX_EFLD_START, &val))
+                       return -EIO;
+               alx_write_mem32(hw, ALX_EFLD, val | ALX_EFLD_START);
+               if (!alx_wait_reg(hw, ALX_EFLD, ALX_EFLD_START, NULL))
+                       return -EIO;
+               if (alx_read_macaddr(hw, addr))
+                       return 0;
+       }
+
+       return -EIO;
+}
+
+void alx_set_macaddr(struct alx_hw *hw, const u8 *addr)
+{
+       u32 val;
+
+       /* for example: 00-0B-6A-F6-00-DC * STAD0=6AF600DC, STAD1=000B */
+       val = be32_to_cpu(*(__be32 *)(addr + 2));
+       alx_write_mem32(hw, ALX_STAD0, val);
+       val = be16_to_cpu(*(__be16 *)addr);
+       alx_write_mem32(hw, ALX_STAD1, val);
+}
+
+static void alx_enable_osc(struct alx_hw *hw)
+{
+       u32 val;
+
+       /* rising edge */
+       val = alx_read_mem32(hw, ALX_MISC);
+       alx_write_mem32(hw, ALX_MISC, val & ~ALX_MISC_INTNLOSC_OPEN);
+       alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
+}
+
+static void alx_reset_osc(struct alx_hw *hw, u8 rev)
+{
+       u32 val, val2;
+
+       /* clear Internal OSC settings, switching OSC by hw itself */
+       val = alx_read_mem32(hw, ALX_MISC3);
+       alx_write_mem32(hw, ALX_MISC3,
+                       (val & ~ALX_MISC3_25M_BY_SW) |
+                       ALX_MISC3_25M_NOTO_INTNL);
+
+       /* 25M clk from chipset may be unstable 1s after de-assert of
+        * PERST, driver need re-calibrate before enter Sleep for WoL
+        */
+       val = alx_read_mem32(hw, ALX_MISC);
+       if (rev >= ALX_REV_B0) {
+               /* restore over current protection def-val,
+                * this val could be reset by MAC-RST
+                */
+               ALX_SET_FIELD(val, ALX_MISC_PSW_OCP, ALX_MISC_PSW_OCP_DEF);
+               /* a 0->1 change will update the internal val of osc */
+               val &= ~ALX_MISC_INTNLOSC_OPEN;
+               alx_write_mem32(hw, ALX_MISC, val);
+               alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
+               /* hw will automatically dis OSC after cab. */
+               val2 = alx_read_mem32(hw, ALX_MSIC2);
+               val2 &= ~ALX_MSIC2_CALB_START;
+               alx_write_mem32(hw, ALX_MSIC2, val2);
+               alx_write_mem32(hw, ALX_MSIC2, val2 | ALX_MSIC2_CALB_START);
+       } else {
+               val &= ~ALX_MISC_INTNLOSC_OPEN;
+               /* disable isolate for rev A devices */
+               if (alx_is_rev_a(rev))
+                       val &= ~ALX_MISC_ISO_EN;
+
+               alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
+               alx_write_mem32(hw, ALX_MISC, val);
+       }
+
+       udelay(20);
+}
+
+static int alx_stop_mac(struct alx_hw *hw)
+{
+       u32 rxq, txq, val;
+       u16 i;
+
+       rxq = alx_read_mem32(hw, ALX_RXQ0);
+       alx_write_mem32(hw, ALX_RXQ0, rxq & ~ALX_RXQ0_EN);
+       txq = alx_read_mem32(hw, ALX_TXQ0);
+       alx_write_mem32(hw, ALX_TXQ0, txq & ~ALX_TXQ0_EN);
+
+       udelay(40);
+
+       hw->rx_ctrl &= ~(ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_TX_EN);
+       alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+
+       for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) {
+               val = alx_read_mem32(hw, ALX_MAC_STS);
+               if (!(val & ALX_MAC_STS_IDLE))
+                       return 0;
+               udelay(10);
+       }
+
+       return -ETIMEDOUT;
+}
+
+int alx_reset_mac(struct alx_hw *hw)
+{
+       u32 val, pmctrl;
+       int i, ret;
+       u8 rev;
+       bool a_cr;
+
+       pmctrl = 0;
+       rev = alx_hw_revision(hw);
+       a_cr = alx_is_rev_a(rev) && alx_hw_with_cr(hw);
+
+       /* disable all interrupts, RXQ/TXQ */
+       alx_write_mem32(hw, ALX_MSIX_MASK, 0xFFFFFFFF);
+       alx_write_mem32(hw, ALX_IMR, 0);
+       alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS);
+
+       ret = alx_stop_mac(hw);
+       if (ret)
+               return ret;
+
+       /* mac reset workaroud */
+       alx_write_mem32(hw, ALX_RFD_PIDX, 1);
+
+       /* dis l0s/l1 before mac reset */
+       if (a_cr) {
+               pmctrl = alx_read_mem32(hw, ALX_PMCTRL);
+               if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN))
+                       alx_write_mem32(hw, ALX_PMCTRL,
+                                       pmctrl & ~(ALX_PMCTRL_L1_EN |
+                                                  ALX_PMCTRL_L0S_EN));
+       }
+
+       /* reset whole mac safely */
+       val = alx_read_mem32(hw, ALX_MASTER);
+       alx_write_mem32(hw, ALX_MASTER,
+                       val | ALX_MASTER_DMA_MAC_RST | ALX_MASTER_OOB_DIS);
+
+       /* make sure it's real idle */
+       udelay(10);
+       for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) {
+               val = alx_read_mem32(hw, ALX_RFD_PIDX);
+               if (val == 0)
+                       break;
+               udelay(10);
+       }
+       for (; i < ALX_DMA_MAC_RST_TO; i++) {
+               val = alx_read_mem32(hw, ALX_MASTER);
+               if ((val & ALX_MASTER_DMA_MAC_RST) == 0)
+                       break;
+               udelay(10);
+       }
+       if (i == ALX_DMA_MAC_RST_TO)
+               return -EIO;
+       udelay(10);
+
+       if (a_cr) {
+               alx_write_mem32(hw, ALX_MASTER, val | ALX_MASTER_PCLKSEL_SRDS);
+               /* restore l0s / l1 */
+               if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN))
+                       alx_write_mem32(hw, ALX_PMCTRL, pmctrl);
+       }
+
+       alx_reset_osc(hw, rev);
+
+       /* clear Internal OSC settings, switching OSC by hw itself,
+        * disable isolate for rev A devices
+        */
+       val = alx_read_mem32(hw, ALX_MISC3);
+       alx_write_mem32(hw, ALX_MISC3,
+                       (val & ~ALX_MISC3_25M_BY_SW) |
+                       ALX_MISC3_25M_NOTO_INTNL);
+       val = alx_read_mem32(hw, ALX_MISC);
+       val &= ~ALX_MISC_INTNLOSC_OPEN;
+       if (alx_is_rev_a(rev))
+               val &= ~ALX_MISC_ISO_EN;
+       alx_write_mem32(hw, ALX_MISC, val);
+       udelay(20);
+
+       /* driver control speed/duplex, hash-alg */
+       alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+
+       val = alx_read_mem32(hw, ALX_SERDES);
+       alx_write_mem32(hw, ALX_SERDES,
+                       val | ALX_SERDES_MACCLK_SLWDWN |
+                       ALX_SERDES_PHYCLK_SLWDWN);
+
+       return 0;
+}
+
+void alx_reset_phy(struct alx_hw *hw)
+{
+       int i;
+       u32 val;
+       u16 phy_val;
+
+       /* (DSP)reset PHY core */
+       val = alx_read_mem32(hw, ALX_PHY_CTRL);
+       val &= ~(ALX_PHY_CTRL_DSPRST_OUT | ALX_PHY_CTRL_IDDQ |
+                ALX_PHY_CTRL_GATE_25M | ALX_PHY_CTRL_POWER_DOWN |
+                ALX_PHY_CTRL_CLS);
+       val |= ALX_PHY_CTRL_RST_ANALOG;
+
+       val |= (ALX_PHY_CTRL_HIB_PULSE | ALX_PHY_CTRL_HIB_EN);
+       alx_write_mem32(hw, ALX_PHY_CTRL, val);
+       udelay(10);
+       alx_write_mem32(hw, ALX_PHY_CTRL, val | ALX_PHY_CTRL_DSPRST_OUT);
+
+       for (i = 0; i < ALX_PHY_CTRL_DSPRST_TO; i++)
+               udelay(10);
+
+       /* phy power saving & hib */
+       alx_write_phy_dbg(hw, ALX_MIIDBG_LEGCYPS, ALX_LEGCYPS_DEF);
+       alx_write_phy_dbg(hw, ALX_MIIDBG_SYSMODCTRL,
+                         ALX_SYSMODCTRL_IECHOADJ_DEF);
+       alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_VDRVBIAS,
+                         ALX_VDRVBIAS_DEF);
+
+       /* EEE advertisement */
+       val = alx_read_mem32(hw, ALX_LPI_CTRL);
+       alx_write_mem32(hw, ALX_LPI_CTRL, val & ~ALX_LPI_CTRL_EN);
+       alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_LOCAL_EEEADV, 0);
+
+       /* phy power saving */
+       alx_write_phy_dbg(hw, ALX_MIIDBG_TST10BTCFG, ALX_TST10BTCFG_DEF);
+       alx_write_phy_dbg(hw, ALX_MIIDBG_SRDSYSMOD, ALX_SRDSYSMOD_DEF);
+       alx_write_phy_dbg(hw, ALX_MIIDBG_TST100BTCFG, ALX_TST100BTCFG_DEF);
+       alx_write_phy_dbg(hw, ALX_MIIDBG_ANACTRL, ALX_ANACTRL_DEF);
+       alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val);
+       alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2,
+                         phy_val & ~ALX_GREENCFG2_GATE_DFSE_EN);
+       /* rtl8139c, 120m issue */
+       alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_NLP78,
+                         ALX_MIIEXT_NLP78_120M_DEF);
+       alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_S3DIG10,
+                         ALX_MIIEXT_S3DIG10_DEF);
+
+       if (hw->lnk_patch) {
+               /* Turn off half amplitude */
+               alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3,
+                                &phy_val);
+               alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3,
+                                 phy_val | ALX_CLDCTRL3_BP_CABLE1TH_DET_GT);
+               /* Turn off Green feature */
+               alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val);
+               alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2,
+                                 phy_val | ALX_GREENCFG2_BP_GREEN);
+               /* Turn off half Bias */
+               alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5,
+                                &phy_val);
+               alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5,
+                                 phy_val | ALX_CLDCTRL5_BP_VD_HLFBIAS);
+       }
+
+       /* set phy interrupt mask */
+       alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP | ALX_IER_LINK_DOWN);
+}
+
+#define ALX_PCI_CMD (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
+
+void alx_reset_pcie(struct alx_hw *hw)
+{
+       u8 rev = alx_hw_revision(hw);
+       u32 val;
+       u16 val16;
+
+       /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */
+       pci_read_config_word(hw->pdev, PCI_COMMAND, &val16);
+       if (!(val16 & ALX_PCI_CMD) || (val16 & PCI_COMMAND_INTX_DISABLE)) {
+               val16 = (val16 | ALX_PCI_CMD) & ~PCI_COMMAND_INTX_DISABLE;
+               pci_write_config_word(hw->pdev, PCI_COMMAND, val16);
+       }
+
+       /* clear WoL setting/status */
+       val = alx_read_mem32(hw, ALX_WOL0);
+       alx_write_mem32(hw, ALX_WOL0, 0);
+
+       val = alx_read_mem32(hw, ALX_PDLL_TRNS1);
+       alx_write_mem32(hw, ALX_PDLL_TRNS1, val & ~ALX_PDLL_TRNS1_D3PLLOFF_EN);
+
+       /* mask some pcie error bits */
+       val = alx_read_mem32(hw, ALX_UE_SVRT);
+       val &= ~(ALX_UE_SVRT_DLPROTERR | ALX_UE_SVRT_FCPROTERR);
+       alx_write_mem32(hw, ALX_UE_SVRT, val);
+
+       /* wol 25M & pclk */
+       val = alx_read_mem32(hw, ALX_MASTER);
+       if (alx_is_rev_a(rev) && alx_hw_with_cr(hw)) {
+               if ((val & ALX_MASTER_WAKEN_25M) == 0 ||
+                   (val & ALX_MASTER_PCLKSEL_SRDS) == 0)
+                       alx_write_mem32(hw, ALX_MASTER,
+                                       val | ALX_MASTER_PCLKSEL_SRDS |
+                                       ALX_MASTER_WAKEN_25M);
+       } else {
+               if ((val & ALX_MASTER_WAKEN_25M) == 0 ||
+                   (val & ALX_MASTER_PCLKSEL_SRDS) != 0)
+                       alx_write_mem32(hw, ALX_MASTER,
+                                       (val & ~ALX_MASTER_PCLKSEL_SRDS) |
+                                       ALX_MASTER_WAKEN_25M);
+       }
+
+       /* ASPM setting */
+       alx_enable_aspm(hw, true, true);
+
+       udelay(10);
+}
+
+void alx_start_mac(struct alx_hw *hw)
+{
+       u32 mac, txq, rxq;
+
+       rxq = alx_read_mem32(hw, ALX_RXQ0);
+       alx_write_mem32(hw, ALX_RXQ0, rxq | ALX_RXQ0_EN);
+       txq = alx_read_mem32(hw, ALX_TXQ0);
+       alx_write_mem32(hw, ALX_TXQ0, txq | ALX_TXQ0_EN);
+
+       mac = hw->rx_ctrl;
+       if (hw->link_speed % 10 == DUPLEX_FULL)
+               mac |= ALX_MAC_CTRL_FULLD;
+       else
+               mac &= ~ALX_MAC_CTRL_FULLD;
+       ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED,
+                     hw->link_speed >= SPEED_1000 ? ALX_MAC_CTRL_SPEED_1000 :
+                                                    ALX_MAC_CTRL_SPEED_10_100);
+       mac |= ALX_MAC_CTRL_TX_EN | ALX_MAC_CTRL_RX_EN;
+       hw->rx_ctrl = mac;
+       alx_write_mem32(hw, ALX_MAC_CTRL, mac);
+}
+
+void alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc)
+{
+       if (fc & ALX_FC_RX)
+               hw->rx_ctrl |= ALX_MAC_CTRL_RXFC_EN;
+       else
+               hw->rx_ctrl &= ~ALX_MAC_CTRL_RXFC_EN;
+
+       if (fc & ALX_FC_TX)
+               hw->rx_ctrl |= ALX_MAC_CTRL_TXFC_EN;
+       else
+               hw->rx_ctrl &= ~ALX_MAC_CTRL_TXFC_EN;
+
+       alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+}
+
+void alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en)
+{
+       u32 pmctrl;
+       u8 rev = alx_hw_revision(hw);
+
+       pmctrl = alx_read_mem32(hw, ALX_PMCTRL);
+
+       ALX_SET_FIELD(pmctrl, ALX_PMCTRL_LCKDET_TIMER,
+                     ALX_PMCTRL_LCKDET_TIMER_DEF);
+       pmctrl |= ALX_PMCTRL_RCVR_WT_1US |
+                 ALX_PMCTRL_L1_CLKSW_EN |
+                 ALX_PMCTRL_L1_SRDSRX_PWD;
+       ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1REQ_TO, ALX_PMCTRL_L1REG_TO_DEF);
+       ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1_TIMER, ALX_PMCTRL_L1_TIMER_16US);
+       pmctrl &= ~(ALX_PMCTRL_L1_SRDS_EN |
+                   ALX_PMCTRL_L1_SRDSPLL_EN |
+                   ALX_PMCTRL_L1_BUFSRX_EN |
+                   ALX_PMCTRL_SADLY_EN |
+                   ALX_PMCTRL_HOTRST_WTEN|
+                   ALX_PMCTRL_L0S_EN |
+                   ALX_PMCTRL_L1_EN |
+                   ALX_PMCTRL_ASPM_FCEN |
+                   ALX_PMCTRL_TXL1_AFTER_L0S |
+                   ALX_PMCTRL_RXL1_AFTER_L0S);
+       if (alx_is_rev_a(rev) && alx_hw_with_cr(hw))
+               pmctrl |= ALX_PMCTRL_L1_SRDS_EN | ALX_PMCTRL_L1_SRDSPLL_EN;
+
+       if (l0s_en)
+               pmctrl |= (ALX_PMCTRL_L0S_EN | ALX_PMCTRL_ASPM_FCEN);
+       if (l1_en)
+               pmctrl |= (ALX_PMCTRL_L1_EN | ALX_PMCTRL_ASPM_FCEN);
+
+       alx_write_mem32(hw, ALX_PMCTRL, pmctrl);
+}
+
+
+static u32 ethadv_to_hw_cfg(struct alx_hw *hw, u32 ethadv_cfg)
+{
+       u32 cfg = 0;
+
+       if (ethadv_cfg & ADVERTISED_Autoneg) {
+               cfg |= ALX_DRV_PHY_AUTO;
+               if (ethadv_cfg & ADVERTISED_10baseT_Half)
+                       cfg |= ALX_DRV_PHY_10;
+               if (ethadv_cfg & ADVERTISED_10baseT_Full)
+                       cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX;
+               if (ethadv_cfg & ADVERTISED_100baseT_Half)
+                       cfg |= ALX_DRV_PHY_100;
+               if (ethadv_cfg & ADVERTISED_100baseT_Full)
+                       cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX;
+               if (ethadv_cfg & ADVERTISED_1000baseT_Half)
+                       cfg |= ALX_DRV_PHY_1000;
+               if (ethadv_cfg & ADVERTISED_1000baseT_Full)
+                       cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX;
+               if (ethadv_cfg & ADVERTISED_Pause)
+                       cfg |= ADVERTISE_PAUSE_CAP;
+               if (ethadv_cfg & ADVERTISED_Asym_Pause)
+                       cfg |= ADVERTISE_PAUSE_ASYM;
+       } else {
+               switch (ethadv_cfg) {
+               case ADVERTISED_10baseT_Half:
+                       cfg |= ALX_DRV_PHY_10;
+                       break;
+               case ADVERTISED_100baseT_Half:
+                       cfg |= ALX_DRV_PHY_100;
+                       break;
+               case ADVERTISED_10baseT_Full:
+                       cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX;
+                       break;
+               case ADVERTISED_100baseT_Full:
+                       cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX;
+                       break;
+               }
+       }
+
+       return cfg;
+}
+
+int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl)
+{
+       u16 adv, giga, cr;
+       u32 val;
+       int err = 0;
+
+       alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, 0);
+       val = alx_read_mem32(hw, ALX_DRV);
+       ALX_SET_FIELD(val, ALX_DRV_PHY, 0);
+
+       if (ethadv & ADVERTISED_Autoneg) {
+               adv = ADVERTISE_CSMA;
+               adv |= ethtool_adv_to_mii_adv_t(ethadv);
+
+               if (flowctrl & ALX_FC_ANEG) {
+                       if (flowctrl & ALX_FC_RX) {
+                               adv |= ADVERTISED_Pause;
+                               if (!(flowctrl & ALX_FC_TX))
+                                       adv |= ADVERTISED_Asym_Pause;
+                       } else if (flowctrl & ALX_FC_TX) {
+                               adv |= ADVERTISED_Asym_Pause;
+                       }
+               }
+               giga = 0;
+               if (alx_hw_giga(hw))
+                       giga = ethtool_adv_to_mii_ctrl1000_t(ethadv);
+
+               cr = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART;
+
+               if (alx_write_phy_reg(hw, MII_ADVERTISE, adv) ||
+                   alx_write_phy_reg(hw, MII_CTRL1000, giga) ||
+                   alx_write_phy_reg(hw, MII_BMCR, cr))
+                       err = -EBUSY;
+       } else {
+               cr = BMCR_RESET;
+               if (ethadv == ADVERTISED_100baseT_Half ||
+                   ethadv == ADVERTISED_100baseT_Full)
+                       cr |= BMCR_SPEED100;
+               if (ethadv == ADVERTISED_10baseT_Full ||
+                   ethadv == ADVERTISED_100baseT_Full)
+                       cr |= BMCR_FULLDPLX;
+
+               err = alx_write_phy_reg(hw, MII_BMCR, cr);
+       }
+
+       if (!err) {
+               alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, ALX_PHY_INITED);
+               val |= ethadv_to_hw_cfg(hw, ethadv);
+       }
+
+       alx_write_mem32(hw, ALX_DRV, val);
+
+       return err;
+}
+
+
+void alx_post_phy_link(struct alx_hw *hw)
+{
+       u16 phy_val, len, agc;
+       u8 revid = alx_hw_revision(hw);
+       bool adj_th = revid == ALX_REV_B0;
+       int speed;
+
+       if (hw->link_speed == SPEED_UNKNOWN)
+               speed = SPEED_UNKNOWN;
+       else
+               speed = hw->link_speed - hw->link_speed % 10;
+
+       if (revid != ALX_REV_B0 && !alx_is_rev_a(revid))
+               return;
+
+       /* 1000BT/AZ, wrong cable length */
+       if (speed != SPEED_UNKNOWN) {
+               alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL6,
+                                &phy_val);
+               len = ALX_GET_FIELD(phy_val, ALX_CLDCTRL6_CAB_LEN);
+               alx_read_phy_dbg(hw, ALX_MIIDBG_AGC, &phy_val);
+               agc = ALX_GET_FIELD(phy_val, ALX_AGC_2_VGA);
+
+               if ((speed == SPEED_1000 &&
+                    (len > ALX_CLDCTRL6_CAB_LEN_SHORT1G ||
+                     (len == 0 && agc > ALX_AGC_LONG1G_LIMT))) ||
+                   (speed == SPEED_100 &&
+                    (len > ALX_CLDCTRL6_CAB_LEN_SHORT100M ||
+                     (len == 0 && agc > ALX_AGC_LONG100M_LIMT)))) {
+                       alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT,
+                                         ALX_AZ_ANADECT_LONG);
+                       alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+                                        &phy_val);
+                       alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+                                         phy_val | ALX_AFE_10BT_100M_TH);
+               } else {
+                       alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT,
+                                         ALX_AZ_ANADECT_DEF);
+                       alx_read_phy_ext(hw, ALX_MIIEXT_ANEG,
+                                        ALX_MIIEXT_AFE, &phy_val);
+                       alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+                                         phy_val & ~ALX_AFE_10BT_100M_TH);
+               }
+
+               /* threshold adjust */
+               if (adj_th && hw->lnk_patch) {
+                       if (speed == SPEED_100) {
+                               alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB,
+                                                 ALX_MSE16DB_UP);
+                       } else if (speed == SPEED_1000) {
+                               /*
+                                * Giga link threshold, raise the tolerance of
+                                * noise 50%
+                                */
+                               alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB,
+                                                &phy_val);
+                               ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH,
+                                             ALX_MSE20DB_TH_HI);
+                               alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB,
+                                                 phy_val);
+                       }
+               }
+       } else {
+               alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+                                &phy_val);
+               alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+                                 phy_val & ~ALX_AFE_10BT_100M_TH);
+
+               if (adj_th && hw->lnk_patch) {
+                       alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB,
+                                         ALX_MSE16DB_DOWN);
+                       alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB, &phy_val);
+                       ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH,
+                                     ALX_MSE20DB_TH_DEF);
+                       alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB, phy_val);
+               }
+       }
+}
+
+
+/* NOTE:
+ *    1. phy link must be established before calling this function
+ *    2. wol option (pattern,magic,link,etc.) is configed before call it.
+ */
+int alx_pre_suspend(struct alx_hw *hw, int speed)
+{
+       u32 master, mac, phy, val;
+       int err = 0;
+
+       master = alx_read_mem32(hw, ALX_MASTER);
+       master &= ~ALX_MASTER_PCLKSEL_SRDS;
+       mac = hw->rx_ctrl;
+       /* 10/100 half */
+       ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED,  ALX_MAC_CTRL_SPEED_10_100);
+       mac &= ~(ALX_MAC_CTRL_FULLD | ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_TX_EN);
+
+       phy = alx_read_mem32(hw, ALX_PHY_CTRL);
+       phy &= ~(ALX_PHY_CTRL_DSPRST_OUT | ALX_PHY_CTRL_CLS);
+       phy |= ALX_PHY_CTRL_RST_ANALOG | ALX_PHY_CTRL_HIB_PULSE |
+              ALX_PHY_CTRL_HIB_EN;
+
+       /* without any activity  */
+       if (!(hw->sleep_ctrl & ALX_SLEEP_ACTIVE)) {
+               err = alx_write_phy_reg(hw, ALX_MII_IER, 0);
+               if (err)
+                       return err;
+               phy |= ALX_PHY_CTRL_IDDQ | ALX_PHY_CTRL_POWER_DOWN;
+       } else {
+               if (hw->sleep_ctrl & (ALX_SLEEP_WOL_MAGIC | ALX_SLEEP_CIFS))
+                       mac |= ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_BRD_EN;
+               if (hw->sleep_ctrl & ALX_SLEEP_CIFS)
+                       mac |= ALX_MAC_CTRL_TX_EN;
+               if (speed % 10 == DUPLEX_FULL)
+                       mac |= ALX_MAC_CTRL_FULLD;
+               if (speed >= SPEED_1000)
+                       ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED,
+                                     ALX_MAC_CTRL_SPEED_1000);
+               phy |= ALX_PHY_CTRL_DSPRST_OUT;
+               err = alx_write_phy_ext(hw, ALX_MIIEXT_ANEG,
+                                       ALX_MIIEXT_S3DIG10,
+                                       ALX_MIIEXT_S3DIG10_SL);
+               if (err)
+                       return err;
+       }
+
+       alx_enable_osc(hw);
+       hw->rx_ctrl = mac;
+       alx_write_mem32(hw, ALX_MASTER, master);
+       alx_write_mem32(hw, ALX_MAC_CTRL, mac);
+       alx_write_mem32(hw, ALX_PHY_CTRL, phy);
+
+       /* set val of PDLL D3PLLOFF */
+       val = alx_read_mem32(hw, ALX_PDLL_TRNS1);
+       val |= ALX_PDLL_TRNS1_D3PLLOFF_EN;
+       alx_write_mem32(hw, ALX_PDLL_TRNS1, val);
+
+       return 0;
+}
+
+bool alx_phy_configured(struct alx_hw *hw)
+{
+       u32 cfg, hw_cfg;
+
+       cfg = ethadv_to_hw_cfg(hw, hw->adv_cfg);
+       cfg = ALX_GET_FIELD(cfg, ALX_DRV_PHY);
+       hw_cfg = alx_get_phy_config(hw);
+
+       if (hw_cfg == ALX_DRV_PHY_UNKNOWN)
+               return false;
+
+       return cfg == hw_cfg;
+}
+
+int alx_get_phy_link(struct alx_hw *hw, int *speed)
+{
+       struct pci_dev *pdev = hw->pdev;
+       u16 bmsr, giga;
+       int err;
+
+       err = alx_read_phy_reg(hw, MII_BMSR, &bmsr);
+       if (err)
+               return err;
+
+       err = alx_read_phy_reg(hw, MII_BMSR, &bmsr);
+       if (err)
+               return err;
+
+       if (!(bmsr & BMSR_LSTATUS)) {
+               *speed = SPEED_UNKNOWN;
+               return 0;
+       }
+
+       /* speed/duplex result is saved in PHY Specific Status Register */
+       err = alx_read_phy_reg(hw, ALX_MII_GIGA_PSSR, &giga);
+       if (err)
+               return err;
+
+       if (!(giga & ALX_GIGA_PSSR_SPD_DPLX_RESOLVED))
+               goto wrong_speed;
+
+       switch (giga & ALX_GIGA_PSSR_SPEED) {
+       case ALX_GIGA_PSSR_1000MBS:
+               *speed = SPEED_1000;
+               break;
+       case ALX_GIGA_PSSR_100MBS:
+               *speed = SPEED_100;
+               break;
+       case ALX_GIGA_PSSR_10MBS:
+               *speed = SPEED_10;
+               break;
+       default:
+               goto wrong_speed;
+       }
+
+       *speed += (giga & ALX_GIGA_PSSR_DPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+       return 1;
+
+wrong_speed:
+       dev_err(&pdev->dev, "invalid PHY speed/duplex: 0x%x\n", giga);
+       return -EINVAL;
+}
+
+int alx_clear_phy_intr(struct alx_hw *hw)
+{
+       u16 isr;
+
+       /* clear interrupt status by reading it */
+       return alx_read_phy_reg(hw, ALX_MII_ISR, &isr);
+}
+
+int alx_config_wol(struct alx_hw *hw)
+{
+       u32 wol = 0;
+       int err = 0;
+
+       /* turn on magic packet event */
+       if (hw->sleep_ctrl & ALX_SLEEP_WOL_MAGIC)
+               wol |= ALX_WOL0_MAGIC_EN | ALX_WOL0_PME_MAGIC_EN;
+
+       /* turn on link up event */
+       if (hw->sleep_ctrl & ALX_SLEEP_WOL_PHY) {
+               wol |=  ALX_WOL0_LINK_EN | ALX_WOL0_PME_LINK;
+               /* only link up can wake up */
+               err = alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP);
+       }
+       alx_write_mem32(hw, ALX_WOL0, wol);
+
+       return err;
+}
+
+void alx_disable_rss(struct alx_hw *hw)
+{
+       u32 ctrl = alx_read_mem32(hw, ALX_RXQ0);
+
+       ctrl &= ~ALX_RXQ0_RSS_HASH_EN;
+       alx_write_mem32(hw, ALX_RXQ0, ctrl);
+}
+
+void alx_configure_basic(struct alx_hw *hw)
+{
+       u32 val, raw_mtu, max_payload;
+       u16 val16;
+       u8 chip_rev = alx_hw_revision(hw);
+
+       alx_set_macaddr(hw, hw->mac_addr);
+
+       alx_write_mem32(hw, ALX_CLK_GATE, ALX_CLK_GATE_ALL);
+
+       /* idle timeout to switch clk_125M */
+       if (chip_rev >= ALX_REV_B0)
+               alx_write_mem32(hw, ALX_IDLE_DECISN_TIMER,
+                               ALX_IDLE_DECISN_TIMER_DEF);
+
+       alx_write_mem32(hw, ALX_SMB_TIMER, hw->smb_timer * 500UL);
+
+       val = alx_read_mem32(hw, ALX_MASTER);
+       val |= ALX_MASTER_IRQMOD2_EN |
+              ALX_MASTER_IRQMOD1_EN |
+              ALX_MASTER_SYSALVTIMER_EN;
+       alx_write_mem32(hw, ALX_MASTER, val);
+       alx_write_mem32(hw, ALX_IRQ_MODU_TIMER,
+                       (hw->imt >> 1) << ALX_IRQ_MODU_TIMER1_SHIFT);
+       /* intr re-trig timeout */
+       alx_write_mem32(hw, ALX_INT_RETRIG, ALX_INT_RETRIG_TO);
+       /* tpd threshold to trig int */
+       alx_write_mem32(hw, ALX_TINT_TPD_THRSHLD, hw->ith_tpd);
+       alx_write_mem32(hw, ALX_TINT_TIMER, hw->imt);
+
+       raw_mtu = hw->mtu + ETH_HLEN;
+       alx_write_mem32(hw, ALX_MTU, raw_mtu + 8);
+       if (raw_mtu > ALX_MTU_JUMBO_TH)
+               hw->rx_ctrl &= ~ALX_MAC_CTRL_FAST_PAUSE;
+
+       if ((raw_mtu + 8) < ALX_TXQ1_JUMBO_TSO_TH)
+               val = (raw_mtu + 8 + 7) >> 3;
+       else
+               val = ALX_TXQ1_JUMBO_TSO_TH >> 3;
+       alx_write_mem32(hw, ALX_TXQ1, val | ALX_TXQ1_ERRLGPKT_DROP_EN);
+
+       max_payload = pcie_get_readrq(hw->pdev) >> 8;
+       /*
+        * if BIOS had changed the default dma read max length,
+        * restore it to default value
+        */
+       if (max_payload < ALX_DEV_CTRL_MAXRRS_MIN)
+               pcie_set_readrq(hw->pdev, 128 << ALX_DEV_CTRL_MAXRRS_MIN);
+
+       val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_TXQ0_TPD_BURSTPREF_SHIFT |
+             ALX_TXQ0_MODE_ENHANCE | ALX_TXQ0_LSO_8023_EN |
+             ALX_TXQ0_SUPT_IPOPT |
+             ALX_TXQ_TXF_BURST_PREF_DEF << ALX_TXQ0_TXF_BURST_PREF_SHIFT;
+       alx_write_mem32(hw, ALX_TXQ0, val);
+       val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q1_NUMPREF_SHIFT |
+             ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q2_NUMPREF_SHIFT |
+             ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q3_NUMPREF_SHIFT |
+             ALX_HQTPD_BURST_EN;
+       alx_write_mem32(hw, ALX_HQTPD, val);
+
+       /* rxq, flow control */
+       val = alx_read_mem32(hw, ALX_SRAM5);
+       val = ALX_GET_FIELD(val, ALX_SRAM_RXF_LEN) << 3;
+       if (val > ALX_SRAM_RXF_LEN_8K) {
+               val16 = ALX_MTU_STD_ALGN >> 3;
+               val = (val - ALX_RXQ2_RXF_FLOW_CTRL_RSVD) >> 3;
+       } else {
+               val16 = ALX_MTU_STD_ALGN >> 3;
+               val = (val - ALX_MTU_STD_ALGN) >> 3;
+       }
+       alx_write_mem32(hw, ALX_RXQ2,
+                       val16 << ALX_RXQ2_RXF_XOFF_THRESH_SHIFT |
+                       val << ALX_RXQ2_RXF_XON_THRESH_SHIFT);
+       val = ALX_RXQ0_NUM_RFD_PREF_DEF << ALX_RXQ0_NUM_RFD_PREF_SHIFT |
+             ALX_RXQ0_RSS_MODE_DIS << ALX_RXQ0_RSS_MODE_SHIFT |
+             ALX_RXQ0_IDT_TBL_SIZE_DEF << ALX_RXQ0_IDT_TBL_SIZE_SHIFT |
+             ALX_RXQ0_RSS_HSTYP_ALL | ALX_RXQ0_RSS_HASH_EN |
+             ALX_RXQ0_IPV6_PARSE_EN;
+
+       if (alx_hw_giga(hw))
+               ALX_SET_FIELD(val, ALX_RXQ0_ASPM_THRESH,
+                             ALX_RXQ0_ASPM_THRESH_100M);
+
+       alx_write_mem32(hw, ALX_RXQ0, val);
+
+       val = alx_read_mem32(hw, ALX_DMA);
+       val = ALX_DMA_RORDER_MODE_OUT << ALX_DMA_RORDER_MODE_SHIFT |
+             ALX_DMA_RREQ_PRI_DATA |
+             max_payload << ALX_DMA_RREQ_BLEN_SHIFT |
+             ALX_DMA_WDLY_CNT_DEF << ALX_DMA_WDLY_CNT_SHIFT |
+             ALX_DMA_RDLY_CNT_DEF << ALX_DMA_RDLY_CNT_SHIFT |
+             (hw->dma_chnl - 1) << ALX_DMA_RCHNL_SEL_SHIFT;
+       alx_write_mem32(hw, ALX_DMA, val);
+
+       /* default multi-tx-q weights */
+       val = ALX_WRR_PRI_RESTRICT_NONE << ALX_WRR_PRI_SHIFT |
+             4 << ALX_WRR_PRI0_SHIFT |
+             4 << ALX_WRR_PRI1_SHIFT |
+             4 << ALX_WRR_PRI2_SHIFT |
+             4 << ALX_WRR_PRI3_SHIFT;
+       alx_write_mem32(hw, ALX_WRR, val);
+}
+
+static inline u32 alx_speed_to_ethadv(int speed)
+{
+       switch (speed) {
+       case SPEED_1000 + DUPLEX_FULL:
+               return ADVERTISED_1000baseT_Full;
+       case SPEED_100 + DUPLEX_FULL:
+               return ADVERTISED_100baseT_Full;
+       case SPEED_100 + DUPLEX_HALF:
+               return ADVERTISED_10baseT_Half;
+       case SPEED_10 + DUPLEX_FULL:
+               return ADVERTISED_10baseT_Full;
+       case SPEED_10 + DUPLEX_HALF:
+               return ADVERTISED_10baseT_Half;
+       default:
+               return 0;
+       }
+}
+
+int alx_select_powersaving_speed(struct alx_hw *hw, int *speed)
+{
+       int i, err, spd;
+       u16 lpa;
+
+       err = alx_get_phy_link(hw, &spd);
+       if (err < 0)
+               return err;
+
+       if (spd == SPEED_UNKNOWN)
+               return 0;
+
+       err = alx_read_phy_reg(hw, MII_LPA, &lpa);
+       if (err)
+               return err;
+
+       if (!(lpa & LPA_LPACK)) {
+               *speed = spd;
+               return 0;
+       }
+
+       if (lpa & LPA_10FULL)
+               *speed = SPEED_10 + DUPLEX_FULL;
+       else if (lpa & LPA_10HALF)
+               *speed = SPEED_10 + DUPLEX_HALF;
+       else if (lpa & LPA_100FULL)
+               *speed = SPEED_100 + DUPLEX_FULL;
+       else
+               *speed = SPEED_100 + DUPLEX_HALF;
+
+       if (*speed != spd) {
+               err = alx_write_phy_reg(hw, ALX_MII_IER, 0);
+               if (err)
+                       return err;
+               err = alx_setup_speed_duplex(hw,
+                                            alx_speed_to_ethadv(*speed) |
+                                            ADVERTISED_Autoneg,
+                                            ALX_FC_ANEG | ALX_FC_RX |
+                                            ALX_FC_TX);
+               if (err)
+                       return err;
+
+               /* wait for linkup */
+               for (i = 0; i < ALX_MAX_SETUP_LNK_CYCLE; i++) {
+                       int speed2;
+
+                       msleep(100);
+
+                       err = alx_get_phy_link(hw, &speed2);
+                       if (err < 0)
+                               return err;
+                       if (speed2 != SPEED_UNKNOWN)
+                               break;
+               }
+               if (i == ALX_MAX_SETUP_LNK_CYCLE)
+                       return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+bool alx_get_phy_info(struct alx_hw *hw)
+{
+       u16  devs1, devs2;
+
+       if (alx_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id[0]) ||
+           alx_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id[1]))
+               return false;
+
+       /* since we haven't PMA/PMD status2 register, we can't
+        * use mdio45_probe function for prtad and mmds.
+        * use fixed MMD3 to get mmds.
+        */
+       if (alx_read_phy_ext(hw, 3, MDIO_DEVS1, &devs1) ||
+           alx_read_phy_ext(hw, 3, MDIO_DEVS2, &devs2))
+               return false;
+       hw->mdio.mmds = devs1 | devs2 << 16;
+
+       return true;
+}
diff --git a/drivers/net/ethernet/atheros/alx/hw.h b/drivers/net/ethernet/atheros/alx/hw.h
new file mode 100644 (file)
index 0000000..65e723d
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * 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_HW_H_
+#define ALX_HW_H_
+#include <linux/types.h>
+#include <linux/mdio.h>
+#include <linux/pci.h>
+#include "reg.h"
+
+/* Transmit Packet Descriptor, contains 4 32-bit words.
+ *
+ *   31               16               0
+ *   +----------------+----------------+
+ *   |    vlan-tag    |   buf length   |
+ *   +----------------+----------------+
+ *   |              Word 1             |
+ *   +----------------+----------------+
+ *   |      Word 2: buf addr lo        |
+ *   +----------------+----------------+
+ *   |      Word 3: buf addr hi        |
+ *   +----------------+----------------+
+ *
+ * Word 2 and 3 combine to form a 64-bit buffer address
+ *
+ * Word 1 has three forms, depending on the state of bit 8/12/13:
+ * if bit8 =='1', the definition is just for custom checksum offload.
+ * if bit8 == '0' && bit12 == '1' && bit13 == '1', the *FIRST* descriptor
+ *     for the skb is special for LSO V2, Word 2 become total skb length ,
+ *     Word 3 is meaningless.
+ * other condition, the definition is for general skb or ip/tcp/udp
+ *     checksum or LSO(TSO) offload.
+ *
+ * Here is the depiction:
+ *
+ *   0-+                                  0-+
+ *   1 |                                  1 |
+ *   2 |                                  2 |
+ *   3 |    Payload offset                3 |    L4 header offset
+ *   4 |        (7:0)                     4 |        (7:0)
+ *   5 |                                  5 |
+ *   6 |                                  6 |
+ *   7-+                                  7-+
+ *   8      Custom csum enable = 1        8      Custom csum enable = 0
+ *   9      General IPv4 checksum         9      General IPv4 checksum
+ *   10     General TCP checksum          10     General TCP checksum
+ *   11     General UDP checksum          11     General UDP checksum
+ *   12     Large Send Segment enable     12     Large Send Segment enable
+ *   13     Large Send Segment type       13     Large Send Segment type
+ *   14     VLAN tagged                   14     VLAN tagged
+ *   15     Insert VLAN tag               15     Insert VLAN tag
+ *   16     IPv4 packet                   16     IPv4 packet
+ *   17     Ethernet frame type           17     Ethernet frame type
+ *   18-+                                 18-+
+ *   19 |                                 19 |
+ *   20 |                                 20 |
+ *   21 |   Custom csum offset            21 |
+ *   22 |       (25:18)                   22 |
+ *   23 |                                 23 |   MSS (30:18)
+ *   24 |                                 24 |
+ *   25-+                                 25 |
+ *   26-+                                 26 |
+ *   27 |                                 27 |
+ *   28 |   Reserved                      28 |
+ *   29 |                                 29 |
+ *   30-+                                 30-+
+ *   31     End of packet                 31     End of packet
+ */
+struct alx_txd {
+       __le16 len;
+       __le16 vlan_tag;
+       __le32 word1;
+       union {
+               __le64 addr;
+               struct {
+                       __le32 pkt_len;
+                       __le32 resvd;
+               } l;
+       } adrl;
+} __packed;
+
+/* tpd word 1 */
+#define TPD_CXSUMSTART_MASK            0x00FF
+#define TPD_CXSUMSTART_SHIFT           0
+#define TPD_L4HDROFFSET_MASK           0x00FF
+#define TPD_L4HDROFFSET_SHIFT          0
+#define TPD_CXSUM_EN_MASK              0x0001
+#define TPD_CXSUM_EN_SHIFT             8
+#define TPD_IP_XSUM_MASK               0x0001
+#define TPD_IP_XSUM_SHIFT              9
+#define TPD_TCP_XSUM_MASK              0x0001
+#define TPD_TCP_XSUM_SHIFT             10
+#define TPD_UDP_XSUM_MASK              0x0001
+#define TPD_UDP_XSUM_SHIFT             11
+#define TPD_LSO_EN_MASK                        0x0001
+#define TPD_LSO_EN_SHIFT               12
+#define TPD_LSO_V2_MASK                        0x0001
+#define TPD_LSO_V2_SHIFT               13
+#define TPD_VLTAGGED_MASK              0x0001
+#define TPD_VLTAGGED_SHIFT             14
+#define TPD_INS_VLTAG_MASK             0x0001
+#define TPD_INS_VLTAG_SHIFT            15
+#define TPD_IPV4_MASK                  0x0001
+#define TPD_IPV4_SHIFT                 16
+#define TPD_ETHTYPE_MASK               0x0001
+#define TPD_ETHTYPE_SHIFT              17
+#define TPD_CXSUMOFFSET_MASK           0x00FF
+#define TPD_CXSUMOFFSET_SHIFT          18
+#define TPD_MSS_MASK                   0x1FFF
+#define TPD_MSS_SHIFT                  18
+#define TPD_EOP_MASK                   0x0001
+#define TPD_EOP_SHIFT                  31
+
+#define DESC_GET(_x, _name) ((_x) >> _name##SHIFT & _name##MASK)
+
+/* Receive Free Descriptor */
+struct alx_rfd {
+       __le64 addr;            /* data buffer address, length is
+                                * declared in register --- every
+                                * buffer has the same size
+                                */
+} __packed;
+
+/* Receive Return Descriptor, contains 4 32-bit words.
+ *
+ *   31               16               0
+ *   +----------------+----------------+
+ *   |              Word 0             |
+ *   +----------------+----------------+
+ *   |     Word 1: RSS Hash value      |
+ *   +----------------+----------------+
+ *   |              Word 2             |
+ *   +----------------+----------------+
+ *   |              Word 3             |
+ *   +----------------+----------------+
+ *
+ * Word 0 depiction         &            Word 2 depiction:
+ *
+ *   0--+                                 0--+
+ *   1  |                                 1  |
+ *   2  |                                 2  |
+ *   3  |                                 3  |
+ *   4  |                                 4  |
+ *   5  |                                 5  |
+ *   6  |                                 6  |
+ *   7  |    IP payload checksum          7  |     VLAN tag
+ *   8  |         (15:0)                  8  |      (15:0)
+ *   9  |                                 9  |
+ *   10 |                                 10 |
+ *   11 |                                 11 |
+ *   12 |                                 12 |
+ *   13 |                                 13 |
+ *   14 |                                 14 |
+ *   15-+                                 15-+
+ *   16-+                                 16-+
+ *   17 |     Number of RFDs              17 |
+ *   18 |        (19:16)                  18 |
+ *   19-+                                 19 |     Protocol ID
+ *   20-+                                 20 |      (23:16)
+ *   21 |                                 21 |
+ *   22 |                                 22 |
+ *   23 |                                 23-+
+ *   24 |                                 24 |     Reserved
+ *   25 |     Start index of RFD-ring     25-+
+ *   26 |         (31:20)                 26 |     RSS Q-num (27:25)
+ *   27 |                                 27-+
+ *   28 |                                 28-+
+ *   29 |                                 29 |     RSS Hash algorithm
+ *   30 |                                 30 |      (31:28)
+ *   31-+                                 31-+
+ *
+ * Word 3 depiction:
+ *
+ *   0--+
+ *   1  |
+ *   2  |
+ *   3  |
+ *   4  |
+ *   5  |
+ *   6  |
+ *   7  |    Packet length (include FCS)
+ *   8  |         (13:0)
+ *   9  |
+ *   10 |
+ *   11 |
+ *   12 |
+ *   13-+
+ *   14      L4 Header checksum error
+ *   15      IPv4 checksum error
+ *   16      VLAN tagged
+ *   17-+
+ *   18 |    Protocol ID (19:17)
+ *   19-+
+ *   20      Receive error summary
+ *   21      FCS(CRC) error
+ *   22      Frame alignment error
+ *   23      Truncated packet
+ *   24      Runt packet
+ *   25      Incomplete packet due to insufficient rx-desc
+ *   26      Broadcast packet
+ *   27      Multicast packet
+ *   28      Ethernet type (EII or 802.3)
+ *   29      FIFO overflow
+ *   30      Length error (for 802.3, length field mismatch with actual len)
+ *   31      Updated, indicate to driver that this RRD is refreshed.
+ */
+struct alx_rrd {
+       __le32 word0;
+       __le32 rss_hash;
+       __le32 word2;
+       __le32 word3;
+} __packed;
+
+/* rrd word 0 */
+#define RRD_XSUM_MASK          0xFFFF
+#define RRD_XSUM_SHIFT         0
+#define RRD_NOR_MASK           0x000F
+#define RRD_NOR_SHIFT          16
+#define RRD_SI_MASK            0x0FFF
+#define RRD_SI_SHIFT           20
+
+/* rrd word 2 */
+#define RRD_VLTAG_MASK         0xFFFF
+#define RRD_VLTAG_SHIFT                0
+#define RRD_PID_MASK           0x00FF
+#define RRD_PID_SHIFT          16
+/* non-ip packet */
+#define RRD_PID_NONIP          0
+/* ipv4(only) */
+#define RRD_PID_IPV4           1
+/* tcp/ipv6 */
+#define RRD_PID_IPV6TCP                2
+/* tcp/ipv4 */
+#define RRD_PID_IPV4TCP                3
+/* udp/ipv6 */
+#define RRD_PID_IPV6UDP                4
+/* udp/ipv4 */
+#define RRD_PID_IPV4UDP                5
+/* ipv6(only) */
+#define RRD_PID_IPV6           6
+/* LLDP packet */
+#define RRD_PID_LLDP           7
+/* 1588 packet */
+#define RRD_PID_1588           8
+#define RRD_RSSQ_MASK          0x0007
+#define RRD_RSSQ_SHIFT         25
+#define RRD_RSSALG_MASK                0x000F
+#define RRD_RSSALG_SHIFT       28
+#define RRD_RSSALG_TCPV6       0x1
+#define RRD_RSSALG_IPV6                0x2
+#define RRD_RSSALG_TCPV4       0x4
+#define RRD_RSSALG_IPV4                0x8
+
+/* rrd word 3 */
+#define RRD_PKTLEN_MASK                0x3FFF
+#define RRD_PKTLEN_SHIFT       0
+#define RRD_ERR_L4_MASK                0x0001
+#define RRD_ERR_L4_SHIFT       14
+#define RRD_ERR_IPV4_MASK      0x0001
+#define RRD_ERR_IPV4_SHIFT     15
+#define RRD_VLTAGGED_MASK      0x0001
+#define RRD_VLTAGGED_SHIFT     16
+#define RRD_OLD_PID_MASK       0x0007
+#define RRD_OLD_PID_SHIFT      17
+#define RRD_ERR_RES_MASK       0x0001
+#define RRD_ERR_RES_SHIFT      20
+#define RRD_ERR_FCS_MASK       0x0001
+#define RRD_ERR_FCS_SHIFT      21
+#define RRD_ERR_FAE_MASK       0x0001
+#define RRD_ERR_FAE_SHIFT      22
+#define RRD_ERR_TRUNC_MASK     0x0001
+#define RRD_ERR_TRUNC_SHIFT    23
+#define RRD_ERR_RUNT_MASK      0x0001
+#define RRD_ERR_RUNT_SHIFT     24
+#define RRD_ERR_ICMP_MASK      0x0001
+#define RRD_ERR_ICMP_SHIFT     25
+#define RRD_BCAST_MASK         0x0001
+#define RRD_BCAST_SHIFT                26
+#define RRD_MCAST_MASK         0x0001
+#define RRD_MCAST_SHIFT                27
+#define RRD_ETHTYPE_MASK       0x0001
+#define RRD_ETHTYPE_SHIFT      28
+#define RRD_ERR_FIFOV_MASK     0x0001
+#define RRD_ERR_FIFOV_SHIFT    29
+#define RRD_ERR_LEN_MASK       0x0001
+#define RRD_ERR_LEN_SHIFT      30
+#define RRD_UPDATED_MASK       0x0001
+#define RRD_UPDATED_SHIFT      31
+
+
+#define ALX_MAX_SETUP_LNK_CYCLE        50
+
+/* for FlowControl */
+#define ALX_FC_RX              0x01
+#define ALX_FC_TX              0x02
+#define ALX_FC_ANEG            0x04
+
+/* for sleep control */
+#define ALX_SLEEP_WOL_PHY      0x00000001
+#define ALX_SLEEP_WOL_MAGIC    0x00000002
+#define ALX_SLEEP_CIFS         0x00000004
+#define ALX_SLEEP_ACTIVE       (ALX_SLEEP_WOL_PHY | \
+                                ALX_SLEEP_WOL_MAGIC | \
+                                ALX_SLEEP_CIFS)
+
+/* for RSS hash type */
+#define ALX_RSS_HASH_TYPE_IPV4         0x1
+#define ALX_RSS_HASH_TYPE_IPV4_TCP     0x2
+#define ALX_RSS_HASH_TYPE_IPV6         0x4
+#define ALX_RSS_HASH_TYPE_IPV6_TCP     0x8
+#define ALX_RSS_HASH_TYPE_ALL          (ALX_RSS_HASH_TYPE_IPV4 | \
+                                        ALX_RSS_HASH_TYPE_IPV4_TCP | \
+                                        ALX_RSS_HASH_TYPE_IPV6 | \
+                                        ALX_RSS_HASH_TYPE_IPV6_TCP)
+#define ALX_DEF_RXBUF_SIZE     1536
+#define ALX_MAX_JUMBO_PKT_SIZE (9*1024)
+#define ALX_MAX_TSO_PKT_SIZE   (7*1024)
+#define ALX_MAX_FRAME_SIZE     ALX_MAX_JUMBO_PKT_SIZE
+#define ALX_MIN_FRAME_SIZE     68
+#define ALX_RAW_MTU(_mtu)      (_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN)
+
+#define ALX_MAX_RX_QUEUES      8
+#define ALX_MAX_TX_QUEUES      4
+#define ALX_MAX_HANDLED_INTRS  5
+
+#define ALX_ISR_MISC           (ALX_ISR_PCIE_LNKDOWN | \
+                                ALX_ISR_DMAW | \
+                                ALX_ISR_DMAR | \
+                                ALX_ISR_SMB | \
+                                ALX_ISR_MANU | \
+                                ALX_ISR_TIMER)
+
+#define ALX_ISR_FATAL          (ALX_ISR_PCIE_LNKDOWN | \
+                                ALX_ISR_DMAW | ALX_ISR_DMAR)
+
+#define ALX_ISR_ALERT          (ALX_ISR_RXF_OV | \
+                                ALX_ISR_TXF_UR | \
+                                ALX_ISR_RFD_UR)
+
+#define ALX_ISR_ALL_QUEUES     (ALX_ISR_TX_Q0 | \
+                                ALX_ISR_TX_Q1 | \
+                                ALX_ISR_TX_Q2 | \
+                                ALX_ISR_TX_Q3 | \
+                                ALX_ISR_RX_Q0 | \
+                                ALX_ISR_RX_Q1 | \
+                                ALX_ISR_RX_Q2 | \
+                                ALX_ISR_RX_Q3 | \
+                                ALX_ISR_RX_Q4 | \
+                                ALX_ISR_RX_Q5 | \
+                                ALX_ISR_RX_Q6 | \
+                                ALX_ISR_RX_Q7)
+
+/* maximum interrupt vectors for msix */
+#define ALX_MAX_MSIX_INTRS     16
+
+#define ALX_GET_FIELD(_data, _field)                                   \
+       (((_data) >> _field ## _SHIFT) & _field ## _MASK)
+
+#define ALX_SET_FIELD(_data, _field, _value)   do {                    \
+               (_data) &= ~(_field ## _MASK << _field ## _SHIFT);      \
+               (_data) |= ((_value) & _field ## _MASK) << _field ## _SHIFT;\
+       } while (0)
+
+struct alx_hw {
+       struct pci_dev *pdev;
+       u8 __iomem *hw_addr;
+
+       /* current & permanent mac addr */
+       u8 mac_addr[ETH_ALEN];
+       u8 perm_addr[ETH_ALEN];
+
+       u16 mtu;
+       u16 imt;
+       u8 dma_chnl;
+       u8 max_dma_chnl;
+       /* tpd threshold to trig INT */
+       u32 ith_tpd;
+       u32 rx_ctrl;
+       u32 mc_hash[2];
+
+       u32 smb_timer;
+       /* SPEED_* + DUPLEX_*, SPEED_UNKNOWN if link is down */
+       int link_speed;
+
+       /* auto-neg advertisement or force mode config */
+       u32 adv_cfg;
+       u8 flowctrl;
+
+       u32 sleep_ctrl;
+
+       spinlock_t mdio_lock;
+       struct mdio_if_info mdio;
+       u16 phy_id[2];
+
+       /* PHY link patch flag */
+       bool lnk_patch;
+};
+
+static inline int alx_hw_revision(struct alx_hw *hw)
+{
+       return hw->pdev->revision >> ALX_PCI_REVID_SHIFT;
+}
+
+static inline bool alx_hw_with_cr(struct alx_hw *hw)
+{
+       return hw->pdev->revision & 1;
+}
+
+static inline bool alx_hw_giga(struct alx_hw *hw)
+{
+       return hw->pdev->device & 1;
+}
+
+static inline void alx_write_mem8(struct alx_hw *hw, u32 reg, u8 val)
+{
+       writeb(val, hw->hw_addr + reg);
+}
+
+static inline void alx_write_mem16(struct alx_hw *hw, u32 reg, u16 val)
+{
+       writew(val, hw->hw_addr + reg);
+}
+
+static inline u16 alx_read_mem16(struct alx_hw *hw, u32 reg)
+{
+       return readw(hw->hw_addr + reg);
+}
+
+static inline void alx_write_mem32(struct alx_hw *hw, u32 reg, u32 val)
+{
+       writel(val, hw->hw_addr + reg);
+}
+
+static inline u32 alx_read_mem32(struct alx_hw *hw, u32 reg)
+{
+       return readl(hw->hw_addr + reg);
+}
+
+static inline void alx_post_write(struct alx_hw *hw)
+{
+       readl(hw->hw_addr);
+}
+
+int alx_get_perm_macaddr(struct alx_hw *hw, u8 *addr);
+void alx_reset_phy(struct alx_hw *hw);
+void alx_reset_pcie(struct alx_hw *hw);
+void alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en);
+int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl);
+void alx_post_phy_link(struct alx_hw *hw);
+int alx_pre_suspend(struct alx_hw *hw, int speed);
+int alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data);
+int alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data);
+int alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata);
+int alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data);
+int alx_get_phy_link(struct alx_hw *hw, int *speed);
+int alx_clear_phy_intr(struct alx_hw *hw);
+int alx_config_wol(struct alx_hw *hw);
+void alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc);
+void alx_start_mac(struct alx_hw *hw);
+int alx_reset_mac(struct alx_hw *hw);
+void alx_set_macaddr(struct alx_hw *hw, const u8 *addr);
+bool alx_phy_configured(struct alx_hw *hw);
+void alx_configure_basic(struct alx_hw *hw);
+void alx_disable_rss(struct alx_hw *hw);
+int alx_select_powersaving_speed(struct alx_hw *hw, int *speed);
+bool alx_get_phy_info(struct alx_hw *hw);
+
+#endif
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
new file mode 100644 (file)
index 0000000..418de8b
--- /dev/null
@@ -0,0 +1,1625 @@
+/*
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/if_vlan.h>
+#include <linux/mdio.h>
+#include <linux/aer.h>
+#include <linux/bitops.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <net/ip6_checksum.h>
+#include <linux/crc32.h>
+#include "alx.h"
+#include "hw.h"
+#include "reg.h"
+
+const char alx_drv_name[] = "alx";
+
+
+static void alx_free_txbuf(struct alx_priv *alx, int entry)
+{
+       struct alx_buffer *txb = &alx->txq.bufs[entry];
+
+       if (dma_unmap_len(txb, size)) {
+               dma_unmap_single(&alx->hw.pdev->dev,
+                                dma_unmap_addr(txb, dma),
+                                dma_unmap_len(txb, size),
+                                DMA_TO_DEVICE);
+               dma_unmap_len_set(txb, size, 0);
+       }
+
+       if (txb->skb) {
+               dev_kfree_skb_any(txb->skb);
+               txb->skb = NULL;
+       }
+}
+
+static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp)
+{
+       struct alx_rx_queue *rxq = &alx->rxq;
+       struct sk_buff *skb;
+       struct alx_buffer *cur_buf;
+       dma_addr_t dma;
+       u16 cur, next, count = 0;
+
+       next = cur = rxq->write_idx;
+       if (++next == alx->rx_ringsz)
+               next = 0;
+       cur_buf = &rxq->bufs[cur];
+
+       while (!cur_buf->skb && next != rxq->read_idx) {
+               struct alx_rfd *rfd = &rxq->rfd[cur];
+
+               skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size, gfp);
+               if (!skb)
+                       break;
+               dma = dma_map_single(&alx->hw.pdev->dev,
+                                    skb->data, alx->rxbuf_size,
+                                    DMA_FROM_DEVICE);
+               if (dma_mapping_error(&alx->hw.pdev->dev, dma)) {
+                       dev_kfree_skb(skb);
+                       break;
+               }
+
+               /* Unfortunately, RX descriptor buffers must be 4-byte
+                * aligned, so we can't use IP alignment.
+                */
+               if (WARN_ON(dma & 3)) {
+                       dev_kfree_skb(skb);
+                       break;
+               }
+
+               cur_buf->skb = skb;
+               dma_unmap_len_set(cur_buf, size, alx->rxbuf_size);
+               dma_unmap_addr_set(cur_buf, dma, dma);
+               rfd->addr = cpu_to_le64(dma);
+
+               cur = next;
+               if (++next == alx->rx_ringsz)
+                       next = 0;
+               cur_buf = &rxq->bufs[cur];
+               count++;
+       }
+
+       if (count) {
+               /* flush all updates before updating hardware */
+               wmb();
+               rxq->write_idx = cur;
+               alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur);
+       }
+
+       return count;
+}
+
+static inline int alx_tpd_avail(struct alx_priv *alx)
+{
+       struct alx_tx_queue *txq = &alx->txq;
+
+       if (txq->write_idx >= txq->read_idx)
+               return alx->tx_ringsz + txq->read_idx - txq->write_idx - 1;
+       return txq->read_idx - txq->write_idx - 1;
+}
+
+static bool alx_clean_tx_irq(struct alx_priv *alx)
+{
+       struct alx_tx_queue *txq = &alx->txq;
+       u16 hw_read_idx, sw_read_idx;
+       unsigned int total_bytes = 0, total_packets = 0;
+       int budget = ALX_DEFAULT_TX_WORK;
+
+       sw_read_idx = txq->read_idx;
+       hw_read_idx = alx_read_mem16(&alx->hw, ALX_TPD_PRI0_CIDX);
+
+       if (sw_read_idx != hw_read_idx) {
+               while (sw_read_idx != hw_read_idx && budget > 0) {
+                       struct sk_buff *skb;
+
+                       skb = txq->bufs[sw_read_idx].skb;
+                       if (skb) {
+                               total_bytes += skb->len;
+                               total_packets++;
+                               budget--;
+                       }
+
+                       alx_free_txbuf(alx, sw_read_idx);
+
+                       if (++sw_read_idx == alx->tx_ringsz)
+                               sw_read_idx = 0;
+               }
+               txq->read_idx = sw_read_idx;
+
+               netdev_completed_queue(alx->dev, total_packets, total_bytes);
+       }
+
+       if (netif_queue_stopped(alx->dev) && netif_carrier_ok(alx->dev) &&
+           alx_tpd_avail(alx) > alx->tx_ringsz/4)
+               netif_wake_queue(alx->dev);
+
+       return sw_read_idx == hw_read_idx;
+}
+
+static void alx_schedule_link_check(struct alx_priv *alx)
+{
+       schedule_work(&alx->link_check_wk);
+}
+
+static void alx_schedule_reset(struct alx_priv *alx)
+{
+       schedule_work(&alx->reset_wk);
+}
+
+static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
+{
+       struct alx_rx_queue *rxq = &alx->rxq;
+       struct alx_rrd *rrd;
+       struct alx_buffer *rxb;
+       struct sk_buff *skb;
+       u16 length, rfd_cleaned = 0;
+
+       while (budget > 0) {
+               rrd = &rxq->rrd[rxq->rrd_read_idx];
+               if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT)))
+                       break;
+               rrd->word3 &= ~cpu_to_le32(1 << RRD_UPDATED_SHIFT);
+
+               if (ALX_GET_FIELD(le32_to_cpu(rrd->word0),
+                                 RRD_SI) != rxq->read_idx ||
+                   ALX_GET_FIELD(le32_to_cpu(rrd->word0),
+                                 RRD_NOR) != 1) {
+                       alx_schedule_reset(alx);
+                       return 0;
+               }
+
+               rxb = &rxq->bufs[rxq->read_idx];
+               dma_unmap_single(&alx->hw.pdev->dev,
+                                dma_unmap_addr(rxb, dma),
+                                dma_unmap_len(rxb, size),
+                                DMA_FROM_DEVICE);
+               dma_unmap_len_set(rxb, size, 0);
+               skb = rxb->skb;
+               rxb->skb = NULL;
+
+               if (rrd->word3 & cpu_to_le32(1 << RRD_ERR_RES_SHIFT) ||
+                   rrd->word3 & cpu_to_le32(1 << RRD_ERR_LEN_SHIFT)) {
+                       rrd->word3 = 0;
+                       dev_kfree_skb_any(skb);
+                       goto next_pkt;
+               }
+
+               length = ALX_GET_FIELD(le32_to_cpu(rrd->word3),
+                                      RRD_PKTLEN) - ETH_FCS_LEN;
+               skb_put(skb, length);
+               skb->protocol = eth_type_trans(skb, alx->dev);
+
+               skb_checksum_none_assert(skb);
+               if (alx->dev->features & NETIF_F_RXCSUM &&
+                   !(rrd->word3 & (cpu_to_le32(1 << RRD_ERR_L4_SHIFT) |
+                                   cpu_to_le32(1 << RRD_ERR_IPV4_SHIFT)))) {
+                       switch (ALX_GET_FIELD(le32_to_cpu(rrd->word2),
+                                             RRD_PID)) {
+                       case RRD_PID_IPV6UDP:
+                       case RRD_PID_IPV4UDP:
+                       case RRD_PID_IPV4TCP:
+                       case RRD_PID_IPV6TCP:
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               break;
+                       }
+               }
+
+               napi_gro_receive(&alx->napi, skb);
+               budget--;
+
+next_pkt:
+               if (++rxq->read_idx == alx->rx_ringsz)
+                       rxq->read_idx = 0;
+               if (++rxq->rrd_read_idx == alx->rx_ringsz)
+                       rxq->rrd_read_idx = 0;
+
+               if (++rfd_cleaned > ALX_RX_ALLOC_THRESH)
+                       rfd_cleaned -= alx_refill_rx_ring(alx, GFP_ATOMIC);
+       }
+
+       if (rfd_cleaned)
+               alx_refill_rx_ring(alx, GFP_ATOMIC);
+
+       return budget > 0;
+}
+
+static int alx_poll(struct napi_struct *napi, int budget)
+{
+       struct alx_priv *alx = container_of(napi, struct alx_priv, napi);
+       struct alx_hw *hw = &alx->hw;
+       bool complete = true;
+       unsigned long flags;
+
+       complete = alx_clean_tx_irq(alx) &&
+                  alx_clean_rx_irq(alx, budget);
+
+       if (!complete)
+               return 1;
+
+       napi_complete(&alx->napi);
+
+       /* enable interrupt */
+       spin_lock_irqsave(&alx->irq_lock, flags);
+       alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
+       alx_write_mem32(hw, ALX_IMR, alx->int_mask);
+       spin_unlock_irqrestore(&alx->irq_lock, flags);
+
+       alx_post_write(hw);
+
+       return 0;
+}
+
+static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
+{
+       struct alx_hw *hw = &alx->hw;
+       bool write_int_mask = false;
+
+       spin_lock(&alx->irq_lock);
+
+       /* ACK interrupt */
+       alx_write_mem32(hw, ALX_ISR, intr | ALX_ISR_DIS);
+       intr &= alx->int_mask;
+
+       if (intr & ALX_ISR_FATAL) {
+               netif_warn(alx, hw, alx->dev,
+                          "fatal interrupt 0x%x, resetting\n", intr);
+               alx_schedule_reset(alx);
+               goto out;
+       }
+
+       if (intr & ALX_ISR_ALERT)
+               netdev_warn(alx->dev, "alert interrupt: 0x%x\n", intr);
+
+       if (intr & ALX_ISR_PHY) {
+               /* suppress PHY interrupt, because the source
+                * is from PHY internal. only the internal status
+                * is cleared, the interrupt status could be cleared.
+                */
+               alx->int_mask &= ~ALX_ISR_PHY;
+               write_int_mask = true;
+               alx_schedule_link_check(alx);
+       }
+
+       if (intr & (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0)) {
+               napi_schedule(&alx->napi);
+               /* mask rx/tx interrupt, enable them when napi complete */
+               alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
+               write_int_mask = true;
+       }
+
+       if (write_int_mask)
+               alx_write_mem32(hw, ALX_IMR, alx->int_mask);
+
+       alx_write_mem32(hw, ALX_ISR, 0);
+
+ out:
+       spin_unlock(&alx->irq_lock);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t alx_intr_msi(int irq, void *data)
+{
+       struct alx_priv *alx = data;
+
+       return alx_intr_handle(alx, alx_read_mem32(&alx->hw, ALX_ISR));
+}
+
+static irqreturn_t alx_intr_legacy(int irq, void *data)
+{
+       struct alx_priv *alx = data;
+       struct alx_hw *hw = &alx->hw;
+       u32 intr;
+
+       intr = alx_read_mem32(hw, ALX_ISR);
+
+       if (intr & ALX_ISR_DIS || !(intr & alx->int_mask))
+               return IRQ_NONE;
+
+       return alx_intr_handle(alx, intr);
+}
+
+static void alx_init_ring_ptrs(struct alx_priv *alx)
+{
+       struct alx_hw *hw = &alx->hw;
+       u32 addr_hi = ((u64)alx->descmem.dma) >> 32;
+
+       alx->rxq.read_idx = 0;
+       alx->rxq.write_idx = 0;
+       alx->rxq.rrd_read_idx = 0;
+       alx_write_mem32(hw, ALX_RX_BASE_ADDR_HI, addr_hi);
+       alx_write_mem32(hw, ALX_RRD_ADDR_LO, alx->rxq.rrd_dma);
+       alx_write_mem32(hw, ALX_RRD_RING_SZ, alx->rx_ringsz);
+       alx_write_mem32(hw, ALX_RFD_ADDR_LO, alx->rxq.rfd_dma);
+       alx_write_mem32(hw, ALX_RFD_RING_SZ, alx->rx_ringsz);
+       alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size);
+
+       alx->txq.read_idx = 0;
+       alx->txq.write_idx = 0;
+       alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi);
+       alx_write_mem32(hw, ALX_TPD_PRI0_ADDR_LO, alx->txq.tpd_dma);
+       alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz);
+
+       /* load these pointers into the chip */
+       alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR);
+}
+
+static void alx_free_txring_buf(struct alx_priv *alx)
+{
+       struct alx_tx_queue *txq = &alx->txq;
+       int i;
+
+       if (!txq->bufs)
+               return;
+
+       for (i = 0; i < alx->tx_ringsz; i++)
+               alx_free_txbuf(alx, i);
+
+       memset(txq->bufs, 0, alx->tx_ringsz * sizeof(struct alx_buffer));
+       memset(txq->tpd, 0, alx->tx_ringsz * sizeof(struct alx_txd));
+       txq->write_idx = 0;
+       txq->read_idx = 0;
+
+       netdev_reset_queue(alx->dev);
+}
+
+static void alx_free_rxring_buf(struct alx_priv *alx)
+{
+       struct alx_rx_queue *rxq = &alx->rxq;
+       struct alx_buffer *cur_buf;
+       u16 i;
+
+       if (rxq == NULL)
+               return;
+
+       for (i = 0; i < alx->rx_ringsz; i++) {
+               cur_buf = rxq->bufs + i;
+               if (cur_buf->skb) {
+                       dma_unmap_single(&alx->hw.pdev->dev,
+                                        dma_unmap_addr(cur_buf, dma),
+                                        dma_unmap_len(cur_buf, size),
+                                        DMA_FROM_DEVICE);
+                       dev_kfree_skb(cur_buf->skb);
+                       cur_buf->skb = NULL;
+                       dma_unmap_len_set(cur_buf, size, 0);
+                       dma_unmap_addr_set(cur_buf, dma, 0);
+               }
+       }
+
+       rxq->write_idx = 0;
+       rxq->read_idx = 0;
+       rxq->rrd_read_idx = 0;
+}
+
+static void alx_free_buffers(struct alx_priv *alx)
+{
+       alx_free_txring_buf(alx);
+       alx_free_rxring_buf(alx);
+}
+
+static int alx_reinit_rings(struct alx_priv *alx)
+{
+       alx_free_buffers(alx);
+
+       alx_init_ring_ptrs(alx);
+
+       if (!alx_refill_rx_ring(alx, GFP_KERNEL))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void alx_add_mc_addr(struct alx_hw *hw, const u8 *addr, u32 *mc_hash)
+{
+       u32 crc32, bit, reg;
+
+       crc32 = ether_crc(ETH_ALEN, addr);
+       reg = (crc32 >> 31) & 0x1;
+       bit = (crc32 >> 26) & 0x1F;
+
+       mc_hash[reg] |= BIT(bit);
+}
+
+static void __alx_set_rx_mode(struct net_device *netdev)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+       struct netdev_hw_addr *ha;
+       u32 mc_hash[2] = {};
+
+       if (!(netdev->flags & IFF_ALLMULTI)) {
+               netdev_for_each_mc_addr(ha, netdev)
+                       alx_add_mc_addr(hw, ha->addr, mc_hash);
+
+               alx_write_mem32(hw, ALX_HASH_TBL0, mc_hash[0]);
+               alx_write_mem32(hw, ALX_HASH_TBL1, mc_hash[1]);
+       }
+
+       hw->rx_ctrl &= ~(ALX_MAC_CTRL_MULTIALL_EN | ALX_MAC_CTRL_PROMISC_EN);
+       if (netdev->flags & IFF_PROMISC)
+               hw->rx_ctrl |= ALX_MAC_CTRL_PROMISC_EN;
+       if (netdev->flags & IFF_ALLMULTI)
+               hw->rx_ctrl |= ALX_MAC_CTRL_MULTIALL_EN;
+
+       alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+}
+
+static void alx_set_rx_mode(struct net_device *netdev)
+{
+       __alx_set_rx_mode(netdev);
+}
+
+static int alx_set_mac_address(struct net_device *netdev, void *data)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+       struct sockaddr *addr = data;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       if (netdev->addr_assign_type & NET_ADDR_RANDOM)
+               netdev->addr_assign_type ^= NET_ADDR_RANDOM;
+
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+       memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len);
+       alx_set_macaddr(hw, hw->mac_addr);
+
+       return 0;
+}
+
+static int alx_alloc_descriptors(struct alx_priv *alx)
+{
+       alx->txq.bufs = kcalloc(alx->tx_ringsz,
+                               sizeof(struct alx_buffer),
+                               GFP_KERNEL);
+       if (!alx->txq.bufs)
+               return -ENOMEM;
+
+       alx->rxq.bufs = kcalloc(alx->rx_ringsz,
+                               sizeof(struct alx_buffer),
+                               GFP_KERNEL);
+       if (!alx->rxq.bufs)
+               goto out_free;
+
+       /* physical tx/rx ring descriptors
+        *
+        * Allocate them as a single chunk because they must not cross a
+        * 4G boundary (hardware has a single register for high 32 bits
+        * of addresses only)
+        */
+       alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz +
+                           sizeof(struct alx_rrd) * alx->rx_ringsz +
+                           sizeof(struct alx_rfd) * alx->rx_ringsz;
+       alx->descmem.virt = dma_zalloc_coherent(&alx->hw.pdev->dev,
+                                               alx->descmem.size,
+                                               &alx->descmem.dma,
+                                               GFP_KERNEL);
+       if (!alx->descmem.virt)
+               goto out_free;
+
+       alx->txq.tpd = (void *)alx->descmem.virt;
+       alx->txq.tpd_dma = alx->descmem.dma;
+
+       /* alignment requirement for next block */
+       BUILD_BUG_ON(sizeof(struct alx_txd) % 8);
+
+       alx->rxq.rrd =
+               (void *)((u8 *)alx->descmem.virt +
+                        sizeof(struct alx_txd) * alx->tx_ringsz);
+       alx->rxq.rrd_dma = alx->descmem.dma +
+                          sizeof(struct alx_txd) * alx->tx_ringsz;
+
+       /* alignment requirement for next block */
+       BUILD_BUG_ON(sizeof(struct alx_rrd) % 8);
+
+       alx->rxq.rfd =
+               (void *)((u8 *)alx->descmem.virt +
+                        sizeof(struct alx_txd) * alx->tx_ringsz +
+                        sizeof(struct alx_rrd) * alx->rx_ringsz);
+       alx->rxq.rfd_dma = alx->descmem.dma +
+                          sizeof(struct alx_txd) * alx->tx_ringsz +
+                          sizeof(struct alx_rrd) * alx->rx_ringsz;
+
+       return 0;
+out_free:
+       kfree(alx->txq.bufs);
+       kfree(alx->rxq.bufs);
+       return -ENOMEM;
+}
+
+static int alx_alloc_rings(struct alx_priv *alx)
+{
+       int err;
+
+       err = alx_alloc_descriptors(alx);
+       if (err)
+               return err;
+
+       alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
+       alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
+       alx->tx_ringsz = alx->tx_ringsz;
+
+       netif_napi_add(alx->dev, &alx->napi, alx_poll, 64);
+
+       alx_reinit_rings(alx);
+       return 0;
+}
+
+static void alx_free_rings(struct alx_priv *alx)
+{
+       netif_napi_del(&alx->napi);
+       alx_free_buffers(alx);
+
+       kfree(alx->txq.bufs);
+       kfree(alx->rxq.bufs);
+
+       dma_free_coherent(&alx->hw.pdev->dev,
+                         alx->descmem.size,
+                         alx->descmem.virt,
+                         alx->descmem.dma);
+}
+
+static void alx_config_vector_mapping(struct alx_priv *alx)
+{
+       struct alx_hw *hw = &alx->hw;
+
+       alx_write_mem32(hw, ALX_MSI_MAP_TBL1, 0);
+       alx_write_mem32(hw, ALX_MSI_MAP_TBL2, 0);
+       alx_write_mem32(hw, ALX_MSI_ID_MAP, 0);
+}
+
+static void alx_irq_enable(struct alx_priv *alx)
+{
+       struct alx_hw *hw = &alx->hw;
+
+       /* level-1 interrupt switch */
+       alx_write_mem32(hw, ALX_ISR, 0);
+       alx_write_mem32(hw, ALX_IMR, alx->int_mask);
+       alx_post_write(hw);
+}
+
+static void alx_irq_disable(struct alx_priv *alx)
+{
+       struct alx_hw *hw = &alx->hw;
+
+       alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS);
+       alx_write_mem32(hw, ALX_IMR, 0);
+       alx_post_write(hw);
+
+       synchronize_irq(alx->hw.pdev->irq);
+}
+
+static int alx_request_irq(struct alx_priv *alx)
+{
+       struct pci_dev *pdev = alx->hw.pdev;
+       struct alx_hw *hw = &alx->hw;
+       int err;
+       u32 msi_ctrl;
+
+       msi_ctrl = (hw->imt >> 1) << ALX_MSI_RETRANS_TM_SHIFT;
+
+       if (!pci_enable_msi(alx->hw.pdev)) {
+               alx->msi = true;
+
+               alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER,
+                               msi_ctrl | ALX_MSI_MASK_SEL_LINE);
+               err = request_irq(pdev->irq, alx_intr_msi, 0,
+                                 alx->dev->name, alx);
+               if (!err)
+                       goto out;
+               /* fall back to legacy interrupt */
+               pci_disable_msi(alx->hw.pdev);
+       }
+
+       alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, 0);
+       err = request_irq(pdev->irq, alx_intr_legacy, IRQF_SHARED,
+                         alx->dev->name, alx);
+out:
+       if (!err)
+               alx_config_vector_mapping(alx);
+       return err;
+}
+
+static void alx_free_irq(struct alx_priv *alx)
+{
+       struct pci_dev *pdev = alx->hw.pdev;
+
+       free_irq(pdev->irq, alx);
+
+       if (alx->msi) {
+               pci_disable_msi(alx->hw.pdev);
+               alx->msi = false;
+       }
+}
+
+static int alx_identify_hw(struct alx_priv *alx)
+{
+       struct alx_hw *hw = &alx->hw;
+       int rev = alx_hw_revision(hw);
+
+       if (rev > ALX_REV_C0)
+               return -EINVAL;
+
+       hw->max_dma_chnl = rev >= ALX_REV_B0 ? 4 : 2;
+
+       return 0;
+}
+
+static int alx_init_sw(struct alx_priv *alx)
+{
+       struct pci_dev *pdev = alx->hw.pdev;
+       struct alx_hw *hw = &alx->hw;
+       int err;
+
+       err = alx_identify_hw(alx);
+       if (err) {
+               dev_err(&pdev->dev, "unrecognized chip, aborting\n");
+               return err;
+       }
+
+       alx->hw.lnk_patch =
+               pdev->device == ALX_DEV_ID_AR8161 &&
+               pdev->subsystem_vendor == PCI_VENDOR_ID_ATTANSIC &&
+               pdev->subsystem_device == 0x0091 &&
+               pdev->revision == 0;
+
+       hw->smb_timer = 400;
+       hw->mtu = alx->dev->mtu;
+       alx->rxbuf_size = ALIGN(ALX_RAW_MTU(hw->mtu), 8);
+       alx->tx_ringsz = 256;
+       alx->rx_ringsz = 512;
+       hw->sleep_ctrl = ALX_SLEEP_WOL_MAGIC | ALX_SLEEP_WOL_PHY;
+       hw->imt = 200;
+       alx->int_mask = ALX_ISR_MISC;
+       hw->dma_chnl = hw->max_dma_chnl;
+       hw->ith_tpd = alx->tx_ringsz / 3;
+       hw->link_speed = SPEED_UNKNOWN;
+       hw->adv_cfg = ADVERTISED_Autoneg |
+                     ADVERTISED_10baseT_Half |
+                     ADVERTISED_10baseT_Full |
+                     ADVERTISED_100baseT_Full |
+                     ADVERTISED_100baseT_Half |
+                     ADVERTISED_1000baseT_Full;
+       hw->flowctrl = ALX_FC_ANEG | ALX_FC_RX | ALX_FC_TX;
+
+       hw->rx_ctrl = ALX_MAC_CTRL_WOLSPED_SWEN |
+                     ALX_MAC_CTRL_MHASH_ALG_HI5B |
+                     ALX_MAC_CTRL_BRD_EN |
+                     ALX_MAC_CTRL_PCRCE |
+                     ALX_MAC_CTRL_CRCE |
+                     ALX_MAC_CTRL_RXFC_EN |
+                     ALX_MAC_CTRL_TXFC_EN |
+                     7 << ALX_MAC_CTRL_PRMBLEN_SHIFT;
+
+       return err;
+}
+
+
+static netdev_features_t alx_fix_features(struct net_device *netdev,
+                                         netdev_features_t features)
+{
+       if (netdev->mtu > ALX_MAX_TSO_PKT_SIZE)
+               features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+
+       return features;
+}
+
+static void alx_netif_stop(struct alx_priv *alx)
+{
+       alx->dev->trans_start = jiffies;
+       if (netif_carrier_ok(alx->dev)) {
+               netif_carrier_off(alx->dev);
+               netif_tx_disable(alx->dev);
+               napi_disable(&alx->napi);
+       }
+}
+
+static void alx_halt(struct alx_priv *alx)
+{
+       struct alx_hw *hw = &alx->hw;
+
+       alx_netif_stop(alx);
+       hw->link_speed = SPEED_UNKNOWN;
+
+       alx_reset_mac(hw);
+
+       /* disable l0s/l1 */
+       alx_enable_aspm(hw, false, false);
+       alx_irq_disable(alx);
+       alx_free_buffers(alx);
+}
+
+static void alx_configure(struct alx_priv *alx)
+{
+       struct alx_hw *hw = &alx->hw;
+
+       alx_configure_basic(hw);
+       alx_disable_rss(hw);
+       __alx_set_rx_mode(alx->dev);
+
+       alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+}
+
+static void alx_activate(struct alx_priv *alx)
+{
+       /* hardware setting lost, restore it */
+       alx_reinit_rings(alx);
+       alx_configure(alx);
+
+       /* clear old interrupts */
+       alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS);
+
+       alx_irq_enable(alx);
+
+       alx_schedule_link_check(alx);
+}
+
+static void alx_reinit(struct alx_priv *alx)
+{
+       ASSERT_RTNL();
+
+       alx_halt(alx);
+       alx_activate(alx);
+}
+
+static int alx_change_mtu(struct net_device *netdev, int mtu)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       int max_frame = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+
+       if ((max_frame < ALX_MIN_FRAME_SIZE) ||
+           (max_frame > ALX_MAX_FRAME_SIZE))
+               return -EINVAL;
+
+       if (netdev->mtu == mtu)
+               return 0;
+
+       netdev->mtu = mtu;
+       alx->hw.mtu = mtu;
+       alx->rxbuf_size = mtu > ALX_DEF_RXBUF_SIZE ?
+                          ALIGN(max_frame, 8) : ALX_DEF_RXBUF_SIZE;
+       netdev_update_features(netdev);
+       if (netif_running(netdev))
+               alx_reinit(alx);
+       return 0;
+}
+
+static void alx_netif_start(struct alx_priv *alx)
+{
+       netif_tx_wake_all_queues(alx->dev);
+       napi_enable(&alx->napi);
+       netif_carrier_on(alx->dev);
+}
+
+static int __alx_open(struct alx_priv *alx, bool resume)
+{
+       int err;
+
+       if (!resume)
+               netif_carrier_off(alx->dev);
+
+       err = alx_alloc_rings(alx);
+       if (err)
+               return err;
+
+       alx_configure(alx);
+
+       err = alx_request_irq(alx);
+       if (err)
+               goto out_free_rings;
+
+       /* clear old interrupts */
+       alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS);
+
+       alx_irq_enable(alx);
+
+       if (!resume)
+               netif_tx_start_all_queues(alx->dev);
+
+       alx_schedule_link_check(alx);
+       return 0;
+
+out_free_rings:
+       alx_free_rings(alx);
+       return err;
+}
+
+static void __alx_stop(struct alx_priv *alx)
+{
+       alx_halt(alx);
+       alx_free_irq(alx);
+       alx_free_rings(alx);
+}
+
+static const char *alx_speed_desc(u16 speed)
+{
+       switch (speed) {
+       case SPEED_1000 + DUPLEX_FULL:
+               return "1 Gbps Full";
+       case SPEED_100 + DUPLEX_FULL:
+               return "100 Mbps Full";
+       case SPEED_100 + DUPLEX_HALF:
+               return "100 Mbps Half";
+       case SPEED_10 + DUPLEX_FULL:
+               return "10 Mbps Full";
+       case SPEED_10 + DUPLEX_HALF:
+               return "10 Mbps Half";
+       default:
+               return "Unknown speed";
+       }
+}
+
+static void alx_check_link(struct alx_priv *alx)
+{
+       struct alx_hw *hw = &alx->hw;
+       unsigned long flags;
+       int speed, old_speed;
+       int err;
+
+       /* clear PHY internal interrupt status, otherwise the main
+        * interrupt status will be asserted forever
+        */
+       alx_clear_phy_intr(hw);
+
+       err = alx_get_phy_link(hw, &speed);
+       if (err < 0)
+               goto reset;
+
+       spin_lock_irqsave(&alx->irq_lock, flags);
+       alx->int_mask |= ALX_ISR_PHY;
+       alx_write_mem32(hw, ALX_IMR, alx->int_mask);
+       spin_unlock_irqrestore(&alx->irq_lock, flags);
+
+       old_speed = hw->link_speed;
+
+       if (old_speed == speed)
+               return;
+       hw->link_speed = speed;
+
+       if (speed != SPEED_UNKNOWN) {
+               netif_info(alx, link, alx->dev,
+                          "NIC Up: %s\n", alx_speed_desc(speed));
+               alx_post_phy_link(hw);
+               alx_enable_aspm(hw, true, true);
+               alx_start_mac(hw);
+
+               if (old_speed == SPEED_UNKNOWN)
+                       alx_netif_start(alx);
+       } else {
+               /* link is now down */
+               alx_netif_stop(alx);
+               netif_info(alx, link, alx->dev, "Link Down\n");
+               err = alx_reset_mac(hw);
+               if (err)
+                       goto reset;
+               alx_irq_disable(alx);
+
+               /* MAC reset causes all HW settings to be lost, restore all */
+               err = alx_reinit_rings(alx);
+               if (err)
+                       goto reset;
+               alx_configure(alx);
+               alx_enable_aspm(hw, false, true);
+               alx_post_phy_link(hw);
+               alx_irq_enable(alx);
+       }
+
+       return;
+
+reset:
+       alx_schedule_reset(alx);
+}
+
+static int alx_open(struct net_device *netdev)
+{
+       return __alx_open(netdev_priv(netdev), false);
+}
+
+static int alx_stop(struct net_device *netdev)
+{
+       __alx_stop(netdev_priv(netdev));
+       return 0;
+}
+
+static int __alx_shutdown(struct pci_dev *pdev, bool *wol_en)
+{
+       struct alx_priv *alx = pci_get_drvdata(pdev);
+       struct net_device *netdev = alx->dev;
+       struct alx_hw *hw = &alx->hw;
+       int err, speed;
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev))
+               __alx_stop(alx);
+
+#ifdef CONFIG_PM_SLEEP
+       err = pci_save_state(pdev);
+       if (err)
+               return err;
+#endif
+
+       err = alx_select_powersaving_speed(hw, &speed);
+       if (err)
+               return err;
+       err = alx_clear_phy_intr(hw);
+       if (err)
+               return err;
+       err = alx_pre_suspend(hw, speed);
+       if (err)
+               return err;
+       err = alx_config_wol(hw);
+       if (err)
+               return err;
+
+       *wol_en = false;
+       if (hw->sleep_ctrl & ALX_SLEEP_ACTIVE) {
+               netif_info(alx, wol, netdev,
+                          "wol: ctrl=%X, speed=%X\n",
+                          hw->sleep_ctrl, speed);
+               device_set_wakeup_enable(&pdev->dev, true);
+               *wol_en = true;
+       }
+
+       pci_disable_device(pdev);
+
+       return 0;
+}
+
+static void alx_shutdown(struct pci_dev *pdev)
+{
+       int err;
+       bool wol_en;
+
+       err = __alx_shutdown(pdev, &wol_en);
+       if (!err) {
+               pci_wake_from_d3(pdev, wol_en);
+               pci_set_power_state(pdev, PCI_D3hot);
+       } else {
+               dev_err(&pdev->dev, "shutdown fail %d\n", err);
+       }
+}
+
+static void alx_link_check(struct work_struct *work)
+{
+       struct alx_priv *alx;
+
+       alx = container_of(work, struct alx_priv, link_check_wk);
+
+       rtnl_lock();
+       alx_check_link(alx);
+       rtnl_unlock();
+}
+
+static void alx_reset(struct work_struct *work)
+{
+       struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk);
+
+       rtnl_lock();
+       alx_reinit(alx);
+       rtnl_unlock();
+}
+
+static int alx_tx_csum(struct sk_buff *skb, struct alx_txd *first)
+{
+       u8 cso, css;
+
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
+
+       cso = skb_checksum_start_offset(skb);
+       if (cso & 1)
+               return -EINVAL;
+
+       css = cso + skb->csum_offset;
+       first->word1 |= cpu_to_le32((cso >> 1) << TPD_CXSUMSTART_SHIFT);
+       first->word1 |= cpu_to_le32((css >> 1) << TPD_CXSUMOFFSET_SHIFT);
+       first->word1 |= cpu_to_le32(1 << TPD_CXSUM_EN_SHIFT);
+
+       return 0;
+}
+
+static int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb)
+{
+       struct alx_tx_queue *txq = &alx->txq;
+       struct alx_txd *tpd, *first_tpd;
+       dma_addr_t dma;
+       int maplen, f, first_idx = txq->write_idx;
+
+       first_tpd = &txq->tpd[txq->write_idx];
+       tpd = first_tpd;
+
+       maplen = skb_headlen(skb);
+       dma = dma_map_single(&alx->hw.pdev->dev, skb->data, maplen,
+                            DMA_TO_DEVICE);
+       if (dma_mapping_error(&alx->hw.pdev->dev, dma))
+               goto err_dma;
+
+       dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen);
+       dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma);
+
+       tpd->adrl.addr = cpu_to_le64(dma);
+       tpd->len = cpu_to_le16(maplen);
+
+       for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
+               struct skb_frag_struct *frag;
+
+               frag = &skb_shinfo(skb)->frags[f];
+
+               if (++txq->write_idx == alx->tx_ringsz)
+                       txq->write_idx = 0;
+               tpd = &txq->tpd[txq->write_idx];
+
+               tpd->word1 = first_tpd->word1;
+
+               maplen = skb_frag_size(frag);
+               dma = skb_frag_dma_map(&alx->hw.pdev->dev, frag, 0,
+                                      maplen, DMA_TO_DEVICE);
+               if (dma_mapping_error(&alx->hw.pdev->dev, dma))
+                       goto err_dma;
+               dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen);
+               dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma);
+
+               tpd->adrl.addr = cpu_to_le64(dma);
+               tpd->len = cpu_to_le16(maplen);
+       }
+
+       /* last TPD, set EOP flag and store skb */
+       tpd->word1 |= cpu_to_le32(1 << TPD_EOP_SHIFT);
+       txq->bufs[txq->write_idx].skb = skb;
+
+       if (++txq->write_idx == alx->tx_ringsz)
+               txq->write_idx = 0;
+
+       return 0;
+
+err_dma:
+       f = first_idx;
+       while (f != txq->write_idx) {
+               alx_free_txbuf(alx, f);
+               if (++f == alx->tx_ringsz)
+                       f = 0;
+       }
+       return -ENOMEM;
+}
+
+static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
+                                 struct net_device *netdev)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_tx_queue *txq = &alx->txq;
+       struct alx_txd *first;
+       int tpdreq = skb_shinfo(skb)->nr_frags + 1;
+
+       if (alx_tpd_avail(alx) < tpdreq) {
+               netif_stop_queue(alx->dev);
+               goto drop;
+       }
+
+       first = &txq->tpd[txq->write_idx];
+       memset(first, 0, sizeof(*first));
+
+       if (alx_tx_csum(skb, first))
+               goto drop;
+
+       if (alx_map_tx_skb(alx, skb) < 0)
+               goto drop;
+
+       netdev_sent_queue(alx->dev, skb->len);
+
+       /* flush updates before updating hardware */
+       wmb();
+       alx_write_mem16(&alx->hw, ALX_TPD_PRI0_PIDX, txq->write_idx);
+
+       if (alx_tpd_avail(alx) < alx->tx_ringsz/8)
+               netif_stop_queue(alx->dev);
+
+       return NETDEV_TX_OK;
+
+drop:
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+static void alx_tx_timeout(struct net_device *dev)
+{
+       struct alx_priv *alx = netdev_priv(dev);
+
+       alx_schedule_reset(alx);
+}
+
+static int alx_mdio_read(struct net_device *netdev,
+                        int prtad, int devad, u16 addr)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+       u16 val;
+       int err;
+
+       if (prtad != hw->mdio.prtad)
+               return -EINVAL;
+
+       if (devad == MDIO_DEVAD_NONE)
+               err = alx_read_phy_reg(hw, addr, &val);
+       else
+               err = alx_read_phy_ext(hw, devad, addr, &val);
+
+       if (err)
+               return err;
+       return val;
+}
+
+static int alx_mdio_write(struct net_device *netdev,
+                         int prtad, int devad, u16 addr, u16 val)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+
+       if (prtad != hw->mdio.prtad)
+               return -EINVAL;
+
+       if (devad == MDIO_DEVAD_NONE)
+               return alx_write_phy_reg(hw, addr, val);
+
+       return alx_write_phy_ext(hw, devad, addr, val);
+}
+
+static int alx_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+
+       if (!netif_running(netdev))
+               return -EAGAIN;
+
+       return mdio_mii_ioctl(&alx->hw.mdio, if_mii(ifr), cmd);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void alx_poll_controller(struct net_device *netdev)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+
+       if (alx->msi)
+               alx_intr_msi(0, alx);
+       else
+               alx_intr_legacy(0, alx);
+}
+#endif
+
+static const struct net_device_ops alx_netdev_ops = {
+       .ndo_open               = alx_open,
+       .ndo_stop               = alx_stop,
+       .ndo_start_xmit         = alx_start_xmit,
+       .ndo_set_rx_mode        = alx_set_rx_mode,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = alx_set_mac_address,
+       .ndo_change_mtu         = alx_change_mtu,
+       .ndo_do_ioctl           = alx_ioctl,
+       .ndo_tx_timeout         = alx_tx_timeout,
+       .ndo_fix_features       = alx_fix_features,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = alx_poll_controller,
+#endif
+};
+
+static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       struct net_device *netdev;
+       struct alx_priv *alx;
+       struct alx_hw *hw;
+       bool phy_configured;
+       int bars, pm_cap, err;
+
+       err = pci_enable_device_mem(pdev);
+       if (err)
+               return err;
+
+       /* The alx chip can DMA to 64-bit addresses, but it uses a single
+        * shared register for the high 32 bits, so only a single, aligned,
+        * 4 GB physical address range can be used for descriptors.
+        */
+       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
+           !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+               dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n");
+       } else {
+               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+               if (err) {
+                       err = dma_set_coherent_mask(&pdev->dev,
+                                                   DMA_BIT_MASK(32));
+                       if (err) {
+                               dev_err(&pdev->dev,
+                                       "No usable DMA config, aborting\n");
+                               goto out_pci_disable;
+                       }
+               }
+       }
+
+       bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       err = pci_request_selected_regions(pdev, bars, alx_drv_name);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "pci_request_selected_regions failed(bars:%d)\n", bars);
+               goto out_pci_disable;
+       }
+
+       pci_enable_pcie_error_reporting(pdev);
+       pci_set_master(pdev);
+
+       pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+       if (pm_cap == 0) {
+               dev_err(&pdev->dev,
+                       "Can't find power management capability, aborting\n");
+               err = -EIO;
+               goto out_pci_release;
+       }
+
+       err = pci_set_power_state(pdev, PCI_D0);
+       if (err)
+               goto out_pci_release;
+
+       netdev = alloc_etherdev(sizeof(*alx));
+       if (!netdev) {
+               err = -ENOMEM;
+               goto out_pci_release;
+       }
+
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+       alx = netdev_priv(netdev);
+       alx->dev = netdev;
+       alx->hw.pdev = pdev;
+       alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP |
+                         NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR | NETIF_MSG_WOL;
+       hw = &alx->hw;
+       pci_set_drvdata(pdev, alx);
+
+       hw->hw_addr = pci_ioremap_bar(pdev, 0);
+       if (!hw->hw_addr) {
+               dev_err(&pdev->dev, "cannot map device registers\n");
+               err = -EIO;
+               goto out_free_netdev;
+       }
+
+       netdev->netdev_ops = &alx_netdev_ops;
+       SET_ETHTOOL_OPS(netdev, &alx_ethtool_ops);
+       netdev->irq = pdev->irq;
+       netdev->watchdog_timeo = ALX_WATCHDOG_TIME;
+
+       if (ent->driver_data & ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG)
+               pdev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
+
+       err = alx_init_sw(alx);
+       if (err) {
+               dev_err(&pdev->dev, "net device private data init failed\n");
+               goto out_unmap;
+       }
+
+       alx_reset_pcie(hw);
+
+       phy_configured = alx_phy_configured(hw);
+
+       if (!phy_configured)
+               alx_reset_phy(hw);
+
+       err = alx_reset_mac(hw);
+       if (err) {
+               dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err);
+               goto out_unmap;
+       }
+
+       /* setup link to put it in a known good starting state */
+       if (!phy_configured) {
+               err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "failed to configure PHY speed/duplex (err=%d)\n",
+                               err);
+                       goto out_unmap;
+               }
+       }
+
+       netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+
+       if (alx_get_perm_macaddr(hw, hw->perm_addr)) {
+               dev_warn(&pdev->dev,
+                        "Invalid permanent address programmed, using random one\n");
+               eth_hw_addr_random(netdev);
+               memcpy(hw->perm_addr, netdev->dev_addr, netdev->addr_len);
+       }
+
+       memcpy(hw->mac_addr, hw->perm_addr, ETH_ALEN);
+       memcpy(netdev->dev_addr, hw->mac_addr, ETH_ALEN);
+       memcpy(netdev->perm_addr, hw->perm_addr, ETH_ALEN);
+
+       hw->mdio.prtad = 0;
+       hw->mdio.mmds = 0;
+       hw->mdio.dev = netdev;
+       hw->mdio.mode_support = MDIO_SUPPORTS_C45 |
+                               MDIO_SUPPORTS_C22 |
+                               MDIO_EMULATE_C22;
+       hw->mdio.mdio_read = alx_mdio_read;
+       hw->mdio.mdio_write = alx_mdio_write;
+
+       if (!alx_get_phy_info(hw)) {
+               dev_err(&pdev->dev, "failed to identify PHY\n");
+               err = -EIO;
+               goto out_unmap;
+       }
+
+       INIT_WORK(&alx->link_check_wk, alx_link_check);
+       INIT_WORK(&alx->reset_wk, alx_reset);
+       spin_lock_init(&alx->hw.mdio_lock);
+       spin_lock_init(&alx->irq_lock);
+
+       netif_carrier_off(netdev);
+
+       err = register_netdev(netdev);
+       if (err) {
+               dev_err(&pdev->dev, "register netdevice failed\n");
+               goto out_unmap;
+       }
+
+       device_set_wakeup_enable(&pdev->dev, hw->sleep_ctrl);
+
+       netdev_info(netdev,
+                   "Qualcomm Atheros AR816x/AR817x Ethernet [%pM]\n",
+                   netdev->dev_addr);
+
+       return 0;
+
+out_unmap:
+       iounmap(hw->hw_addr);
+out_free_netdev:
+       free_netdev(netdev);
+out_pci_release:
+       pci_release_selected_regions(pdev, bars);
+out_pci_disable:
+       pci_disable_device(pdev);
+       return err;
+}
+
+static void alx_remove(struct pci_dev *pdev)
+{
+       struct alx_priv *alx = pci_get_drvdata(pdev);
+       struct alx_hw *hw = &alx->hw;
+
+       cancel_work_sync(&alx->link_check_wk);
+       cancel_work_sync(&alx->reset_wk);
+
+       /* restore permanent mac address */
+       alx_set_macaddr(hw, hw->perm_addr);
+
+       unregister_netdev(alx->dev);
+       iounmap(hw->hw_addr);
+       pci_release_selected_regions(pdev,
+                                    pci_select_bars(pdev, IORESOURCE_MEM));
+
+       pci_disable_pcie_error_reporting(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+
+       free_netdev(alx->dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int alx_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       int err;
+       bool wol_en;
+
+       err = __alx_shutdown(pdev, &wol_en);
+       if (err) {
+               dev_err(&pdev->dev, "shutdown fail in suspend %d\n", err);
+               return err;
+       }
+
+       if (wol_en) {
+               pci_prepare_to_sleep(pdev);
+       } else {
+               pci_wake_from_d3(pdev, false);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
+
+       return 0;
+}
+
+static int alx_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct alx_priv *alx = pci_get_drvdata(pdev);
+       struct net_device *netdev = alx->dev;
+       struct alx_hw *hw = &alx->hw;
+       int err;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       pci_save_state(pdev);
+
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+       pci_enable_wake(pdev, PCI_D3cold, 0);
+
+       hw->link_speed = SPEED_UNKNOWN;
+       alx->int_mask = ALX_ISR_MISC;
+
+       alx_reset_pcie(hw);
+       alx_reset_phy(hw);
+
+       err = alx_reset_mac(hw);
+       if (err) {
+               netif_err(alx, hw, alx->dev,
+                         "resume:reset_mac fail %d\n", err);
+               return -EIO;
+       }
+
+       err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl);
+       if (err) {
+               netif_err(alx, hw, alx->dev,
+                         "resume:setup_speed_duplex fail %d\n", err);
+               return -EIO;
+       }
+
+       if (netif_running(netdev)) {
+               err = __alx_open(alx, true);
+               if (err)
+                       return err;
+       }
+
+       netif_device_attach(netdev);
+
+       return err;
+}
+#endif
+
+static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev,
+                                              pci_channel_state_t state)
+{
+       struct alx_priv *alx = pci_get_drvdata(pdev);
+       struct net_device *netdev = alx->dev;
+       pci_ers_result_t rc = PCI_ERS_RESULT_NEED_RESET;
+
+       dev_info(&pdev->dev, "pci error detected\n");
+
+       rtnl_lock();
+
+       if (netif_running(netdev)) {
+               netif_device_detach(netdev);
+               alx_halt(alx);
+       }
+
+       if (state == pci_channel_io_perm_failure)
+               rc = PCI_ERS_RESULT_DISCONNECT;
+       else
+               pci_disable_device(pdev);
+
+       rtnl_unlock();
+
+       return rc;
+}
+
+static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev)
+{
+       struct alx_priv *alx = pci_get_drvdata(pdev);
+       struct alx_hw *hw = &alx->hw;
+       pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT;
+
+       dev_info(&pdev->dev, "pci error slot reset\n");
+
+       rtnl_lock();
+
+       if (pci_enable_device(pdev)) {
+               dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n");
+               goto out;
+       }
+
+       pci_set_master(pdev);
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+       pci_enable_wake(pdev, PCI_D3cold, 0);
+
+       alx_reset_pcie(hw);
+       if (!alx_reset_mac(hw))
+               rc = PCI_ERS_RESULT_RECOVERED;
+out:
+       pci_cleanup_aer_uncorrect_error_status(pdev);
+
+       rtnl_unlock();
+
+       return rc;
+}
+
+static void alx_pci_error_resume(struct pci_dev *pdev)
+{
+       struct alx_priv *alx = pci_get_drvdata(pdev);
+       struct net_device *netdev = alx->dev;
+
+       dev_info(&pdev->dev, "pci error resume\n");
+
+       rtnl_lock();
+
+       if (netif_running(netdev)) {
+               alx_activate(alx);
+               netif_device_attach(netdev);
+       }
+
+       rtnl_unlock();
+}
+
+static const struct pci_error_handlers alx_err_handlers = {
+       .error_detected = alx_pci_error_detected,
+       .slot_reset     = alx_pci_error_slot_reset,
+       .resume         = alx_pci_error_resume,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
+#define ALX_PM_OPS      (&alx_pm_ops)
+#else
+#define ALX_PM_OPS      NULL
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(alx_pci_tbl) = {
+       { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8161),
+         .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
+       { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200),
+         .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
+       { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162),
+         .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
+       { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) },
+       { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8172) },
+       {}
+};
+
+static struct pci_driver alx_driver = {
+       .name        = alx_drv_name,
+       .id_table    = alx_pci_tbl,
+       .probe       = alx_probe,
+       .remove      = alx_remove,
+       .shutdown    = alx_shutdown,
+       .err_handler = &alx_err_handlers,
+       .driver.pm   = ALX_PM_OPS,
+};
+
+module_pci_driver(alx_driver);
+MODULE_DEVICE_TABLE(pci, alx_pci_tbl);
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_AUTHOR("Qualcomm Corporation, <nic-devel@qualcomm.com>");
+MODULE_DESCRIPTION(
+       "Qualcomm Atheros(R) AR816x/AR817x PCI-E Ethernet Network Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/atheros/alx/reg.h b/drivers/net/ethernet/atheros/alx/reg.h
new file mode 100644 (file)
index 0000000..e4358c9
--- /dev/null
@@ -0,0 +1,810 @@
+/*
+ * 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_REG_H
+#define ALX_REG_H
+
+#define ALX_DEV_ID_AR8161                              0x1091
+#define ALX_DEV_ID_E2200                               0xe091
+#define ALX_DEV_ID_AR8162                              0x1090
+#define ALX_DEV_ID_AR8171                              0x10A1
+#define ALX_DEV_ID_AR8172                              0x10A0
+
+/* rev definition,
+ * bit(0): with xD support
+ * bit(1): with Card Reader function
+ * bit(7:2): real revision
+ */
+#define ALX_PCI_REVID_SHIFT                            3
+#define ALX_REV_A0                                     0
+#define ALX_REV_A1                                     1
+#define ALX_REV_B0                                     2
+#define ALX_REV_C0                                     3
+
+#define ALX_DEV_CTRL                                   0x0060
+#define ALX_DEV_CTRL_MAXRRS_MIN                                2
+
+#define ALX_MSIX_MASK                                  0x0090
+
+#define ALX_UE_SVRT                                    0x010C
+#define ALX_UE_SVRT_FCPROTERR                          BIT(13)
+#define ALX_UE_SVRT_DLPROTERR                          BIT(4)
+
+/* eeprom & flash load register */
+#define ALX_EFLD                                       0x0204
+#define ALX_EFLD_F_EXIST                               BIT(10)
+#define ALX_EFLD_E_EXIST                               BIT(9)
+#define ALX_EFLD_STAT                                  BIT(5)
+#define ALX_EFLD_START                                 BIT(0)
+
+/* eFuse load register */
+#define ALX_SLD                                                0x0218
+#define ALX_SLD_STAT                                   BIT(12)
+#define ALX_SLD_START                                  BIT(11)
+#define ALX_SLD_MAX_TO                                 100
+
+#define ALX_PDLL_TRNS1                                 0x1104
+#define ALX_PDLL_TRNS1_D3PLLOFF_EN                     BIT(11)
+
+#define ALX_PMCTRL                                     0x12F8
+#define ALX_PMCTRL_HOTRST_WTEN                         BIT(31)
+/* bit30: L0s/L1 controlled by MAC based on throughput(setting in 15A0) */
+#define ALX_PMCTRL_ASPM_FCEN                           BIT(30)
+#define ALX_PMCTRL_SADLY_EN                            BIT(29)
+#define ALX_PMCTRL_LCKDET_TIMER_MASK                   0xF
+#define ALX_PMCTRL_LCKDET_TIMER_SHIFT                  24
+#define ALX_PMCTRL_LCKDET_TIMER_DEF                    0xC
+/* bit[23:20] if pm_request_l1 time > @, then enter L0s not L1 */
+#define ALX_PMCTRL_L1REQ_TO_MASK                       0xF
+#define ALX_PMCTRL_L1REQ_TO_SHIFT                      20
+#define ALX_PMCTRL_L1REG_TO_DEF                                0xF
+#define ALX_PMCTRL_TXL1_AFTER_L0S                      BIT(19)
+#define ALX_PMCTRL_L1_TIMER_MASK                       0x7
+#define ALX_PMCTRL_L1_TIMER_SHIFT                      16
+#define ALX_PMCTRL_L1_TIMER_16US                       4
+#define ALX_PMCTRL_RCVR_WT_1US                         BIT(15)
+/* bit13: enable pcie clk switch in L1 state */
+#define ALX_PMCTRL_L1_CLKSW_EN                         BIT(13)
+#define ALX_PMCTRL_L0S_EN                              BIT(12)
+#define ALX_PMCTRL_RXL1_AFTER_L0S                      BIT(11)
+#define ALX_PMCTRL_L1_BUFSRX_EN                                BIT(7)
+/* bit6: power down serdes RX */
+#define ALX_PMCTRL_L1_SRDSRX_PWD                       BIT(6)
+#define ALX_PMCTRL_L1_SRDSPLL_EN                       BIT(5)
+#define ALX_PMCTRL_L1_SRDS_EN                          BIT(4)
+#define ALX_PMCTRL_L1_EN                               BIT(3)
+
+/*******************************************************/
+/* following registers are mapped only to memory space */
+/*******************************************************/
+
+#define ALX_MASTER                                     0x1400
+/* bit12: 1:alwys select pclk from serdes, not sw to 25M */
+#define ALX_MASTER_PCLKSEL_SRDS                                BIT(12)
+/* bit11: irq moduration for rx */
+#define ALX_MASTER_IRQMOD2_EN                          BIT(11)
+/* bit10: irq moduration for tx/rx */
+#define ALX_MASTER_IRQMOD1_EN                          BIT(10)
+#define ALX_MASTER_SYSALVTIMER_EN                      BIT(7)
+#define ALX_MASTER_OOB_DIS                             BIT(6)
+/* bit5: wakeup without pcie clk */
+#define ALX_MASTER_WAKEN_25M                           BIT(5)
+/* bit0: MAC & DMA reset */
+#define ALX_MASTER_DMA_MAC_RST                         BIT(0)
+#define ALX_DMA_MAC_RST_TO                             50
+
+#define ALX_IRQ_MODU_TIMER                             0x1408
+#define ALX_IRQ_MODU_TIMER1_MASK                       0xFFFF
+#define ALX_IRQ_MODU_TIMER1_SHIFT                      0
+
+#define ALX_PHY_CTRL                                   0x140C
+#define ALX_PHY_CTRL_100AB_EN                          BIT(17)
+/* bit14: affect MAC & PHY, go to low power sts */
+#define ALX_PHY_CTRL_POWER_DOWN                                BIT(14)
+/* bit13: 1:pll always ON, 0:can switch in lpw */
+#define ALX_PHY_CTRL_PLL_ON                            BIT(13)
+#define ALX_PHY_CTRL_RST_ANALOG                                BIT(12)
+#define ALX_PHY_CTRL_HIB_PULSE                         BIT(11)
+#define ALX_PHY_CTRL_HIB_EN                            BIT(10)
+#define ALX_PHY_CTRL_IDDQ                              BIT(7)
+#define ALX_PHY_CTRL_GATE_25M                          BIT(5)
+#define ALX_PHY_CTRL_LED_MODE                          BIT(2)
+/* bit0: out of dsp RST state */
+#define ALX_PHY_CTRL_DSPRST_OUT                                BIT(0)
+#define ALX_PHY_CTRL_DSPRST_TO                         80
+#define ALX_PHY_CTRL_CLS       (ALX_PHY_CTRL_LED_MODE | \
+                                ALX_PHY_CTRL_100AB_EN | \
+                                ALX_PHY_CTRL_PLL_ON)
+
+#define ALX_MAC_STS                                    0x1410
+#define ALX_MAC_STS_TXQ_BUSY                           BIT(3)
+#define ALX_MAC_STS_RXQ_BUSY                           BIT(2)
+#define ALX_MAC_STS_TXMAC_BUSY                         BIT(1)
+#define ALX_MAC_STS_RXMAC_BUSY                         BIT(0)
+#define ALX_MAC_STS_IDLE       (ALX_MAC_STS_TXQ_BUSY | \
+                                ALX_MAC_STS_RXQ_BUSY | \
+                                ALX_MAC_STS_TXMAC_BUSY | \
+                                ALX_MAC_STS_RXMAC_BUSY)
+
+#define ALX_MDIO                                       0x1414
+#define ALX_MDIO_MODE_EXT                              BIT(30)
+#define ALX_MDIO_BUSY                                  BIT(27)
+#define ALX_MDIO_CLK_SEL_MASK                          0x7
+#define ALX_MDIO_CLK_SEL_SHIFT                         24
+#define ALX_MDIO_CLK_SEL_25MD4                         0
+#define ALX_MDIO_CLK_SEL_25MD128                       7
+#define ALX_MDIO_START                                 BIT(23)
+#define ALX_MDIO_SPRES_PRMBL                           BIT(22)
+/* bit21: 1:read,0:write */
+#define ALX_MDIO_OP_READ                               BIT(21)
+#define ALX_MDIO_REG_MASK                              0x1F
+#define ALX_MDIO_REG_SHIFT                             16
+#define ALX_MDIO_DATA_MASK                             0xFFFF
+#define ALX_MDIO_DATA_SHIFT                            0
+#define ALX_MDIO_MAX_AC_TO                             120
+
+#define ALX_MDIO_EXTN                                  0x1448
+#define ALX_MDIO_EXTN_DEVAD_MASK                       0x1F
+#define ALX_MDIO_EXTN_DEVAD_SHIFT                      16
+#define ALX_MDIO_EXTN_REG_MASK                         0xFFFF
+#define ALX_MDIO_EXTN_REG_SHIFT                                0
+
+#define ALX_SERDES                                     0x1424
+#define ALX_SERDES_PHYCLK_SLWDWN                       BIT(18)
+#define ALX_SERDES_MACCLK_SLWDWN                       BIT(17)
+
+#define ALX_LPI_CTRL                                   0x1440
+#define ALX_LPI_CTRL_EN                                        BIT(0)
+
+/* for B0+, bit[13..] for C0+ */
+#define ALX_HRTBT_EXT_CTRL                             0x1AD0
+#define L1F_HRTBT_EXT_CTRL_PERIOD_HIGH_MASK            0x3F
+#define L1F_HRTBT_EXT_CTRL_PERIOD_HIGH_SHIFT           24
+#define L1F_HRTBT_EXT_CTRL_SWOI_STARTUP_PKT_EN         BIT(23)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_FRAGMENTED           BIT(22)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_FRAGMENTED           BIT(21)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_KEEPALIVE_EN         BIT(20)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_HAS_VLAN             BIT(19)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_IS_8023              BIT(18)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_IS_IPV6              BIT(17)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_KEEPALIVE_EN         BIT(16)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_HAS_VLAN             BIT(15)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_IS_8023              BIT(14)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_IS_IPV6              BIT(13)
+#define ALX_HRTBT_EXT_CTRL_NS_EN                       BIT(12)
+#define ALX_HRTBT_EXT_CTRL_FRAG_LEN_MASK               0xFF
+#define ALX_HRTBT_EXT_CTRL_FRAG_LEN_SHIFT              4
+#define ALX_HRTBT_EXT_CTRL_IS_8023                     BIT(3)
+#define ALX_HRTBT_EXT_CTRL_IS_IPV6                     BIT(2)
+#define ALX_HRTBT_EXT_CTRL_WAKEUP_EN                   BIT(1)
+#define ALX_HRTBT_EXT_CTRL_ARP_EN                      BIT(0)
+
+#define ALX_HRTBT_REM_IPV4_ADDR                                0x1AD4
+#define ALX_HRTBT_HOST_IPV4_ADDR                       0x1478
+#define ALX_HRTBT_REM_IPV6_ADDR3                       0x1AD8
+#define ALX_HRTBT_REM_IPV6_ADDR2                       0x1ADC
+#define ALX_HRTBT_REM_IPV6_ADDR1                       0x1AE0
+#define ALX_HRTBT_REM_IPV6_ADDR0                       0x1AE4
+
+/* 1B8C ~ 1B94 for C0+ */
+#define ALX_SWOI_ACER_CTRL                             0x1B8C
+#define ALX_SWOI_ORIG_ACK_NAK_EN                       BIT(20)
+#define ALX_SWOI_ORIG_ACK_NAK_PKT_LEN_MASK             0XFF
+#define ALX_SWOI_ORIG_ACK_NAK_PKT_LEN_SHIFT            12
+#define ALX_SWOI_ORIG_ACK_ADDR_MASK                    0XFFF
+#define ALX_SWOI_ORIG_ACK_ADDR_SHIFT                   0
+
+#define ALX_SWOI_IOAC_CTRL_2                           0x1B90
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_FRAG_LEN_MASK      0xFF
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_FRAG_LEN_SHIFT     24
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_PKT_LEN_MASK       0xFFF
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_PKT_LEN_SHIFT      12
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_HDR_ADDR_MASK      0xFFF
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_HDR_ADDR_SHIFT     0
+
+#define ALX_SWOI_IOAC_CTRL_3                           0x1B94
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_FRAG_LEN_MASK      0xFF
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_FRAG_LEN_SHIFT     24
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_PKT_LEN_MASK       0xFFF
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_PKT_LEN_SHIFT      12
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_HDR_ADDR_MASK      0xFFF
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_HDR_ADDR_SHIFT     0
+
+/* for B0 */
+#define ALX_IDLE_DECISN_TIMER                          0x1474
+/* 1ms */
+#define ALX_IDLE_DECISN_TIMER_DEF                      0x400
+
+#define ALX_MAC_CTRL                                   0x1480
+#define ALX_MAC_CTRL_FAST_PAUSE                                BIT(31)
+#define ALX_MAC_CTRL_WOLSPED_SWEN                      BIT(30)
+/* bit29: 1:legacy(hi5b), 0:marvl(lo5b)*/
+#define ALX_MAC_CTRL_MHASH_ALG_HI5B                    BIT(29)
+#define ALX_MAC_CTRL_BRD_EN                            BIT(26)
+#define ALX_MAC_CTRL_MULTIALL_EN                       BIT(25)
+#define ALX_MAC_CTRL_SPEED_MASK                                0x3
+#define ALX_MAC_CTRL_SPEED_SHIFT                       20
+#define ALX_MAC_CTRL_SPEED_10_100                      1
+#define ALX_MAC_CTRL_SPEED_1000                                2
+#define ALX_MAC_CTRL_PROMISC_EN                                BIT(15)
+#define ALX_MAC_CTRL_VLANSTRIP                         BIT(14)
+#define ALX_MAC_CTRL_PRMBLEN_MASK                      0xF
+#define ALX_MAC_CTRL_PRMBLEN_SHIFT                     10
+#define ALX_MAC_CTRL_PCRCE                             BIT(7)
+#define ALX_MAC_CTRL_CRCE                              BIT(6)
+#define ALX_MAC_CTRL_FULLD                             BIT(5)
+#define ALX_MAC_CTRL_RXFC_EN                           BIT(3)
+#define ALX_MAC_CTRL_TXFC_EN                           BIT(2)
+#define ALX_MAC_CTRL_RX_EN                             BIT(1)
+#define ALX_MAC_CTRL_TX_EN                             BIT(0)
+
+#define ALX_STAD0                                      0x1488
+#define ALX_STAD1                                      0x148C
+
+#define ALX_HASH_TBL0                                  0x1490
+#define ALX_HASH_TBL1                                  0x1494
+
+#define ALX_MTU                                                0x149C
+#define ALX_MTU_JUMBO_TH                               1514
+#define ALX_MTU_STD_ALGN                               1536
+
+#define ALX_SRAM5                                      0x1524
+#define ALX_SRAM_RXF_LEN_MASK                          0xFFF
+#define ALX_SRAM_RXF_LEN_SHIFT                         0
+#define ALX_SRAM_RXF_LEN_8K                            (8*1024)
+
+#define ALX_SRAM9                                      0x1534
+#define ALX_SRAM_LOAD_PTR                              BIT(0)
+
+#define ALX_RX_BASE_ADDR_HI                            0x1540
+
+#define ALX_TX_BASE_ADDR_HI                            0x1544
+
+#define ALX_RFD_ADDR_LO                                        0x1550
+#define ALX_RFD_RING_SZ                                        0x1560
+#define ALX_RFD_BUF_SZ                                 0x1564
+
+#define ALX_RRD_ADDR_LO                                        0x1568
+#define ALX_RRD_RING_SZ                                        0x1578
+
+/* pri3: highest, pri0: lowest */
+#define ALX_TPD_PRI3_ADDR_LO                           0x14E4
+#define ALX_TPD_PRI2_ADDR_LO                           0x14E0
+#define ALX_TPD_PRI1_ADDR_LO                           0x157C
+#define ALX_TPD_PRI0_ADDR_LO                           0x1580
+
+/* producer index is 16bit */
+#define ALX_TPD_PRI3_PIDX                              0x1618
+#define ALX_TPD_PRI2_PIDX                              0x161A
+#define ALX_TPD_PRI1_PIDX                              0x15F0
+#define ALX_TPD_PRI0_PIDX                              0x15F2
+
+/* consumer index is 16bit */
+#define ALX_TPD_PRI3_CIDX                              0x161C
+#define ALX_TPD_PRI2_CIDX                              0x161E
+#define ALX_TPD_PRI1_CIDX                              0x15F4
+#define ALX_TPD_PRI0_CIDX                              0x15F6
+
+#define ALX_TPD_RING_SZ                                        0x1584
+
+#define ALX_TXQ0                                       0x1590
+#define ALX_TXQ0_TXF_BURST_PREF_MASK                   0xFFFF
+#define ALX_TXQ0_TXF_BURST_PREF_SHIFT                  16
+#define ALX_TXQ_TXF_BURST_PREF_DEF                     0x200
+#define ALX_TXQ0_LSO_8023_EN                           BIT(7)
+#define ALX_TXQ0_MODE_ENHANCE                          BIT(6)
+#define ALX_TXQ0_EN                                    BIT(5)
+#define ALX_TXQ0_SUPT_IPOPT                            BIT(4)
+#define ALX_TXQ0_TPD_BURSTPREF_MASK                    0xF
+#define ALX_TXQ0_TPD_BURSTPREF_SHIFT                   0
+#define ALX_TXQ_TPD_BURSTPREF_DEF                      5
+
+#define ALX_TXQ1                                       0x1594
+/* bit11:  drop large packet, len > (rfd buf) */
+#define ALX_TXQ1_ERRLGPKT_DROP_EN                      BIT(11)
+#define ALX_TXQ1_JUMBO_TSO_TH                          (7*1024)
+
+#define ALX_RXQ0                                       0x15A0
+#define ALX_RXQ0_EN                                    BIT(31)
+#define ALX_RXQ0_RSS_HASH_EN                           BIT(29)
+#define ALX_RXQ0_RSS_MODE_MASK                         0x3
+#define ALX_RXQ0_RSS_MODE_SHIFT                                26
+#define ALX_RXQ0_RSS_MODE_DIS                          0
+#define ALX_RXQ0_RSS_MODE_MQMI                         3
+#define ALX_RXQ0_NUM_RFD_PREF_MASK                     0x3F
+#define ALX_RXQ0_NUM_RFD_PREF_SHIFT                    20
+#define ALX_RXQ0_NUM_RFD_PREF_DEF                      8
+#define ALX_RXQ0_IDT_TBL_SIZE_MASK                     0x1FF
+#define ALX_RXQ0_IDT_TBL_SIZE_SHIFT                    8
+#define ALX_RXQ0_IDT_TBL_SIZE_DEF                      0x100
+#define ALX_RXQ0_IDT_TBL_SIZE_NORMAL                   128
+#define ALX_RXQ0_IPV6_PARSE_EN                         BIT(7)
+#define ALX_RXQ0_RSS_HSTYP_MASK                                0xF
+#define ALX_RXQ0_RSS_HSTYP_SHIFT                       2
+#define ALX_RXQ0_RSS_HSTYP_IPV6_TCP_EN                 BIT(5)
+#define ALX_RXQ0_RSS_HSTYP_IPV6_EN                     BIT(4)
+#define ALX_RXQ0_RSS_HSTYP_IPV4_TCP_EN                 BIT(3)
+#define ALX_RXQ0_RSS_HSTYP_IPV4_EN                     BIT(2)
+#define ALX_RXQ0_RSS_HSTYP_ALL         (ALX_RXQ0_RSS_HSTYP_IPV6_TCP_EN | \
+                                        ALX_RXQ0_RSS_HSTYP_IPV4_TCP_EN | \
+                                        ALX_RXQ0_RSS_HSTYP_IPV6_EN | \
+                                        ALX_RXQ0_RSS_HSTYP_IPV4_EN)
+#define ALX_RXQ0_ASPM_THRESH_MASK                      0x3
+#define ALX_RXQ0_ASPM_THRESH_SHIFT                     0
+#define ALX_RXQ0_ASPM_THRESH_100M                      3
+
+#define ALX_RXQ2                                       0x15A8
+#define ALX_RXQ2_RXF_XOFF_THRESH_MASK                  0xFFF
+#define ALX_RXQ2_RXF_XOFF_THRESH_SHIFT                 16
+#define ALX_RXQ2_RXF_XON_THRESH_MASK                   0xFFF
+#define ALX_RXQ2_RXF_XON_THRESH_SHIFT                  0
+/* Size = tx-packet(1522) + IPG(12) + SOF(8) + 64(Pause) + IPG(12) + SOF(8) +
+ *        rx-packet(1522) + delay-of-link(64)
+ *      = 3212.
+ */
+#define ALX_RXQ2_RXF_FLOW_CTRL_RSVD                    3212
+
+#define ALX_DMA                                                0x15C0
+#define ALX_DMA_RCHNL_SEL_MASK                         0x3
+#define ALX_DMA_RCHNL_SEL_SHIFT                                26
+#define ALX_DMA_WDLY_CNT_MASK                          0xF
+#define ALX_DMA_WDLY_CNT_SHIFT                         16
+#define ALX_DMA_WDLY_CNT_DEF                           4
+#define ALX_DMA_RDLY_CNT_MASK                          0x1F
+#define ALX_DMA_RDLY_CNT_SHIFT                         11
+#define ALX_DMA_RDLY_CNT_DEF                           15
+/* bit10: 0:tpd with pri, 1: data */
+#define ALX_DMA_RREQ_PRI_DATA                          BIT(10)
+#define ALX_DMA_RREQ_BLEN_MASK                         0x7
+#define ALX_DMA_RREQ_BLEN_SHIFT                                4
+#define ALX_DMA_RORDER_MODE_MASK                       0x7
+#define ALX_DMA_RORDER_MODE_SHIFT                      0
+#define ALX_DMA_RORDER_MODE_OUT                                4
+
+#define ALX_WOL0                                       0x14A0
+#define ALX_WOL0_PME_LINK                              BIT(5)
+#define ALX_WOL0_LINK_EN                               BIT(4)
+#define ALX_WOL0_PME_MAGIC_EN                          BIT(3)
+#define ALX_WOL0_MAGIC_EN                              BIT(2)
+
+#define ALX_RFD_PIDX                                   0x15E0
+
+#define ALX_RFD_CIDX                                   0x15F8
+
+/* MIB */
+#define ALX_MIB_BASE                                   0x1700
+#define ALX_MIB_RX_OK                                  (ALX_MIB_BASE + 0)
+#define ALX_MIB_RX_ERRADDR                             (ALX_MIB_BASE + 92)
+#define ALX_MIB_TX_OK                                  (ALX_MIB_BASE + 96)
+#define ALX_MIB_TX_MCCNT                               (ALX_MIB_BASE + 192)
+
+#define ALX_RX_STATS_BIN                               ALX_MIB_RX_OK
+#define ALX_RX_STATS_END                               ALX_MIB_RX_ERRADDR
+#define ALX_TX_STATS_BIN                               ALX_MIB_TX_OK
+#define ALX_TX_STATS_END                               ALX_MIB_TX_MCCNT
+
+#define ALX_ISR                                                0x1600
+#define ALX_ISR_DIS                                    BIT(31)
+#define ALX_ISR_RX_Q7                                  BIT(30)
+#define ALX_ISR_RX_Q6                                  BIT(29)
+#define ALX_ISR_RX_Q5                                  BIT(28)
+#define ALX_ISR_RX_Q4                                  BIT(27)
+#define ALX_ISR_PCIE_LNKDOWN                           BIT(26)
+#define ALX_ISR_RX_Q3                                  BIT(19)
+#define ALX_ISR_RX_Q2                                  BIT(18)
+#define ALX_ISR_RX_Q1                                  BIT(17)
+#define ALX_ISR_RX_Q0                                  BIT(16)
+#define ALX_ISR_TX_Q0                                  BIT(15)
+#define ALX_ISR_PHY                                    BIT(12)
+#define ALX_ISR_DMAW                                   BIT(10)
+#define ALX_ISR_DMAR                                   BIT(9)
+#define ALX_ISR_TXF_UR                                 BIT(8)
+#define ALX_ISR_TX_Q3                                  BIT(7)
+#define ALX_ISR_TX_Q2                                  BIT(6)
+#define ALX_ISR_TX_Q1                                  BIT(5)
+#define ALX_ISR_RFD_UR                                 BIT(4)
+#define ALX_ISR_RXF_OV                                 BIT(3)
+#define ALX_ISR_MANU                                   BIT(2)
+#define ALX_ISR_TIMER                                  BIT(1)
+#define ALX_ISR_SMB                                    BIT(0)
+
+#define ALX_IMR                                                0x1604
+
+/* re-send assert msg if SW no response */
+#define ALX_INT_RETRIG                                 0x1608
+/* 40ms */
+#define ALX_INT_RETRIG_TO                              20000
+
+#define ALX_SMB_TIMER                                  0x15C4
+
+#define ALX_TINT_TPD_THRSHLD                           0x15C8
+
+#define ALX_TINT_TIMER                                 0x15CC
+
+#define ALX_CLK_GATE                                   0x1814
+#define ALX_CLK_GATE_RXMAC                             BIT(5)
+#define ALX_CLK_GATE_TXMAC                             BIT(4)
+#define ALX_CLK_GATE_RXQ                               BIT(3)
+#define ALX_CLK_GATE_TXQ                               BIT(2)
+#define ALX_CLK_GATE_DMAR                              BIT(1)
+#define ALX_CLK_GATE_DMAW                              BIT(0)
+#define ALX_CLK_GATE_ALL               (ALX_CLK_GATE_RXMAC | \
+                                        ALX_CLK_GATE_TXMAC | \
+                                        ALX_CLK_GATE_RXQ | \
+                                        ALX_CLK_GATE_TXQ | \
+                                        ALX_CLK_GATE_DMAR | \
+                                        ALX_CLK_GATE_DMAW)
+
+/* interop between drivers */
+#define ALX_DRV                                                0x1804
+#define ALX_DRV_PHY_AUTO                               BIT(28)
+#define ALX_DRV_PHY_1000                               BIT(27)
+#define ALX_DRV_PHY_100                                        BIT(26)
+#define ALX_DRV_PHY_10                                 BIT(25)
+#define ALX_DRV_PHY_DUPLEX                             BIT(24)
+/* bit23: adv Pause */
+#define ALX_DRV_PHY_PAUSE                              BIT(23)
+/* bit22: adv Asym Pause */
+#define ALX_DRV_PHY_MASK                               0xFF
+#define ALX_DRV_PHY_SHIFT                              21
+#define ALX_DRV_PHY_UNKNOWN                            0
+
+/* flag of phy inited */
+#define ALX_PHY_INITED                                 0x003F
+
+/* reg 1830 ~ 186C for C0+, 16 bit map patterns and wake packet detection */
+#define ALX_WOL_CTRL2                                  0x1830
+#define ALX_WOL_CTRL2_DATA_STORE                       BIT(3)
+#define ALX_WOL_CTRL2_PTRN_EVT                         BIT(2)
+#define ALX_WOL_CTRL2_PME_PTRN_EN                      BIT(1)
+#define ALX_WOL_CTRL2_PTRN_EN                          BIT(0)
+
+#define ALX_WOL_CTRL3                                  0x1834
+#define ALX_WOL_CTRL3_PTRN_ADDR_MASK                   0xFFFFF
+#define ALX_WOL_CTRL3_PTRN_ADDR_SHIFT                  0
+
+#define ALX_WOL_CTRL4                                  0x1838
+#define ALX_WOL_CTRL4_PT15_MATCH                       BIT(31)
+#define ALX_WOL_CTRL4_PT14_MATCH                       BIT(30)
+#define ALX_WOL_CTRL4_PT13_MATCH                       BIT(29)
+#define ALX_WOL_CTRL4_PT12_MATCH                       BIT(28)
+#define ALX_WOL_CTRL4_PT11_MATCH                       BIT(27)
+#define ALX_WOL_CTRL4_PT10_MATCH                       BIT(26)
+#define ALX_WOL_CTRL4_PT9_MATCH                                BIT(25)
+#define ALX_WOL_CTRL4_PT8_MATCH                                BIT(24)
+#define ALX_WOL_CTRL4_PT7_MATCH                                BIT(23)
+#define ALX_WOL_CTRL4_PT6_MATCH                                BIT(22)
+#define ALX_WOL_CTRL4_PT5_MATCH                                BIT(21)
+#define ALX_WOL_CTRL4_PT4_MATCH                                BIT(20)
+#define ALX_WOL_CTRL4_PT3_MATCH                                BIT(19)
+#define ALX_WOL_CTRL4_PT2_MATCH                                BIT(18)
+#define ALX_WOL_CTRL4_PT1_MATCH                                BIT(17)
+#define ALX_WOL_CTRL4_PT0_MATCH                                BIT(16)
+#define ALX_WOL_CTRL4_PT15_EN                          BIT(15)
+#define ALX_WOL_CTRL4_PT14_EN                          BIT(14)
+#define ALX_WOL_CTRL4_PT13_EN                          BIT(13)
+#define ALX_WOL_CTRL4_PT12_EN                          BIT(12)
+#define ALX_WOL_CTRL4_PT11_EN                          BIT(11)
+#define ALX_WOL_CTRL4_PT10_EN                          BIT(10)
+#define ALX_WOL_CTRL4_PT9_EN                           BIT(9)
+#define ALX_WOL_CTRL4_PT8_EN                           BIT(8)
+#define ALX_WOL_CTRL4_PT7_EN                           BIT(7)
+#define ALX_WOL_CTRL4_PT6_EN                           BIT(6)
+#define ALX_WOL_CTRL4_PT5_EN                           BIT(5)
+#define ALX_WOL_CTRL4_PT4_EN                           BIT(4)
+#define ALX_WOL_CTRL4_PT3_EN                           BIT(3)
+#define ALX_WOL_CTRL4_PT2_EN                           BIT(2)
+#define ALX_WOL_CTRL4_PT1_EN                           BIT(1)
+#define ALX_WOL_CTRL4_PT0_EN                           BIT(0)
+
+#define ALX_WOL_CTRL5                                  0x183C
+#define ALX_WOL_CTRL5_PT3_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT3_LEN_SHIFT                    24
+#define ALX_WOL_CTRL5_PT2_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT2_LEN_SHIFT                    16
+#define ALX_WOL_CTRL5_PT1_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT1_LEN_SHIFT                    8
+#define ALX_WOL_CTRL5_PT0_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT0_LEN_SHIFT                    0
+
+#define ALX_WOL_CTRL6                                  0x1840
+#define ALX_WOL_CTRL5_PT7_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT7_LEN_SHIFT                    24
+#define ALX_WOL_CTRL5_PT6_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT6_LEN_SHIFT                    16
+#define ALX_WOL_CTRL5_PT5_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT5_LEN_SHIFT                    8
+#define ALX_WOL_CTRL5_PT4_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT4_LEN_SHIFT                    0
+
+#define ALX_WOL_CTRL7                                  0x1844
+#define ALX_WOL_CTRL5_PT11_LEN_MASK                    0xFF
+#define ALX_WOL_CTRL5_PT11_LEN_SHIFT                   24
+#define ALX_WOL_CTRL5_PT10_LEN_MASK                    0xFF
+#define ALX_WOL_CTRL5_PT10_LEN_SHIFT                   16
+#define ALX_WOL_CTRL5_PT9_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT9_LEN_SHIFT                    8
+#define ALX_WOL_CTRL5_PT8_LEN_MASK                     0xFF
+#define ALX_WOL_CTRL5_PT8_LEN_SHIFT                    0
+
+#define ALX_WOL_CTRL8                                  0x1848
+#define ALX_WOL_CTRL5_PT15_LEN_MASK                    0xFF
+#define ALX_WOL_CTRL5_PT15_LEN_SHIFT                   24
+#define ALX_WOL_CTRL5_PT14_LEN_MASK                    0xFF
+#define ALX_WOL_CTRL5_PT14_LEN_SHIFT                   16
+#define ALX_WOL_CTRL5_PT13_LEN_MASK                    0xFF
+#define ALX_WOL_CTRL5_PT13_LEN_SHIFT                   8
+#define ALX_WOL_CTRL5_PT12_LEN_MASK                    0xFF
+#define ALX_WOL_CTRL5_PT12_LEN_SHIFT                   0
+
+#define ALX_ACER_FIXED_PTN0                            0x1850
+#define ALX_ACER_FIXED_PTN0_MASK                       0xFFFFFFFF
+#define ALX_ACER_FIXED_PTN0_SHIFT                      0
+
+#define ALX_ACER_FIXED_PTN1                            0x1854
+#define ALX_ACER_FIXED_PTN1_MASK                       0xFFFF
+#define ALX_ACER_FIXED_PTN1_SHIFT                      0
+
+#define ALX_ACER_RANDOM_NUM0                           0x1858
+#define ALX_ACER_RANDOM_NUM0_MASK                      0xFFFFFFFF
+#define ALX_ACER_RANDOM_NUM0_SHIFT                     0
+
+#define ALX_ACER_RANDOM_NUM1                           0x185C
+#define ALX_ACER_RANDOM_NUM1_MASK                      0xFFFFFFFF
+#define ALX_ACER_RANDOM_NUM1_SHIFT                     0
+
+#define ALX_ACER_RANDOM_NUM2                           0x1860
+#define ALX_ACER_RANDOM_NUM2_MASK                      0xFFFFFFFF
+#define ALX_ACER_RANDOM_NUM2_SHIFT                     0
+
+#define ALX_ACER_RANDOM_NUM3                           0x1864
+#define ALX_ACER_RANDOM_NUM3_MASK                      0xFFFFFFFF
+#define ALX_ACER_RANDOM_NUM3_SHIFT                     0
+
+#define ALX_ACER_MAGIC                                 0x1868
+#define ALX_ACER_MAGIC_EN                              BIT(31)
+#define ALX_ACER_MAGIC_PME_EN                          BIT(30)
+#define ALX_ACER_MAGIC_MATCH                           BIT(29)
+#define ALX_ACER_MAGIC_FF_CHECK                                BIT(10)
+#define ALX_ACER_MAGIC_RAN_LEN_MASK                    0x1F
+#define ALX_ACER_MAGIC_RAN_LEN_SHIFT                   5
+#define ALX_ACER_MAGIC_FIX_LEN_MASK                    0x1F
+#define ALX_ACER_MAGIC_FIX_LEN_SHIFT                   0
+
+#define ALX_ACER_TIMER                                 0x186C
+#define ALX_ACER_TIMER_EN                              BIT(31)
+#define ALX_ACER_TIMER_PME_EN                          BIT(30)
+#define ALX_ACER_TIMER_MATCH                           BIT(29)
+#define ALX_ACER_TIMER_THRES_MASK                      0x1FFFF
+#define ALX_ACER_TIMER_THRES_SHIFT                     0
+#define ALX_ACER_TIMER_THRES_DEF                       1
+
+/* RSS definitions */
+#define ALX_RSS_KEY0                                   0x14B0
+#define ALX_RSS_KEY1                                   0x14B4
+#define ALX_RSS_KEY2                                   0x14B8
+#define ALX_RSS_KEY3                                   0x14BC
+#define ALX_RSS_KEY4                                   0x14C0
+#define ALX_RSS_KEY5                                   0x14C4
+#define ALX_RSS_KEY6                                   0x14C8
+#define ALX_RSS_KEY7                                   0x14CC
+#define ALX_RSS_KEY8                                   0x14D0
+#define ALX_RSS_KEY9                                   0x14D4
+
+#define ALX_RSS_IDT_TBL0                               0x1B00
+
+#define ALX_MSI_MAP_TBL1                               0x15D0
+#define ALX_MSI_MAP_TBL1_TXQ1_SHIFT                    20
+#define ALX_MSI_MAP_TBL1_TXQ0_SHIFT                    16
+#define ALX_MSI_MAP_TBL1_RXQ3_SHIFT                    12
+#define ALX_MSI_MAP_TBL1_RXQ2_SHIFT                    8
+#define ALX_MSI_MAP_TBL1_RXQ1_SHIFT                    4
+#define ALX_MSI_MAP_TBL1_RXQ0_SHIFT                    0
+
+#define ALX_MSI_MAP_TBL2                               0x15D8
+#define ALX_MSI_MAP_TBL2_TXQ3_SHIFT                    20
+#define ALX_MSI_MAP_TBL2_TXQ2_SHIFT                    16
+#define ALX_MSI_MAP_TBL2_RXQ7_SHIFT                    12
+#define ALX_MSI_MAP_TBL2_RXQ6_SHIFT                    8
+#define ALX_MSI_MAP_TBL2_RXQ5_SHIFT                    4
+#define ALX_MSI_MAP_TBL2_RXQ4_SHIFT                    0
+
+#define ALX_MSI_ID_MAP                                 0x15D4
+
+#define ALX_MSI_RETRANS_TIMER                          0x1920
+/* bit16: 1:line,0:standard */
+#define ALX_MSI_MASK_SEL_LINE                          BIT(16)
+#define ALX_MSI_RETRANS_TM_MASK                                0xFFFF
+#define ALX_MSI_RETRANS_TM_SHIFT                       0
+
+/* CR DMA ctrl */
+
+/* TX QoS */
+#define ALX_WRR                                                0x1938
+#define ALX_WRR_PRI_MASK                               0x3
+#define ALX_WRR_PRI_SHIFT                              29
+#define ALX_WRR_PRI_RESTRICT_NONE                      3
+#define ALX_WRR_PRI3_MASK                              0x1F
+#define ALX_WRR_PRI3_SHIFT                             24
+#define ALX_WRR_PRI2_MASK                              0x1F
+#define ALX_WRR_PRI2_SHIFT                             16
+#define ALX_WRR_PRI1_MASK                              0x1F
+#define ALX_WRR_PRI1_SHIFT                             8
+#define ALX_WRR_PRI0_MASK                              0x1F
+#define ALX_WRR_PRI0_SHIFT                             0
+
+#define ALX_HQTPD                                      0x193C
+#define ALX_HQTPD_BURST_EN                             BIT(31)
+#define ALX_HQTPD_Q3_NUMPREF_MASK                      0xF
+#define ALX_HQTPD_Q3_NUMPREF_SHIFT                     8
+#define ALX_HQTPD_Q2_NUMPREF_MASK                      0xF
+#define ALX_HQTPD_Q2_NUMPREF_SHIFT                     4
+#define ALX_HQTPD_Q1_NUMPREF_MASK                      0xF
+#define ALX_HQTPD_Q1_NUMPREF_SHIFT                     0
+
+#define ALX_MISC                                       0x19C0
+#define ALX_MISC_PSW_OCP_MASK                          0x7
+#define ALX_MISC_PSW_OCP_SHIFT                         21
+#define ALX_MISC_PSW_OCP_DEF                           0x7
+#define ALX_MISC_ISO_EN                                        BIT(12)
+#define ALX_MISC_INTNLOSC_OPEN                         BIT(3)
+
+#define ALX_MSIC2                                      0x19C8
+#define ALX_MSIC2_CALB_START                           BIT(0)
+
+#define ALX_MISC3                                      0x19CC
+/* bit1: 1:Software control 25M */
+#define ALX_MISC3_25M_BY_SW                            BIT(1)
+/* bit0: 25M switch to intnl OSC */
+#define ALX_MISC3_25M_NOTO_INTNL                       BIT(0)
+
+/* MSIX tbl in memory space */
+#define ALX_MSIX_ENTRY_BASE                            0x2000
+
+/********************* PHY regs definition ***************************/
+
+/* PHY Specific Status Register */
+#define ALX_MII_GIGA_PSSR                              0x11
+#define ALX_GIGA_PSSR_SPD_DPLX_RESOLVED                        0x0800
+#define ALX_GIGA_PSSR_DPLX                             0x2000
+#define ALX_GIGA_PSSR_SPEED                            0xC000
+#define ALX_GIGA_PSSR_10MBS                            0x0000
+#define ALX_GIGA_PSSR_100MBS                           0x4000
+#define ALX_GIGA_PSSR_1000MBS                          0x8000
+
+/* PHY Interrupt Enable Register */
+#define ALX_MII_IER                                    0x12
+#define ALX_IER_LINK_UP                                        0x0400
+#define ALX_IER_LINK_DOWN                              0x0800
+
+/* PHY Interrupt Status Register */
+#define ALX_MII_ISR                                    0x13
+
+#define ALX_MII_DBG_ADDR                               0x1D
+#define ALX_MII_DBG_DATA                               0x1E
+
+/***************************** debug port *************************************/
+
+#define ALX_MIIDBG_ANACTRL                             0x00
+#define ALX_ANACTRL_DEF                                        0x02EF
+
+#define ALX_MIIDBG_SYSMODCTRL                          0x04
+/* en half bias */
+#define ALX_SYSMODCTRL_IECHOADJ_DEF                    0xBB8B
+
+#define ALX_MIIDBG_SRDSYSMOD                           0x05
+#define ALX_SRDSYSMOD_DEEMP_EN                         0x0040
+#define ALX_SRDSYSMOD_DEF                              0x2C46
+
+#define ALX_MIIDBG_HIBNEG                              0x0B
+#define ALX_HIBNEG_PSHIB_EN                            0x8000
+#define ALX_HIBNEG_HIB_PSE                             0x1000
+#define ALX_HIBNEG_DEF                                 0xBC40
+#define ALX_HIBNEG_NOHIB       (ALX_HIBNEG_DEF & \
+                                ~(ALX_HIBNEG_PSHIB_EN | ALX_HIBNEG_HIB_PSE))
+
+#define ALX_MIIDBG_TST10BTCFG                          0x12
+#define ALX_TST10BTCFG_DEF                             0x4C04
+
+#define ALX_MIIDBG_AZ_ANADECT                          0x15
+#define ALX_AZ_ANADECT_DEF                             0x3220
+#define ALX_AZ_ANADECT_LONG                            0x3210
+
+#define ALX_MIIDBG_MSE16DB                             0x18
+#define ALX_MSE16DB_UP                                 0x05EA
+#define ALX_MSE16DB_DOWN                               0x02EA
+
+#define ALX_MIIDBG_MSE20DB                             0x1C
+#define ALX_MSE20DB_TH_MASK                            0x7F
+#define ALX_MSE20DB_TH_SHIFT                           2
+#define ALX_MSE20DB_TH_DEF                             0x2E
+#define ALX_MSE20DB_TH_HI                              0x54
+
+#define ALX_MIIDBG_AGC                                 0x23
+#define ALX_AGC_2_VGA_MASK                             0x3FU
+#define ALX_AGC_2_VGA_SHIFT                            8
+#define ALX_AGC_LONG1G_LIMT                            40
+#define ALX_AGC_LONG100M_LIMT                          44
+
+#define ALX_MIIDBG_LEGCYPS                             0x29
+#define ALX_LEGCYPS_EN                                 0x8000
+#define ALX_LEGCYPS_DEF                                        0x129D
+
+#define ALX_MIIDBG_TST100BTCFG                         0x36
+#define ALX_TST100BTCFG_DEF                            0xE12C
+
+#define ALX_MIIDBG_GREENCFG                            0x3B
+#define ALX_GREENCFG_DEF                               0x7078
+
+#define ALX_MIIDBG_GREENCFG2                           0x3D
+#define ALX_GREENCFG2_BP_GREEN                         0x8000
+#define ALX_GREENCFG2_GATE_DFSE_EN                     0x0080
+
+/******* dev 3 *********/
+#define ALX_MIIEXT_PCS                                 3
+
+#define ALX_MIIEXT_CLDCTRL3                            0x8003
+#define ALX_CLDCTRL3_BP_CABLE1TH_DET_GT                        0x8000
+
+#define ALX_MIIEXT_CLDCTRL5                            0x8005
+#define ALX_CLDCTRL5_BP_VD_HLFBIAS                     0x4000
+
+#define ALX_MIIEXT_CLDCTRL6                            0x8006
+#define ALX_CLDCTRL6_CAB_LEN_MASK                      0xFF
+#define ALX_CLDCTRL6_CAB_LEN_SHIFT                     0
+#define ALX_CLDCTRL6_CAB_LEN_SHORT1G                   116
+#define ALX_CLDCTRL6_CAB_LEN_SHORT100M                 152
+
+#define ALX_MIIEXT_VDRVBIAS                            0x8062
+#define ALX_VDRVBIAS_DEF                               0x3
+
+/********* dev 7 **********/
+#define ALX_MIIEXT_ANEG                                        7
+
+#define ALX_MIIEXT_LOCAL_EEEADV                                0x3C
+#define ALX_LOCAL_EEEADV_1000BT                                0x0004
+#define ALX_LOCAL_EEEADV_100BT                         0x0002
+
+#define ALX_MIIEXT_AFE                                 0x801A
+#define ALX_AFE_10BT_100M_TH                           0x0040
+
+#define ALX_MIIEXT_S3DIG10                             0x8023
+/* bit0: 1:bypass 10BT rx fifo, 0:original 10BT rx */
+#define ALX_MIIEXT_S3DIG10_SL                          0x0001
+#define ALX_MIIEXT_S3DIG10_DEF                         0
+
+#define ALX_MIIEXT_NLP78                               0x8027
+#define ALX_MIIEXT_NLP78_120M_DEF                      0x8A05
+
+#endif
index c777b90..a13463e 100644 (file)
@@ -744,6 +744,9 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
                status = tg3_ape_read32(tp, gnt + off);
                if (status == bit)
                        break;
+               if (pci_channel_offline(tp->pdev))
+                       break;
+
                udelay(10);
        }
 
@@ -1635,6 +1638,9 @@ static void tg3_wait_for_event_ack(struct tg3 *tp)
        for (i = 0; i < delay_cnt; i++) {
                if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
                        break;
+               if (pci_channel_offline(tp->pdev))
+                       break;
+
                udelay(8);
        }
 }
@@ -1813,6 +1819,9 @@ static int tg3_poll_fw(struct tg3 *tp)
                for (i = 0; i < 200; i++) {
                        if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
                                return 0;
+                       if (pci_channel_offline(tp->pdev))
+                               return -ENODEV;
+
                        udelay(100);
                }
                return -ENODEV;
@@ -1823,6 +1832,15 @@ static int tg3_poll_fw(struct tg3 *tp)
                tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
                if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
                        break;
+               if (pci_channel_offline(tp->pdev)) {
+                       if (!tg3_flag(tp, NO_FWARE_REPORTED)) {
+                               tg3_flag_set(tp, NO_FWARE_REPORTED);
+                               netdev_info(tp->dev, "No firmware running\n");
+                       }
+
+                       break;
+               }
+
                udelay(10);
        }
 
@@ -3520,6 +3538,8 @@ static int tg3_pause_cpu(struct tg3 *tp, u32 cpu_base)
                tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
                if (tr32(cpu_base + CPU_MODE) & CPU_MODE_HALT)
                        break;
+               if (pci_channel_offline(tp->pdev))
+                       return -EBUSY;
        }
 
        return (i == iters) ? -EBUSY : 0;
@@ -8589,6 +8609,14 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, boo
        tw32_f(ofs, val);
 
        for (i = 0; i < MAX_WAIT_CNT; i++) {
+               if (pci_channel_offline(tp->pdev)) {
+                       dev_err(&tp->pdev->dev,
+                               "tg3_stop_block device offline, "
+                               "ofs=%lx enable_bit=%x\n",
+                               ofs, enable_bit);
+                       return -ENODEV;
+               }
+
                udelay(100);
                val = tr32(ofs);
                if ((val & enable_bit) == 0)
@@ -8612,6 +8640,13 @@ static int tg3_abort_hw(struct tg3 *tp, bool silent)
 
        tg3_disable_ints(tp);
 
+       if (pci_channel_offline(tp->pdev)) {
+               tp->rx_mode &= ~(RX_MODE_ENABLE | TX_MODE_ENABLE);
+               tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
+               err = -ENODEV;
+               goto err_no_dev;
+       }
+
        tp->rx_mode &= ~RX_MODE_ENABLE;
        tw32_f(MAC_RX_MODE, tp->rx_mode);
        udelay(10);
@@ -8660,6 +8695,7 @@ static int tg3_abort_hw(struct tg3 *tp, bool silent)
        err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE, silent);
        err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE, silent);
 
+err_no_dev:
        for (i = 0; i < tp->irq_cnt; i++) {
                struct tg3_napi *tnapi = &tp->napi[i];
                if (tnapi->hw_status)
index a667015..d48099f 100644 (file)
@@ -516,6 +516,7 @@ fec_restart(struct net_device *ndev, int duplex)
        /* Set MII speed */
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
+#if !defined(CONFIG_M5272)
        /* set RX checksum */
        val = readl(fep->hwp + FEC_RACC);
        if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
@@ -523,6 +524,7 @@ fec_restart(struct net_device *ndev, int duplex)
        else
                val &= ~FEC_RACC_OPTIONS;
        writel(val, fep->hwp + FEC_RACC);
+#endif
 
        /*
         * The phy interface and speed need to get configured
@@ -575,6 +577,7 @@ fec_restart(struct net_device *ndev, int duplex)
 #endif
        }
 
+#if !defined(CONFIG_M5272)
        /* enable pause frame*/
        if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
            ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
@@ -592,6 +595,7 @@ fec_restart(struct net_device *ndev, int duplex)
        } else {
                rcntl &= ~FEC_ENET_FCE;
        }
+#endif /* !defined(CONFIG_M5272) */
 
        writel(rcntl, fep->hwp + FEC_R_CNTRL);
 
@@ -1205,7 +1209,9 @@ static int fec_enet_mii_probe(struct net_device *ndev)
        /* mask with MAC supported features */
        if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
                phy_dev->supported &= PHY_GBIT_FEATURES;
+#if !defined(CONFIG_M5272)
                phy_dev->supported |= SUPPORTED_Pause;
+#endif
        }
        else
                phy_dev->supported &= PHY_BASIC_FEATURES;
@@ -1390,6 +1396,8 @@ static int fec_enet_get_ts_info(struct net_device *ndev,
        }
 }
 
+#if !defined(CONFIG_M5272)
+
 static void fec_enet_get_pauseparam(struct net_device *ndev,
                                    struct ethtool_pauseparam *pause)
 {
@@ -1436,9 +1444,13 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
        return 0;
 }
 
+#endif /* !defined(CONFIG_M5272) */
+
 static const struct ethtool_ops fec_enet_ethtool_ops = {
+#if !defined(CONFIG_M5272)
        .get_pauseparam         = fec_enet_get_pauseparam,
        .set_pauseparam         = fec_enet_set_pauseparam,
+#endif
        .get_settings           = fec_enet_get_settings,
        .set_settings           = fec_enet_set_settings,
        .get_drvinfo            = fec_enet_get_drvinfo,
@@ -1874,10 +1886,12 @@ fec_probe(struct platform_device *pdev)
        /* setup board info structure */
        fep = netdev_priv(ndev);
 
+#if !defined(CONFIG_M5272)
        /* default enable pause frame auto negotiation */
        if (pdev->id_entry &&
            (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
                fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
+#endif
 
        fep->hwp = devm_request_and_ioremap(&pdev->dev, r);
        fep->pdev = pdev;
index 2ad1494..d1cbfb1 100644 (file)
@@ -1757,7 +1757,7 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index)
        memset(rxq->rx_desc_area, 0, size);
 
        rxq->rx_desc_area_size = size;
-       rxq->rx_skb = kmalloc_array(rxq->rx_ring_size, sizeof(*rxq->rx_skb),
+       rxq->rx_skb = kcalloc(rxq->rx_ring_size, sizeof(*rxq->rx_skb),
                                    GFP_KERNEL);
        if (rxq->rx_skb == NULL)
                goto out_free;
index 339bb32..1c8af8b 100644 (file)
@@ -1015,7 +1015,7 @@ static int rxq_init(struct net_device *dev)
        int rx_desc_num = pep->rx_ring_size;
 
        /* Allocate RX skb rings */
-       pep->rx_skb = kmalloc(sizeof(*pep->rx_skb) * pep->rx_ring_size,
+       pep->rx_skb = kzalloc(sizeof(*pep->rx_skb) * pep->rx_ring_size,
                             GFP_KERNEL);
        if (!pep->rx_skb)
                return -ENOMEM;
@@ -1076,7 +1076,7 @@ static int txq_init(struct net_device *dev)
        int size = 0, i = 0;
        int tx_desc_num = pep->tx_ring_size;
 
-       pep->tx_skb = kmalloc(sizeof(*pep->tx_skb) * pep->tx_ring_size,
+       pep->tx_skb = kzalloc(sizeof(*pep->tx_skb) * pep->tx_ring_size,
                             GFP_KERNEL);
        if (!pep->tx_skb)
                return -ENOMEM;
index 2f4a260..8a43499 100644 (file)
@@ -632,6 +632,9 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
                dev->caps.cqe_size   = 32;
        }
 
+       dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS;
+       mlx4_warn(dev, "Timestamping is not supported in slave mode.\n");
+
        slave_adjust_steering_mode(dev, &dev_cap, &hca_param);
 
        return 0;
index 921729f..91a8a5d 100644 (file)
 union mgmt_port_ring_entry {
        u64 d64;
        struct {
-               u64    reserved_62_63:2;
+#define RING_ENTRY_CODE_DONE 0xf
+#define RING_ENTRY_CODE_MORE 0x10
+#ifdef __BIG_ENDIAN_BITFIELD
+               u64 reserved_62_63:2;
                /* Length of the buffer/packet in bytes */
-               u64    len:14;
+               u64 len:14;
                /* For TX, signals that the packet should be timestamped */
-               u64    tstamp:1;
+               u64 tstamp:1;
                /* The RX error code */
-               u64    code:7;
-#define RING_ENTRY_CODE_DONE 0xf
-#define RING_ENTRY_CODE_MORE 0x10
+               u64 code:7;
                /* Physical address of the buffer */
-               u64    addr:40;
+               u64 addr:40;
+#else
+               u64 addr:40;
+               u64 code:7;
+               u64 tstamp:1;
+               u64 len:14;
+               u64 reserved_62_63:2;
+#endif
        } s;
 };
 
@@ -1141,10 +1149,13 @@ static int octeon_mgmt_open(struct net_device *netdev)
                /* For compensation state to lock. */
                ndelay(1040 * NS_PER_PHY_CLK);
 
-               /* Some Ethernet switches cannot handle standard
-                * Interframe Gap, increase to 16 bytes.
+               /* Default Interframe Gaps are too small.  Recommended
+                * workaround is.
+                *
+                * AGL_GMX_TX_IFG[IFG1]=14
+                * AGL_GMX_TX_IFG[IFG2]=10
                 */
-               cvmx_write_csr(CVMX_AGL_GMX_TX_IFG, 0x88);
+               cvmx_write_csr(CVMX_AGL_GMX_TX_IFG, 0xae);
        }
 
        octeon_mgmt_rx_fill_ring(netdev);
index 43562c2..6acf82b 100644 (file)
@@ -642,7 +642,7 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
                                qlcnic_83xx_config_intrpt(adapter, 0);
                }
                /* Allow dma queues to drain after context reset */
-               msleep(20);
+               mdelay(20);
        }
 }
 
index 5e3982f..e29fe8d 100644 (file)
@@ -380,8 +380,9 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
        .eesipr_value   = 0x01ff009f,
 
        .tx_check       = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
-       .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
-                         EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
+       .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
+                         EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE |
+                         EESR_ECI,
        .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
 
        .apr            = 1,
@@ -427,8 +428,9 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
        .eesipr_value   = DMAC_M_RFRMER | DMAC_M_ECI | 0x01ff009f,
 
        .tx_check       = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
-       .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
-                         EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
+       .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
+                         EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE |
+                         EESR_ECI,
        .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
 
        .apr            = 1,
@@ -478,8 +480,9 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
        .rmcr_value     = 0x00000001,
 
        .tx_check       = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
-       .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
-                         EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
+       .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
+                         EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE |
+                         EESR_ECI,
        .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
 
        .apr            = 1,
@@ -592,9 +595,9 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data_giga = {
        .eesipr_value   = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
 
        .tx_check       = EESR_TC1 | EESR_FTC,
-       .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
-                         EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
-                         EESR_ECI,
+       .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
+                         EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
+                         EESR_TDE | EESR_ECI,
        .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
                          EESR_TFE,
        .fdr_value      = 0x0000072f,
@@ -674,9 +677,9 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
        .eesipr_value   = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
 
        .tx_check       = EESR_TC1 | EESR_FTC,
-       .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
-                         EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
-                         EESR_ECI,
+       .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
+                         EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
+                         EESR_TDE | EESR_ECI,
        .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
                          EESR_TFE,
 
@@ -811,9 +814,9 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
        .eesipr_value   = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
 
        .tx_check       = EESR_TC1 | EESR_FTC,
-       .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
-                         EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
-                         EESR_ECI,
+       .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
+                         EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
+                         EESR_TDE | EESR_ECI,
        .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
                          EESR_TFE,
 
@@ -1549,11 +1552,12 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
 
 ignore_link:
        if (intr_status & EESR_TWB) {
-               /* Write buck end. unused write back interrupt */
-               if (intr_status & EESR_TABT)    /* Transmit Abort int */
+               /* Unused write back interrupt */
+               if (intr_status & EESR_TABT) {  /* Transmit Abort int */
                        ndev->stats.tx_aborted_errors++;
                        if (netif_msg_tx_err(mdp))
                                dev_err(&ndev->dev, "Transmit Abort\n");
+               }
        }
 
        if (intr_status & EESR_RABT) {
index 1ddc9f2..62689a5 100644 (file)
@@ -253,7 +253,7 @@ enum EESR_BIT {
 
 #define DEFAULT_TX_CHECK       (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | \
                                 EESR_RTO)
-#define DEFAULT_EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | \
+#define DEFAULT_EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE | \
                                 EESR_RDE | EESR_RFRMER | EESR_ADE | \
                                 EESR_TFE | EESR_TDE | EESR_ECI)
 #define DEFAULT_TX_ERROR_CHECK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | \
index 39e4cb3..4a14a94 100644 (file)
@@ -2139,7 +2139,7 @@ show_phy_type(struct device *dev, struct device_attribute *attr, char *buf)
        struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
        return sprintf(buf, "%d\n", efx->phy_type);
 }
-static DEVICE_ATTR(phy_type, 0644, show_phy_type, NULL);
+static DEVICE_ATTR(phy_type, 0444, show_phy_type, NULL);
 
 static int efx_register_netdev(struct efx_nic *efx)
 {
index 7788fbe..9517697 100644 (file)
@@ -297,8 +297,8 @@ struct dma_features {
 #define MAC_RNABLE_RX          0x00000004      /* Receiver Enable */
 
 /* Default LPI timers */
-#define STMMAC_DEFAULT_LIT_LS_TIMER    0x3E8
-#define STMMAC_DEFAULT_TWT_LS_TIMER    0x0
+#define STMMAC_DEFAULT_LIT_LS  0x3E8
+#define STMMAC_DEFAULT_TWT_LS  0x0
 
 #define STMMAC_CHAIN_MODE      0x1
 #define STMMAC_RING_MODE       0x2
index ee919ca..e9eab29 100644 (file)
@@ -130,7 +130,7 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
 static int eee_timer = STMMAC_DEFAULT_LPI_TIMER;
 module_param(eee_timer, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
-#define STMMAC_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x))
+#define STMMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x))
 
 /* By default the driver will use the ring mode to manage tx and rx descriptors
  * but passing this value so user can force to use the chain instead of the ring
@@ -288,7 +288,7 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)
        struct stmmac_priv *priv = (struct stmmac_priv *)arg;
 
        stmmac_enable_eee_mode(priv);
-       mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_TIMER(eee_timer));
+       mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
 }
 
 /**
@@ -304,22 +304,34 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 {
        bool ret = false;
 
+       /* Using PCS we cannot dial with the phy registers at this stage
+        * so we do not support extra feature like EEE.
+        */
+       if ((priv->pcs == STMMAC_PCS_RGMII) || (priv->pcs == STMMAC_PCS_TBI) ||
+           (priv->pcs == STMMAC_PCS_RTBI))
+               goto out;
+
        /* MAC core supports the EEE feature. */
        if (priv->dma_cap.eee) {
                /* Check if the PHY supports EEE */
                if (phy_init_eee(priv->phydev, 1))
                        goto out;
 
-               priv->eee_active = 1;
-               init_timer(&priv->eee_ctrl_timer);
-               priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
-               priv->eee_ctrl_timer.data = (unsigned long)priv;
-               priv->eee_ctrl_timer.expires = STMMAC_LPI_TIMER(eee_timer);
-               add_timer(&priv->eee_ctrl_timer);
-
-               priv->hw->mac->set_eee_timer(priv->ioaddr,
-                                            STMMAC_DEFAULT_LIT_LS_TIMER,
-                                            priv->tx_lpi_timer);
+               if (!priv->eee_active) {
+                       priv->eee_active = 1;
+                       init_timer(&priv->eee_ctrl_timer);
+                       priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
+                       priv->eee_ctrl_timer.data = (unsigned long)priv;
+                       priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer);
+                       add_timer(&priv->eee_ctrl_timer);
+
+                       priv->hw->mac->set_eee_timer(priv->ioaddr,
+                                                    STMMAC_DEFAULT_LIT_LS,
+                                                    priv->tx_lpi_timer);
+               } else
+                       /* Set HW EEE according to the speed */
+                       priv->hw->mac->set_eee_pls(priv->ioaddr,
+                                                  priv->phydev->link);
 
                pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
 
@@ -329,20 +341,6 @@ out:
        return ret;
 }
 
-/**
- * stmmac_eee_adjust: adjust HW EEE according to the speed
- * @priv: driver private structure
- * Description:
- *     When the EEE has been already initialised we have to
- *     modify the PLS bit in the LPI ctrl & status reg according
- *     to the PHY link status. For this reason.
- */
-static void stmmac_eee_adjust(struct stmmac_priv *priv)
-{
-       if (priv->eee_enabled)
-               priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
-}
-
 /* stmmac_get_tx_hwtstamp: get HW TX timestamps
  * @priv: driver private structure
  * @entry : descriptor index to be used.
@@ -769,7 +767,10 @@ static void stmmac_adjust_link(struct net_device *dev)
        if (new_state && netif_msg_link(priv))
                phy_print_status(phydev);
 
-       stmmac_eee_adjust(priv);
+       /* At this stage, it could be needed to setup the EEE or adjust some
+        * MAC related HW registers.
+        */
+       priv->eee_enabled = stmmac_eee_init(priv);
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1277,7 +1278,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
 
        if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
                stmmac_enable_eee_mode(priv);
-               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_TIMER(eee_timer));
+               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
        }
        spin_unlock(&priv->tx_lock);
 }
@@ -1671,14 +1672,9 @@ static int stmmac_open(struct net_device *dev)
        if (priv->phydev)
                phy_start(priv->phydev);
 
-       priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER;
+       priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
 
-       /* Using PCS we cannot dial with the phy registers at this stage
-        * so we do not support extra feature like EEE.
-        */
-       if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
-           priv->pcs != STMMAC_PCS_RTBI)
-               priv->eee_enabled = stmmac_eee_init(priv);
+       priv->eee_enabled = stmmac_eee_init(priv);
 
        stmmac_init_tx_coalesce(priv);
 
index 21a5b29..d1a769f 100644 (file)
@@ -1679,7 +1679,7 @@ static int cpsw_probe(struct platform_device *pdev)
        priv->rx_packet_max = max(rx_packet_max, 128);
        priv->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL);
        priv->irq_enabled = true;
-       if (!ndev) {
+       if (!priv->cpts) {
                pr_err("error allocating cpts\n");
                goto clean_ndev_ret;
        }
@@ -1973,9 +1973,12 @@ static int cpsw_suspend(struct device *dev)
 {
        struct platform_device  *pdev = to_platform_device(dev);
        struct net_device       *ndev = platform_get_drvdata(pdev);
+       struct cpsw_priv        *priv = netdev_priv(ndev);
 
        if (netif_running(ndev))
                cpsw_ndo_stop(ndev);
+       soft_reset("sliver 0", &priv->slaves[0].sliver->soft_reset);
+       soft_reset("sliver 1", &priv->slaves[1].sliver->soft_reset);
        pm_runtime_put_sync(&pdev->dev);
 
        return 0;
index 49dfd59..053c84f 100644 (file)
@@ -705,6 +705,13 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
        }
 
        buffer = dma_map_single(ctlr->dev, data, len, chan->dir);
+       ret = dma_mapping_error(ctlr->dev, buffer);
+       if (ret) {
+               cpdma_desc_free(ctlr->pool, desc, 1);
+               ret = -EINVAL;
+               goto unlock_ret;
+       }
+
        mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
        cpdma_desc_to_port(chan, mode, directed);
 
index ab2307b..4dccead 100644 (file)
@@ -285,7 +285,9 @@ int netvsc_recv_callback(struct hv_device *device_obj,
 
        skb->protocol = eth_type_trans(skb, net);
        skb->ip_summed = CHECKSUM_NONE;
-       __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), packet->vlan_tci);
+       if (packet->vlan_tci & VLAN_TAG_PRESENT)
+               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+                                      packet->vlan_tci);
 
        net->stats.rx_packets++;
        net->stats.rx_bytes += packet->total_data_buflen;
index 59e9605..b6dd6a7 100644 (file)
@@ -524,8 +524,10 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
                        return -EMSGSIZE;
                num_pages = get_user_pages_fast(base, size, 0, &page[i]);
                if (num_pages != size) {
-                       for (i = 0; i < num_pages; i++)
-                               put_page(page[i]);
+                       int j;
+
+                       for (j = 0; j < num_pages; j++)
+                               put_page(page[i + j]);
                        return -EFAULT;
                }
                truesize = size * PAGE_SIZE;
index bfa9bb4..9c61f87 100644 (file)
@@ -1010,8 +1010,10 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
                        return -EMSGSIZE;
                num_pages = get_user_pages_fast(base, size, 0, &page[i]);
                if (num_pages != size) {
-                       for (i = 0; i < num_pages; i++)
-                               put_page(page[i]);
+                       int j;
+
+                       for (j = 0; j < num_pages; j++)
+                               put_page(page[i + j]);
                        return -EFAULT;
                }
                truesize = size * PAGE_SIZE;
index d095d0d..5645921 100644 (file)
@@ -590,7 +590,13 @@ static const struct usb_device_id products[] = {
        {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)},    /* HP un2400 Gobi Modem Device */
        {QMI_GOBI1K_DEVICE(0x04da, 0x250d)},    /* Panasonic Gobi Modem device */
        {QMI_GOBI1K_DEVICE(0x413c, 0x8172)},    /* Dell Gobi Modem device */
-       {QMI_GOBI1K_DEVICE(0x1410, 0xa001)},    /* Novatel Gobi Modem device */
+       {QMI_GOBI1K_DEVICE(0x1410, 0xa001)},    /* Novatel/Verizon USB-1000 */
+       {QMI_GOBI1K_DEVICE(0x1410, 0xa002)},    /* Novatel Gobi Modem device */
+       {QMI_GOBI1K_DEVICE(0x1410, 0xa003)},    /* Novatel Gobi Modem device */
+       {QMI_GOBI1K_DEVICE(0x1410, 0xa004)},    /* Novatel Gobi Modem device */
+       {QMI_GOBI1K_DEVICE(0x1410, 0xa005)},    /* Novatel Gobi Modem device */
+       {QMI_GOBI1K_DEVICE(0x1410, 0xa006)},    /* Novatel Gobi Modem device */
+       {QMI_GOBI1K_DEVICE(0x1410, 0xa007)},    /* Novatel Gobi Modem device */
        {QMI_GOBI1K_DEVICE(0x0b05, 0x1776)},    /* Asus Gobi Modem device */
        {QMI_GOBI1K_DEVICE(0x19d2, 0xfff3)},    /* ONDA Gobi Modem device */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9001)},    /* Generic Gobi Modem device */
index 3b1d2ee..57325f3 100644 (file)
@@ -565,18 +565,22 @@ skip:
 
 /* Watch incoming packets to learn mapping between Ethernet address
  * and Tunnel endpoint.
+ * Return true if packet is bogus and should be droppped.
  */
-static void vxlan_snoop(struct net_device *dev,
+static bool vxlan_snoop(struct net_device *dev,
                        __be32 src_ip, const u8 *src_mac)
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_fdb *f;
-       int err;
 
        f = vxlan_find_mac(vxlan, src_mac);
        if (likely(f)) {
                if (likely(f->remote.remote_ip == src_ip))
-                       return;
+                       return false;
+
+               /* Don't migrate static entries, drop packets */
+               if (f->state & NUD_NOARP)
+                       return true;
 
                if (net_ratelimit())
                        netdev_info(dev,
@@ -588,14 +592,19 @@ static void vxlan_snoop(struct net_device *dev,
        } else {
                /* learned new entry */
                spin_lock(&vxlan->hash_lock);
-               err = vxlan_fdb_create(vxlan, src_mac, src_ip,
-                                      NUD_REACHABLE,
-                                      NLM_F_EXCL|NLM_F_CREATE,
-                                      vxlan->dst_port,
-                                      vxlan->default_dst.remote_vni,
-                                      0, NTF_SELF);
+
+               /* close off race between vxlan_flush and incoming packets */
+               if (netif_running(dev))
+                       vxlan_fdb_create(vxlan, src_mac, src_ip,
+                                        NUD_REACHABLE,
+                                        NLM_F_EXCL|NLM_F_CREATE,
+                                        vxlan->dst_port,
+                                        vxlan->default_dst.remote_vni,
+                                        0, NTF_SELF);
                spin_unlock(&vxlan->hash_lock);
        }
+
+       return false;
 }
 
 
@@ -727,8 +736,9 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                               vxlan->dev->dev_addr) == 0)
                goto drop;
 
-       if (vxlan->flags & VXLAN_F_LEARN)
-               vxlan_snoop(skb->dev, oip->saddr, eth_hdr(skb)->h_source);
+       if ((vxlan->flags & VXLAN_F_LEARN) &&
+           vxlan_snoop(skb->dev, oip->saddr, eth_hdr(skb)->h_source))
+               goto drop;
 
        __skb_tunnel_rx(skb, vxlan->dev);
        skb_reset_network_header(skb);
@@ -1151,9 +1161,11 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
                struct sk_buff *skb1;
 
                skb1 = skb_clone(skb, GFP_ATOMIC);
-               rc1 = vxlan_xmit_one(skb1, dev, rdst, did_rsc);
-               if (rc == NETDEV_TX_OK)
-                       rc = rc1;
+               if (skb1) {
+                       rc1 = vxlan_xmit_one(skb1, dev, rdst, did_rsc);
+                       if (rc == NETDEV_TX_OK)
+                               rc = rc1;
+               }
        }
 
        rc1 = vxlan_xmit_one(skb, dev, rdst0, did_rsc);
index 147614e..6a8a382 100644 (file)
@@ -384,21 +384,37 @@ static int dlci_del(struct dlci_add *dlci)
        struct frad_local       *flp;
        struct net_device       *master, *slave;
        int                     err;
+       bool                    found = false;
+
+       rtnl_lock();
 
        /* validate slave device */
        master = __dev_get_by_name(&init_net, dlci->devname);
-       if (!master)
-               return -ENODEV;
+       if (!master) {
+               err = -ENODEV;
+               goto out;
+       }
+
+       list_for_each_entry(dlp, &dlci_devs, list) {
+               if (dlp->master == master) {
+                       found = true;
+                       break;
+               }
+       }
+       if (!found) {
+               err = -ENODEV;
+               goto out;
+       }
 
        if (netif_running(master)) {
-               return -EBUSY;
+               err = -EBUSY;
+               goto out;
        }
 
        dlp = netdev_priv(master);
        slave = dlp->slave;
        flp = netdev_priv(slave);
 
-       rtnl_lock();
        err = (*flp->deassoc)(slave, master);
        if (!err) {
                list_del(&dlp->list);
@@ -407,8 +423,8 @@ static int dlci_del(struct dlci_add *dlci)
 
                dev_put(slave);
        }
+out:
        rtnl_unlock();
-
        return err;
 }
 
index 0743a47..62f1b76 100644 (file)
@@ -1174,7 +1174,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                mutex_lock(&priv->htc_pm_lock);
 
                priv->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
-               if (priv->ps_idle)
+               if (!priv->ps_idle)
                        chip_reset = true;
 
                mutex_unlock(&priv->htc_pm_lock);
index 1c9b1ba..83ab6be 100644 (file)
@@ -1570,6 +1570,8 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
            txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
                return;
 
+       rcu_read_lock();
+
        ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
        last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);
 
@@ -1608,8 +1610,10 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
 
                if (ac == last_ac ||
                    txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
-                       return;
+                       break;
        }
+
+       rcu_read_unlock();
 }
 
 /***********/
index b98f223..2c59357 100644 (file)
@@ -930,6 +930,10 @@ fail:
                        brcmf_fws_del_interface(ifp);
                        brcmf_fws_deinit(drvr);
                }
+               if (drvr->iflist[0]) {
+                       free_netdev(ifp->ndev);
+                       drvr->iflist[0] = NULL;
+               }
                if (p2p_ifp) {
                        free_netdev(p2p_ifp->ndev);
                        drvr->iflist[1] = NULL;
index 28e7aee..9fd6f2f 100644 (file)
@@ -3074,21 +3074,8 @@ static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
  */
 static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
 {
-       /* disallow PS when one of the following global conditions meets */
-       if (!wlc->pub->associated)
-               return false;
-
-       /* disallow PS when one of these meets when not scanning */
-       if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
-               return false;
-
-       if (wlc->bsscfg->type == BRCMS_TYPE_AP)
-               return false;
-
-       if (wlc->bsscfg->type == BRCMS_TYPE_ADHOC)
-               return false;
-
-       return true;
+       /* not supporting PS so always return false for now */
+       return false;
 }
 
 static void brcms_c_statsupd(struct brcms_c_info *wlc)
index c9f197d..fe31590 100644 (file)
@@ -816,6 +816,7 @@ out:
                rs_sta->last_txrate_idx = idx;
                info->control.rates[0].idx = rs_sta->last_txrate_idx;
        }
+       info->control.rates[0].count = 1;
 
        D_RATE("leave: %d\n", idx);
 }
index 1fc0b22..ed3c42a 100644 (file)
@@ -2268,7 +2268,7 @@ il4965_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta,
                info->control.rates[0].flags = 0;
        }
        info->control.rates[0].idx = rate_idx;
-
+       info->control.rates[0].count = 1;
 }
 
 static void *
index 907bd6e..10fbb17 100644 (file)
@@ -2799,7 +2799,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
                info->control.rates[0].flags = 0;
        }
        info->control.rates[0].idx = rate_idx;
-
+       info->control.rates[0].count = 1;
 }
 
 static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
index 707446f..cd1ad00 100644 (file)
@@ -1378,7 +1378,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
        struct iwl_chain_noise_data *data = &priv->chain_noise_data;
        int ret;
 
-       if (!(priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED))
+       if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED)
                return;
 
        if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
index 39aad98..40fed1f 100644 (file)
@@ -1000,10 +1000,12 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
         */
        if (load_module) {
                err = request_module("%s", op->name);
+#ifdef CONFIG_IWLWIFI_OPMODE_MODULAR
                if (err)
                        IWL_ERR(drv,
                                "failed to load module %s (error %d), is dynamic loading enabled?\n",
                                op->name, err);
+#endif
        }
        return;
 
index 55334d5..b99fe31 100644 (file)
@@ -2546,6 +2546,7 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
                info->control.rates[0].flags = 0;
        }
        info->control.rates[0].idx = rate_idx;
+       info->control.rates[0].count = 1;
 }
 
 static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
index f212f16..48c1891 100644 (file)
@@ -180,7 +180,8 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
                tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
                return;
        } else if (ieee80211_is_back_req(fc)) {
-               tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
+               tx_cmd->tx_flags |=
+                       cpu_to_le32(TX_CMD_FLG_ACK | TX_CMD_FLG_BAR);
        }
 
        /* HT rate doesn't make sense for a non data frame */
index b52d70c..72f32e5 100644 (file)
@@ -3027,19 +3027,26 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
         * TODO: we do not use +6 dBm option to do not increase power beyond
         * regulatory limit, however this could be utilized for devices with
         * CAPABILITY_POWER_LIMIT.
+        *
+        * TODO: add different temperature compensation code for RT3290 & RT5390
+        * to allow to use BBP_R1 for those chips.
         */
-       rt2800_bbp_read(rt2x00dev, 1, &r1);
-       if (delta <= -12) {
-               power_ctrl = 2;
-               delta += 12;
-       } else if (delta <= -6) {
-               power_ctrl = 1;
-               delta += 6;
-       } else {
-               power_ctrl = 0;
+       if (!rt2x00_rt(rt2x00dev, RT3290) &&
+           !rt2x00_rt(rt2x00dev, RT5390)) {
+               rt2800_bbp_read(rt2x00dev, 1, &r1);
+               if (delta <= -12) {
+                       power_ctrl = 2;
+                       delta += 12;
+               } else if (delta <= -6) {
+                       power_ctrl = 1;
+                       delta += 6;
+               } else {
+                       power_ctrl = 0;
+               }
+               rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl);
+               rt2800_bbp_write(rt2x00dev, 1, r1);
        }
-       rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl);
-       rt2800_bbp_write(rt2x00dev, 1, r1);
+
        offset = TX_PWR_CFG_0;
 
        for (i = 0; i < EEPROM_TXPOWER_BYRATE_SIZE; i += 2) {
index 716aa93..59df857 100644 (file)
@@ -61,6 +61,7 @@ static DEFINE_MUTEX(bridge_mutex);
 static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
 static void acpiphp_sanitize_bus(struct pci_bus *bus);
 static void acpiphp_set_hpp_values(struct pci_bus *bus);
+static void hotplug_event_func(acpi_handle handle, u32 type, void *context);
 static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
 static void free_bridge(struct kref *kref);
 
@@ -147,7 +148,7 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
 
 
 static const struct acpi_dock_ops acpiphp_dock_ops = {
-       .handler = handle_hotplug_event_func,
+       .handler = hotplug_event_func,
 };
 
 /* Check whether the PCI device is managed by native PCIe hotplug driver */
@@ -179,6 +180,20 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
        return true;
 }
 
+static void acpiphp_dock_init(void *data)
+{
+       struct acpiphp_func *func = data;
+
+       get_bridge(func->slot->bridge);
+}
+
+static void acpiphp_dock_release(void *data)
+{
+       struct acpiphp_func *func = data;
+
+       put_bridge(func->slot->bridge);
+}
+
 /* callback routine to register each ACPI PCI slot object */
 static acpi_status
 register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -298,7 +313,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
                 */
                newfunc->flags &= ~FUNC_HAS_EJ0;
                if (register_hotplug_dock_device(handle,
-                       &acpiphp_dock_ops, newfunc))
+                       &acpiphp_dock_ops, newfunc,
+                       acpiphp_dock_init, acpiphp_dock_release))
                        dbg("failed to register dock device\n");
 
                /* we need to be notified when dock events happen
@@ -670,6 +686,7 @@ static int __ref enable_device(struct acpiphp_slot *slot)
        struct pci_bus *bus = slot->bridge->pci_bus;
        struct acpiphp_func *func;
        int num, max, pass;
+       LIST_HEAD(add_list);
 
        if (slot->flags & SLOT_ENABLED)
                goto err_exit;
@@ -694,13 +711,15 @@ static int __ref enable_device(struct acpiphp_slot *slot)
                                max = pci_scan_bridge(bus, dev, max, pass);
                                if (pass && dev->subordinate) {
                                        check_hotplug_bridge(slot, dev);
-                                       pci_bus_size_bridges(dev->subordinate);
+                                       pcibios_resource_survey_bus(dev->subordinate);
+                                       __pci_bus_size_bridges(dev->subordinate,
+                                                              &add_list);
                                }
                        }
                }
        }
 
-       pci_bus_assign_resources(bus);
+       __pci_bus_assign_resources(bus, &add_list, NULL);
        acpiphp_sanitize_bus(bus);
        acpiphp_set_hpp_values(bus);
        acpiphp_set_acpi_region(slot);
@@ -1065,22 +1084,12 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
        alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
 }
 
-static void _handle_hotplug_event_func(struct work_struct *work)
+static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
 {
-       struct acpiphp_func *func;
+       struct acpiphp_func *func = context;
        char objname[64];
        struct acpi_buffer buffer = { .length = sizeof(objname),
                                      .pointer = objname };
-       struct acpi_hp_work *hp_work;
-       acpi_handle handle;
-       u32 type;
-
-       hp_work = container_of(work, struct acpi_hp_work, work);
-       handle = hp_work->handle;
-       type = hp_work->type;
-       func = (struct acpiphp_func *)hp_work->context;
-
-       acpi_scan_lock_acquire();
 
        acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1113,6 +1122,18 @@ static void _handle_hotplug_event_func(struct work_struct *work)
                warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
                break;
        }
+}
+
+static void _handle_hotplug_event_func(struct work_struct *work)
+{
+       struct acpi_hp_work *hp_work;
+       struct acpiphp_func *func;
+
+       hp_work = container_of(work, struct acpi_hp_work, work);
+       func = hp_work->context;
+       acpi_scan_lock_acquire();
+
+       hotplug_event_func(hp_work->handle, hp_work->type, func);
 
        acpi_scan_lock_release();
        kfree(hp_work); /* allocated in handle_hotplug_event_func */
index 68678ed..d1182c4 100644 (file)
@@ -202,6 +202,11 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                    struct resource *res, unsigned int reg);
 int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type);
 void pci_configure_ari(struct pci_dev *dev);
+void __ref __pci_bus_size_bridges(struct pci_bus *bus,
+                       struct list_head *realloc_head);
+void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
+                                     struct list_head *realloc_head,
+                                     struct list_head *fail_head);
 
 /**
  * pci_ari_enabled - query ARI forwarding status
index 16abaaa..d254e23 100644 (file)
@@ -1044,7 +1044,7 @@ handle_done:
        ;
 }
 
-static void __ref __pci_bus_size_bridges(struct pci_bus *bus,
+void __ref __pci_bus_size_bridges(struct pci_bus *bus,
                        struct list_head *realloc_head)
 {
        struct pci_dev *dev;
@@ -1115,9 +1115,9 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
-static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
-                                        struct list_head *realloc_head,
-                                        struct list_head *fail_head)
+void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
+                                     struct list_head *realloc_head,
+                                     struct list_head *fail_head)
 {
        struct pci_bus *b;
        struct pci_dev *dev;
index d8fa37d..2c9155b 100644 (file)
@@ -439,7 +439,7 @@ static int tps6586x_regulator_remove(struct platform_device *pdev)
 
 static struct platform_driver tps6586x_regulator_driver = {
        .driver = {
-               .name   = "tps6586x-pmic",
+               .name   = "tps6586x-regulator",
                .owner  = THIS_MODULE,
        },
        .probe          = tps6586x_regulator_probe,
index 292b24f..32ae6c6 100644 (file)
@@ -1656,9 +1656,12 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
 
        if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN &&
            fcoe->realdev->features & NETIF_F_HW_VLAN_CTAG_TX) {
-               skb->vlan_tci = VLAN_TAG_PRESENT |
-                               vlan_dev_vlan_id(fcoe->netdev);
+               /* must set skb->dev before calling vlan_put_tag */
                skb->dev = fcoe->realdev;
+               skb = __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+                                            vlan_dev_vlan_id(fcoe->netdev));
+               if (!skb)
+                       return -ENOMEM;
        } else
                skb->dev = fcoe->netdev;
 
index cd743c5..795843d 100644 (file)
@@ -1548,9 +1548,6 @@ static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip)
 {
        struct fcoe_fcf *fcf;
        struct fcoe_fcf *best = fip->sel_fcf;
-       struct fcoe_fcf *first;
-
-       first = list_first_entry(&fip->fcfs, struct fcoe_fcf, list);
 
        list_for_each_entry(fcf, &fip->fcfs, list) {
                LIBFCOE_FIP_DBG(fip, "consider FCF fab %16.16llx "
@@ -1568,17 +1565,15 @@ static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip)
                                        "" : "un");
                        continue;
                }
-               if (fcf->fabric_name != first->fabric_name ||
-                   fcf->vfid != first->vfid ||
-                   fcf->fc_map != first->fc_map) {
+               if (!best || fcf->pri < best->pri || best->flogi_sent)
+                       best = fcf;
+               if (fcf->fabric_name != best->fabric_name ||
+                   fcf->vfid != best->vfid ||
+                   fcf->fc_map != best->fc_map) {
                        LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
                                        "or FC-MAP\n");
                        return NULL;
                }
-               if (fcf->flogi_sent)
-                       continue;
-               if (!best || fcf->pri < best->pri || best->flogi_sent)
-                       best = fcf;
        }
        fip->sel_fcf = best;
        if (best) {
index 82a3c1e..6c4cedb 100644 (file)
@@ -8980,19 +8980,6 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
        if (!ioa_cfg->res_entries)
                goto out;
 
-       if (ioa_cfg->sis64) {
-               ioa_cfg->target_ids = kzalloc(sizeof(unsigned long) *
-                                             BITS_TO_LONGS(ioa_cfg->max_devs_supported), GFP_KERNEL);
-               ioa_cfg->array_ids = kzalloc(sizeof(unsigned long) *
-                                            BITS_TO_LONGS(ioa_cfg->max_devs_supported), GFP_KERNEL);
-               ioa_cfg->vset_ids = kzalloc(sizeof(unsigned long) *
-                                           BITS_TO_LONGS(ioa_cfg->max_devs_supported), GFP_KERNEL);
-
-               if (!ioa_cfg->target_ids || !ioa_cfg->array_ids
-                       || !ioa_cfg->vset_ids)
-                       goto out_free_res_entries;
-       }
-
        for (i = 0; i < ioa_cfg->max_devs_supported; i++) {
                list_add_tail(&ioa_cfg->res_entries[i].queue, &ioa_cfg->free_res_q);
                ioa_cfg->res_entries[i].ioa_cfg = ioa_cfg;
@@ -9089,9 +9076,6 @@ out_free_vpd_cbs:
                            ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma);
 out_free_res_entries:
        kfree(ioa_cfg->res_entries);
-       kfree(ioa_cfg->target_ids);
-       kfree(ioa_cfg->array_ids);
-       kfree(ioa_cfg->vset_ids);
        goto out;
 }
 
index a1fb840..07a85ce 100644 (file)
@@ -1440,9 +1440,9 @@ struct ipr_ioa_cfg {
        /*
         * Bitmaps for SIS64 generated target values
         */
-       unsigned long *target_ids;
-       unsigned long *array_ids;
-       unsigned long *vset_ids;
+       unsigned long target_ids[BITS_TO_LONGS(IPR_MAX_SIS64_DEVS)];
+       unsigned long array_ids[BITS_TO_LONGS(IPR_MAX_SIS64_DEVS)];
+       unsigned long vset_ids[BITS_TO_LONGS(IPR_MAX_SIS64_DEVS)];
 
        u16 type; /* CCIN of the card */
 
index c772d8d..8b928c6 100644 (file)
@@ -463,13 +463,7 @@ static void fc_exch_delete(struct fc_exch *ep)
        fc_exch_release(ep);    /* drop hold for exch in mp */
 }
 
-/**
- * fc_seq_send() - Send a frame using existing sequence/exchange pair
- * @lport: The local port that the exchange will be sent on
- * @sp:           The sequence to be sent
- * @fp:           The frame to be sent on the exchange
- */
-static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
+static int fc_seq_send_locked(struct fc_lport *lport, struct fc_seq *sp,
                       struct fc_frame *fp)
 {
        struct fc_exch *ep;
@@ -479,7 +473,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
        u8 fh_type = fh->fh_type;
 
        ep = fc_seq_exch(sp);
-       WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT);
+       WARN_ON(!(ep->esb_stat & ESB_ST_SEQ_INIT));
 
        f_ctl = ntoh24(fh->fh_f_ctl);
        fc_exch_setup_hdr(ep, fp, f_ctl);
@@ -502,17 +496,34 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
        error = lport->tt.frame_send(lport, fp);
 
        if (fh_type == FC_TYPE_BLS)
-               return error;
+               goto out;
 
        /*
         * Update the exchange and sequence flags,
         * assuming all frames for the sequence have been sent.
         * We can only be called to send once for each sequence.
         */
-       spin_lock_bh(&ep->ex_lock);
        ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ;   /* not first seq */
        if (f_ctl & FC_FC_SEQ_INIT)
                ep->esb_stat &= ~ESB_ST_SEQ_INIT;
+out:
+       return error;
+}
+
+/**
+ * fc_seq_send() - Send a frame using existing sequence/exchange pair
+ * @lport: The local port that the exchange will be sent on
+ * @sp:           The sequence to be sent
+ * @fp:           The frame to be sent on the exchange
+ */
+static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
+                      struct fc_frame *fp)
+{
+       struct fc_exch *ep;
+       int error;
+       ep = fc_seq_exch(sp);
+       spin_lock_bh(&ep->ex_lock);
+       error = fc_seq_send_locked(lport, sp, fp);
        spin_unlock_bh(&ep->ex_lock);
        return error;
 }
@@ -629,7 +640,7 @@ static int fc_exch_abort_locked(struct fc_exch *ep,
        if (fp) {
                fc_fill_fc_hdr(fp, FC_RCTL_BA_ABTS, ep->did, ep->sid,
                               FC_TYPE_BLS, FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
-               error = fc_seq_send(ep->lp, sp, fp);
+               error = fc_seq_send_locked(ep->lp, sp, fp);
        } else
                error = -ENOBUFS;
        return error;
@@ -1132,7 +1143,7 @@ static void fc_seq_send_last(struct fc_seq *sp, struct fc_frame *fp,
        f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT;
        f_ctl |= ep->f_ctl;
        fc_fill_fc_hdr(fp, rctl, ep->did, ep->sid, fh_type, f_ctl, 0);
-       fc_seq_send(ep->lp, sp, fp);
+       fc_seq_send_locked(ep->lp, sp, fp);
 }
 
 /**
@@ -1307,8 +1318,8 @@ static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp)
                ap->ba_low_seq_cnt = htons(sp->cnt);
        }
        sp = fc_seq_start_next_locked(sp);
-       spin_unlock_bh(&ep->ex_lock);
        fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS);
+       spin_unlock_bh(&ep->ex_lock);
        fc_frame_free(rx_fp);
        return;
 
index d518d17..6bbb944 100644 (file)
@@ -1962,7 +1962,7 @@ static int fc_rport_fcp_prli(struct fc_rport_priv *rdata, u32 spp_len,
                rdata->flags |= FC_RP_FLAGS_RETRY;
        rdata->supported_classes = FC_COS_CLASS3;
 
-       if (!(lport->service_params & FC_RPORT_ROLE_FCP_INITIATOR))
+       if (!(lport->service_params & FCP_SPPF_INIT_FCN))
                return 0;
 
        spp->spp_flags |= rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
index 98ab921..0a5c895 100644 (file)
@@ -278,3 +278,14 @@ qla2x00_do_host_ramp_up(scsi_qla_host_t *vha)
 
        set_bit(HOST_RAMP_UP_QUEUE_DEPTH, &vha->dpc_flags);
 }
+
+static inline void
+qla2x00_handle_mbx_completion(struct qla_hw_data *ha, int status)
+{
+       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+           (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+               set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+               clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+               complete(&ha->mbx_intr_comp);
+       }
+}
index 259d920..d2a4c75 100644 (file)
@@ -104,14 +104,9 @@ qla2100_intr_handler(int irq, void *dev_id)
                        RD_REG_WORD(&reg->hccr);
                }
        }
+       qla2x00_handle_mbx_completion(ha, status);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
-           (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
-               set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               complete(&ha->mbx_intr_comp);
-       }
-
        return (IRQ_HANDLED);
 }
 
@@ -221,14 +216,9 @@ qla2300_intr_handler(int irq, void *dev_id)
                WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
                RD_REG_WORD_RELAXED(&reg->hccr);
        }
+       qla2x00_handle_mbx_completion(ha, status);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
-           (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
-               set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               complete(&ha->mbx_intr_comp);
-       }
-
        return (IRQ_HANDLED);
 }
 
@@ -2613,14 +2603,9 @@ qla24xx_intr_handler(int irq, void *dev_id)
                if (unlikely(IS_QLA83XX(ha) && (ha->pdev->revision == 1)))
                        ndelay(3500);
        }
+       qla2x00_handle_mbx_completion(ha, status);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
-           (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
-               set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               complete(&ha->mbx_intr_comp);
-       }
-
        return IRQ_HANDLED;
 }
 
@@ -2763,13 +2748,9 @@ qla24xx_msix_default(int irq, void *dev_id)
                }
                WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
        } while (0);
+       qla2x00_handle_mbx_completion(ha, status);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
-           (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
-               set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               complete(&ha->mbx_intr_comp);
-       }
        return IRQ_HANDLED;
 }
 
index 9e5d89d..3587ec2 100644 (file)
@@ -179,8 +179,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 
                wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
 
-               clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
-
        } else {
                ql_dbg(ql_dbg_mbx, vha, 0x1011,
                    "Cmd=%x Polling Mode.\n", command);
index 937fed8..a6df558 100644 (file)
@@ -148,9 +148,6 @@ qlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp)
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
                wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
-
-               clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
-
        } else {
                ql_dbg(ql_dbg_mbx, vha, 0x112c,
                    "Cmd=%x Polling Mode.\n", command);
@@ -2934,13 +2931,10 @@ qlafx00_intr_handler(int irq, void *dev_id)
                QLAFX00_CLR_INTR_REG(ha, clr_intr);
                QLAFX00_RD_INTR_REG(ha);
        }
+
+       qla2x00_handle_mbx_completion(ha, status);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
-           (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
-               set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               complete(&ha->mbx_intr_comp);
-       }
        return IRQ_HANDLED;
 }
 
index 10754f5..cce0cd0 100644 (file)
@@ -2074,9 +2074,6 @@ qla82xx_intr_handler(int irq, void *dev_id)
                }
                WRT_REG_DWORD(&reg->host_int, 0);
        }
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       if (!ha->flags.msi_enabled)
-               qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
 
 #ifdef QL_DEBUG_LEVEL_17
        if (!irq && ha->flags.eeh_busy)
@@ -2085,11 +2082,12 @@ qla82xx_intr_handler(int irq, void *dev_id)
                    status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
 #endif
 
-       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
-           (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
-               set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-               complete(&ha->mbx_intr_comp);
-       }
+       qla2x00_handle_mbx_completion(ha, status);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       if (!ha->flags.msi_enabled)
+               qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
+
        return IRQ_HANDLED;
 }
 
@@ -2149,8 +2147,6 @@ qla82xx_msix_default(int irq, void *dev_id)
                WRT_REG_DWORD(&reg->host_int, 0);
        } while (0);
 
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
 #ifdef QL_DEBUG_LEVEL_17
        if (!irq && ha->flags.eeh_busy)
                ql_log(ql_log_warn, vha, 0x5044,
@@ -2158,11 +2154,9 @@ qla82xx_msix_default(int irq, void *dev_id)
                    status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
 #endif
 
-       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
-               (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
-                       set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-                       complete(&ha->mbx_intr_comp);
-       }
+       qla2x00_handle_mbx_completion(ha, status);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
        return IRQ_HANDLED;
 }
 
@@ -3345,7 +3339,7 @@ void qla82xx_clear_pending_mbx(scsi_qla_host_t *vha)
                ha->flags.mbox_busy = 0;
                ql_log(ql_log_warn, vha, 0x6010,
                    "Doing premature completion of mbx command.\n");
-               if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags))
+               if (test_and_clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags))
                        complete(&ha->mbx_intr_comp);
        }
 }
index 6430195..ffd7a81 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1135,13 +1135,6 @@ void setup_new_exec(struct linux_binprm * bprm)
                        set_dumpable(current->mm, suid_dumpable);
        }
 
-       /*
-        * Flush performance counters when crossing a
-        * security domain:
-        */
-       if (!get_dumpable(current->mm))
-               perf_event_exit_task(current);
-
        /* An exec changes our domain. We are no longer part of the thread
           group */
 
@@ -1205,6 +1198,15 @@ void install_exec_creds(struct linux_binprm *bprm)
 
        commit_creds(bprm->cred);
        bprm->cred = NULL;
+
+       /*
+        * Disable monitoring for regular users
+        * when executing setuid binaries. Must
+        * wait until new credentials are committed
+        * by commit_creds() above
+        */
+       if (get_dumpable(current->mm) != SUID_DUMP_USER)
+               perf_event_exit_task(current);
        /*
         * cred_guard_mutex must be held at least to this point to prevent
         * ptrace_attach() from altering our determination of the task's
index de08c92..605af51 100644 (file)
@@ -349,31 +349,50 @@ static unsigned int vfs_dent_type(uint8_t type)
 static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 {
        int err, over = 0;
+       loff_t pos = file->f_pos;
        struct qstr nm;
        union ubifs_key key;
        struct ubifs_dent_node *dent;
        struct inode *dir = file_inode(file);
        struct ubifs_info *c = dir->i_sb->s_fs_info;
 
-       dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
+       dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, pos);
 
-       if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
+       if (pos > UBIFS_S_KEY_HASH_MASK || pos == 2)
                /*
                 * The directory was seek'ed to a senseless position or there
                 * are no more entries.
                 */
                return 0;
 
+       if (file->f_version == 0) {
+               /*
+                * The file was seek'ed, which means that @file->private_data
+                * is now invalid. This may also be just the first
+                * 'ubifs_readdir()' invocation, in which case
+                * @file->private_data is NULL, and the below code is
+                * basically a no-op.
+                */
+               kfree(file->private_data);
+               file->private_data = NULL;
+       }
+
+       /*
+        * 'generic_file_llseek()' unconditionally sets @file->f_version to
+        * zero, and we use this for detecting whether the file was seek'ed.
+        */
+       file->f_version = 1;
+
        /* File positions 0 and 1 correspond to "." and ".." */
-       if (file->f_pos == 0) {
+       if (pos == 0) {
                ubifs_assert(!file->private_data);
                over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR);
                if (over)
                        return 0;
-               file->f_pos = 1;
+               file->f_pos = pos = 1;
        }
 
-       if (file->f_pos == 1) {
+       if (pos == 1) {
                ubifs_assert(!file->private_data);
                over = filldir(dirent, "..", 2, 1,
                               parent_ino(file->f_path.dentry), DT_DIR);
@@ -389,7 +408,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
                        goto out;
                }
 
-               file->f_pos = key_hash_flash(c, &dent->key);
+               file->f_pos = pos = key_hash_flash(c, &dent->key);
                file->private_data = dent;
        }
 
@@ -397,17 +416,16 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
        if (!dent) {
                /*
                 * The directory was seek'ed to and is now readdir'ed.
-                * Find the entry corresponding to @file->f_pos or the
-                * closest one.
+                * Find the entry corresponding to @pos or the closest one.
                 */
-               dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
+               dent_key_init_hash(c, &key, dir->i_ino, pos);
                nm.name = NULL;
                dent = ubifs_tnc_next_ent(c, &key, &nm);
                if (IS_ERR(dent)) {
                        err = PTR_ERR(dent);
                        goto out;
                }
-               file->f_pos = key_hash_flash(c, &dent->key);
+               file->f_pos = pos = key_hash_flash(c, &dent->key);
                file->private_data = dent;
        }
 
@@ -419,7 +437,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
                             ubifs_inode(dir)->creat_sqnum);
 
                nm.len = le16_to_cpu(dent->nlen);
-               over = filldir(dirent, dent->name, nm.len, file->f_pos,
+               over = filldir(dirent, dent->name, nm.len, pos,
                               le64_to_cpu(dent->inum),
                               vfs_dent_type(dent->type));
                if (over)
@@ -435,9 +453,17 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
                }
 
                kfree(file->private_data);
-               file->f_pos = key_hash_flash(c, &dent->key);
+               file->f_pos = pos = key_hash_flash(c, &dent->key);
                file->private_data = dent;
                cond_resched();
+
+               if (file->f_version == 0)
+                       /*
+                        * The file was seek'ed meanwhile, lets return and start
+                        * reading direntries from the new position on the next
+                        * invocation.
+                        */
+                       return 0;
        }
 
 out:
@@ -448,15 +474,13 @@ out:
 
        kfree(file->private_data);
        file->private_data = NULL;
+       /* 2 is a special value indicating that there are no more direntries */
        file->f_pos = 2;
        return 0;
 }
 
-/* If a directory is seeked, we have to free saved readdir() state */
 static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int whence)
 {
-       kfree(file->private_data);
-       file->private_data = NULL;
        return generic_file_llseek(file, offset, whence);
 }
 
index e6168a2..b420939 100644 (file)
@@ -123,7 +123,9 @@ extern int register_dock_notifier(struct notifier_block *nb);
 extern void unregister_dock_notifier(struct notifier_block *nb);
 extern int register_hotplug_dock_device(acpi_handle handle,
                                        const struct acpi_dock_ops *ops,
-                                       void *context);
+                                       void *context,
+                                       void (*init)(void *),
+                                       void (*release)(void *));
 extern void unregister_hotplug_dock_device(acpi_handle handle);
 #else
 static inline int is_dock_device(acpi_handle handle)
@@ -139,7 +141,9 @@ static inline void unregister_dock_notifier(struct notifier_block *nb)
 }
 static inline int register_hotplug_dock_device(acpi_handle handle,
                                               const struct acpi_dock_ops *ops,
-                                              void *context)
+                                              void *context,
+                                              void (*init)(void *),
+                                              void (*release)(void *))
 {
        return -ENODEV;
 }
index 52bd03b..637fa71 100644 (file)
@@ -44,7 +44,7 @@ struct vlan_hdr {
  *     struct vlan_ethhdr - vlan ethernet header (ethhdr + vlan_hdr)
  *     @h_dest: destination ethernet address
  *     @h_source: source ethernet address
- *     @h_vlan_proto: ethernet protocol (always 0x8100)
+ *     @h_vlan_proto: ethernet protocol
  *     @h_vlan_TCI: priority and VLAN ID
  *     @h_vlan_encapsulated_proto: packet type ID or len
  */
index 60584b1..96e4c21 100644 (file)
@@ -1695,6 +1695,7 @@ extern int                init_dummy_netdev(struct net_device *dev);
 extern struct net_device       *dev_get_by_index(struct net *net, int ifindex);
 extern struct net_device       *__dev_get_by_index(struct net *net, int ifindex);
 extern struct net_device       *dev_get_by_index_rcu(struct net *net, int ifindex);
+extern int             netdev_get_name(struct net *net, char *name, int ifindex);
 extern int             dev_restart(struct net_device *dev);
 #ifdef CONFIG_NETPOLL_TRAP
 extern int             netpoll_trap(void);
index 9c676ea..dec1748 100644 (file)
@@ -627,6 +627,7 @@ static inline struct rtable *skb_rtable(const struct sk_buff *skb)
 }
 
 extern void kfree_skb(struct sk_buff *skb);
+extern void kfree_skb_list(struct sk_buff *segs);
 extern void skb_tx_error(struct sk_buff *skb);
 extern void consume_skb(struct sk_buff *skb);
 extern void           __kfree_skb(struct sk_buff *skb);
index ab5d499..bdc6e87 100644 (file)
@@ -261,6 +261,7 @@ header-y += net_dropmon.h
 header-y += net_tstamp.h
 header-y += netconf.h
 header-y += netdevice.h
+header-y += netlink_diag.h
 header-y += netfilter.h
 header-y += netfilter_arp.h
 header-y += netfilter_bridge.h
index a64f8ae..20185ea 100644 (file)
@@ -120,7 +120,7 @@ static int task_bp_pinned(int cpu, struct perf_event *bp, enum bp_type_idx type)
        list_for_each_entry(iter, &bp_task_head, hw.bp_list) {
                if (iter->hw.bp_target == tsk &&
                    find_slot_idx(iter) == type &&
-                   cpu == iter->cpu)
+                   (iter->cpu < 0 || cpu == iter->cpu))
                        count += hw_breakpoint_weight(iter);
        }
 
@@ -149,7 +149,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
                return;
        }
 
-       for_each_online_cpu(cpu) {
+       for_each_possible_cpu(cpu) {
                unsigned int nr;
 
                nr = per_cpu(nr_cpu_bp_pinned[type], cpu);
@@ -235,7 +235,7 @@ toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type,
        if (cpu >= 0) {
                toggle_bp_task_slot(bp, cpu, enable, type, weight);
        } else {
-               for_each_online_cpu(cpu)
+               for_each_possible_cpu(cpu)
                        toggle_bp_task_slot(bp, cpu, enable, type, weight);
        }
 
index aed981a..335a7ae 100644 (file)
@@ -665,20 +665,22 @@ static int ptrace_peek_siginfo(struct task_struct *child,
                if (unlikely(is_compat_task())) {
                        compat_siginfo_t __user *uinfo = compat_ptr(data);
 
-                       ret = copy_siginfo_to_user32(uinfo, &info);
-                       ret |= __put_user(info.si_code, &uinfo->si_code);
+                       if (copy_siginfo_to_user32(uinfo, &info) ||
+                           __put_user(info.si_code, &uinfo->si_code)) {
+                               ret = -EFAULT;
+                               break;
+                       }
+
                } else
 #endif
                {
                        siginfo_t __user *uinfo = (siginfo_t __user *) data;
 
-                       ret = copy_siginfo_to_user(uinfo, &info);
-                       ret |= __put_user(info.si_code, &uinfo->si_code);
-               }
-
-               if (ret) {
-                       ret = -EFAULT;
-                       break;
+                       if (copy_siginfo_to_user(uinfo, &info) ||
+                           __put_user(info.si_code, &uinfo->si_code)) {
+                               ret = -EFAULT;
+                               break;
+                       }
                }
 
                data += sizeof(siginfo_t);
index b4c2455..20d6fba 100644 (file)
@@ -599,8 +599,6 @@ void tick_broadcast_oneshot_control(unsigned long reason)
        } else {
                if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
                        clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
-                       if (dev->next_event.tv64 == KTIME_MAX)
-                               goto out;
                        /*
                         * The cpu which was handling the broadcast
                         * timer marked this cpu in the broadcast
@@ -615,6 +613,11 @@ void tick_broadcast_oneshot_control(unsigned long reason)
                                goto out;
 
                        /*
+                        * Bail out if there is no next event.
+                        */
+                       if (dev->next_event.tv64 == KTIME_MAX)
+                               goto out;
+                       /*
                         * If the pending bit is not set, then we are
                         * either the CPU handling the broadcast
                         * interrupt or we got woken by something else.
index d817c93..ace5e55 100644 (file)
@@ -341,7 +341,6 @@ static void hci_init1_req(struct hci_request *req, unsigned long opt)
 
 static void bredr_setup(struct hci_request *req)
 {
-       struct hci_cp_delete_stored_link_key cp;
        __le16 param;
        __u8 flt_type;
 
@@ -365,10 +364,6 @@ static void bredr_setup(struct hci_request *req)
        param = __constant_cpu_to_le16(0x7d00);
        hci_req_add(req, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
 
-       bacpy(&cp.bdaddr, BDADDR_ANY);
-       cp.delete_all = 0x01;
-       hci_req_add(req, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
-
        /* Read page scan parameters */
        if (req->hdev->hci_ver > BLUETOOTH_VER_1_1) {
                hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL);
@@ -602,6 +597,16 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
        struct hci_dev *hdev = req->hdev;
        u8 p;
 
+       /* Only send HCI_Delete_Stored_Link_Key if it is supported */
+       if (hdev->commands[6] & 0x80) {
+               struct hci_cp_delete_stored_link_key cp;
+
+               bacpy(&cp.bdaddr, BDADDR_ANY);
+               cp.delete_all = 0x01;
+               hci_req_add(req, HCI_OP_DELETE_STORED_LINK_KEY,
+                           sizeof(cp), &cp);
+       }
+
        if (hdev->commands[5] & 0x10)
                hci_setup_link_policy(req);
 
index 24bee07..68843a2 100644 (file)
@@ -2852,6 +2852,9 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code,
        BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %u",
               conn, code, ident, dlen);
 
+       if (conn->mtu < L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE)
+               return NULL;
+
        len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
        count = min_t(unsigned int, conn->mtu, len);
 
@@ -4330,7 +4333,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
        struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
        u16 type, result;
 
-       if (cmd_len != sizeof(*rsp))
+       if (cmd_len < sizeof(*rsp))
                return -EPROTO;
 
        type   = __le16_to_cpu(rsp->type);
index 81f2389..d6448e3 100644 (file)
@@ -465,8 +465,9 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        skb_set_transport_header(skb, skb->len);
        mldq = (struct mld_msg *) icmp6_hdr(skb);
 
-       interval = ipv6_addr_any(group) ? br->multicast_last_member_interval :
-                                         br->multicast_query_response_interval;
+       interval = ipv6_addr_any(group) ?
+                       br->multicast_query_response_interval :
+                       br->multicast_last_member_interval;
 
        mldq->mld_type = ICMPV6_MGM_QUERY;
        mldq->mld_code = 0;
index fc1e289..faebb39 100644 (file)
@@ -792,6 +792,40 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
 EXPORT_SYMBOL(dev_get_by_index);
 
 /**
+ *     netdev_get_name - get a netdevice name, knowing its ifindex.
+ *     @net: network namespace
+ *     @name: a pointer to the buffer where the name will be stored.
+ *     @ifindex: the ifindex of the interface to get the name from.
+ *
+ *     The use of raw_seqcount_begin() and cond_resched() before
+ *     retrying is required as we want to give the writers a chance
+ *     to complete when CONFIG_PREEMPT is not set.
+ */
+int netdev_get_name(struct net *net, char *name, int ifindex)
+{
+       struct net_device *dev;
+       unsigned int seq;
+
+retry:
+       seq = raw_seqcount_begin(&devnet_rename_seq);
+       rcu_read_lock();
+       dev = dev_get_by_index_rcu(net, ifindex);
+       if (!dev) {
+               rcu_read_unlock();
+               return -ENODEV;
+       }
+
+       strcpy(name, dev->name);
+       rcu_read_unlock();
+       if (read_seqcount_retry(&devnet_rename_seq, seq)) {
+               cond_resched();
+               goto retry;
+       }
+
+       return 0;
+}
+
+/**
  *     dev_getbyhwaddr_rcu - find a device by its hardware address
  *     @net: the applicable net namespace
  *     @type: media type of device
index 6cc0481..5b7d0e1 100644 (file)
@@ -19,9 +19,8 @@
 
 static int dev_ifname(struct net *net, struct ifreq __user *arg)
 {
-       struct net_device *dev;
        struct ifreq ifr;
-       unsigned seq;
+       int error;
 
        /*
         *      Fetch the caller's info block.
@@ -30,19 +29,9 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
        if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
                return -EFAULT;
 
-retry:
-       seq = read_seqcount_begin(&devnet_rename_seq);
-       rcu_read_lock();
-       dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex);
-       if (!dev) {
-               rcu_read_unlock();
-               return -ENODEV;
-       }
-
-       strcpy(ifr.ifr_name, dev->name);
-       rcu_read_unlock();
-       if (read_seqcount_retry(&devnet_rename_seq, seq))
-               goto retry;
+       error = netdev_get_name(net, ifr.ifr_name, ifr.ifr_ifindex);
+       if (error)
+               return error;
 
        if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
                return -EFAULT;
index 22efdaa..ce91766 100644 (file)
@@ -60,10 +60,10 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
        [NETIF_F_IPV6_CSUM_BIT] =        "tx-checksum-ipv6",
        [NETIF_F_HIGHDMA_BIT] =          "highdma",
        [NETIF_F_FRAGLIST_BIT] =         "tx-scatter-gather-fraglist",
-       [NETIF_F_HW_VLAN_CTAG_TX_BIT] =  "tx-vlan-ctag-hw-insert",
+       [NETIF_F_HW_VLAN_CTAG_TX_BIT] =  "tx-vlan-hw-insert",
 
-       [NETIF_F_HW_VLAN_CTAG_RX_BIT] =  "rx-vlan-ctag-hw-parse",
-       [NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-ctag-filter",
+       [NETIF_F_HW_VLAN_CTAG_RX_BIT] =  "rx-vlan-hw-parse",
+       [NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-filter",
        [NETIF_F_HW_VLAN_STAG_TX_BIT] =  "tx-vlan-stag-hw-insert",
        [NETIF_F_HW_VLAN_STAG_RX_BIT] =  "rx-vlan-stag-hw-parse",
        [NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter",
index cfd777b..1c1738c 100644 (file)
@@ -483,15 +483,8 @@ EXPORT_SYMBOL(skb_add_rx_frag);
 
 static void skb_drop_list(struct sk_buff **listp)
 {
-       struct sk_buff *list = *listp;
-
+       kfree_skb_list(*listp);
        *listp = NULL;
-
-       do {
-               struct sk_buff *this = list;
-               list = list->next;
-               kfree_skb(this);
-       } while (list);
 }
 
 static inline void skb_drop_fraglist(struct sk_buff *skb)
@@ -651,6 +644,17 @@ void kfree_skb(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(kfree_skb);
 
+void kfree_skb_list(struct sk_buff *segs)
+{
+       while (segs) {
+               struct sk_buff *next = segs->next;
+
+               kfree_skb(segs);
+               segs = next;
+       }
+}
+EXPORT_SYMBOL(kfree_skb_list);
+
 /**
  *     skb_tx_error - report an sk_buff xmit error
  *     @skb: buffer that triggered an error
index 88868a9..d6d024c 100644 (file)
@@ -571,9 +571,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval,
        int ret = -ENOPROTOOPT;
 #ifdef CONFIG_NETDEVICES
        struct net *net = sock_net(sk);
-       struct net_device *dev;
        char devname[IFNAMSIZ];
-       unsigned seq;
 
        if (sk->sk_bound_dev_if == 0) {
                len = 0;
@@ -584,20 +582,9 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval,
        if (len < IFNAMSIZ)
                goto out;
 
-retry:
-       seq = read_seqcount_begin(&devnet_rename_seq);
-       rcu_read_lock();
-       dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
-       ret = -ENODEV;
-       if (!dev) {
-               rcu_read_unlock();
+       ret = netdev_get_name(net, devname, sk->sk_bound_dev_if);
+       if (ret)
                goto out;
-       }
-
-       strcpy(devname, dev->name);
-       rcu_read_unlock();
-       if (read_seqcount_retry(&devnet_rename_seq, seq))
-               goto retry;
 
        len = strlen(devname) + 1;
 
index b2e805a..7856d16 100644 (file)
@@ -178,7 +178,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
 
                                err = __skb_linearize(skb);
                                if (err) {
-                                       kfree_skb(segs);
+                                       kfree_skb_list(segs);
                                        segs = ERR_PTR(err);
                                        goto out;
                                }
index ff4b781..32b0e97 100644 (file)
@@ -125,15 +125,16 @@ static void ulog_send(struct ulog_net *ulog, unsigned int nlgroupnum)
 /* timer function to flush queue in flushtimeout time */
 static void ulog_timer(unsigned long data)
 {
+       unsigned int groupnum = *((unsigned int *)data);
        struct ulog_net *ulog = container_of((void *)data,
                                             struct ulog_net,
-                                            nlgroup[*(unsigned int *)data]);
+                                            nlgroup[groupnum]);
        pr_debug("timer function called, calling ulog_send\n");
 
        /* lock to protect against somebody modifying our structure
         * from ipt_ulog_target at the same time */
        spin_lock_bh(&ulog->lock);
-       ulog_send(ulog, data);
+       ulog_send(ulog, groupnum);
        spin_unlock_bh(&ulog->lock);
 }
 
@@ -407,8 +408,11 @@ static int __net_init ulog_tg_net_init(struct net *net)
 
        spin_lock_init(&ulog->lock);
        /* initialize ulog_buffers */
-       for (i = 0; i < ULOG_MAXNLGROUPS; i++)
-               setup_timer(&ulog->ulog_buffers[i].timer, ulog_timer, i);
+       for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
+               ulog->nlgroup[i] = i;
+               setup_timer(&ulog->ulog_buffers[i].timer, ulog_timer,
+                           (unsigned long)&ulog->nlgroup[i]);
+       }
 
        ulog->nflognl = netlink_kernel_create(net, NETLINK_NFLOG, &cfg);
        if (!ulog->nflognl)
index 7196523..7999fc5 100644 (file)
@@ -1003,7 +1003,7 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
        struct tcp_sock *tp = tcp_sk(sk);
        struct tcp_md5sig_info *md5sig;
 
-       key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET);
+       key = tcp_md5_do_lookup(sk, addr, family);
        if (key) {
                /* Pre-existing entry - just update that one. */
                memcpy(key->key, newkey, newkeylen);
@@ -1048,7 +1048,7 @@ int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family)
        struct tcp_md5sig_key *key;
        struct tcp_md5sig_info *md5sig;
 
-       key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET);
+       key = tcp_md5_do_lookup(sk, addr, family);
        if (!key)
                return -ENOENT;
        hlist_del_rcu(&key->node);
index 1bbf744..4ab4c38 100644 (file)
@@ -2655,6 +2655,9 @@ static void init_loopback(struct net_device *dev)
                        if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))
                                continue;
 
+                       if (sp_ifa->rt)
+                               continue;
+
                        sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0);
 
                        /* Failure cases are ignored */
@@ -4303,6 +4306,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
        struct inet6_ifaddr *ifp;
        struct net_device *dev = idev->dev;
        bool update_rs = false;
+       struct in6_addr ll_addr;
 
        if (token == NULL)
                return -EINVAL;
@@ -4322,11 +4326,9 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
 
        write_unlock_bh(&idev->lock);
 
-       if (!idev->dead && (idev->if_flags & IF_READY)) {
-               struct in6_addr ll_addr;
-
-               ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE |
-                               IFA_F_OPTIMISTIC);
+       if (!idev->dead && (idev->if_flags & IF_READY) &&
+           !ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE |
+                            IFA_F_OPTIMISTIC)) {
 
                /* If we're not ready, then normal ifup will take care
                 * of this. Otherwise, we need to request our rs here.
index dae1949..d5d20cd 100644 (file)
@@ -381,9 +381,8 @@ int ip6_forward(struct sk_buff *skb)
         *      cannot be fragmented, because there is no warranty
         *      that different fragments will go along one path. --ANK
         */
-       if (opt->ra) {
-               u8 *ptr = skb_network_header(skb) + opt->ra;
-               if (ip6_call_ra_chain(skb, (ptr[2]<<8) + ptr[3]))
+       if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) {
+               if (ip6_call_ra_chain(skb, ntohs(opt->ra)))
                        return 0;
        }
 
@@ -822,11 +821,17 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
                                          const struct flowi6 *fl6)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct rt6_info *rt = (struct rt6_info *)dst;
+       struct rt6_info *rt;
 
        if (!dst)
                goto out;
 
+       if (dst->ops->family != AF_INET6) {
+               dst_release(dst);
+               return NULL;
+       }
+
+       rt = (struct rt6_info *)dst;
        /* Yes, checking route validity in not connected
         * case is not very simple. Take into account,
         * that we do not support routing by source, TOS,
index 2712ab2..ca4ffcc 100644 (file)
@@ -1493,7 +1493,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
         */
 
        if (ha)
-               ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha);
+               ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
 
        /*
         *      build redirect option and copy skb over to the new packet.
index 97bcf2b..c9b6a6e 100644 (file)
@@ -204,7 +204,7 @@ static unsigned int __ipv6_conntrack_in(struct net *net,
                if (ct != NULL && !nf_ct_is_untracked(ct)) {
                        help = nfct_help(ct);
                        if ((help && help->helper) || !nf_ct_is_confirmed(ct)) {
-                               nf_conntrack_get_reasm(skb);
+                               nf_conntrack_get_reasm(reasm);
                                NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
                                               (struct net_device *)in,
                                               (struct net_device *)out,
index c5fbd75..9da8620 100644 (file)
@@ -1710,6 +1710,7 @@ static int key_notify_sa_flush(const struct km_event *c)
        hdr->sadb_msg_version = PF_KEY_V2;
        hdr->sadb_msg_errno = (uint8_t) 0;
        hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+       hdr->sadb_msg_reserved = 0;
 
        pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
 
@@ -2699,6 +2700,7 @@ static int key_notify_policy_flush(const struct km_event *c)
        hdr->sadb_msg_errno = (uint8_t) 0;
        hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
        hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+       hdr->sadb_msg_reserved = 0;
        pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
        return 0;
 
index 1a89c80..4fdb306 100644 (file)
@@ -1057,6 +1057,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
 
+       if (sdata->wdev.cac_started) {
+               cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
+               cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,
+                                  GFP_KERNEL);
+       }
+
        drv_stop_ap(sdata->local, sdata);
 
        /* free all potentially still buffered bcast frames */
index 44be28c..9ca8e32 100644 (file)
@@ -1497,10 +1497,11 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
        ieee80211_tx_skb_tid(sdata, skb, 7);
 }
 
-u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action,
+u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                               struct ieee802_11_elems *elems,
                               u64 filter, u32 crc);
-static inline void ieee802_11_parse_elems(u8 *start, size_t len, bool action,
+static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
+                                         bool action,
                                          struct ieee802_11_elems *elems)
 {
        ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
index a8c2130..741448b 100644 (file)
@@ -2522,8 +2522,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        u16 capab_info, aid;
        struct ieee802_11_elems elems;
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
+       const struct cfg80211_bss_ies *bss_ies = NULL;
+       struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
        u32 changed = 0;
        int err;
+       bool ret;
 
        /* AssocResp and ReassocResp have identical structure */
 
@@ -2555,21 +2558,86 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        ifmgd->aid = aid;
 
        /*
+        * Some APs are erroneously not including some information in their
+        * (re)association response frames. Try to recover by using the data
+        * from the beacon or probe response. This seems to afflict mobile
+        * 2G/3G/4G wifi routers, reported models include the "Onda PN51T",
+        * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device.
+        */
+       if ((assoc_data->wmm && !elems.wmm_param) ||
+           (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
+            (!elems.ht_cap_elem || !elems.ht_operation)) ||
+           (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
+            (!elems.vht_cap_elem || !elems.vht_operation))) {
+               const struct cfg80211_bss_ies *ies;
+               struct ieee802_11_elems bss_elems;
+
+               rcu_read_lock();
+               ies = rcu_dereference(cbss->ies);
+               if (ies)
+                       bss_ies = kmemdup(ies, sizeof(*ies) + ies->len,
+                                         GFP_ATOMIC);
+               rcu_read_unlock();
+               if (!bss_ies)
+                       return false;
+
+               ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
+                                      false, &bss_elems);
+               if (assoc_data->wmm &&
+                   !elems.wmm_param && bss_elems.wmm_param) {
+                       elems.wmm_param = bss_elems.wmm_param;
+                       sdata_info(sdata,
+                                  "AP bug: WMM param missing from AssocResp\n");
+               }
+
+               /*
+                * Also check if we requested HT/VHT, otherwise the AP doesn't
+                * have to include the IEs in the (re)association response.
+                */
+               if (!elems.ht_cap_elem && bss_elems.ht_cap_elem &&
+                   !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+                       elems.ht_cap_elem = bss_elems.ht_cap_elem;
+                       sdata_info(sdata,
+                                  "AP bug: HT capability missing from AssocResp\n");
+               }
+               if (!elems.ht_operation && bss_elems.ht_operation &&
+                   !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+                       elems.ht_operation = bss_elems.ht_operation;
+                       sdata_info(sdata,
+                                  "AP bug: HT operation missing from AssocResp\n");
+               }
+               if (!elems.vht_cap_elem && bss_elems.vht_cap_elem &&
+                   !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
+                       elems.vht_cap_elem = bss_elems.vht_cap_elem;
+                       sdata_info(sdata,
+                                  "AP bug: VHT capa missing from AssocResp\n");
+               }
+               if (!elems.vht_operation && bss_elems.vht_operation &&
+                   !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
+                       elems.vht_operation = bss_elems.vht_operation;
+                       sdata_info(sdata,
+                                  "AP bug: VHT operation missing from AssocResp\n");
+               }
+       }
+
+       /*
         * We previously checked these in the beacon/probe response, so
         * they should be present here. This is just a safety net.
         */
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
            (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) {
                sdata_info(sdata,
-                          "HT AP is missing WMM params or HT capability/operation in AssocResp\n");
-               return false;
+                          "HT AP is missing WMM params or HT capability/operation\n");
+               ret = false;
+               goto out;
        }
 
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
            (!elems.vht_cap_elem || !elems.vht_operation)) {
                sdata_info(sdata,
-                          "VHT AP is missing VHT capability/operation in AssocResp\n");
-               return false;
+                          "VHT AP is missing VHT capability/operation\n");
+               ret = false;
+               goto out;
        }
 
        mutex_lock(&sdata->local->sta_mtx);
@@ -2580,7 +2648,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        sta = sta_info_get(sdata, cbss->bssid);
        if (WARN_ON(!sta)) {
                mutex_unlock(&sdata->local->sta_mtx);
-               return false;
+               ret = false;
+               goto out;
        }
 
        sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
@@ -2633,7 +2702,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                           sta->sta.addr);
                WARN_ON(__sta_info_destroy(sta));
                mutex_unlock(&sdata->local->sta_mtx);
-               return false;
+               ret = false;
+               goto out;
        }
 
        mutex_unlock(&sdata->local->sta_mtx);
@@ -2673,7 +2743,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
        ieee80211_sta_reset_beacon_monitor(sdata);
 
-       return true;
+       ret = true;
+ out:
+       kfree(bss_ies);
+       return ret;
 }
 
 static enum rx_mgmt_action __must_check
index d3f414f..a02bef3 100644 (file)
@@ -615,7 +615,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
                if (rates[i].idx < 0)
                        break;
 
-               rate_idx_match_mask(&rates[i], sband, mask, chan_width,
+               rate_idx_match_mask(&rates[i], sband, chan_width, mask,
                                    mcs_mask);
        }
 }
index 27e0715..72e6292 100644 (file)
@@ -661,12 +661,12 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_queue_delayed_work);
 
-u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action,
+u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                               struct ieee802_11_elems *elems,
                               u64 filter, u32 crc)
 {
        size_t left = len;
-       u8 *pos = start;
+       const u8 *pos = start;
        bool calc_crc = filter != 0;
        DECLARE_BITMAP(seen_elems, 256);
        const u8 *ie;
index 05565d2..23b8eb5 100644 (file)
@@ -1442,7 +1442,8 @@ ignore_ipip:
 
        /* do the statistics and put it back */
        ip_vs_in_stats(cp, skb);
-       if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol)
+       if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol ||
+           IPPROTO_SCTP == cih->protocol)
                offset += 2 * sizeof(__u16);
        verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum, &ciph);
 
index 8fe2e99..355d2ef 100644 (file)
@@ -45,7 +45,7 @@ int nf_connlabel_set(struct nf_conn *ct, u16 bit)
        if (test_bit(bit, labels->bits))
                return 0;
 
-       if (test_and_set_bit(bit, labels->bits))
+       if (!test_and_set_bit(bit, labels->bits))
                nf_conntrack_event_cache(IPCT_LABEL, ct);
 
        return 0;
index 6d0f8a1..ecf065f 100644 (file)
@@ -1825,6 +1825,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
                        nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
                                                      (1 << IPCT_ASSURED) |
                                                      (1 << IPCT_HELPER) |
+                                                     (1 << IPCT_LABEL) |
                                                      (1 << IPCT_PROTOINFO) |
                                                      (1 << IPCT_NATSEQADJ) |
                                                      (1 << IPCT_MARK),
index 96ccdf7..dac11f7 100644 (file)
@@ -230,9 +230,10 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
                                        &ct->tuplehash[!dir].tuple.src.u3,
                                        false);
                        if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
-                                          poff, plen, buffer, buflen))
+                                          poff, plen, buffer, buflen)) {
                                nf_ct_helper_log(skb, ct, "cannot mangle received");
                                return NF_DROP;
+                       }
                }
 
                /* The rport= parameter (RFC 3581) contains the port number
index afaebc7..7011c71 100644 (file)
@@ -45,17 +45,22 @@ optlen(const u_int8_t *opt, unsigned int offset)
 
 static int
 tcpmss_mangle_packet(struct sk_buff *skb,
-                    const struct xt_tcpmss_info *info,
+                    const struct xt_action_param *par,
                     unsigned int in_mtu,
                     unsigned int tcphoff,
                     unsigned int minlen)
 {
+       const struct xt_tcpmss_info *info = par->targinfo;
        struct tcphdr *tcph;
        unsigned int tcplen, i;
        __be16 oldval;
        u16 newmss;
        u8 *opt;
 
+       /* This is a fragment, no TCP header is available */
+       if (par->fragoff != 0)
+               return XT_CONTINUE;
+
        if (!skb_make_writable(skb, skb->len))
                return -1;
 
@@ -125,11 +130,17 @@ tcpmss_mangle_packet(struct sk_buff *skb,
 
        skb_put(skb, TCPOLEN_MSS);
 
-       /* RFC 879 states that the default MSS is 536 without specific
-        * knowledge that the destination host is prepared to accept larger.
-        * Since no MSS was provided, we MUST NOT set a value > 536.
+       /*
+        * IPv4: RFC 1122 states "If an MSS option is not received at
+        * connection setup, TCP MUST assume a default send MSS of 536".
+        * IPv6: RFC 2460 states IPv6 has a minimum MTU of 1280 and a minimum
+        * length IPv6 header of 60, ergo the default MSS value is 1220
+        * Since no MSS was provided, we must use the default values
         */
-       newmss = min(newmss, (u16)536);
+       if (par->family == NFPROTO_IPV4)
+               newmss = min(newmss, (u16)536);
+       else
+               newmss = min(newmss, (u16)1220);
 
        opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
        memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
@@ -188,7 +199,7 @@ tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
        __be16 newlen;
        int ret;
 
-       ret = tcpmss_mangle_packet(skb, par->targinfo,
+       ret = tcpmss_mangle_packet(skb, par,
                                   tcpmss_reverse_mtu(skb, PF_INET),
                                   iph->ihl * 4,
                                   sizeof(*iph) + sizeof(struct tcphdr));
@@ -217,7 +228,7 @@ tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
        tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off);
        if (tcphoff < 0)
                return NF_DROP;
-       ret = tcpmss_mangle_packet(skb, par->targinfo,
+       ret = tcpmss_mangle_packet(skb, par,
                                   tcpmss_reverse_mtu(skb, PF_INET6),
                                   tcphoff,
                                   sizeof(*ipv6h) + sizeof(struct tcphdr));
index 1eb1a44..b68fa19 100644 (file)
@@ -48,11 +48,13 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
                return NF_DROP;
 
        len = skb->len - tcphoff;
-       if (len < (int)sizeof(struct tcphdr) ||
-           tcp_hdr(skb)->doff * 4 > len)
+       if (len < (int)sizeof(struct tcphdr))
                return NF_DROP;
 
        tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+       if (tcph->doff * 4 > len)
+               return NF_DROP;
+
        opt  = (u_int8_t *)tcph;
 
        /*
index d5aed3b..b14b7e3 100644 (file)
@@ -1564,12 +1564,17 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
        struct cfg80211_registered_device *dev;
        s64 filter_wiphy = -1;
        bool split = false;
-       struct nlattr **tb = nl80211_fam.attrbuf;
+       struct nlattr **tb;
        int res;
 
+       /* will be zeroed in nlmsg_parse() */
+       tb = kmalloc(sizeof(*tb) * (NL80211_ATTR_MAX + 1), GFP_KERNEL);
+       if (!tb)
+               return -ENOMEM;
+
        mutex_lock(&cfg80211_mutex);
        res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
-                         tb, nl80211_fam.maxattr, nl80211_policy);
+                         tb, NL80211_ATTR_MAX, nl80211_policy);
        if (res == 0) {
                split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
                if (tb[NL80211_ATTR_WIPHY])
@@ -1583,6 +1588,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
                        netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
                        if (!netdev) {
                                mutex_unlock(&cfg80211_mutex);
+                               kfree(tb);
                                return -ENODEV;
                        }
                        if (netdev->ieee80211_ptr) {
@@ -1593,6 +1599,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
                        dev_put(netdev);
                }
        }
+       kfree(tb);
 
        list_for_each_entry(dev, &cfg80211_rdev_list, list) {
                if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))