diff options
245 files changed, 9451 insertions, 1990 deletions
diff --git a/Documentation/cgroups/cpusets.txt b/Documentation/cgroups/cpusets.txt index 7740038d82bc..3c94ff3f9693 100644 --- a/Documentation/cgroups/cpusets.txt +++ b/Documentation/cgroups/cpusets.txt @@ -345,14 +345,14 @@ the named feature on. The implementation is simple. Setting the flag 'cpuset.memory_spread_page' turns on a per-process flag -PF_SPREAD_PAGE for each task that is in that cpuset or subsequently +PFA_SPREAD_PAGE for each task that is in that cpuset or subsequently joins that cpuset. The page allocation calls for the page cache -is modified to perform an inline check for this PF_SPREAD_PAGE task +is modified to perform an inline check for this PFA_SPREAD_PAGE task flag, and if set, a call to a new routine cpuset_mem_spread_node() returns the node to prefer for the allocation. Similarly, setting 'cpuset.memory_spread_slab' turns on the flag -PF_SPREAD_SLAB, and appropriately marked slab caches will allocate +PFA_SPREAD_SLAB, and appropriately marked slab caches will allocate pages from the node returned by cpuset_mem_spread_node(). The cpuset_mem_spread_node() routine is also simple. It uses the diff --git a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt index 578a1fca366e..443bcb6134d5 100644 --- a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt +++ b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt @@ -56,6 +56,9 @@ Required properties: - fsl,data-width : should be <18> or <24> - port: A port node with endpoint definitions as defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + On i.MX5, the internal two-input-multiplexer is used. + Due to hardware limitations, only one port (port@[0,1]) + can be used for each channel (lvds-channel@[0,1], respectively) On i.MX6, there should be four ports (port@[0-3]) that correspond to the four LVDS multiplexer inputs. @@ -78,6 +81,8 @@ ldb: ldb@53fa8008 { "di0", "di1"; lvds-channel@0 { + #address-cells = <1>; + #size-cells = <0>; reg = <0>; fsl,data-mapping = "spwg"; fsl,data-width = <24>; @@ -86,7 +91,9 @@ ldb: ldb@53fa8008 { /* ... */ }; - port { + port@0 { + reg = <0>; + lvds0_in: endpoint { remote-endpoint = <&ipu_di0_lvds0>; }; @@ -94,6 +101,8 @@ ldb: ldb@53fa8008 { }; lvds-channel@1 { + #address-cells = <1>; + #size-cells = <0>; reg = <1>; fsl,data-mapping = "spwg"; fsl,data-width = <24>; @@ -102,7 +111,9 @@ ldb: ldb@53fa8008 { /* ... */ }; - port { + port@1 { + reg = <1>; + lvds1_in: endpoint { remote-endpoint = <&ipu_di1_lvds1>; }; diff --git a/Documentation/devicetree/of_selftest.txt b/Documentation/devicetree/of_selftest.txt new file mode 100644 index 000000000000..3a2f54d07fc5 --- /dev/null +++ b/Documentation/devicetree/of_selftest.txt @@ -0,0 +1,211 @@ +Open Firmware Device Tree Selftest +---------------------------------- + +Author: Gaurav Minocha <[email protected]> + +1. Introduction + +This document explains how the test data required for executing OF selftest +is attached to the live tree dynamically, independent of the machine's +architecture. + +It is recommended to read the following documents before moving ahead. + +[1] Documentation/devicetree/usage-model.txt +[2] http://www.devicetree.org/Device_Tree_Usage + +OF Selftest has been designed to test the interface (include/linux/of.h) +provided to device driver developers to fetch the device information..etc. +from the unflattened device tree data structure. This interface is used by +most of the device drivers in various use cases. + + +2. Test-data + +The Device Tree Source file (drivers/of/testcase-data/testcases.dts) contains +the test data required for executing the unit tests automated in +drivers/of/selftests.c. Currently, following Device Tree Source Include files +(.dtsi) are included in testcase.dts: + +drivers/of/testcase-data/tests-interrupts.dtsi +drivers/of/testcase-data/tests-platform.dtsi +drivers/of/testcase-data/tests-phandle.dtsi +drivers/of/testcase-data/tests-match.dtsi + +When the kernel is build with OF_SELFTEST enabled, then the following make rule + +$(obj)/%.dtb: $(src)/%.dts FORCE + $(call if_changed_dep, dtc) + +is used to compile the DT source file (testcase.dts) into a binary blob +(testcase.dtb), also referred as flattened DT. + +After that, using the following rule the binary blob above is wrapped as an +assembly file (testcase.dtb.S). + +$(obj)/%.dtb.S: $(obj)/%.dtb + $(call cmd, dt_S_dtb) + +The assembly file is compiled into an object file (testcase.dtb.o), and is +linked into the kernel image. + + +2.1. Adding the test data + +Un-flattened device tree structure: + +Un-flattened device tree consists of connected device_node(s) in form of a tree +structure described below. + +// following struct members are used to construct the tree +struct device_node { + ... + struct device_node *parent; + struct device_node *child; + struct device_node *sibling; + struct device_node *allnext; /* next in list of all nodes */ + ... + }; + +Figure 1, describes a generic structure of machine’s un-flattened device tree +considering only child and sibling pointers. There exists another pointer, +*parent, that is used to traverse the tree in the reverse direction. So, at +a particular level the child node and all the sibling nodes will have a parent +pointer pointing to a common node (e.g. child1, sibling2, sibling3, sibling4’s +parent points to root node) + +root (‘/’) + | +child1 -> sibling2 -> sibling3 -> sibling4 -> null + | | | | + | | | null + | | | + | | child31 -> sibling32 -> null + | | | | + | | null null + | | + | child21 -> sibling22 -> sibling23 -> null + | | | | + | null null null + | +child11 -> sibling12 -> sibling13 -> sibling14 -> null + | | | | + | | | null + | | | + null null child131 -> null + | + null + +Figure 1: Generic structure of un-flattened device tree + + +*allnext: it is used to link all the nodes of DT into a list. So, for the + above tree the list would be as follows: + +root->child1->child11->sibling12->sibling13->child131->sibling14->sibling2-> +child21->sibling22->sibling23->sibling3->child31->sibling32->sibling4->null + +Before executing OF selftest, it is required to attach the test data to +machine's device tree (if present). So, when selftest_data_add() is called, +at first it reads the flattened device tree data linked into the kernel image +via the following kernel symbols: + +__dtb_testcases_begin - address marking the start of test data blob +__dtb_testcases_end - address marking the end of test data blob + +Secondly, it calls of_fdt_unflatten_device_tree() to unflatten the flattened +blob. And finally, if the machine’s device tree (i.e live tree) is present, +then it attaches the unflattened test data tree to the live tree, else it +attaches itself as a live device tree. + +attach_node_and_children() uses of_attach_node() to attach the nodes into the +live tree as explained below. To explain the same, the test data tree described + in Figure 2 is attached to the live tree described in Figure 1. + +root (‘/’) + | + testcase-data + | + test-child0 -> test-sibling1 -> test-sibling2 -> test-sibling3 -> null + | | | | + test-child01 null null null + + +allnext list: + +root->testcase-data->test-child0->test-child01->test-sibling1->test-sibling2 +->test-sibling3->null + +Figure 2: Example test data tree to be attached to live tree. + +According to the scenario above, the live tree is already present so it isn’t +required to attach the root(‘/’) node. All other nodes are attached by calling +of_attach_node() on each node. + +In the function of_attach_node(), the new node is attached as the child of the +given parent in live tree. But, if parent already has a child then the new node +replaces the current child and turns it into its sibling. So, when the testcase +data node is attached to the live tree above (Figure 1), the final structure is + as shown in Figure 3. + +root (‘/’) + | +testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null + | | | | | + (...) | | | null + | | child31 -> sibling32 -> null + | | | | + | | null null + | | + | child21 -> sibling22 -> sibling23 -> null + | | | | + | null null null + | + child11 -> sibling12 -> sibling13 -> sibling14 -> null + | | | | + null null | null + | + child131 -> null + | + null +----------------------------------------------------------------------- + +root (‘/’) + | +testcase-data -> child1 -> sibling2 -> sibling3 -> sibling4 -> null + | | | | | + | (...) (...) (...) null + | +test-sibling3 -> test-sibling2 -> test-sibling1 -> test-child0 -> null + | | | | + null null null test-child01 + + +Figure 3: Live device tree structure after attaching the testcase-data. + + +Astute readers would have noticed that test-child0 node becomes the last +sibling compared to the earlier structure (Figure 2). After attaching first +test-child0 the test-sibling1 is attached that pushes the child node +(i.e. test-child0) to become a sibling and makes itself a child node, + as mentioned above. + +If a duplicate node is found (i.e. if a node with same full_name property is +already present in the live tree), then the node isn’t attached rather its +properties are updated to the live tree’s node by calling the function +update_node_properties(). + + +2.2. Removing the test data + +Once the test case execution is complete, selftest_data_remove is called in +order to remove the device nodes attached initially (first the leaf nodes are +detached and then moving up the parent nodes are removed, and eventually the +whole tree). selftest_data_remove() calls detach_node_and_children() that uses +of_detach_node() to detach the nodes from the live device tree. + +To detach a node, of_detach_node() first updates all_next linked list, by +attaching the previous node’s allnext to current node’s allnext pointer. And +then, it either updates the child pointer of given node’s parent to its +sibling or attaches the previous sibling to the given node’s sibling, as +appropriate. That is it :) diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt index 0dffc6e37902..6915c6b27869 100644 --- a/Documentation/networking/pktgen.txt +++ b/Documentation/networking/pktgen.txt @@ -99,6 +99,9 @@ Examples: pgset "clone_skb 1" sets the number of copies of the same packet pgset "clone_skb 0" use single SKB for all transmits + pgset "burst 8" uses xmit_more API to queue 8 copies of the same + packet and update HW tx queue tail pointer once. + "burst 1" is the default pgset "pkt_size 9014" sets packet size to 9014 pgset "frags 5" packet will consist of 5 fragments pgset "count 200000" sets number of packets to send, set to zero diff --git a/MAINTAINERS b/MAINTAINERS index f8db3c3acc67..78b9f3b77a87 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2098,7 +2098,7 @@ S: Supported F: drivers/scsi/bfa/ BROCADE BNA 10 GIGABIT ETHERNET DRIVER -M: Rasesh Mody <[email protected]> +M: Rasesh Mody <[email protected]> S: Supported F: drivers/net/ethernet/brocade/bna/ @@ -3012,9 +3012,8 @@ S: Supported F: drivers/acpi/dock.c DOCUMENTATION -M: Randy Dunlap <[email protected]> +M: Jiri Kosina <[email protected]> -T: quilt http://www.infradead.org/~rdunlap/Doc/patches/ S: Maintained F: Documentation/ X: Documentation/ABI/ @@ -3551,6 +3550,11 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git F: drivers/video/fbdev/s1d13xxxfb.c F: include/video/s1d13xxxfb.h +ET131X NETWORK DRIVER +M: Mark Einon <[email protected]> +S: Odd Fixes +F: drivers/net/ethernet/agere/ + ETHERNET BRIDGE M: Stephen Hemminger <[email protected]> @@ -4477,7 +4481,6 @@ M: Mika Westerberg <[email protected]> S: Maintained -F: drivers/i2c/i2c-acpi.c I2C-TAOS-EVM DRIVER M: Jean Delvare <[email protected]> @@ -8696,11 +8699,6 @@ M: H Hartley Sweeten <[email protected]> S: Odd Fixes F: drivers/staging/comedi/ -STAGING - ET131X NETWORK DRIVER -M: Mark Einon <[email protected]> -S: Odd Fixes -F: drivers/staging/et131x/ - STAGING - FLARION FT1000 DRIVERS M: Marek Belisko <[email protected]> S: Odd Fixes @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 17 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Shuffling Zombie Juror # *DOCUMENTATION* diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts index e03fbf3c6889..b40cdadb1f87 100644 --- a/arch/arm/boot/dts/dra7-evm.dts +++ b/arch/arm/boot/dts/dra7-evm.dts @@ -447,22 +447,19 @@ gpmc,device-width = <2>; gpmc,sync-clk-ps = <0>; gpmc,cs-on-ns = <0>; - gpmc,cs-rd-off-ns = <40>; - gpmc,cs-wr-off-ns = <40>; + gpmc,cs-rd-off-ns = <80>; + gpmc,cs-wr-off-ns = <80>; gpmc,adv-on-ns = <0>; - gpmc,adv-rd-off-ns = <30>; - gpmc,adv-wr-off-ns = <30>; - gpmc,we-on-ns = <5>; - gpmc,we-off-ns = <25>; - gpmc,oe-on-ns = <2>; - gpmc,oe-off-ns = <20>; - gpmc,access-ns = <20>; - gpmc,wr-access-ns = <40>; - gpmc,rd-cycle-ns = <40>; - gpmc,wr-cycle-ns = <40>; - gpmc,wait-pin = <0>; - gpmc,wait-on-read; - gpmc,wait-on-write; + gpmc,adv-rd-off-ns = <60>; + gpmc,adv-wr-off-ns = <60>; + gpmc,we-on-ns = <10>; + gpmc,we-off-ns = <50>; + gpmc,oe-on-ns = <4>; + gpmc,oe-off-ns = <40>; + gpmc,access-ns = <40>; + gpmc,wr-access-ns = <80>; + gpmc,rd-cycle-ns = <80>; + gpmc,wr-cycle-ns = <80>; gpmc,bus-turnaround-ns = <0>; gpmc,cycle2cycle-delay-ns = <0>; gpmc,clk-activation-ns = <0>; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index c6c58c1c00e3..6b675a02066f 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -423,10 +423,14 @@ status = "disabled"; lvds-channel@0 { + #address-cells = <1>; + #size-cells = <0>; reg = <0>; status = "disabled"; - port { + port@0 { + reg = <0>; + lvds0_in: endpoint { remote-endpoint = <&ipu_di0_lvds0>; }; @@ -434,10 +438,14 @@ }; lvds-channel@1 { + #address-cells = <1>; + #size-cells = <0>; reg = <1>; status = "disabled"; - port { + port@1 { + reg = <1>; + lvds1_in: endpoint { remote-endpoint = <&ipu_di1_lvds1>; }; diff --git a/arch/arm/boot/dts/k2e-clocks.dtsi b/arch/arm/boot/dts/k2e-clocks.dtsi index 598afe91c676..4773d6af66a0 100644 --- a/arch/arm/boot/dts/k2e-clocks.dtsi +++ b/arch/arm/boot/dts/k2e-clocks.dtsi @@ -40,7 +40,7 @@ clocks { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk16>; - clock-output-names = "usb"; + clock-output-names = "usb1"; reg = <0x02350004 0xb00>, <0x02350000 0x400>; reg-names = "control", "domain"; domain-id = <0>; @@ -60,8 +60,8 @@ clocks { #clock-cells = <0>; compatible = "ti,keystone,psc-clock"; clocks = <&chipclk12>; - clock-output-names = "pcie"; - reg = <0x0235006c 0xb00>, <0x02350000 0x400>; + clock-output-names = "pcie1"; + reg = <0x0235006c 0xb00>, <0x02350048 0x400>; reg-names = "control", "domain"; domain-id = <18>; }; diff --git a/arch/arm/boot/dts/omap5-cm-t54.dts b/arch/arm/boot/dts/omap5-cm-t54.dts index b8698ca68647..429471aa7a1f 100644 --- a/arch/arm/boot/dts/omap5-cm-t54.dts +++ b/arch/arm/boot/dts/omap5-cm-t54.dts @@ -353,13 +353,12 @@ }; ldo8_reg: ldo8 { - /* VDD_3v0: Does not go anywhere */ + /* VDD_3V_GP: act led/serial console */ regulator-name = "ldo8"; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; + regulator-always-on; regulator-boot-on; - /* Unused */ - status = "disabled"; }; ldo9_reg: ldo9 { diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 79ecb4f34ffb..10e78d00a0bb 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -466,6 +466,7 @@ static inline void __sync_cache_range_r(volatile void *p, size_t size) */ #define v7_exit_coherency_flush(level) \ asm volatile( \ + ".arch armv7-a \n\t" \ "stmfd sp!, {fp, ip} \n\t" \ "mrc p15, 0, r0, c1, c0, 0 @ get SCTLR \n\t" \ "bic r0, r0, #"__stringify(CR_C)" \n\t" \ diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h index 36172adda9d0..5f833f7adba1 100644 --- a/arch/arm/include/asm/tls.h +++ b/arch/arm/include/asm/tls.h @@ -81,6 +81,7 @@ static inline void set_tls(unsigned long val) asm("mcr p15, 0, %0, c13, c0, 3" : : "r" (val)); } else { +#ifdef CONFIG_KUSER_HELPERS /* * User space must never try to access this * directly. Expect your app to break @@ -89,6 +90,7 @@ static inline void set_tls(unsigned long val) * entry-armv.S for details) */ *((unsigned int *)0xffff0ff0) = val; +#endif } } diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c index 08d731294bcd..b206d7790c77 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/kernel/kprobes-test.c @@ -110,10 +110,13 @@ * * @ TESTCASE_START * bl __kprobes_test_case_start - * @ start of inline data... + * .pushsection .rodata + * "10: * .ascii "mov r0, r7" @ text title for test case * .byte 0 - * .align 2, 0 + * .popsection + * @ start of inline data... + * .word 10b @ pointer to title in .rodata section * * @ TEST_ARG_REG * .byte ARG_TYPE_REG @@ -971,7 +974,7 @@ void __naked __kprobes_test_case_start(void) __asm__ __volatile__ ( "stmdb sp!, {r4-r11} \n\t" "sub sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t" - "bic r0, lr, #1 @ r0 = inline title string \n\t" + "bic r0, lr, #1 @ r0 = inline data \n\t" "mov r1, sp \n\t" "bl kprobes_test_case_start \n\t" "bx r0 \n\t" @@ -1349,15 +1352,14 @@ static unsigned long next_instruction(unsigned long pc) return pc + 4; } -static uintptr_t __used kprobes_test_case_start(const char *title, void *stack) +static uintptr_t __used kprobes_test_case_start(const char **title, void *stack) { struct test_arg *args; struct test_arg_end *end_arg; unsigned long test_code; - args = (struct test_arg *)PTR_ALIGN(title + strlen(title) + 1, 4); - - current_title = title; + current_title = *title++; + args = (struct test_arg *)title; current_args = args; current_stack = stack; diff --git a/arch/arm/kernel/kprobes-test.h b/arch/arm/kernel/kprobes-test.h index eecc90a0fd91..4430990e90e7 100644 --- a/arch/arm/kernel/kprobes-test.h +++ b/arch/arm/kernel/kprobes-test.h @@ -111,11 +111,14 @@ struct test_arg_end { #define TESTCASE_START(title) \ __asm__ __volatile__ ( \ "bl __kprobes_test_case_start \n\t" \ + ".pushsection .rodata \n\t" \ + "10: \n\t" \ /* don't use .asciz here as 'title' may be */ \ /* multiple strings to be concatenated. */ \ ".ascii "#title" \n\t" \ ".byte 0 \n\t" \ - ".align 2, 0 \n\t" + ".popsection \n\t" \ + ".word 10b \n\t" #define TEST_ARG_REG(reg, val) \ ".byte "__stringify(ARG_TYPE_REG)" \n\t" \ diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c index 84acdfd1d715..5a75cdc81891 100644 --- a/arch/arm/mach-imx/clk-gate2.c +++ b/arch/arm/mach-imx/clk-gate2.c @@ -97,7 +97,7 @@ static int clk_gate2_is_enabled(struct clk_hw *hw) struct clk_gate2 *gate = to_clk_gate2(hw); if (gate->share_count) - return !!(*gate->share_count); + return !!__clk_get_enable_count(hw->clk); else return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx); } @@ -127,10 +127,6 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, gate->bit_idx = bit_idx; gate->flags = clk_gate2_flags; gate->lock = lock; - - /* Initialize share_count per hardware state */ - if (share_count) - *share_count = clk_gate2_reg_is_enabled(reg, bit_idx) ? 1 : 0; gate->share_count = share_count; init.name = name; diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index e7189dcc9309..08d4167cc7c5 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -1,9 +1,6 @@ menu "TI OMAP/AM/DM/DRA Family" depends on ARCH_MULTI_V6 || ARCH_MULTI_V7 -config ARCH_OMAP - bool - config ARCH_OMAP2 bool "TI OMAP2" depends on ARCH_MULTI_V6 diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 8fd87a3055bf..9e91a4e7519a 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2065,7 +2065,7 @@ static void _reconfigure_io_chain(void) spin_lock_irqsave(&io_chain_lock, flags); - if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl()) + if (cpu_is_omap34xx()) omap3xxx_prm_reconfigure_io_chain(); else if (cpu_is_omap44xx()) omap44xx_prm_reconfigure_io_chain(); diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index 2458be6fc67b..372de3edf4a5 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -45,7 +45,7 @@ static struct omap_prcm_irq_setup omap3_prcm_irq_setup = { .ocp_barrier = &omap3xxx_prm_ocp_barrier, .save_and_clear_irqen = &omap3xxx_prm_save_and_clear_irqen, .restore_irqen = &omap3xxx_prm_restore_irqen, - .reconfigure_io_chain = &omap3xxx_prm_reconfigure_io_chain, + .reconfigure_io_chain = NULL, }; /* @@ -369,15 +369,30 @@ void __init omap3_prm_init_pm(bool has_uart4, bool has_iva) } /** - * omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain + * omap3430_pre_es3_1_reconfigure_io_chain - restart wake-up daisy chain + * + * The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only + * thing we can do is toggle EN_IO bit for earlier omaps. + */ +void omap3430_pre_es3_1_reconfigure_io_chain(void) +{ + omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, + PM_WKEN); + omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, + PM_WKEN); + omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN); +} + +/** + * omap3_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain * * Clear any previously-latched I/O wakeup events and ensure that the * I/O wakeup gates are aligned with the current mux settings. Works * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No - * return value. + * return value. These registers are only available in 3430 es3.1 and later. */ -void omap3xxx_prm_reconfigure_io_chain(void) +void omap3_prm_reconfigure_io_chain(void) { int i = 0; @@ -400,6 +415,15 @@ void omap3xxx_prm_reconfigure_io_chain(void) } /** + * omap3xxx_prm_reconfigure_io_chain - reconfigure I/O chain + */ +void omap3xxx_prm_reconfigure_io_chain(void) +{ + if (omap3_prcm_irq_setup.reconfigure_io_chain) + omap3_prcm_irq_setup.reconfigure_io_chain(); +} + +/** * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches * * Activates the I/O wakeup event latches and allows events logged by @@ -656,6 +680,13 @@ static int omap3xxx_prm_late_init(void) if (!(prm_features & PRM_HAS_IO_WAKEUP)) return 0; + if (omap3_has_io_chain_ctrl()) + omap3_prcm_irq_setup.reconfigure_io_chain = + omap3_prm_reconfigure_io_chain; + else + omap3_prcm_irq_setup.reconfigure_io_chain = + omap3430_pre_es3_1_reconfigure_io_chain; + omap3xxx_prm_enable_io_wakeup(); ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup); if (!ret) diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 630fa916bbc6..04b013fbc98f 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -61,7 +61,7 @@ EXPORT_SYMBOL(get_clock_tick_rate); /* * For non device-tree builds, keep legacy timer init */ -void pxa_timer_init(void) +void __init pxa_timer_init(void) { pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x40a00000), get_clock_tick_rate()); diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 0c1ab49e5f7b..83792f4324ea 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -41,6 +41,7 @@ * This code is not portable to processors with late data abort handling. */ #define CODING_BITS(i) (i & 0x0e000000) +#define COND_BITS(i) (i & 0xf0000000) #define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */ #define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */ @@ -821,6 +822,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) break; case 0x04000000: /* ldr or str immediate */ + if (COND_BITS(instr) == 0xf0000000) /* NEON VLDn, VSTn */ + goto bad; offset.un = OFFSET_BITS(instr); handler = do_alignment_ldrstr; break; diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S index b64e67c7f176..d3daed0ae0ad 100644 --- a/arch/arm/mm/proc-v7-3level.S +++ b/arch/arm/mm/proc-v7-3level.S @@ -157,9 +157,9 @@ ENDPROC(cpu_v7_set_pte_ext) * TFR EV X F IHD LR S * .EEE ..EE PUI. .TAT 4RVI ZWRS BLDP WCAM * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced - * 11 0 110 1 0011 1100 .111 1101 < we want + * 11 0 110 0 0011 1100 .111 1101 < we want */ .align 2 .type v7_crval, #object v7_crval: - crval clear=0x0120c302, mmuset=0x30c23c7d, ucset=0x00c01c7c + crval clear=0x0122c302, mmuset=0x30c03c7d, ucset=0x00c01c7c diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 02fc10d2d63b..d055db32ffcb 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -1,3 +1,6 @@ +config ARCH_OMAP + bool + if ARCH_OMAP menu "TI OMAP Common Features" diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 5d25462de8a6..2f7c734771f4 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -129,7 +129,11 @@ NESTED(_mcount, PT_SIZE, ra) nop #endif b ftrace_stub +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#else nop +#endif static_trace: MCOUNT_SAVE_REGS @@ -139,6 +143,9 @@ static_trace: move a1, AT /* arg2: parent's return address */ MCOUNT_RESTORE_REGS +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#endif .globl ftrace_stub ftrace_stub: RETURN_BACK @@ -183,6 +190,11 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra) jal prepare_ftrace_return nop MCOUNT_RESTORE_REGS +#ifndef CONFIG_DYNAMIC_FTRACE +#ifdef CONFIG_32BIT + addiu sp, sp, 8 +#endif +#endif RETURN_BACK END(ftrace_graph_caller) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index bf0fc6b16ad9..7a4727795a70 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -650,9 +650,9 @@ static inline int cop1_64bit(struct pt_regs *xcp) #define SIFROMREG(si, x) \ do { \ if (cop1_64bit(xcp)) \ - (si) = get_fpr32(&ctx->fpr[x], 0); \ + (si) = (int)get_fpr32(&ctx->fpr[x], 0); \ else \ - (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ + (si) = (int)get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ } while (0) #define SITOREG(si, x) \ @@ -667,7 +667,7 @@ do { \ } \ } while (0) -#define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1)) +#define SIFROMHREG(si, x) ((si) = (int)get_fpr32(&ctx->fpr[x], 1)) #define SITOHREG(si, x) \ do { \ diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 7a801a310e37..0fcd9133790c 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -33,8 +33,7 @@ VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone ifeq ($(CONFIG_EFI_STUB), y) - VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ - $(objtree)/drivers/firmware/efi/libstub/lib.a + VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o endif $(obj)/vmlinux: $(VMLINUX_OBJS) FORCE diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index fc6091abedb7..d39189ba7f8e 100644 --- a/arch/x86/boot/compressed/aslr.c +++ b/arch/x86/boot/compressed/aslr.c @@ -183,12 +183,27 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size, static bool mem_avoid_overlap(struct mem_vector *img) { int i; + struct setup_data *ptr; for (i = 0; i < MEM_AVOID_MAX; i++) { if (mem_overlaps(img, &mem_avoid[i])) return true; } + /* Avoid all entries in the setup_data linked list. */ + ptr = (struct setup_data *)(unsigned long)real_mode->hdr.setup_data; + while (ptr) { + struct mem_vector avoid; + + avoid.start = (u64)ptr; + avoid.size = sizeof(*ptr) + ptr->len; + + if (mem_overlaps(img, &avoid)) + return true; + + ptr = (struct setup_data *)(unsigned long)ptr->next; + } + return false; } diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index dca9842d8f91..de8eebd6f67c 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -19,7 +19,10 @@ static efi_system_table_t *sys_table; -struct efi_config *efi_early; +static struct efi_config *efi_early; + +#define efi_call_early(f, ...) \ + efi_early->call(efi_early->f, __VA_ARGS__); #define BOOT_SERVICES(bits) \ static void setup_boot_services##bits(struct efi_config *c) \ @@ -265,21 +268,25 @@ void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str) offset = offsetof(typeof(*out), output_string); output_string = efi_early->text_output + offset; + out = (typeof(out))(unsigned long)efi_early->text_output; func = (u64 *)output_string; - efi_early->call(*func, efi_early->text_output, str); + efi_early->call(*func, out, str); } else { struct efi_simple_text_output_protocol_32 *out; u32 *func; offset = offsetof(typeof(*out), output_string); output_string = efi_early->text_output + offset; + out = (typeof(out))(unsigned long)efi_early->text_output; func = (u32 *)output_string; - efi_early->call(*func, efi_early->text_output, str); + efi_early->call(*func, out, str); } } +#include "../../../../drivers/firmware/efi/libstub/efi-stub-helper.c" + static void find_bits(unsigned long mask, u8 *pos, u8 *size) { u8 first, len; @@ -360,7 +367,7 @@ free_struct: return status; } -static efi_status_t +static void setup_efi_pci32(struct boot_params *params, void **pci_handle, unsigned long size) { @@ -403,8 +410,6 @@ setup_efi_pci32(struct boot_params *params, void **pci_handle, data = (struct setup_data *)rom; } - - return status; } static efi_status_t @@ -463,7 +468,7 @@ free_struct: } -static efi_status_t +static void setup_efi_pci64(struct boot_params *params, void **pci_handle, unsigned long size) { @@ -506,11 +511,18 @@ setup_efi_pci64(struct boot_params *params, void **pci_handle, data = (struct setup_data *)rom; } - - return status; } -static efi_status_t setup_efi_pci(struct boot_params *params) +/* + * There's no way to return an informative status from this function, + * because any analysis (and printing of error messages) needs to be + * done directly at the EFI function call-site. + * + * For example, EFI_INVALID_PARAMETER could indicate a bug or maybe we + * just didn't find any PCI devices, but there's no way to tell outside + * the context of the call. + */ +static void setup_efi_pci(struct boot_params *params) { efi_status_t status; void **pci_handle = NULL; @@ -527,7 +539,7 @@ static efi_status_t setup_efi_pci(struct boot_params *params) size, (void **)&pci_handle); if (status != EFI_SUCCESS) - return status; + return; status = efi_call_early(locate_handle, EFI_LOCATE_BY_PROTOCOL, &pci_proto, @@ -538,13 +550,12 @@ static efi_status_t setup_efi_pci(struct boot_params *params) goto free_handle; if (efi_early->is64) - status = setup_efi_pci64(params, pci_handle, size); + setup_efi_pci64(params, pci_handle, size); else - status = setup_efi_pci32(params, pci_handle, size); + setup_efi_pci32(params, pci_handle, size); free_handle: efi_call_early(free_pool, pci_handle); - return status; } static void @@ -1380,10 +1391,7 @@ struct boot_params *efi_main(struct efi_config *c, setup_graphics(boot_params); - status = setup_efi_pci(boot_params); - if (status != EFI_SUCCESS) { - efi_printk(sys_table, "setup_efi_pci() failed!\n"); - } + setup_efi_pci(boot_params); status = efi_call_early(allocate_pool, EFI_LOADER_DATA, sizeof(*gdt), (void **)&gdt); diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h index d487e727f1ec..c88c31ecad12 100644 --- a/arch/x86/boot/compressed/eboot.h +++ b/arch/x86/boot/compressed/eboot.h @@ -103,4 +103,20 @@ struct efi_uga_draw_protocol { void *blt; }; +struct efi_config { + u64 image_handle; + u64 table; + u64 allocate_pool; + u64 allocate_pages; + u64 get_memory_map; + u64 free_pool; + u64 free_pages; + u64 locate_handle; + u64 handle_protocol; + u64 exit_boot_services; + u64 text_output; + efi_status_t (*call)(unsigned long, ...); + bool is64; +} __packed; + #endif /* BOOT_COMPRESSED_EBOOT_H */ diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 044a2fd3c5fe..0ec241ede5a2 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -159,30 +159,6 @@ static inline efi_status_t efi_thunk_set_virtual_address_map( } #endif /* CONFIG_EFI_MIXED */ - -/* arch specific definitions used by the stub code */ - -struct efi_config { - u64 image_handle; - u64 table; - u64 allocate_pool; - u64 allocate_pages; - u64 get_memory_map; - u64 free_pool; - u64 free_pages; - u64 locate_handle; - u64 handle_protocol; - u64 exit_boot_services; - u64 text_output; - efi_status_t (*call)(unsigned long, ...); - bool is64; -} __packed; - -extern struct efi_config *efi_early; - -#define efi_call_early(f, ...) \ - efi_early->call(efi_early->f, __VA_ARGS__); - extern bool efi_reboot_required(void); #else diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index b0910f97a3ea..ffb1733ac91f 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -106,14 +106,14 @@ enum fixed_addresses { __end_of_permanent_fixed_addresses, /* - * 256 temporary boot-time mappings, used by early_ioremap(), + * 512 temporary boot-time mappings, used by early_ioremap(), * before ioremap() is functional. * - * If necessary we round it up to the next 256 pages boundary so + * If necessary we round it up to the next 512 pages boundary so * that we can have a single pgd entry and a single pte table: */ #define NR_FIX_BTMAPS 64 -#define FIX_BTMAPS_SLOTS 4 +#define FIX_BTMAPS_SLOTS 8 #define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS) FIX_BTMAP_END = (__end_of_permanent_fixed_addresses ^ diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 2d872e08fab9..42a2dca984b3 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1284,6 +1284,9 @@ static void remove_siblinginfo(int cpu) for_each_cpu(sibling, cpu_sibling_mask(cpu)) cpumask_clear_cpu(cpu, cpu_sibling_mask(sibling)); + for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) + cpumask_clear_cpu(cpu, cpu_llc_shared_mask(sibling)); + cpumask_clear(cpu_llc_shared_mask(cpu)); cpumask_clear(cpu_sibling_mask(cpu)); cpumask_clear(cpu_core_mask(cpu)); c->phys_proc_id = 0; diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index fddc1e86f9d0..b0ea767c8696 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -419,7 +419,6 @@ static int acpi_lpss_create_device(struct acpi_device *adev, adev->driver_data = pdata; pdev = acpi_create_platform_device(adev); if (!IS_ERR_OR_NULL(pdev)) { - device_enable_async_suspend(&pdev->dev); return 1; } diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 1f9aba5fb81f..2747279fbe3c 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -254,6 +254,7 @@ struct acpi_create_field_info { u32 field_bit_position; u32 field_bit_length; u16 resource_length; + u16 pin_number_index; u8 field_flags; u8 attribute; u8 field_type; diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 22fb6449d3d6..8abb393dafab 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -264,6 +264,7 @@ struct acpi_object_region_field { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length; union acpi_operand_object *region_obj; /* Containing op_region object */ u8 *resource_buffer; /* resource_template for serial regions/fields */ + u16 pin_number_index; /* Index relative to previous Connection/Template */ }; struct acpi_object_bank_field { diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 3661c8e90540..c57666196672 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -360,6 +360,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, */ info->resource_buffer = NULL; info->connection_node = NULL; + info->pin_number_index = 0; /* * A Connection() is either an actual resource descriptor (buffer) @@ -437,6 +438,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, } info->field_bit_position += info->field_bit_length; + info->pin_number_index++; /* Index relative to previous Connection() */ break; default: diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 9957297d1580..8eb8575e8c16 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -142,6 +142,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, union acpi_operand_object *region_obj2; void *region_context = NULL; struct acpi_connection_info *context; + acpi_physical_address address; ACPI_FUNCTION_TRACE(ev_address_space_dispatch); @@ -231,25 +232,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* We have everything we need, we can invoke the address space handler */ handler = handler_desc->address_space.handler; - - ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, - "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", - ®ion_obj->region.handler->address_space, handler, - ACPI_FORMAT_NATIVE_UINT(region_obj->region.address + - region_offset), - acpi_ut_get_region_name(region_obj->region. - space_id))); + address = (region_obj->region.address + region_offset); /* * Special handling for generic_serial_bus and general_purpose_io: * There are three extra parameters that must be passed to the * handler via the context: - * 1) Connection buffer, a resource template from Connection() op. - * 2) Length of the above buffer. - * 3) Actual access length from the access_as() op. + * 1) Connection buffer, a resource template from Connection() op + * 2) Length of the above buffer + * 3) Actual access length from the access_as() op + * + * In addition, for general_purpose_io, the Address and bit_width fields + * are defined as follows: + * 1) Address is the pin number index of the field (bit offset from + * the previous Connection) + * 2) bit_width is the actual bit length of the field (number of pins) */ - if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) || - (region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) && + if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) && context && field_obj) { /* Get the Connection (resource_template) buffer */ @@ -258,6 +257,24 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, context->length = field_obj->field.resource_length; context->access_length = field_obj->field.access_length; } + if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) && + context && field_obj) { + + /* Get the Connection (resource_template) buffer */ + + context->connection = field_obj->field.resource_buffer; + context->length = field_obj->field.resource_length; + context->access_length = field_obj->field.access_length; + address = field_obj->field.pin_number_index; + bit_width = field_obj->field.bit_length; + } + + ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, + "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", + ®ion_obj->region.handler->address_space, handler, + ACPI_FORMAT_NATIVE_UINT(address), + acpi_ut_get_region_name(region_obj->region. + space_id))); if (!(handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { @@ -271,9 +288,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* Call the handler */ - status = handler(function, - (region_obj->region.address + region_offset), - bit_width, value, context, + status = handler(function, address, bit_width, value, context, region_obj2->extra.region_context); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 6907ce0c704c..b994845ed359 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -253,6 +253,37 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, buffer = &buffer_desc->integer.value; } + if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && + (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GPIO)) { + /* + * For GPIO (general_purpose_io), the Address will be the bit offset + * from the previous Connection() operator, making it effectively a + * pin number index. The bit_length is the length of the field, which + * is thus the number of pins. + */ + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "GPIO FieldRead [FROM]: Pin %u Bits %u\n", + obj_desc->field.pin_number_index, + obj_desc->field.bit_length)); + + /* Lock entire transaction if requested */ + + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + + /* Perform the write */ + + status = acpi_ex_access_region(obj_desc, 0, + (u64 *)buffer, ACPI_READ); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); + if (ACPI_FAILURE(status)) { + acpi_ut_remove_reference(buffer_desc); + } else { + *ret_buffer_desc = buffer_desc; + } + return_ACPI_STATUS(status); + } + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", obj_desc, obj_desc->common.type, buffer, @@ -413,6 +444,42 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, *result_desc = buffer_desc; return_ACPI_STATUS(status); + } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && + (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GPIO)) { + /* + * For GPIO (general_purpose_io), we will bypass the entire field + * mechanism and handoff the bit address and bit width directly to + * the handler. The Address will be the bit offset + * from the previous Connection() operator, making it effectively a + * pin number index. The bit_length is the length of the field, which + * is thus the number of pins. + */ + if (source_desc->common.type != ACPI_TYPE_INTEGER) { + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); + } + + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", + acpi_ut_get_type_name(source_desc->common. + type), + source_desc->common.type, + (u32)source_desc->integer.value, + obj_desc->field.pin_number_index, + obj_desc->field.bit_length)); + + buffer = &source_desc->integer.value; + + /* Lock entire transaction if requested */ + + acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); + + /* Perform the write */ + + status = acpi_ex_access_region(obj_desc, 0, + (u64 *)buffer, ACPI_WRITE); + acpi_ex_release_global_lock(obj_desc->common_field.field_flags); + return_ACPI_STATUS(status); } /* Get a pointer to the data to be written */ diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index ee3f872870bc..118e942005e5 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -484,6 +484,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) obj_desc->field.resource_length = info->resource_length; } + obj_desc->field.pin_number_index = info->pin_number_index; + /* Allow full data read from EC address space */ if ((obj_desc->field.region_obj->region.space_id == diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 76f7cff64594..c8ead9f97375 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -99,6 +99,13 @@ static void container_device_detach(struct acpi_device *adev) device_unregister(dev); } +static void container_device_online(struct acpi_device *adev) +{ + struct device *dev = acpi_driver_data(adev); + + kobject_uevent(&dev->kobj, KOBJ_ONLINE); +} + static struct acpi_scan_handler container_handler = { .ids = container_device_ids, .attach = container_device_attach, @@ -106,6 +113,7 @@ static struct acpi_scan_handler container_handler = { .hotplug = { .enabled = true, .demand_offline = true, + .notify_online = container_device_online, }, }; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 3bf7764659a4..ae44d8654c82 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -130,7 +130,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, list_for_each_entry(id, &acpi_dev->pnp.ids, list) { count = snprintf(&modalias[len], size, "%s:", id->id); if (count < 0) - return EINVAL; + return -EINVAL; if (count >= size) return -ENOMEM; len += count; @@ -2189,6 +2189,9 @@ static void acpi_bus_attach(struct acpi_device *device) ok: list_for_each_entry(child, &device->children, node) acpi_bus_attach(child); + + if (device->handler && device->handler->hotplug.notify_online) + device->handler->hotplug.notify_online(device); } /** diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index fcbda105616e..8e7e18567ae6 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -750,6 +750,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"), }, }, + { + .callback = video_disable_native_backlight, + .ident = "ThinkPad X201s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"), + }, + }, /* The native backlight controls do not work on some older machines */ { diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 551e01061434..95254585db86 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -188,31 +188,31 @@ static struct l3_flagmux_data omap_l3_flagmux_clk3 = { }; static struct l3_masters_data omap_l3_masters[] = { - { 0x0 , "MPU"}, - { 0x10, "CS_ADP"}, - { 0x14, "xxx"}, - { 0x20, "DSP"}, - { 0x30, "IVAHD"}, - { 0x40, "ISS"}, - { 0x44, "DucatiM3"}, - { 0x48, "FaceDetect"}, - { 0x50, "SDMA_Rd"}, - { 0x54, "SDMA_Wr"}, - { 0x58, "xxx"}, - { 0x5C, "xxx"}, - { 0x60, "SGX"}, - { 0x70, "DSS"}, - { 0x80, "C2C"}, - { 0x88, "xxx"}, - { 0x8C, "xxx"}, - { 0x90, "HSI"}, - { 0xA0, "MMC1"}, - { 0xA4, "MMC2"}, - { 0xA8, "MMC6"}, - { 0xB0, "UNIPRO1"}, - { 0xC0, "USBHOSTHS"}, - { 0xC4, "USBOTGHS"}, - { 0xC8, "USBHOSTFS"} + { 0x00, "MPU"}, + { 0x04, "CS_ADP"}, + { 0x05, "xxx"}, + { 0x08, "DSP"}, + { 0x0C, "IVAHD"}, + { 0x10, "ISS"}, + { 0x11, "DucatiM3"}, + { 0x12, "FaceDetect"}, + { 0x14, "SDMA_Rd"}, + { 0x15, "SDMA_Wr"}, + { 0x16, "xxx"}, + { 0x17, "xxx"}, + { 0x18, "SGX"}, + { 0x1C, "DSS"}, + { 0x20, "C2C"}, + { 0x22, "xxx"}, + { 0x23, "xxx"}, + { 0x24, "HSI"}, + { 0x28, "MMC1"}, + { 0x29, "MMC2"}, + { 0x2A, "MMC6"}, + { 0x2C, "UNIPRO1"}, + { 0x30, "USBHOSTHS"}, + { 0x31, "USBOTGHS"}, + { 0x32, "USBHOSTFS"} }; static struct l3_flagmux_data *omap_l3_flagmux[] = { diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d9fdeddcef96..6e93e7f98358 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1289,6 +1289,8 @@ err_get_freq: per_cpu(cpufreq_cpu_data, j) = NULL; write_unlock_irqrestore(&cpufreq_driver_lock, flags); + up_write(&policy->rwsem); + if (cpufreq_driver->exit) cpufreq_driver->exit(policy); err_set_policy_cpu: @@ -1656,6 +1658,8 @@ void cpufreq_suspend(void) if (!cpufreq_driver) return; + cpufreq_suspended = true; + if (!has_target()) return; @@ -1670,8 +1674,6 @@ void cpufreq_suspend(void) pr_err("%s: Failed to suspend driver: %p\n", __func__, policy); } - - cpufreq_suspended = true; } /** @@ -1687,13 +1689,13 @@ void cpufreq_resume(void) if (!cpufreq_driver) return; + cpufreq_suspended = false; + if (!has_target()) return; pr_debug("%s: Resuming Governors\n", __func__); - cpufreq_suspended = false; - list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) pr_err("%s: Failed to resume driver: %p\n", __func__, diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 4cf7d9a950d7..bbea8243f9e8 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -1017,6 +1017,11 @@ static int omap_dma_resume(struct omap_chan *c) return -EINVAL; if (c->paused) { + mb(); + + /* Restore channel link register */ + omap_dma_chan_write(c, CLNK_CTRL, c->desc->clnk_ctrl); + omap_dma_start(c, c->desc); c->paused = false; } diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index d8be608a9f3b..aef6a95adef5 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -7,4 +7,4 @@ obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o obj-$(CONFIG_UEFI_CPER) += cper.o obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o -obj-$(CONFIG_EFI_STUB) += libstub/ +obj-$(CONFIG_EFI_ARM_STUB) += libstub/ diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index d62eaaa75397..687476fb39e3 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -377,8 +377,10 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, struct gpio_chip *chip = achip->chip; struct acpi_resource_gpio *agpio; struct acpi_resource *ares; + int pin_index = (int)address; acpi_status status; bool pull_up; + int length; int i; status = acpi_buffer_to_resource(achip->conn_info.connection, @@ -400,7 +402,8 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, return AE_BAD_PARAMETER; } - for (i = 0; i < agpio->pin_table_length; i++) { + length = min(agpio->pin_table_length, (u16)(pin_index + bits)); + for (i = pin_index; i < length; ++i) { unsigned pin = agpio->pin_table[i]; struct acpi_gpio_connection *conn; struct gpio_desc *desc; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 15cc0bb65dda..c68d037de656 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -413,12 +413,12 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, return; } - irq_set_chained_handler(parent_irq, parent_handler); /* * The parent irqchip is already using the chip_data for this * irqchip, so our callbacks simply use the handler_data. */ irq_set_handler_data(parent_irq, gpiochip); + irq_set_chained_handler(parent_irq, parent_handler); } EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); @@ -1674,7 +1674,7 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, set_bit(FLAG_OPEN_SOURCE, &desc->flags); /* No particular flag request, return here... */ - if (flags & GPIOD_FLAGS_BIT_DIR_SET) + if (!(flags & GPIOD_FLAGS_BIT_DIR_SET)) return desc; /* Process flags */ diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index dea99d92fb4a..4b7ed5289217 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -709,11 +709,13 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring) BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count)); BUG_ON(!validate_regs_sorted(ring)); - ret = init_hash_table(ring, cmd_tables, cmd_table_count); - if (ret) { - DRM_ERROR("CMD: cmd_parser_init failed!\n"); - fini_hash_table(ring); - return ret; + if (hash_empty(ring->cmd_hash)) { + ret = init_hash_table(ring, cmd_tables, cmd_table_count); + if (ret) { + DRM_ERROR("CMD: cmd_parser_init failed!\n"); + fini_hash_table(ring); + return ret; + } } ring->needs_cmd_parser = true; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ca34de7f6a7b..5a9de21637b7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -732,7 +732,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, if (tmp & HDMI_MODE_SELECT_HDMI) pipe_config->has_hdmi_sink = true; - if (tmp & HDMI_MODE_SELECT_HDMI) + if (tmp & SDVO_AUDIO_ENABLE) pipe_config->has_audio = true; if (!HAS_PCH_SPLIT(dev) && diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index fa9565957f9d..3d546c606b43 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -4803,7 +4803,7 @@ struct bonaire_mqd */ static int cik_cp_compute_resume(struct radeon_device *rdev) { - int r, i, idx; + int r, i, j, idx; u32 tmp; bool use_doorbell = true; u64 hqd_gpu_addr; @@ -4922,7 +4922,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) mqd->queue_state.cp_hqd_pq_wptr= 0; if (RREG32(CP_HQD_ACTIVE) & 1) { WREG32(CP_HQD_DEQUEUE_REQUEST, 1); - for (i = 0; i < rdev->usec_timeout; i++) { + for (j = 0; j < rdev->usec_timeout; j++) { if (!(RREG32(CP_HQD_ACTIVE) & 1)) break; udelay(1); @@ -7751,17 +7751,17 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -8251,6 +8251,7 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); @@ -8259,7 +8260,6 @@ restart_ih: if (queue_thermal) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index dbca60c7d097..e50807c29f69 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -4749,17 +4749,17 @@ static u32 evergreen_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -5137,6 +5137,7 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); @@ -5145,7 +5146,6 @@ restart_ih: if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 3cfb50056f7a..ea5c9af722ef 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3792,17 +3792,17 @@ static u32 r600_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -4048,6 +4048,7 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); @@ -4056,7 +4057,6 @@ restart_ih: if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5f05b4c84338..3247bfd14410 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -106,6 +106,7 @@ extern int radeon_vm_block_size; extern int radeon_deep_color; extern int radeon_use_pflipirq; extern int radeon_bapm; +extern int radeon_backlight; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 75223dd3a8a3..12c8329644c4 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -123,6 +123,10 @@ static struct radeon_px_quirk radeon_px_quirk_list[] = { * https://bugzilla.kernel.org/show_bug.cgi?id=51381 */ { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX }, + /* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU + * https://bugzilla.kernel.org/show_bug.cgi?id=51381 + */ + { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX }, /* macbook pro 8.2 */ { PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP }, { 0, 0, 0, 0, 0 }, diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 4126fd0937a2..f9d17b29b343 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -181,6 +181,7 @@ int radeon_vm_block_size = -1; int radeon_deep_color = 0; int radeon_use_pflipirq = 2; int radeon_bapm = -1; +int radeon_backlight = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -263,6 +264,9 @@ module_param_named(use_pflipirq, radeon_use_pflipirq, int, 0444); MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(bapm, radeon_bapm, int, 0444); +MODULE_PARM_DESC(backlight, "backlight support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(backlight, radeon_backlight, int, 0444); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 3c2094c25b53..15edf23b465c 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -158,10 +158,43 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8 return ret; } +static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder, + struct drm_connector *connector) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + bool use_bl = false; + + if (!(radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))) + return; + + if (radeon_backlight == 0) { + return; + } else if (radeon_backlight == 1) { + use_bl = true; + } else if (radeon_backlight == -1) { + /* Quirks */ + /* Amilo Xi 2550 only works with acpi bl */ + if ((rdev->pdev->device == 0x9583) && + (rdev->pdev->subsystem_vendor == 0x1734) && + (rdev->pdev->subsystem_device == 0x1107)) + use_bl = false; + else + use_bl = true; + } + + if (use_bl) { + if (rdev->is_atom_bios) + radeon_atom_backlight_init(radeon_encoder, connector); + else + radeon_legacy_backlight_init(radeon_encoder, connector); + rdev->mode_info.bl_encoder = radeon_encoder; + } +} + void radeon_link_encoder_connector(struct drm_device *dev) { - struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; struct radeon_connector *radeon_connector; struct drm_encoder *encoder; @@ -174,13 +207,8 @@ radeon_link_encoder_connector(struct drm_device *dev) radeon_encoder = to_radeon_encoder(encoder); if (radeon_encoder->devices & radeon_connector->devices) { drm_mode_connector_attach_encoder(connector, encoder); - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (rdev->is_atom_bios) - radeon_atom_backlight_init(radeon_encoder, connector); - else - radeon_legacy_backlight_init(radeon_encoder, connector); - rdev->mode_info.bl_encoder = radeon_encoder; - } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + radeon_encoder_add_backlight(radeon_encoder, connector); } } } diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 6bce40847753..3a0b973e8a96 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6316,17 +6316,17 @@ static inline u32 si_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -6664,13 +6664,13 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index e0228b228256..1722f50f2473 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -2,11 +2,8 @@ # Makefile for the i2c core. # -i2ccore-y := i2c-core.o -i2ccore-$(CONFIG_ACPI) += i2c-acpi.o - obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o -obj-$(CONFIG_I2C) += i2ccore.o +obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-$(CONFIG_I2C_MUX) += i2c-mux.o diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 984492553e95..d9ee43c80cde 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -497,7 +497,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->wr_len_cmd = dma_size; desc->control |= ISMT_DESC_BLK; priv->dma_buffer[0] = command; - memcpy(&priv->dma_buffer[1], &data->block[1], dma_size); + memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); } else { /* Block Read */ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); @@ -525,7 +525,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->wr_len_cmd = dma_size; desc->control |= ISMT_DESC_I2C; priv->dma_buffer[0] = command; - memcpy(&priv->dma_buffer[1], &data->block[1], dma_size); + memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); } else { /* i2c Block Read */ dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 7170fc892829..65a21fed08b5 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -429,7 +429,7 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, ret = mxs_i2c_pio_wait_xfer_end(i2c); if (ret) { dev_err(i2c->dev, - "PIO: Failed to send SELECT command!\n"); + "PIO: Failed to send READ command!\n"); goto cleanup; } diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 1cc146cfc1f3..e506fcd3ca04 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -76,8 +76,8 @@ #define RCAR_IRQ_RECV (MNR | MAL | MST | MAT | MDR) #define RCAR_IRQ_STOP (MST) -#define RCAR_IRQ_ACK_SEND (~(MAT | MDE)) -#define RCAR_IRQ_ACK_RECV (~(MAT | MDR)) +#define RCAR_IRQ_ACK_SEND (~(MAT | MDE) & 0xFF) +#define RCAR_IRQ_ACK_RECV (~(MAT | MDR) & 0xFF) #define ID_LAST_MSG (1 << 0) #define ID_IOERROR (1 << 1) diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index e637c32ae517..93cfc837200b 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -433,12 +433,11 @@ static void rk3x_i2c_set_scl_rate(struct rk3x_i2c *i2c, unsigned long scl_rate) unsigned long i2c_rate = clk_get_rate(i2c->clk); unsigned int div; - /* SCL rate = (clk rate) / (8 * DIV) */ - div = DIV_ROUND_UP(i2c_rate, scl_rate * 8); - - /* The lower and upper half of the CLKDIV reg describe the length of - * SCL low & high periods. */ - div = DIV_ROUND_UP(div, 2); + /* set DIV = DIVH = DIVL + * SCL rate = (clk rate) / (8 * (DIVH + 1 + DIVL + 1)) + * = (clk rate) / (16 * (DIV + 1)) + */ + div = DIV_ROUND_UP(i2c_rate, scl_rate * 16) - 1; i2c_writel(i2c, (div << 16) | (div & 0xffff), REG_CLKDIV); } diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 87d0371cebb7..efba1ebe16ba 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -380,34 +380,33 @@ static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) { int ret; if (!i2c_dev->hw->has_single_clk_source) { - ret = clk_prepare_enable(i2c_dev->fast_clk); + ret = clk_enable(i2c_dev->fast_clk); if (ret < 0) { dev_err(i2c_dev->dev, "Enabling fast clk failed, err %d\n", ret); return ret; } } - ret = clk_prepare_enable(i2c_dev->div_clk); + ret = clk_enable(i2c_dev->div_clk); if (ret < 0) { dev_err(i2c_dev->dev, "Enabling div clk failed, err %d\n", ret); - clk_disable_unprepare(i2c_dev->fast_clk); + clk_disable(i2c_dev->fast_clk); } return ret; } static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) { - clk_disable_unprepare(i2c_dev->div_clk); + clk_disable(i2c_dev->div_clk); if (!i2c_dev->hw->has_single_clk_source) - clk_disable_unprepare(i2c_dev->fast_clk); + clk_disable(i2c_dev->fast_clk); } static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) { u32 val; int err = 0; - int clk_multiplier = I2C_CLK_MULTIPLIER_STD_FAST_MODE; u32 clk_divisor; err = tegra_i2c_clock_enable(i2c_dev); @@ -428,9 +427,6 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) i2c_writel(i2c_dev, val, I2C_CNFG); i2c_writel(i2c_dev, 0, I2C_INT_MASK); - clk_multiplier *= (i2c_dev->hw->clk_divisor_std_fast_mode + 1); - clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * clk_multiplier); - /* Make sure clock divisor programmed correctly */ clk_divisor = i2c_dev->hw->clk_divisor_hs_mode; clk_divisor |= i2c_dev->hw->clk_divisor_std_fast_mode << @@ -712,6 +708,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) void __iomem *base; int irq; int ret = 0; + int clk_multiplier = I2C_CLK_MULTIPLIER_STD_FAST_MODE; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); @@ -777,17 +774,39 @@ static int tegra_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c_dev); + if (!i2c_dev->hw->has_single_clk_source) { + ret = clk_prepare(i2c_dev->fast_clk); + if (ret < 0) { + dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret); + return ret; + } + } + + clk_multiplier *= (i2c_dev->hw->clk_divisor_std_fast_mode + 1); + ret = clk_set_rate(i2c_dev->div_clk, + i2c_dev->bus_clk_rate * clk_multiplier); + if (ret) { + dev_err(i2c_dev->dev, "Clock rate change failed %d\n", ret); + goto unprepare_fast_clk; + } + + ret = clk_prepare(i2c_dev->div_clk); + if (ret < 0) { + dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret); + goto unprepare_fast_clk; + } + ret = tegra_i2c_init(i2c_dev); if (ret) { dev_err(&pdev->dev, "Failed to initialize i2c controller"); - return ret; + goto unprepare_div_clk; } ret = devm_request_irq(&pdev->dev, i2c_dev->irq, tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev); if (ret) { dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq); - return ret; + goto unprepare_div_clk; } i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); @@ -803,16 +822,30 @@ static int tegra_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c_dev->adapter); if (ret) { dev_err(&pdev->dev, "Failed to add I2C adapter\n"); - return ret; + goto unprepare_div_clk; } return 0; + +unprepare_div_clk: + clk_unprepare(i2c_dev->div_clk); + +unprepare_fast_clk: + if (!i2c_dev->hw->has_single_clk_source) + clk_unprepare(i2c_dev->fast_clk); + + return ret; } static int tegra_i2c_remove(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); i2c_del_adapter(&i2c_dev->adapter); + + clk_unprepare(i2c_dev->div_clk); + if (!i2c_dev->hw->has_single_clk_source) + clk_unprepare(i2c_dev->fast_clk); + return 0; } diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c deleted file mode 100644 index 0dbc18c15c43..000000000000 --- a/drivers/i2c/i2c-acpi.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * I2C ACPI code - * - * Copyright (C) 2014 Intel Corp - * - * Author: Lan Tianyu <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program 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. - */ -#define pr_fmt(fmt) "I2C/ACPI : " fmt - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/i2c.h> -#include <linux/acpi.h> - -struct acpi_i2c_handler_data { - struct acpi_connection_info info; - struct i2c_adapter *adapter; -}; - -struct gsb_buffer { - u8 status; - u8 len; - union { - u16 wdata; - u8 bdata; - u8 data[0]; - }; -} __packed; - -static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) -{ - struct i2c_board_info *info = data; - - if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { - struct acpi_resource_i2c_serialbus *sb; - - sb = &ares->data.i2c_serial_bus; - if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { - info->addr = sb->slave_address; - if (sb->access_mode == ACPI_I2C_10BIT_MODE) - info->flags |= I2C_CLIENT_TEN; - } - } else if (info->irq < 0) { - struct resource r; - - if (acpi_dev_resource_interrupt(ares, 0, &r)) - info->irq = r.start; - } - - /* Tell the ACPI core to skip this resource */ - return 1; -} - -static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, - void *data, void **return_value) -{ - struct i2c_adapter *adapter = data; - struct list_head resource_list; - struct i2c_board_info info; - struct acpi_device *adev; - int ret; - - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - if (acpi_bus_get_status(adev) || !adev->status.present) - return AE_OK; - - memset(&info, 0, sizeof(info)); - info.acpi_node.companion = adev; - info.irq = -1; - - INIT_LIST_HEAD(&resource_list); - ret = acpi_dev_get_resources(adev, &resource_list, - acpi_i2c_add_resource, &info); - acpi_dev_free_resource_list(&resource_list); - - if (ret < 0 || !info.addr) - return AE_OK; - - adev->power.flags.ignore_parent = true; - strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); - if (!i2c_new_device(adapter, &info)) { - adev->power.flags.ignore_parent = false; - dev_err(&adapter->dev, - "failed to add I2C device %s from ACPI\n", - dev_name(&adev->dev)); - } - - return AE_OK; -} - -/** - * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter - * @adap: pointer to adapter - * - * Enumerate all I2C slave devices behind this adapter by walking the ACPI - * namespace. When a device is found it will be added to the Linux device - * model and bound to the corresponding ACPI handle. - */ -void acpi_i2c_register_devices(struct i2c_adapter *adap) -{ - acpi_handle handle; - acpi_status status; - - if (!adap->dev.parent) - return; - - handle = ACPI_HANDLE(adap->dev.parent); - if (!handle) - return; - - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, - acpi_i2c_add_device, NULL, - adap, NULL); - if (ACPI_FAILURE(status)) - dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); -} - -#ifdef CONFIG_ACPI_I2C_OPREGION -static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, - u8 cmd, u8 *data, u8 data_len) -{ - - struct i2c_msg msgs[2]; - int ret; - u8 *buffer; - - buffer = kzalloc(data_len, GFP_KERNEL); - if (!buffer) - return AE_NO_MEMORY; - - msgs[0].addr = client->addr; - msgs[0].flags = client->flags; - msgs[0].len = 1; - msgs[0].buf = &cmd; - - msgs[1].addr = client->addr; - msgs[1].flags = client->flags | I2C_M_RD; - msgs[1].len = data_len; - msgs[1].buf = buffer; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - dev_err(&client->adapter->dev, "i2c read failed\n"); - else - memcpy(data, buffer, data_len); - - kfree(buffer); - return ret; -} - -static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, - u8 cmd, u8 *data, u8 data_len) -{ - - struct i2c_msg msgs[1]; - u8 *buffer; - int ret = AE_OK; - - buffer = kzalloc(data_len + 1, GFP_KERNEL); - if (!buffer) - return AE_NO_MEMORY; - - buffer[0] = cmd; - memcpy(buffer + 1, data, data_len); - - msgs[0].addr = client->addr; - msgs[0].flags = client->flags; - msgs[0].len = data_len + 1; - msgs[0].buf = buffer; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - dev_err(&client->adapter->dev, "i2c write failed\n"); - - kfree(buffer); - return ret; -} - -static acpi_status -acpi_i2c_space_handler(u32 function, acpi_physical_address command, - u32 bits, u64 *value64, - void *handler_context, void *region_context) -{ - struct gsb_buffer *gsb = (struct gsb_buffer *)value64; - struct acpi_i2c_handler_data *data = handler_context; - struct acpi_connection_info *info = &data->info; - struct acpi_resource_i2c_serialbus *sb; - struct i2c_adapter *adapter = data->adapter; - struct i2c_client client; - struct acpi_resource *ares; - u32 accessor_type = function >> 16; - u8 action = function & ACPI_IO_MASK; - acpi_status ret = AE_OK; - int status; - - ret = acpi_buffer_to_resource(info->connection, info->length, &ares); - if (ACPI_FAILURE(ret)) - return ret; - - if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { - ret = AE_BAD_PARAMETER; - goto err; - } - - sb = &ares->data.i2c_serial_bus; - if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) { - ret = AE_BAD_PARAMETER; - goto err; - } - - memset(&client, 0, sizeof(client)); - client.adapter = adapter; - client.addr = sb->slave_address; - client.flags = 0; - - if (sb->access_mode == ACPI_I2C_10BIT_MODE) - client.flags |= I2C_CLIENT_TEN; - - switch (accessor_type) { - case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: - if (action == ACPI_READ) { - status = i2c_smbus_read_byte(&client); - if (status >= 0) { - gsb->bdata = status; - status = 0; - } - } else { - status = i2c_smbus_write_byte(&client, gsb->bdata); - } - break; - - case ACPI_GSB_ACCESS_ATTRIB_BYTE: - if (action == ACPI_READ) { - status = i2c_smbus_read_byte_data(&client, command); - if (status >= 0) { - gsb->bdata = status; - status = 0; - } - } else { - status = i2c_smbus_write_byte_data(&client, command, - gsb->bdata); - } - break; - - case ACPI_GSB_ACCESS_ATTRIB_WORD: - if (action == ACPI_READ) { - status = i2c_smbus_read_word_data(&client, command); - if (status >= 0) { - gsb->wdata = status; - status = 0; - } - } else { - status = i2c_smbus_write_word_data(&client, command, - gsb->wdata); - } - break; - - case ACPI_GSB_ACCESS_ATTRIB_BLOCK: - if (action == ACPI_READ) { - status = i2c_smbus_read_block_data(&client, command, - gsb->data); - if (status >= 0) { - gsb->len = status; - status = 0; - } - } else { - status = i2c_smbus_write_block_data(&client, command, - gsb->len, gsb->data); - } - break; - - case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: - if (action == ACPI_READ) { - status = acpi_gsb_i2c_read_bytes(&client, command, - gsb->data, info->access_length); - if (status > 0) - status = 0; - } else { - status = acpi_gsb_i2c_write_bytes(&client, command, - gsb->data, info->access_length); - } - break; - - default: - pr_info("protocol(0x%02x) is not supported.\n", accessor_type); - ret = AE_BAD_PARAMETER; - goto err; - } - - gsb->status = status; - - err: - ACPI_FREE(ares); - return ret; -} - - -int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) -{ - acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); - struct acpi_i2c_handler_data *data; - acpi_status status; - - if (!handle) - return -ENODEV; - - data = kzalloc(sizeof(struct acpi_i2c_handler_data), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->adapter = adapter; - status = acpi_bus_attach_private_data(handle, (void *)data); - if (ACPI_FAILURE(status)) { - kfree(data); - return -ENOMEM; - } - - status = acpi_install_address_space_handler(handle, - ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler, - NULL, - data); - if (ACPI_FAILURE(status)) { - dev_err(&adapter->dev, "Error installing i2c space handler\n"); - acpi_bus_detach_private_data(handle); - kfree(data); - return -ENOMEM; - } - - return 0; -} - -void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) -{ - acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); - struct acpi_i2c_handler_data *data; - acpi_status status; - - if (!handle) - return; - - acpi_remove_address_space_handler(handle, - ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler); - - status = acpi_bus_get_private_data(handle, (void **)&data); - if (ACPI_SUCCESS(status)) - kfree(data); - - acpi_bus_detach_private_data(handle); -} -#endif diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 632057a44615..ccfbbab82a15 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -27,6 +27,8 @@ OF support is copyright (c) 2008 Jochen Friedrich <[email protected]> (based on a previous patch from Jon Smirl <[email protected]>) and (c) 2013 Wolfram Sang <[email protected]> + I2C ACPI code Copyright (C) 2014 Intel Corp + Author: Lan Tianyu <[email protected]> */ #include <linux/module.h> @@ -78,6 +80,368 @@ void i2c_transfer_trace_unreg(void) static_key_slow_dec(&i2c_trace_msg); } +#if defined(CONFIG_ACPI) +struct acpi_i2c_handler_data { + struct acpi_connection_info info; + struct i2c_adapter *adapter; +}; + +struct gsb_buffer { + u8 status; + u8 len; + union { + u16 wdata; + u8 bdata; + u8 data[0]; + }; +} __packed; + +static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) +{ + struct i2c_board_info *info = data; + + if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + struct acpi_resource_i2c_serialbus *sb; + + sb = &ares->data.i2c_serial_bus; + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { + info->addr = sb->slave_address; + if (sb->access_mode == ACPI_I2C_10BIT_MODE) + info->flags |= I2C_CLIENT_TEN; + } + } else if (info->irq < 0) { + struct resource r; + + if (acpi_dev_resource_interrupt(ares, 0, &r)) + info->irq = r.start; + } + + /* Tell the ACPI core to skip this resource */ + return 1; +} + +static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct i2c_adapter *adapter = data; + struct list_head resource_list; + struct i2c_board_info info; + struct acpi_device *adev; + int ret; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + if (acpi_bus_get_status(adev) || !adev->status.present) + return AE_OK; + + memset(&info, 0, sizeof(info)); + info.acpi_node.companion = adev; + info.irq = -1; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, + acpi_i2c_add_resource, &info); + acpi_dev_free_resource_list(&resource_list); + + if (ret < 0 || !info.addr) + return AE_OK; + + adev->power.flags.ignore_parent = true; + strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); + if (!i2c_new_device(adapter, &info)) { + adev->power.flags.ignore_parent = false; + dev_err(&adapter->dev, + "failed to add I2C device %s from ACPI\n", + dev_name(&adev->dev)); + } + + return AE_OK; +} + +/** + * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter + * @adap: pointer to adapter + * + * Enumerate all I2C slave devices behind this adapter by walking the ACPI + * namespace. When a device is found it will be added to the Linux device + * model and bound to the corresponding ACPI handle. + */ +static void acpi_i2c_register_devices(struct i2c_adapter *adap) +{ + acpi_handle handle; + acpi_status status; + + if (!adap->dev.parent) + return; + + handle = ACPI_HANDLE(adap->dev.parent); + if (!handle) + return; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + acpi_i2c_add_device, NULL, + adap, NULL); + if (ACPI_FAILURE(status)) + dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); +} + +#else /* CONFIG_ACPI */ +static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } +#endif /* CONFIG_ACPI */ + +#ifdef CONFIG_ACPI_I2C_OPREGION +static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, + u8 cmd, u8 *data, u8 data_len) +{ + + struct i2c_msg msgs[2]; + int ret; + u8 *buffer; + + buffer = kzalloc(data_len, GFP_KERNEL); + if (!buffer) + return AE_NO_MEMORY; + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags; + msgs[0].len = 1; + msgs[0].buf = &cmd; + + msgs[1].addr = client->addr; + msgs[1].flags = client->flags | I2C_M_RD; + msgs[1].len = data_len; + msgs[1].buf = buffer; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + dev_err(&client->adapter->dev, "i2c read failed\n"); + else + memcpy(data, buffer, data_len); + + kfree(buffer); + return ret; +} + +static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + u8 cmd, u8 *data, u8 data_len) +{ + + struct i2c_msg msgs[1]; + u8 *buffer; + int ret = AE_OK; + + buffer = kzalloc(data_len + 1, GFP_KERNEL); + if (!buffer) + return AE_NO_MEMORY; + + buffer[0] = cmd; + memcpy(buffer + 1, data, data_len); + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags; + msgs[0].len = data_len + 1; + msgs[0].buf = buffer; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + dev_err(&client->adapter->dev, "i2c write failed\n"); + + kfree(buffer); + return ret; +} + +static acpi_status +acpi_i2c_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, + void *handler_context, void *region_context) +{ + struct gsb_buffer *gsb = (struct gsb_buffer *)value64; + struct acpi_i2c_handler_data *data = handler_context; + struct acpi_connection_info *info = &data->info; + struct acpi_resource_i2c_serialbus *sb; + struct i2c_adapter *adapter = data->adapter; + struct i2c_client client; + struct acpi_resource *ares; + u32 accessor_type = function >> 16; + u8 action = function & ACPI_IO_MASK; + acpi_status ret = AE_OK; + int status; + + ret = acpi_buffer_to_resource(info->connection, info->length, &ares); + if (ACPI_FAILURE(ret)) + return ret; + + if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { + ret = AE_BAD_PARAMETER; + goto err; + } + + sb = &ares->data.i2c_serial_bus; + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) { + ret = AE_BAD_PARAMETER; + goto err; + } + + memset(&client, 0, sizeof(client)); + client.adapter = adapter; + client.addr = sb->slave_address; + client.flags = 0; + + if (sb->access_mode == ACPI_I2C_10BIT_MODE) + client.flags |= I2C_CLIENT_TEN; + + switch (accessor_type) { + case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: + if (action == ACPI_READ) { + status = i2c_smbus_read_byte(&client); + if (status >= 0) { + gsb->bdata = status; + status = 0; + } + } else { + status = i2c_smbus_write_byte(&client, gsb->bdata); + } + break; + + case ACPI_GSB_ACCESS_ATTRIB_BYTE: + if (action == ACPI_READ) { + status = i2c_smbus_read_byte_data(&client, command); + if (status >= 0) { + gsb->bdata = status; + status = 0; + } + } else { + status = i2c_smbus_write_byte_data(&client, command, + gsb->bdata); + } + break; + + case ACPI_GSB_ACCESS_ATTRIB_WORD: + if (action == ACPI_READ) { + status = i2c_smbus_read_word_data(&client, command); + if (status >= 0) { + gsb->wdata = status; + status = 0; + } + } else { + status = i2c_smbus_write_word_data(&client, command, + gsb->wdata); + } + break; + + case ACPI_GSB_ACCESS_ATTRIB_BLOCK: + if (action == ACPI_READ) { + status = i2c_smbus_read_block_data(&client, command, + gsb->data); + if (status >= 0) { + gsb->len = status; + status = 0; + } + } else { + status = i2c_smbus_write_block_data(&client, command, + gsb->len, gsb->data); + } + break; + + case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: + if (action == ACPI_READ) { + status = acpi_gsb_i2c_read_bytes(&client, command, + gsb->data, info->access_length); + if (status > 0) + status = 0; + } else { + status = acpi_gsb_i2c_write_bytes(&client, command, + gsb->data, info->access_length); + } + break; + + default: + pr_info("protocol(0x%02x) is not supported.\n", accessor_type); + ret = AE_BAD_PARAMETER; + goto err; + } + + gsb->status = status; + + err: + ACPI_FREE(ares); + return ret; +} + + +static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) +{ + acpi_handle handle; + struct acpi_i2c_handler_data *data; + acpi_status status; + + if (!adapter->dev.parent) + return -ENODEV; + + handle = ACPI_HANDLE(adapter->dev.parent); + + if (!handle) + return -ENODEV; + + data = kzalloc(sizeof(struct acpi_i2c_handler_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->adapter = adapter; + status = acpi_bus_attach_private_data(handle, (void *)data); + if (ACPI_FAILURE(status)) { + kfree(data); + return -ENOMEM; + } + + status = acpi_install_address_space_handler(handle, + ACPI_ADR_SPACE_GSBUS, + &acpi_i2c_space_handler, + NULL, + data); + if (ACPI_FAILURE(status)) { + dev_err(&adapter->dev, "Error installing i2c space handler\n"); + acpi_bus_detach_private_data(handle); + kfree(data); + return -ENOMEM; + } + + return 0; +} + +static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) +{ + acpi_handle handle; + struct acpi_i2c_handler_data *data; + acpi_status status; + + if (!adapter->dev.parent) + return; + + handle = ACPI_HANDLE(adapter->dev.parent); + + if (!handle) + return; + + acpi_remove_address_space_handler(handle, + ACPI_ADR_SPACE_GSBUS, + &acpi_i2c_space_handler); + + status = acpi_bus_get_private_data(handle, (void **)&data); + if (ACPI_SUCCESS(status)) + kfree(data); + + acpi_bus_detach_private_data(handle); +} +#else /* CONFIG_ACPI_I2C_OPREGION */ +static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) +{ } + +static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) +{ return 0; } +#endif /* CONFIG_ACPI_I2C_OPREGION */ + /* ------------------------------------------------------------------------- */ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index e4056279166d..10cfce5119a9 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -752,7 +752,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries, return ERR_PTR(-EINVAL); entries = roundup_pow_of_two(entries + 1); - if (entries > dev->mdev->caps.max_cqes) + if (entries > dev->mdev->caps.gen.max_cqes) return ERR_PTR(-EINVAL); cq = kzalloc(sizeof(*cq), GFP_KERNEL); @@ -919,7 +919,7 @@ int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) int err; u32 fsel; - if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_CQ_MODER)) + if (!(dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_CQ_MODER)) return -ENOSYS; in = kzalloc(sizeof(*in), GFP_KERNEL); @@ -1074,7 +1074,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) int uninitialized_var(cqe_size); unsigned long flags; - if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_RESIZE_CQ)) { + if (!(dev->mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_RESIZE_CQ)) { pr_info("Firmware does not support resize CQ\n"); return -ENOSYS; } @@ -1083,7 +1083,7 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) return -EINVAL; entries = roundup_pow_of_two(entries + 1); - if (entries > dev->mdev->caps.max_cqes + 1) + if (entries > dev->mdev->caps.gen.max_cqes + 1) return -EINVAL; if (entries == ibcq->cqe + 1) diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index b514bbb5610f..657af9a1167c 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -129,7 +129,7 @@ int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port) packet_error = be16_to_cpu(out_mad->status); - dev->mdev->caps.ext_port_cap[port - 1] = (!err && !packet_error) ? + dev->mdev->caps.gen.ext_port_cap[port - 1] = (!err && !packet_error) ? MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO : 0; out: diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index d8907b20522a..f3114d1132fb 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -157,11 +157,13 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, struct mlx5_ib_dev *dev = to_mdev(ibdev); struct ib_smp *in_mad = NULL; struct ib_smp *out_mad = NULL; + struct mlx5_general_caps *gen; int err = -ENOMEM; int max_rq_sg; int max_sq_sg; u64 flags; + gen = &dev->mdev->caps.gen; in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); if (!in_mad || !out_mad) @@ -183,7 +185,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_RC_RNR_NAK_GEN; - flags = dev->mdev->caps.flags; + flags = gen->flags; if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR) props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; if (flags & MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR) @@ -213,30 +215,31 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, memcpy(&props->sys_image_guid, out_mad->data + 4, 8); props->max_mr_size = ~0ull; - props->page_size_cap = dev->mdev->caps.min_page_sz; - props->max_qp = 1 << dev->mdev->caps.log_max_qp; - props->max_qp_wr = dev->mdev->caps.max_wqes; - max_rq_sg = dev->mdev->caps.max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg); - max_sq_sg = (dev->mdev->caps.max_sq_desc_sz - sizeof(struct mlx5_wqe_ctrl_seg)) / + props->page_size_cap = gen->min_page_sz; + props->max_qp = 1 << gen->log_max_qp; + props->max_qp_wr = gen->max_wqes; + max_rq_sg = gen->max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg); + max_sq_sg = (gen->max_sq_desc_sz - sizeof(struct mlx5_wqe_ctrl_seg)) / sizeof(struct mlx5_wqe_data_seg); props->max_sge = min(max_rq_sg, max_sq_sg); - props->max_cq = 1 << dev->mdev->caps.log_max_cq; - props->max_cqe = dev->mdev->caps.max_cqes - 1; - props->max_mr = 1 << dev->mdev->caps.log_max_mkey; - props->max_pd = 1 << dev->mdev->caps.log_max_pd; - props->max_qp_rd_atom = dev->mdev->caps.max_ra_req_qp; - props->max_qp_init_rd_atom = dev->mdev->caps.max_ra_res_qp; + props->max_cq = 1 << gen->log_max_cq; + props->max_cqe = gen->max_cqes - 1; + props->max_mr = 1 << gen->log_max_mkey; + props->max_pd = 1 << gen->log_max_pd; + props->max_qp_rd_atom = 1 << gen->log_max_ra_req_qp; + props->max_qp_init_rd_atom = 1 << gen->log_max_ra_res_qp; + props->max_srq = 1 << gen->log_max_srq; + props->max_srq_wr = gen->max_srq_wqes - 1; + props->local_ca_ack_delay = gen->local_ca_ack_delay; props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; - props->max_srq = 1 << dev->mdev->caps.log_max_srq; - props->max_srq_wr = dev->mdev->caps.max_srq_wqes - 1; props->max_srq_sge = max_rq_sg - 1; props->max_fast_reg_page_list_len = (unsigned int)-1; - props->local_ca_ack_delay = dev->mdev->caps.local_ca_ack_delay; + props->local_ca_ack_delay = gen->local_ca_ack_delay; props->atomic_cap = IB_ATOMIC_NONE; props->masked_atomic_cap = IB_ATOMIC_NONE; props->max_pkeys = be16_to_cpup((__be16 *)(out_mad->data + 28)); - props->max_mcast_grp = 1 << dev->mdev->caps.log_max_mcg; - props->max_mcast_qp_attach = dev->mdev->caps.max_qp_mcg; + props->max_mcast_grp = 1 << gen->log_max_mcg; + props->max_mcast_qp_attach = gen->max_qp_mcg; props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * props->max_mcast_grp; props->max_map_per_fmr = INT_MAX; /* no limit in ConnectIB */ @@ -254,10 +257,12 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, struct mlx5_ib_dev *dev = to_mdev(ibdev); struct ib_smp *in_mad = NULL; struct ib_smp *out_mad = NULL; + struct mlx5_general_caps *gen; int ext_active_speed; int err = -ENOMEM; - if (port < 1 || port > dev->mdev->caps.num_ports) { + gen = &dev->mdev->caps.gen; + if (port < 1 || port > gen->num_ports) { mlx5_ib_warn(dev, "invalid port number %d\n", port); return -EINVAL; } @@ -288,8 +293,8 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, props->phys_state = out_mad->data[33] >> 4; props->port_cap_flags = be32_to_cpup((__be32 *)(out_mad->data + 20)); props->gid_tbl_len = out_mad->data[50]; - props->max_msg_sz = 1 << to_mdev(ibdev)->mdev->caps.log_max_msg; - props->pkey_tbl_len = to_mdev(ibdev)->mdev->caps.port[port - 1].pkey_table_len; + props->max_msg_sz = 1 << gen->log_max_msg; + props->pkey_tbl_len = gen->port[port - 1].pkey_table_len; props->bad_pkey_cntr = be16_to_cpup((__be16 *)(out_mad->data + 46)); props->qkey_viol_cntr = be16_to_cpup((__be16 *)(out_mad->data + 48)); props->active_width = out_mad->data[31] & 0xf; @@ -316,7 +321,7 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, /* If reported active speed is QDR, check if is FDR-10 */ if (props->active_speed == 4) { - if (dev->mdev->caps.ext_port_cap[port - 1] & + if (gen->ext_port_cap[port - 1] & MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) { init_query_mad(in_mad); in_mad->attr_id = MLX5_ATTR_EXTENDED_PORT_INFO; @@ -470,6 +475,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, struct mlx5_ib_alloc_ucontext_req_v2 req; struct mlx5_ib_alloc_ucontext_resp resp; struct mlx5_ib_ucontext *context; + struct mlx5_general_caps *gen; struct mlx5_uuar_info *uuari; struct mlx5_uar *uars; int gross_uuars; @@ -480,6 +486,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, int i; size_t reqlen; + gen = &dev->mdev->caps.gen; if (!dev->ib_active) return ERR_PTR(-EAGAIN); @@ -512,14 +519,14 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, num_uars = req.total_num_uuars / MLX5_NON_FP_BF_REGS_PER_PAGE; gross_uuars = num_uars * MLX5_BF_REGS_PER_PAGE; - resp.qp_tab_size = 1 << dev->mdev->caps.log_max_qp; - resp.bf_reg_size = dev->mdev->caps.bf_reg_size; + resp.qp_tab_size = 1 << gen->log_max_qp; + resp.bf_reg_size = gen->bf_reg_size; resp.cache_line_size = L1_CACHE_BYTES; - resp.max_sq_desc_sz = dev->mdev->caps.max_sq_desc_sz; - resp.max_rq_desc_sz = dev->mdev->caps.max_rq_desc_sz; - resp.max_send_wqebb = dev->mdev->caps.max_wqes; - resp.max_recv_wr = dev->mdev->caps.max_wqes; - resp.max_srq_recv_wr = dev->mdev->caps.max_srq_wqes; + resp.max_sq_desc_sz = gen->max_sq_desc_sz; + resp.max_rq_desc_sz = gen->max_rq_desc_sz; + resp.max_send_wqebb = gen->max_wqes; + resp.max_recv_wr = gen->max_wqes; + resp.max_srq_recv_wr = gen->max_srq_wqes; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) @@ -565,7 +572,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, mutex_init(&context->db_page_mutex); resp.tot_uuars = req.total_num_uuars; - resp.num_ports = dev->mdev->caps.num_ports; + resp.num_ports = gen->num_ports; err = ib_copy_to_udata(udata, &resp, sizeof(resp) - sizeof(resp.reserved)); if (err) @@ -967,9 +974,11 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context, static void get_ext_port_caps(struct mlx5_ib_dev *dev) { + struct mlx5_general_caps *gen; int port; - for (port = 1; port <= dev->mdev->caps.num_ports; port++) + gen = &dev->mdev->caps.gen; + for (port = 1; port <= gen->num_ports; port++) mlx5_query_ext_port_caps(dev, port); } @@ -977,9 +986,11 @@ static int get_port_caps(struct mlx5_ib_dev *dev) { struct ib_device_attr *dprops = NULL; struct ib_port_attr *pprops = NULL; + struct mlx5_general_caps *gen; int err = 0; int port; + gen = &dev->mdev->caps.gen; pprops = kmalloc(sizeof(*pprops), GFP_KERNEL); if (!pprops) goto out; @@ -994,14 +1005,14 @@ static int get_port_caps(struct mlx5_ib_dev *dev) goto out; } - for (port = 1; port <= dev->mdev->caps.num_ports; port++) { + for (port = 1; port <= gen->num_ports; port++) { err = mlx5_ib_query_port(&dev->ib_dev, port, pprops); if (err) { mlx5_ib_warn(dev, "query_port %d failed %d\n", port, err); break; } - dev->mdev->caps.port[port - 1].pkey_table_len = dprops->max_pkeys; - dev->mdev->caps.port[port - 1].gid_table_len = pprops->gid_tbl_len; + gen->port[port - 1].pkey_table_len = dprops->max_pkeys; + gen->port[port - 1].gid_table_len = pprops->gid_tbl_len; mlx5_ib_dbg(dev, "pkey_table_len %d, gid_table_len %d\n", dprops->max_pkeys, pprops->gid_tbl_len); } @@ -1279,8 +1290,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) strlcpy(dev->ib_dev.name, "mlx5_%d", IB_DEVICE_NAME_MAX); dev->ib_dev.owner = THIS_MODULE; dev->ib_dev.node_type = RDMA_NODE_IB_CA; - dev->ib_dev.local_dma_lkey = mdev->caps.reserved_lkey; - dev->num_ports = mdev->caps.num_ports; + dev->ib_dev.local_dma_lkey = mdev->caps.gen.reserved_lkey; + dev->num_ports = mdev->caps.gen.num_ports; dev->ib_dev.phys_port_cnt = dev->num_ports; dev->ib_dev.num_comp_vectors = dev->num_comp_vectors; dev->ib_dev.dma_device = &mdev->pdev->dev; @@ -1355,7 +1366,7 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list; dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status; - if (mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC) { + if (mdev->caps.gen.flags & MLX5_DEV_CAP_FLAG_XRC) { dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd; dev->ib_dev.dealloc_xrcd = mlx5_ib_dealloc_xrcd; dev->ib_dev.uverbs_cmd_mask |= diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 8c574b63d77b..dbfe498870c1 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -158,11 +158,13 @@ static void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type) static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, int has_rq, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd) { + struct mlx5_general_caps *gen; int wqe_size; int wq_size; + gen = &dev->mdev->caps.gen; /* Sanity check RQ size before proceeding */ - if (cap->max_recv_wr > dev->mdev->caps.max_wqes) + if (cap->max_recv_wr > gen->max_wqes) return -EINVAL; if (!has_rq) { @@ -182,10 +184,10 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size; wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB); qp->rq.wqe_cnt = wq_size / wqe_size; - if (wqe_size > dev->mdev->caps.max_rq_desc_sz) { + if (wqe_size > gen->max_rq_desc_sz) { mlx5_ib_dbg(dev, "wqe_size %d, max %d\n", wqe_size, - dev->mdev->caps.max_rq_desc_sz); + gen->max_rq_desc_sz); return -EINVAL; } qp->rq.wqe_shift = ilog2(wqe_size); @@ -266,9 +268,11 @@ static int calc_send_wqe(struct ib_qp_init_attr *attr) static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, struct mlx5_ib_qp *qp) { + struct mlx5_general_caps *gen; int wqe_size; int wq_size; + gen = &dev->mdev->caps.gen; if (!attr->cap.max_send_wr) return 0; @@ -277,9 +281,9 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, if (wqe_size < 0) return wqe_size; - if (wqe_size > dev->mdev->caps.max_sq_desc_sz) { + if (wqe_size > gen->max_sq_desc_sz) { mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n", - wqe_size, dev->mdev->caps.max_sq_desc_sz); + wqe_size, gen->max_sq_desc_sz); return -EINVAL; } @@ -292,9 +296,9 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size); qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB; - if (qp->sq.wqe_cnt > dev->mdev->caps.max_wqes) { + if (qp->sq.wqe_cnt > gen->max_wqes) { mlx5_ib_dbg(dev, "wqe count(%d) exceeds limits(%d)\n", - qp->sq.wqe_cnt, dev->mdev->caps.max_wqes); + qp->sq.wqe_cnt, gen->max_wqes); return -ENOMEM; } qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB); @@ -309,11 +313,13 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd) { + struct mlx5_general_caps *gen; int desc_sz = 1 << qp->sq.wqe_shift; - if (desc_sz > dev->mdev->caps.max_sq_desc_sz) { + gen = &dev->mdev->caps.gen; + if (desc_sz > gen->max_sq_desc_sz) { mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n", - desc_sz, dev->mdev->caps.max_sq_desc_sz); + desc_sz, gen->max_sq_desc_sz); return -EINVAL; } @@ -325,9 +331,9 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev, qp->sq.wqe_cnt = ucmd->sq_wqe_count; - if (qp->sq.wqe_cnt > dev->mdev->caps.max_wqes) { + if (qp->sq.wqe_cnt > gen->max_wqes) { mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n", - qp->sq.wqe_cnt, dev->mdev->caps.max_wqes); + qp->sq.wqe_cnt, gen->max_wqes); return -EINVAL; } @@ -803,16 +809,18 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, struct mlx5_ib_resources *devr = &dev->devr; struct mlx5_ib_create_qp_resp resp; struct mlx5_create_qp_mbox_in *in; + struct mlx5_general_caps *gen; struct mlx5_ib_create_qp ucmd; int inlen = sizeof(*in); int err; + gen = &dev->mdev->caps.gen; mutex_init(&qp->mutex); spin_lock_init(&qp->sq.lock); spin_lock_init(&qp->rq.lock); if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) { - if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)) { + if (!(gen->flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)) { mlx5_ib_dbg(dev, "block multicast loopback isn't supported\n"); return -EINVAL; } else { @@ -851,9 +859,9 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, mlx5_ib_dbg(dev, "invalid rq params\n"); return -EINVAL; } - if (ucmd.sq_wqe_count > dev->mdev->caps.max_wqes) { + if (ucmd.sq_wqe_count > gen->max_wqes) { mlx5_ib_dbg(dev, "requested sq_wqe_count (%d) > max allowed (%d)\n", - ucmd.sq_wqe_count, dev->mdev->caps.max_wqes); + ucmd.sq_wqe_count, gen->max_wqes); return -EINVAL; } err = create_user_qp(dev, pd, qp, udata, &in, &resp, &inlen); @@ -1144,6 +1152,7 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *init_attr, struct ib_udata *udata) { + struct mlx5_general_caps *gen; struct mlx5_ib_dev *dev; struct mlx5_ib_qp *qp; u16 xrcdn = 0; @@ -1161,11 +1170,12 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, } dev = to_mdev(to_mxrcd(init_attr->xrcd)->ibxrcd.device); } + gen = &dev->mdev->caps.gen; switch (init_attr->qp_type) { case IB_QPT_XRC_TGT: case IB_QPT_XRC_INI: - if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC)) { + if (!(gen->flags & MLX5_DEV_CAP_FLAG_XRC)) { mlx5_ib_dbg(dev, "XRC not supported\n"); return ERR_PTR(-ENOSYS); } @@ -1272,6 +1282,9 @@ enum { static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate) { + struct mlx5_general_caps *gen; + + gen = &dev->mdev->caps.gen; if (rate == IB_RATE_PORT_CURRENT) { return 0; } else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_300_GBPS) { @@ -1279,7 +1292,7 @@ static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate) } else { while (rate != IB_RATE_2_5_GBPS && !(1 << (rate + MLX5_STAT_RATE_OFFSET) & - dev->mdev->caps.stat_rate_support)) + gen->stat_rate_support)) --rate; } @@ -1290,8 +1303,10 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah, struct mlx5_qp_path *path, u8 port, int attr_mask, u32 path_flags, const struct ib_qp_attr *attr) { + struct mlx5_general_caps *gen; int err; + gen = &dev->mdev->caps.gen; path->fl = (path_flags & MLX5_PATH_FLAG_FL) ? 0x80 : 0; path->free_ar = (path_flags & MLX5_PATH_FLAG_FREE_AR) ? 0x80 : 0; @@ -1318,9 +1333,9 @@ static int mlx5_set_path(struct mlx5_ib_dev *dev, const struct ib_ah_attr *ah, path->port = port; if (ah->ah_flags & IB_AH_GRH) { - if (ah->grh.sgid_index >= dev->mdev->caps.port[port - 1].gid_table_len) { + if (ah->grh.sgid_index >= gen->port[port - 1].gid_table_len) { pr_err(KERN_ERR "sgid_index (%u) too large. max is %d\n", - ah->grh.sgid_index, dev->mdev->caps.port[port - 1].gid_table_len); + ah->grh.sgid_index, gen->port[port - 1].gid_table_len); return -EINVAL; } @@ -1492,6 +1507,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, struct mlx5_ib_qp *qp = to_mqp(ibqp); struct mlx5_ib_cq *send_cq, *recv_cq; struct mlx5_qp_context *context; + struct mlx5_general_caps *gen; struct mlx5_modify_qp_mbox_in *in; struct mlx5_ib_pd *pd; enum mlx5_qp_state mlx5_cur, mlx5_new; @@ -1500,6 +1516,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, int mlx5_st; int err; + gen = &dev->mdev->caps.gen; in = kzalloc(sizeof(*in), GFP_KERNEL); if (!in) return -ENOMEM; @@ -1539,7 +1556,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, err = -EINVAL; goto out; } - context->mtu_msgmax = (attr->path_mtu << 5) | dev->mdev->caps.log_max_msg; + context->mtu_msgmax = (attr->path_mtu << 5) | gen->log_max_msg; } if (attr_mask & IB_QP_DEST_QPN) @@ -1685,9 +1702,11 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, struct mlx5_ib_dev *dev = to_mdev(ibqp->device); struct mlx5_ib_qp *qp = to_mqp(ibqp); enum ib_qp_state cur_state, new_state; + struct mlx5_general_caps *gen; int err = -EINVAL; int port; + gen = &dev->mdev->caps.gen; mutex_lock(&qp->mutex); cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state; @@ -1699,21 +1718,21 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, goto out; if ((attr_mask & IB_QP_PORT) && - (attr->port_num == 0 || attr->port_num > dev->mdev->caps.num_ports)) + (attr->port_num == 0 || attr->port_num > gen->num_ports)) goto out; if (attr_mask & IB_QP_PKEY_INDEX) { port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; - if (attr->pkey_index >= dev->mdev->caps.port[port - 1].pkey_table_len) + if (attr->pkey_index >= gen->port[port - 1].pkey_table_len) goto out; } if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && - attr->max_rd_atomic > dev->mdev->caps.max_ra_res_qp) + attr->max_rd_atomic > (1 << gen->log_max_ra_res_qp)) goto out; if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && - attr->max_dest_rd_atomic > dev->mdev->caps.max_ra_req_qp) + attr->max_dest_rd_atomic > (1 << gen->log_max_ra_req_qp)) goto out; if (cur_state == new_state && cur_state == IB_QPS_RESET) { @@ -2893,7 +2912,8 @@ static void to_ib_ah_attr(struct mlx5_ib_dev *ibdev, struct ib_ah_attr *ib_ah_at memset(ib_ah_attr, 0, sizeof(*ib_ah_attr)); ib_ah_attr->port_num = path->port; - if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports) + if (ib_ah_attr->port_num == 0 || + ib_ah_attr->port_num > dev->caps.gen.num_ports) return; ib_ah_attr->sl = path->sl & 0xf; @@ -3011,10 +3031,12 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev, struct ib_udata *udata) { struct mlx5_ib_dev *dev = to_mdev(ibdev); + struct mlx5_general_caps *gen; struct mlx5_ib_xrcd *xrcd; int err; - if (!(dev->mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC)) + gen = &dev->mdev->caps.gen; + if (!(gen->flags & MLX5_DEV_CAP_FLAG_XRC)) return ERR_PTR(-ENOSYS); xrcd = kmalloc(sizeof(*xrcd), GFP_KERNEL); diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 70bd131ba646..97cc1baaa8e3 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -238,6 +238,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, struct ib_udata *udata) { struct mlx5_ib_dev *dev = to_mdev(pd->device); + struct mlx5_general_caps *gen; struct mlx5_ib_srq *srq; int desc_size; int buf_size; @@ -247,11 +248,12 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, int is_xrc; u32 flgs, xrcdn; + gen = &dev->mdev->caps.gen; /* Sanity check SRQ size before proceeding */ - if (init_attr->attr.max_wr >= dev->mdev->caps.max_srq_wqes) { + if (init_attr->attr.max_wr >= gen->max_srq_wqes) { mlx5_ib_dbg(dev, "max_wr %d, cap %d\n", init_attr->attr.max_wr, - dev->mdev->caps.max_srq_wqes); + gen->max_srq_wqes); return ERR_PTR(-EINVAL); } diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 713e3ddb43bd..40b7d6c0ff17 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -466,6 +466,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { }, }, { + /* Asus X450LCP */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"), + }, + }, + { /* Avatar AVIU-145A6 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Intel"), diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c index 6e797e502cfa..4073d1684d07 100644 --- a/drivers/isdn/capi/capiutil.c +++ b/drivers/isdn/capi/capiutil.c @@ -205,11 +205,8 @@ static unsigned command_2_index(unsigned c, unsigned sc) { if (c & 0x80) c = 0x9 + (c & 0x0f); - else if (c <= 0x0f); else if (c == 0x41) c = 0x9 + 0x1; - else if (c == 0xff) - c = 0x00; return (sc & 3) * (0x9 + 0x9) + c; } diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 7459b127ddd5..dcae14aef376 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -1243,7 +1243,8 @@ static void do_action(int action, struct cardstate *cs, break; case ACT_FAILDLE0: cs->cur_at_seq = SEQ_NONE; - dev_warn(cs->dev, "Could not leave DLE mode.\n"); + dev_warn(cs->dev, "Error leaving DLE mode.\n"); + cs->dle = 0; at_state2 = &cs->bcs[cs->curchannel].at_state; disconnect(&at_state2); schedule_init(cs, MS_RECOVER); diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 00d40773b07f..82e91ba1acd3 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -135,14 +135,13 @@ struct usb_cardstate { /* Output buffer */ unsigned char *bulk_out_buffer; int bulk_out_size; - __u8 bulk_out_endpointAddr; + int bulk_out_epnum; struct urb *bulk_out_urb; /* Input buffer */ unsigned char *rcvbuf; int rcvbuf_size; struct urb *read_urb; - __u8 int_in_endpointAddr; char bchars[6]; /* for request 0x19 */ }; @@ -466,7 +465,7 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, usb_sndbulkpipe(ucs->udev, - ucs->bulk_out_endpointAddr & 0x0f), + ucs->bulk_out_epnum), cb->buf + cb->offset, count, gigaset_write_bulk_callback, cs); @@ -628,8 +627,7 @@ static int write_modem(struct cardstate *cs) if (cs->connected) { usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, usb_sndbulkpipe(ucs->udev, - ucs->bulk_out_endpointAddr & - 0x0f), + ucs->bulk_out_epnum), ucs->bulk_out_buffer, count, gigaset_write_bulk_callback, cs); ret = usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC); @@ -714,7 +712,7 @@ static int gigaset_probe(struct usb_interface *interface, buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); ucs->bulk_out_size = buffer_size; - ucs->bulk_out_endpointAddr = endpoint->bEndpointAddress; + ucs->bulk_out_epnum = usb_endpoint_num(endpoint); ucs->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!ucs->bulk_out_buffer) { dev_err(cs->dev, "Couldn't allocate bulk_out_buffer\n"); @@ -741,7 +739,6 @@ static int gigaset_probe(struct usb_interface *interface, } buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); ucs->rcvbuf_size = buffer_size; - ucs->int_in_endpointAddr = endpoint->bEndpointAddress; ucs->rcvbuf = kmalloc(buffer_size, GFP_KERNEL); if (!ucs->rcvbuf) { dev_err(cs->dev, "Couldn't allocate rcvbuf\n"); @@ -750,8 +747,7 @@ static int gigaset_probe(struct usb_interface *interface, } /* Fill the interrupt urb and send it to the core */ usb_fill_int_urb(ucs->read_urb, udev, - usb_rcvintpipe(udev, - usb_endpoint_num(endpoint)), + usb_rcvintpipe(udev, usb_endpoint_num(endpoint)), ucs->rcvbuf, buffer_size, gigaset_read_int_callback, cs, endpoint->bInterval); diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index e78d6b32431d..98d73aab52fe 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -65,7 +65,7 @@ config CAN_LEDS config CAN_AT91 tristate "Atmel AT91 onchip CAN controller" - depends on ARCH_AT91 || COMPILE_TEST + depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM ---help--- This is a driver for the SoC CAN controller in Atmel's AT91SAM9263 and AT91SAM9X5 processors. diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index ea0697eaeff5..9234d808cbb3 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -47,6 +47,7 @@ config NET_DSA_MV88E6171 config NET_DSA_BCM_SF2 tristate "Broadcom Starfighter 2 Ethernet switch support" + depends on HAS_IOMEM select NET_DSA select NET_DSA_TAG_BRCM select FIXED_PHY if NET_DSA_BCM_SF2=y diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 0005e3792e6d..1ed1fbba5d58 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -20,6 +20,7 @@ config SUNGEM_PHY source "drivers/net/ethernet/3com/Kconfig" source "drivers/net/ethernet/adaptec/Kconfig" source "drivers/net/ethernet/aeroflex/Kconfig" +source "drivers/net/ethernet/agere/Kconfig" source "drivers/net/ethernet/allwinner/Kconfig" source "drivers/net/ethernet/alteon/Kconfig" source "drivers/net/ethernet/altera/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 153bf2dd9fad..6e0b629e9859 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_NET_VENDOR_3COM) += 3com/ obj-$(CONFIG_NET_VENDOR_8390) += 8390/ obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/ obj-$(CONFIG_GRETH) += aeroflex/ +obj-$(CONFIG_NET_VENDOR_AGERE) += agere/ obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/ obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/ obj-$(CONFIG_ALTERA_TSE) += altera/ diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c index afa66847e10b..8ed4d3408ef6 100644 --- a/drivers/net/ethernet/adi/bfin_mac.c +++ b/drivers/net/ethernet/adi/bfin_mac.c @@ -1692,9 +1692,6 @@ static int bfin_mac_probe(struct platform_device *pdev) lp->vlan1_mask = ETH_P_8021Q | mii_bus_data->vlan1_mask; lp->vlan2_mask = ETH_P_8021Q | mii_bus_data->vlan2_mask; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(ndev); - ndev->netdev_ops = &bfin_mac_netdev_ops; ndev->ethtool_ops = &bfin_mac_ethtool_ops; diff --git a/drivers/net/ethernet/agere/Kconfig b/drivers/net/ethernet/agere/Kconfig new file mode 100644 index 000000000000..63e805de619e --- /dev/null +++ b/drivers/net/ethernet/agere/Kconfig @@ -0,0 +1,31 @@ +# +# Agere device configuration +# + +config NET_VENDOR_AGERE + bool "Agere devices" + default y + depends on PCI + ---help--- + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Agere devices. If you say Y, you will be asked + for your specific card in the following questions. + +if NET_VENDOR_AGERE + +config ET131X + tristate "Agere ET-1310 Gigabit Ethernet support" + depends on PCI + select PHYLIB + ---help--- + This driver supports Agere ET-1310 ethernet adapters. + + To compile this driver as a module, choose M here. The module + will be called et131x. + +endif # NET_VENDOR_AGERE diff --git a/drivers/net/ethernet/agere/Makefile b/drivers/net/ethernet/agere/Makefile new file mode 100644 index 000000000000..027ff9453fe1 --- /dev/null +++ b/drivers/net/ethernet/agere/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Agere ET-131x ethernet driver +# + +obj-$(CONFIG_ET131X) += et131x.o diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c new file mode 100644 index 000000000000..384dc163851b --- /dev/null +++ b/drivers/net/ethernet/agere/et131x.c @@ -0,0 +1,4121 @@ +/* Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + * Copyright (c) 2011 Mark Einon <[email protected]> + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <linux/bitops.h> +#include <linux/io.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> +#include <linux/crc32.h> +#include <linux/random.h> +#include <linux/phy.h> + +#include "et131x.h" + +MODULE_AUTHOR("Victor Soriano <[email protected]>"); +MODULE_AUTHOR("Mark Einon <[email protected]>"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("10/100/1000 Base-T Ethernet Driver for the ET1310 by Agere Systems"); + +/* EEPROM defines */ +#define MAX_NUM_REGISTER_POLLS 1000 +#define MAX_NUM_WRITE_RETRIES 2 + +/* MAC defines */ +#define COUNTER_WRAP_16_BIT 0x10000 +#define COUNTER_WRAP_12_BIT 0x1000 + +/* PCI defines */ +#define INTERNAL_MEM_SIZE 0x400 /* 1024 of internal memory */ +#define INTERNAL_MEM_RX_OFFSET 0x1FF /* 50% Tx, 50% Rx */ + +/* ISR defines */ +/* For interrupts, normal running is: + * rxdma_xfr_done, phy_interrupt, mac_stat_interrupt, + * watchdog_interrupt & txdma_xfer_done + * + * In both cases, when flow control is enabled for either Tx or bi-direction, + * we additional enable rx_fbr0_low and rx_fbr1_low, so we know when the + * buffer rings are running low. + */ +#define INT_MASK_DISABLE 0xffffffff + +/* NOTE: Masking out MAC_STAT Interrupt for now... + * #define INT_MASK_ENABLE 0xfff6bf17 + * #define INT_MASK_ENABLE_NO_FLOW 0xfff6bfd7 + */ +#define INT_MASK_ENABLE 0xfffebf17 +#define INT_MASK_ENABLE_NO_FLOW 0xfffebfd7 + +/* General defines */ +/* Packet and header sizes */ +#define NIC_MIN_PACKET_SIZE 60 + +/* Multicast list size */ +#define NIC_MAX_MCAST_LIST 128 + +/* Supported Filters */ +#define ET131X_PACKET_TYPE_DIRECTED 0x0001 +#define ET131X_PACKET_TYPE_MULTICAST 0x0002 +#define ET131X_PACKET_TYPE_BROADCAST 0x0004 +#define ET131X_PACKET_TYPE_PROMISCUOUS 0x0008 +#define ET131X_PACKET_TYPE_ALL_MULTICAST 0x0010 + +/* Tx Timeout */ +#define ET131X_TX_TIMEOUT (1 * HZ) +#define NIC_SEND_HANG_THRESHOLD 0 + +/* MP_ADAPTER flags */ +#define FMP_ADAPTER_INTERRUPT_IN_USE 0x00000008 + +/* MP_SHARED flags */ +#define FMP_ADAPTER_LOWER_POWER 0x00200000 + +#define FMP_ADAPTER_NON_RECOVER_ERROR 0x00800000 +#define FMP_ADAPTER_HARDWARE_ERROR 0x04000000 + +#define FMP_ADAPTER_FAIL_SEND_MASK 0x3ff00000 + +/* Some offsets in PCI config space that are actually used. */ +#define ET1310_PCI_MAC_ADDRESS 0xA4 +#define ET1310_PCI_EEPROM_STATUS 0xB2 +#define ET1310_PCI_ACK_NACK 0xC0 +#define ET1310_PCI_REPLAY 0xC2 +#define ET1310_PCI_L0L1LATENCY 0xCF + +/* PCI Product IDs */ +#define ET131X_PCI_DEVICE_ID_GIG 0xED00 /* ET1310 1000 Base-T 8 */ +#define ET131X_PCI_DEVICE_ID_FAST 0xED01 /* ET1310 100 Base-T */ + +/* Define order of magnitude converter */ +#define NANO_IN_A_MICRO 1000 + +#define PARM_RX_NUM_BUFS_DEF 4 +#define PARM_RX_TIME_INT_DEF 10 +#define PARM_RX_MEM_END_DEF 0x2bc +#define PARM_TX_TIME_INT_DEF 40 +#define PARM_TX_NUM_BUFS_DEF 4 +#define PARM_DMA_CACHE_DEF 0 + +/* RX defines */ +#define FBR_CHUNKS 32 +#define MAX_DESC_PER_RING_RX 1024 + +/* number of RFDs - default and min */ +#define RFD_LOW_WATER_MARK 40 +#define NIC_DEFAULT_NUM_RFD 1024 +#define NUM_FBRS 2 + +#define MAX_PACKETS_HANDLED 256 + +#define ALCATEL_MULTICAST_PKT 0x01000000 +#define ALCATEL_BROADCAST_PKT 0x02000000 + +/* typedefs for Free Buffer Descriptors */ +struct fbr_desc { + u32 addr_lo; + u32 addr_hi; + u32 word2; /* Bits 10-31 reserved, 0-9 descriptor */ +}; + +/* Packet Status Ring Descriptors + * + * Word 0: + * + * top 16 bits are from the Alcatel Status Word as enumerated in + * PE-MCXMAC Data Sheet IPD DS54 0210-1 (also IPD-DS80 0205-2) + * + * 0: hp hash pass + * 1: ipa IP checksum assist + * 2: ipp IP checksum pass + * 3: tcpa TCP checksum assist + * 4: tcpp TCP checksum pass + * 5: wol WOL Event + * 6: rxmac_error RXMAC Error Indicator + * 7: drop Drop packet + * 8: ft Frame Truncated + * 9: jp Jumbo Packet + * 10: vp VLAN Packet + * 11-15: unused + * 16: asw_prev_pkt_dropped e.g. IFG too small on previous + * 17: asw_RX_DV_event short receive event detected + * 18: asw_false_carrier_event bad carrier since last good packet + * 19: asw_code_err one or more nibbles signalled as errors + * 20: asw_CRC_err CRC error + * 21: asw_len_chk_err frame length field incorrect + * 22: asw_too_long frame length > 1518 bytes + * 23: asw_OK valid CRC + no code error + * 24: asw_multicast has a multicast address + * 25: asw_broadcast has a broadcast address + * 26: asw_dribble_nibble spurious bits after EOP + * 27: asw_control_frame is a control frame + * 28: asw_pause_frame is a pause frame + * 29: asw_unsupported_op unsupported OP code + * 30: asw_VLAN_tag VLAN tag detected + * 31: asw_long_evt Rx long event + * + * Word 1: + * 0-15: length length in bytes + * 16-25: bi Buffer Index + * 26-27: ri Ring Index + * 28-31: reserved + */ +struct pkt_stat_desc { + u32 word0; + u32 word1; +}; + +/* Typedefs for the RX DMA status word */ + +/* rx status word 0 holds part of the status bits of the Rx DMA engine + * that get copied out to memory by the ET-1310. Word 0 is a 32 bit word + * which contains the Free Buffer ring 0 and 1 available offset. + * + * bit 0-9 FBR1 offset + * bit 10 Wrap flag for FBR1 + * bit 16-25 FBR0 offset + * bit 26 Wrap flag for FBR0 + */ + +/* RXSTAT_WORD1_t structure holds part of the status bits of the Rx DMA engine + * that get copied out to memory by the ET-1310. Word 3 is a 32 bit word + * which contains the Packet Status Ring available offset. + * + * bit 0-15 reserved + * bit 16-27 PSRoffset + * bit 28 PSRwrap + * bit 29-31 unused + */ + +/* struct rx_status_block is a structure representing the status of the Rx + * DMA engine it sits in free memory, and is pointed to by 0x101c / 0x1020 + */ +struct rx_status_block { + u32 word0; + u32 word1; +}; + +/* Structure for look-up table holding free buffer ring pointers, addresses + * and state. + */ +struct fbr_lookup { + void *virt[MAX_DESC_PER_RING_RX]; + u32 bus_high[MAX_DESC_PER_RING_RX]; + u32 bus_low[MAX_DESC_PER_RING_RX]; + void *ring_virtaddr; + dma_addr_t ring_physaddr; + void *mem_virtaddrs[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; + dma_addr_t mem_physaddrs[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; + u32 local_full; + u32 num_entries; + dma_addr_t buffsize; +}; + +/* struct rx_ring is the structure representing the adaptor's local + * reference(s) to the rings + */ +struct rx_ring { + struct fbr_lookup *fbr[NUM_FBRS]; + void *ps_ring_virtaddr; + dma_addr_t ps_ring_physaddr; + u32 local_psr_full; + u32 psr_entries; + + struct rx_status_block *rx_status_block; + dma_addr_t rx_status_bus; + + struct list_head recv_list; + u32 num_ready_recv; + + u32 num_rfd; + + bool unfinished_receives; +}; + +/* TX defines */ +/* word 2 of the control bits in the Tx Descriptor ring for the ET-1310 + * + * 0-15: length of packet + * 16-27: VLAN tag + * 28: VLAN CFI + * 29-31: VLAN priority + * + * word 3 of the control bits in the Tx Descriptor ring for the ET-1310 + * + * 0: last packet in the sequence + * 1: first packet in the sequence + * 2: interrupt the processor when this pkt sent + * 3: Control word - no packet data + * 4: Issue half-duplex backpressure : XON/XOFF + * 5: send pause frame + * 6: Tx frame has error + * 7: append CRC + * 8: MAC override + * 9: pad packet + * 10: Packet is a Huge packet + * 11: append VLAN tag + * 12: IP checksum assist + * 13: TCP checksum assist + * 14: UDP checksum assist + */ +#define TXDESC_FLAG_LASTPKT 0x0001 +#define TXDESC_FLAG_FIRSTPKT 0x0002 +#define TXDESC_FLAG_INTPROC 0x0004 + +/* struct tx_desc represents each descriptor on the ring */ +struct tx_desc { + u32 addr_hi; + u32 addr_lo; + u32 len_vlan; /* control words how to xmit the */ + u32 flags; /* data (detailed above) */ +}; + +/* The status of the Tx DMA engine it sits in free memory, and is pointed to + * by 0x101c / 0x1020. This is a DMA10 type + */ + +/* TCB (Transmit Control Block: Host Side) */ +struct tcb { + struct tcb *next; /* Next entry in ring */ + u32 count; /* Used to spot stuck/lost packets */ + u32 stale; /* Used to spot stuck/lost packets */ + struct sk_buff *skb; /* Network skb we are tied to */ + u32 index; /* Ring indexes */ + u32 index_start; +}; + +/* Structure representing our local reference(s) to the ring */ +struct tx_ring { + /* TCB (Transmit Control Block) memory and lists */ + struct tcb *tcb_ring; + + /* List of TCBs that are ready to be used */ + struct tcb *tcb_qhead; + struct tcb *tcb_qtail; + + /* list of TCBs that are currently being sent. */ + struct tcb *send_head; + struct tcb *send_tail; + int used; + + /* The actual descriptor ring */ + struct tx_desc *tx_desc_ring; + dma_addr_t tx_desc_ring_pa; + + /* send_idx indicates where we last wrote to in the descriptor ring. */ + u32 send_idx; + + /* The location of the write-back status block */ + u32 *tx_status; + dma_addr_t tx_status_pa; + + /* Packets since the last IRQ: used for interrupt coalescing */ + int since_irq; +}; + +/* Do not change these values: if changed, then change also in respective + * TXdma and Rxdma engines + */ +#define NUM_DESC_PER_RING_TX 512 /* TX Do not change these values */ +#define NUM_TCB 64 + +/* These values are all superseded by registry entries to facilitate tuning. + * Once the desired performance has been achieved, the optimal registry values + * should be re-populated to these #defines: + */ +#define TX_ERROR_PERIOD 1000 + +#define LO_MARK_PERCENT_FOR_PSR 15 +#define LO_MARK_PERCENT_FOR_RX 15 + +/* RFD (Receive Frame Descriptor) */ +struct rfd { + struct list_head list_node; + struct sk_buff *skb; + u32 len; /* total size of receive frame */ + u16 bufferindex; + u8 ringindex; +}; + +/* Flow Control */ +#define FLOW_BOTH 0 +#define FLOW_TXONLY 1 +#define FLOW_RXONLY 2 +#define FLOW_NONE 3 + +/* Struct to define some device statistics */ +struct ce_stats { + u32 multicast_pkts_rcvd; + u32 rcvd_pkts_dropped; + + u32 tx_underflows; + u32 tx_collisions; + u32 tx_excessive_collisions; + u32 tx_first_collisions; + u32 tx_late_collisions; + u32 tx_max_pkt_errs; + u32 tx_deferred; + + u32 rx_overflows; + u32 rx_length_errs; + u32 rx_align_errs; + u32 rx_crc_errs; + u32 rx_code_violations; + u32 rx_other_errs; + + u32 interrupt_status; +}; + +/* The private adapter structure */ +struct et131x_adapter { + struct net_device *netdev; + struct pci_dev *pdev; + struct mii_bus *mii_bus; + struct phy_device *phydev; + struct napi_struct napi; + + /* Flags that indicate current state of the adapter */ + u32 flags; + + /* local link state, to determine if a state change has occurred */ + int link; + + /* Configuration */ + u8 rom_addr[ETH_ALEN]; + u8 addr[ETH_ALEN]; + bool has_eeprom; + u8 eeprom_data[2]; + + spinlock_t tcb_send_qlock; /* protects the tx_ring send tcb list */ + spinlock_t tcb_ready_qlock; /* protects the tx_ring ready tcb list */ + spinlock_t rcv_lock; /* protects the rx_ring receive list */ + + /* Packet Filter and look ahead size */ + u32 packet_filter; + + /* multicast list */ + u32 multicast_addr_count; + u8 multicast_list[NIC_MAX_MCAST_LIST][ETH_ALEN]; + + /* Pointer to the device's PCI register space */ + struct address_map __iomem *regs; + + /* Registry parameters */ + u8 wanted_flow; /* Flow we want for 802.3x flow control */ + u32 registry_jumbo_packet; /* Max supported ethernet packet size */ + + /* Derived from the registry: */ + u8 flow; /* flow control validated by the far-end */ + + /* Minimize init-time */ + struct timer_list error_timer; + + /* variable putting the phy into coma mode when boot up with no cable + * plugged in after 5 seconds + */ + u8 boot_coma; + + /* Tx Memory Variables */ + struct tx_ring tx_ring; + + /* Rx Memory Variables */ + struct rx_ring rx_ring; + + struct ce_stats stats; +}; + +static int eeprom_wait_ready(struct pci_dev *pdev, u32 *status) +{ + u32 reg; + int i; + + /* 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and + * bits 7,1:0 both equal to 1, at least once after reset. + * Subsequent operations need only to check that bits 1:0 are equal + * to 1 prior to starting a single byte read/write + */ + for (i = 0; i < MAX_NUM_REGISTER_POLLS; i++) { + if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP, ®)) + return -EIO; + + /* I2C idle and Phy Queue Avail both true */ + if ((reg & 0x3000) == 0x3000) { + if (status) + *status = reg; + return reg & 0xFF; + } + } + return -ETIMEDOUT; +} + +static int eeprom_write(struct et131x_adapter *adapter, u32 addr, u8 data) +{ + struct pci_dev *pdev = adapter->pdev; + int index = 0; + int retries; + int err = 0; + int writeok = 0; + u32 status; + u32 val = 0; + + /* For an EEPROM, an I2C single byte write is defined as a START + * condition followed by the device address, EEPROM address, one byte + * of data and a STOP condition. The STOP condition will trigger the + * EEPROM's internally timed write cycle to the nonvolatile memory. + * All inputs are disabled during this write cycle and the EEPROM will + * not respond to any access until the internal write is complete. + */ + err = eeprom_wait_ready(pdev, NULL); + if (err < 0) + return err; + + /* 2. Write to the LBCIF Control Register: bit 7=1, bit 6=1, bit 3=0, + * and bits 1:0 both =0. Bit 5 should be set according to the + * type of EEPROM being accessed (1=two byte addressing, 0=one + * byte addressing). + */ + if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER, + LBCIF_CONTROL_LBCIF_ENABLE | + LBCIF_CONTROL_I2C_WRITE)) + return -EIO; + + /* Prepare EEPROM address for Step 3 */ + for (retries = 0; retries < MAX_NUM_WRITE_RETRIES; retries++) { + if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER, addr)) + break; + /* Write the data to the LBCIF Data Register (the I2C write + * will begin). + */ + if (pci_write_config_byte(pdev, LBCIF_DATA_REGISTER, data)) + break; + /* Monitor bit 1:0 of the LBCIF Status Register. When bits + * 1:0 are both equal to 1, the I2C write has completed and the + * internal write cycle of the EEPROM is about to start. + * (bits 1:0 = 01 is a legal state while waiting from both + * equal to 1, but bits 1:0 = 10 is invalid and implies that + * something is broken). + */ + err = eeprom_wait_ready(pdev, &status); + if (err < 0) + return 0; + + /* Check bit 3 of the LBCIF Status Register. If equal to 1, + * an error has occurred.Don't break here if we are revision + * 1, this is so we do a blind write for load bug. + */ + if ((status & LBCIF_STATUS_GENERAL_ERROR) && + adapter->pdev->revision == 0) + break; + + /* Check bit 2 of the LBCIF Status Register. If equal to 1 an + * ACK error has occurred on the address phase of the write. + * This could be due to an actual hardware failure or the + * EEPROM may still be in its internal write cycle from a + * previous write. This write operation was ignored and must be + *repeated later. + */ + if (status & LBCIF_STATUS_ACK_ERROR) { + /* This could be due to an actual hardware failure + * or the EEPROM may still be in its internal write + * cycle from a previous write. This write operation + * was ignored and must be repeated later. + */ + udelay(10); + continue; + } + + writeok = 1; + break; + } + + udelay(10); + + while (1) { + if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER, + LBCIF_CONTROL_LBCIF_ENABLE)) + writeok = 0; + + /* Do read until internal ACK_ERROR goes away meaning write + * completed + */ + do { + pci_write_config_dword(pdev, + LBCIF_ADDRESS_REGISTER, + addr); + do { + pci_read_config_dword(pdev, + LBCIF_DATA_REGISTER, + &val); + } while ((val & 0x00010000) == 0); + } while (val & 0x00040000); + + if ((val & 0xFF00) != 0xC000 || index == 10000) + break; + index++; + } + return writeok ? 0 : -EIO; +} + +static int eeprom_read(struct et131x_adapter *adapter, u32 addr, u8 *pdata) +{ + struct pci_dev *pdev = adapter->pdev; + int err; + u32 status; + + /* A single byte read is similar to the single byte write, with the + * exception of the data flow: + */ + err = eeprom_wait_ready(pdev, NULL); + if (err < 0) + return err; + /* Write to the LBCIF Control Register: bit 7=1, bit 6=0, bit 3=0, + * and bits 1:0 both =0. Bit 5 should be set according to the type + * of EEPROM being accessed (1=two byte addressing, 0=one byte + * addressing). + */ + if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER, + LBCIF_CONTROL_LBCIF_ENABLE)) + return -EIO; + /* Write the address to the LBCIF Address Register (I2C read will + * begin). + */ + if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER, addr)) + return -EIO; + /* Monitor bit 0 of the LBCIF Status Register. When = 1, I2C read + * is complete. (if bit 1 =1 and bit 0 stays = 0, a hardware failure + * has occurred). + */ + err = eeprom_wait_ready(pdev, &status); + if (err < 0) + return err; + /* Regardless of error status, read data byte from LBCIF Data + * Register. + */ + *pdata = err; + + return (status & LBCIF_STATUS_ACK_ERROR) ? -EIO : 0; +} + +static int et131x_init_eeprom(struct et131x_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + u8 eestatus; + + pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, &eestatus); + + /* THIS IS A WORKAROUND: + * I need to call this function twice to get my card in a + * LG M1 Express Dual running. I tried also a msleep before this + * function, because I thought there could be some time conditions + * but it didn't work. Call the whole function twice also work. + */ + if (pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, &eestatus)) { + dev_err(&pdev->dev, + "Could not read PCI config space for EEPROM Status\n"); + return -EIO; + } + + /* Determine if the error(s) we care about are present. If they are + * present we need to fail. + */ + if (eestatus & 0x4C) { + int write_failed = 0; + + if (pdev->revision == 0x01) { + int i; + static const u8 eedata[4] = { 0xFE, 0x13, 0x10, 0xFF }; + + /* Re-write the first 4 bytes if we have an eeprom + * present and the revision id is 1, this fixes the + * corruption seen with 1310 B Silicon + */ + for (i = 0; i < 3; i++) + if (eeprom_write(adapter, i, eedata[i]) < 0) + write_failed = 1; + } + if (pdev->revision != 0x01 || write_failed) { + dev_err(&pdev->dev, + "Fatal EEPROM Status Error - 0x%04x\n", + eestatus); + + /* This error could mean that there was an error + * reading the eeprom or that the eeprom doesn't exist. + * We will treat each case the same and not try to + * gather additional information that normally would + * come from the eeprom, like MAC Address + */ + adapter->has_eeprom = 0; + return -EIO; + } + } + adapter->has_eeprom = 1; + + /* Read the EEPROM for information regarding LED behavior. Refer to + * et131x_xcvr_init() for its use. + */ + eeprom_read(adapter, 0x70, &adapter->eeprom_data[0]); + eeprom_read(adapter, 0x71, &adapter->eeprom_data[1]); + + if (adapter->eeprom_data[0] != 0xcd) + /* Disable all optional features */ + adapter->eeprom_data[1] = 0x00; + + return 0; +} + +static void et131x_rx_dma_enable(struct et131x_adapter *adapter) +{ + /* Setup the receive dma configuration register for normal operation */ + u32 csr = ET_RXDMA_CSR_FBR1_ENABLE; + struct rx_ring *rx_ring = &adapter->rx_ring; + + if (rx_ring->fbr[1]->buffsize == 4096) + csr |= ET_RXDMA_CSR_FBR1_SIZE_LO; + else if (rx_ring->fbr[1]->buffsize == 8192) + csr |= ET_RXDMA_CSR_FBR1_SIZE_HI; + else if (rx_ring->fbr[1]->buffsize == 16384) + csr |= ET_RXDMA_CSR_FBR1_SIZE_LO | ET_RXDMA_CSR_FBR1_SIZE_HI; + + csr |= ET_RXDMA_CSR_FBR0_ENABLE; + if (rx_ring->fbr[0]->buffsize == 256) + csr |= ET_RXDMA_CSR_FBR0_SIZE_LO; + else if (rx_ring->fbr[0]->buffsize == 512) + csr |= ET_RXDMA_CSR_FBR0_SIZE_HI; + else if (rx_ring->fbr[0]->buffsize == 1024) + csr |= ET_RXDMA_CSR_FBR0_SIZE_LO | ET_RXDMA_CSR_FBR0_SIZE_HI; + writel(csr, &adapter->regs->rxdma.csr); + + csr = readl(&adapter->regs->rxdma.csr); + if (csr & ET_RXDMA_CSR_HALT_STATUS) { + udelay(5); + csr = readl(&adapter->regs->rxdma.csr); + if (csr & ET_RXDMA_CSR_HALT_STATUS) { + dev_err(&adapter->pdev->dev, + "RX Dma failed to exit halt state. CSR 0x%08x\n", + csr); + } + } +} + +static void et131x_rx_dma_disable(struct et131x_adapter *adapter) +{ + u32 csr; + /* Setup the receive dma configuration register */ + writel(ET_RXDMA_CSR_HALT | ET_RXDMA_CSR_FBR1_ENABLE, + &adapter->regs->rxdma.csr); + csr = readl(&adapter->regs->rxdma.csr); + if (!(csr & ET_RXDMA_CSR_HALT_STATUS)) { + udelay(5); + csr = readl(&adapter->regs->rxdma.csr); + if (!(csr & ET_RXDMA_CSR_HALT_STATUS)) + dev_err(&adapter->pdev->dev, + "RX Dma failed to enter halt state. CSR 0x%08x\n", + csr); + } +} + +static void et131x_tx_dma_enable(struct et131x_adapter *adapter) +{ + /* Setup the transmit dma configuration register for normal + * operation + */ + writel(ET_TXDMA_SNGL_EPKT | (PARM_DMA_CACHE_DEF << ET_TXDMA_CACHE_SHIFT), + &adapter->regs->txdma.csr); +} + +static inline void add_10bit(u32 *v, int n) +{ + *v = INDEX10(*v + n) | (*v & ET_DMA10_WRAP); +} + +static inline void add_12bit(u32 *v, int n) +{ + *v = INDEX12(*v + n) | (*v & ET_DMA12_WRAP); +} + +static void et1310_config_mac_regs1(struct et131x_adapter *adapter) +{ + struct mac_regs __iomem *macregs = &adapter->regs->mac; + u32 station1; + u32 station2; + u32 ipg; + + /* First we need to reset everything. Write to MAC configuration + * register 1 to perform reset. + */ + writel(ET_MAC_CFG1_SOFT_RESET | ET_MAC_CFG1_SIM_RESET | + ET_MAC_CFG1_RESET_RXMC | ET_MAC_CFG1_RESET_TXMC | + ET_MAC_CFG1_RESET_RXFUNC | ET_MAC_CFG1_RESET_TXFUNC, + ¯egs->cfg1); + + /* Next lets configure the MAC Inter-packet gap register */ + ipg = 0x38005860; /* IPG1 0x38 IPG2 0x58 B2B 0x60 */ + ipg |= 0x50 << 8; /* ifg enforce 0x50 */ + writel(ipg, ¯egs->ipg); + + /* Next lets configure the MAC Half Duplex register */ + /* BEB trunc 0xA, Ex Defer, Rexmit 0xF Coll 0x37 */ + writel(0x00A1F037, ¯egs->hfdp); + + /* Next lets configure the MAC Interface Control register */ + writel(0, ¯egs->if_ctrl); + + writel(ET_MAC_MIIMGMT_CLK_RST, ¯egs->mii_mgmt_cfg); + + /* Next lets configure the MAC Station Address register. These + * values are read from the EEPROM during initialization and stored + * in the adapter structure. We write what is stored in the adapter + * structure to the MAC Station Address registers high and low. This + * station address is used for generating and checking pause control + * packets. + */ + station2 = (adapter->addr[1] << ET_MAC_STATION_ADDR2_OC2_SHIFT) | + (adapter->addr[0] << ET_MAC_STATION_ADDR2_OC1_SHIFT); + station1 = (adapter->addr[5] << ET_MAC_STATION_ADDR1_OC6_SHIFT) | + (adapter->addr[4] << ET_MAC_STATION_ADDR1_OC5_SHIFT) | + (adapter->addr[3] << ET_MAC_STATION_ADDR1_OC4_SHIFT) | + adapter->addr[2]; + writel(station1, ¯egs->station_addr_1); + writel(station2, ¯egs->station_addr_2); + + /* Max ethernet packet in bytes that will be passed by the mac without + * being truncated. Allow the MAC to pass 4 more than our max packet + * size. This is 4 for the Ethernet CRC. + * + * Packets larger than (registry_jumbo_packet) that do not contain a + * VLAN ID will be dropped by the Rx function. + */ + writel(adapter->registry_jumbo_packet + 4, ¯egs->max_fm_len); + + /* clear out MAC config reset */ + writel(0, ¯egs->cfg1); +} + +static void et1310_config_mac_regs2(struct et131x_adapter *adapter) +{ + int32_t delay = 0; + struct mac_regs __iomem *mac = &adapter->regs->mac; + struct phy_device *phydev = adapter->phydev; + u32 cfg1; + u32 cfg2; + u32 ifctrl; + u32 ctl; + + ctl = readl(&adapter->regs->txmac.ctl); + cfg1 = readl(&mac->cfg1); + cfg2 = readl(&mac->cfg2); + ifctrl = readl(&mac->if_ctrl); + + /* Set up the if mode bits */ + cfg2 &= ~ET_MAC_CFG2_IFMODE_MASK; + if (phydev->speed == SPEED_1000) { + cfg2 |= ET_MAC_CFG2_IFMODE_1000; + ifctrl &= ~ET_MAC_IFCTRL_PHYMODE; + } else { + cfg2 |= ET_MAC_CFG2_IFMODE_100; + ifctrl |= ET_MAC_IFCTRL_PHYMODE; + } + + cfg1 |= ET_MAC_CFG1_RX_ENABLE | ET_MAC_CFG1_TX_ENABLE | + ET_MAC_CFG1_TX_FLOW; + + cfg1 &= ~(ET_MAC_CFG1_LOOPBACK | ET_MAC_CFG1_RX_FLOW); + if (adapter->flow == FLOW_RXONLY || adapter->flow == FLOW_BOTH) + cfg1 |= ET_MAC_CFG1_RX_FLOW; + writel(cfg1, &mac->cfg1); + + /* Now we need to initialize the MAC Configuration 2 register */ + /* preamble 7, check length, huge frame off, pad crc, crc enable + * full duplex off + */ + cfg2 |= 0x7 << ET_MAC_CFG2_PREAMBLE_SHIFT; + cfg2 |= ET_MAC_CFG2_IFMODE_LEN_CHECK; + cfg2 |= ET_MAC_CFG2_IFMODE_PAD_CRC; + cfg2 |= ET_MAC_CFG2_IFMODE_CRC_ENABLE; + cfg2 &= ~ET_MAC_CFG2_IFMODE_HUGE_FRAME; + cfg2 &= ~ET_MAC_CFG2_IFMODE_FULL_DPLX; + + if (phydev->duplex == DUPLEX_FULL) + cfg2 |= ET_MAC_CFG2_IFMODE_FULL_DPLX; + + ifctrl &= ~ET_MAC_IFCTRL_GHDMODE; + if (phydev->duplex == DUPLEX_HALF) + ifctrl |= ET_MAC_IFCTRL_GHDMODE; + + writel(ifctrl, &mac->if_ctrl); + writel(cfg2, &mac->cfg2); + + do { + udelay(10); + delay++; + cfg1 = readl(&mac->cfg1); + } while ((cfg1 & ET_MAC_CFG1_WAIT) != ET_MAC_CFG1_WAIT && delay < 100); + + if (delay == 100) { + dev_warn(&adapter->pdev->dev, + "Syncd bits did not respond correctly cfg1 word 0x%08x\n", + cfg1); + } + + ctl |= ET_TX_CTRL_TXMAC_ENABLE | ET_TX_CTRL_FC_DISABLE; + writel(ctl, &adapter->regs->txmac.ctl); + + if (adapter->flags & FMP_ADAPTER_LOWER_POWER) { + et131x_rx_dma_enable(adapter); + et131x_tx_dma_enable(adapter); + } +} + +static int et1310_in_phy_coma(struct et131x_adapter *adapter) +{ + u32 pmcsr = readl(&adapter->regs->global.pm_csr); + + return ET_PM_PHY_SW_COMA & pmcsr ? 1 : 0; +} + +static void et1310_setup_device_for_multicast(struct et131x_adapter *adapter) +{ + struct rxmac_regs __iomem *rxmac = &adapter->regs->rxmac; + u32 hash1 = 0; + u32 hash2 = 0; + u32 hash3 = 0; + u32 hash4 = 0; + u32 pm_csr; + + /* If ET131X_PACKET_TYPE_MULTICAST is specified, then we provision + * the multi-cast LIST. If it is NOT specified, (and "ALL" is not + * specified) then we should pass NO multi-cast addresses to the + * driver. + */ + if (adapter->packet_filter & ET131X_PACKET_TYPE_MULTICAST) { + int i; + + /* Loop through our multicast array and set up the device */ + for (i = 0; i < adapter->multicast_addr_count; i++) { + u32 result; + + result = ether_crc(6, adapter->multicast_list[i]); + + result = (result & 0x3F800000) >> 23; + + if (result < 32) { + hash1 |= (1 << result); + } else if ((31 < result) && (result < 64)) { + result -= 32; + hash2 |= (1 << result); + } else if ((63 < result) && (result < 96)) { + result -= 64; + hash3 |= (1 << result); + } else { + result -= 96; + hash4 |= (1 << result); + } + } + } + + /* Write out the new hash to the device */ + pm_csr = readl(&adapter->regs->global.pm_csr); + if (!et1310_in_phy_coma(adapter)) { + writel(hash1, &rxmac->multi_hash1); + writel(hash2, &rxmac->multi_hash2); + writel(hash3, &rxmac->multi_hash3); + writel(hash4, &rxmac->multi_hash4); + } +} + +static void et1310_setup_device_for_unicast(struct et131x_adapter *adapter) +{ + struct rxmac_regs __iomem *rxmac = &adapter->regs->rxmac; + u32 uni_pf1; + u32 uni_pf2; + u32 uni_pf3; + u32 pm_csr; + + /* Set up unicast packet filter reg 3 to be the first two octets of + * the MAC address for both address + * + * Set up unicast packet filter reg 2 to be the octets 2 - 5 of the + * MAC address for second address + * + * Set up unicast packet filter reg 3 to be the octets 2 - 5 of the + * MAC address for first address + */ + uni_pf3 = (adapter->addr[0] << ET_RX_UNI_PF_ADDR2_1_SHIFT) | + (adapter->addr[1] << ET_RX_UNI_PF_ADDR2_2_SHIFT) | + (adapter->addr[0] << ET_RX_UNI_PF_ADDR1_1_SHIFT) | + adapter->addr[1]; + + uni_pf2 = (adapter->addr[2] << ET_RX_UNI_PF_ADDR2_3_SHIFT) | + (adapter->addr[3] << ET_RX_UNI_PF_ADDR2_4_SHIFT) | + (adapter->addr[4] << ET_RX_UNI_PF_ADDR2_5_SHIFT) | + adapter->addr[5]; + + uni_pf1 = (adapter->addr[2] << ET_RX_UNI_PF_ADDR1_3_SHIFT) | + (adapter->addr[3] << ET_RX_UNI_PF_ADDR1_4_SHIFT) | + (adapter->addr[4] << ET_RX_UNI_PF_ADDR1_5_SHIFT) | + adapter->addr[5]; + + pm_csr = readl(&adapter->regs->global.pm_csr); + if (!et1310_in_phy_coma(adapter)) { + writel(uni_pf1, &rxmac->uni_pf_addr1); + writel(uni_pf2, &rxmac->uni_pf_addr2); + writel(uni_pf3, &rxmac->uni_pf_addr3); + } +} + +static void et1310_config_rxmac_regs(struct et131x_adapter *adapter) +{ + struct rxmac_regs __iomem *rxmac = &adapter->regs->rxmac; + struct phy_device *phydev = adapter->phydev; + u32 sa_lo; + u32 sa_hi = 0; + u32 pf_ctrl = 0; + u32 __iomem *wolw; + + /* Disable the MAC while it is being configured (also disable WOL) */ + writel(0x8, &rxmac->ctrl); + + /* Initialize WOL to disabled. */ + writel(0, &rxmac->crc0); + writel(0, &rxmac->crc12); + writel(0, &rxmac->crc34); + + /* We need to set the WOL mask0 - mask4 next. We initialize it to + * its default Values of 0x00000000 because there are not WOL masks + * as of this time. + */ + for (wolw = &rxmac->mask0_word0; wolw <= &rxmac->mask4_word3; wolw++) + writel(0, wolw); + + /* Lets setup the WOL Source Address */ + sa_lo = (adapter->addr[2] << ET_RX_WOL_LO_SA3_SHIFT) | + (adapter->addr[3] << ET_RX_WOL_LO_SA4_SHIFT) | + (adapter->addr[4] << ET_RX_WOL_LO_SA5_SHIFT) | + adapter->addr[5]; + writel(sa_lo, &rxmac->sa_lo); + + sa_hi = (u32)(adapter->addr[0] << ET_RX_WOL_HI_SA1_SHIFT) | + adapter->addr[1]; + writel(sa_hi, &rxmac->sa_hi); + + /* Disable all Packet Filtering */ + writel(0, &rxmac->pf_ctrl); + + /* Let's initialize the Unicast Packet filtering address */ + if (adapter->packet_filter & ET131X_PACKET_TYPE_DIRECTED) { + et1310_setup_device_for_unicast(adapter); + pf_ctrl |= ET_RX_PFCTRL_UNICST_FILTER_ENABLE; + } else { + writel(0, &rxmac->uni_pf_addr1); + writel(0, &rxmac->uni_pf_addr2); + writel(0, &rxmac->uni_pf_addr3); + } + + /* Let's initialize the Multicast hash */ + if (!(adapter->packet_filter & ET131X_PACKET_TYPE_ALL_MULTICAST)) { + pf_ctrl |= ET_RX_PFCTRL_MLTCST_FILTER_ENABLE; + et1310_setup_device_for_multicast(adapter); + } + + /* Runt packet filtering. Didn't work in version A silicon. */ + pf_ctrl |= (NIC_MIN_PACKET_SIZE + 4) << ET_RX_PFCTRL_MIN_PKT_SZ_SHIFT; + pf_ctrl |= ET_RX_PFCTRL_FRAG_FILTER_ENABLE; + + if (adapter->registry_jumbo_packet > 8192) + /* In order to transmit jumbo packets greater than 8k, the + * FIFO between RxMAC and RxDMA needs to be reduced in size + * to (16k - Jumbo packet size). In order to implement this, + * we must use "cut through" mode in the RxMAC, which chops + * packets down into segments which are (max_size * 16). In + * this case we selected 256 bytes, since this is the size of + * the PCI-Express TLP's that the 1310 uses. + * + * seg_en on, fc_en off, size 0x10 + */ + writel(0x41, &rxmac->mcif_ctrl_max_seg); + else + writel(0, &rxmac->mcif_ctrl_max_seg); + + writel(0, &rxmac->mcif_water_mark); + writel(0, &rxmac->mif_ctrl); + writel(0, &rxmac->space_avail); + + /* Initialize the the mif_ctrl register + * bit 3: Receive code error. One or more nibbles were signaled as + * errors during the reception of the packet. Clear this + * bit in Gigabit, set it in 100Mbit. This was derived + * experimentally at UNH. + * bit 4: Receive CRC error. The packet's CRC did not match the + * internally generated CRC. + * bit 5: Receive length check error. Indicates that frame length + * field value in the packet does not match the actual data + * byte length and is not a type field. + * bit 16: Receive frame truncated. + * bit 17: Drop packet enable + */ + if (phydev && phydev->speed == SPEED_100) + writel(0x30038, &rxmac->mif_ctrl); + else + writel(0x30030, &rxmac->mif_ctrl); + + /* Finally we initialize RxMac to be enabled & WOL disabled. Packet + * filter is always enabled since it is where the runt packets are + * supposed to be dropped. For version A silicon, runt packet + * dropping doesn't work, so it is disabled in the pf_ctrl register, + * but we still leave the packet filter on. + */ + writel(pf_ctrl, &rxmac->pf_ctrl); + writel(ET_RX_CTRL_RXMAC_ENABLE | ET_RX_CTRL_WOL_DISABLE, &rxmac->ctrl); +} + +static void et1310_config_txmac_regs(struct et131x_adapter *adapter) +{ + struct txmac_regs __iomem *txmac = &adapter->regs->txmac; + + /* We need to update the Control Frame Parameters + * cfpt - control frame pause timer set to 64 (0x40) + * cfep - control frame extended pause timer set to 0x0 + */ + if (adapter->flow == FLOW_NONE) + writel(0, &txmac->cf_param); + else + writel(0x40, &txmac->cf_param); +} + +static void et1310_config_macstat_regs(struct et131x_adapter *adapter) +{ + struct macstat_regs __iomem *macstat = &adapter->regs->macstat; + u32 __iomem *reg; + + /* initialize all the macstat registers to zero on the device */ + for (reg = &macstat->txrx_0_64_byte_frames; + reg <= &macstat->carry_reg2; reg++) + writel(0, reg); + + /* Unmask any counters that we want to track the overflow of. + * Initially this will be all counters. It may become clear later + * that we do not need to track all counters. + */ + writel(0xFFFFBE32, &macstat->carry_reg1_mask); + writel(0xFFFE7E8B, &macstat->carry_reg2_mask); +} + +static int et131x_phy_mii_read(struct et131x_adapter *adapter, u8 addr, + u8 reg, u16 *value) +{ + struct mac_regs __iomem *mac = &adapter->regs->mac; + int status = 0; + u32 delay = 0; + u32 mii_addr; + u32 mii_cmd; + u32 mii_indicator; + + /* Save a local copy of the registers we are dealing with so we can + * set them back + */ + mii_addr = readl(&mac->mii_mgmt_addr); + mii_cmd = readl(&mac->mii_mgmt_cmd); + + /* Stop the current operation */ + writel(0, &mac->mii_mgmt_cmd); + + /* Set up the register we need to read from on the correct PHY */ + writel(ET_MAC_MII_ADDR(addr, reg), &mac->mii_mgmt_addr); + + writel(0x1, &mac->mii_mgmt_cmd); + + do { + udelay(50); + delay++; + mii_indicator = readl(&mac->mii_mgmt_indicator); + } while ((mii_indicator & ET_MAC_MGMT_WAIT) && delay < 50); + + /* If we hit the max delay, we could not read the register */ + if (delay == 50) { + dev_warn(&adapter->pdev->dev, + "reg 0x%08x could not be read\n", reg); + dev_warn(&adapter->pdev->dev, "status is 0x%08x\n", + mii_indicator); + + status = -EIO; + goto out; + } + + /* If we hit here we were able to read the register and we need to + * return the value to the caller + */ + *value = readl(&mac->mii_mgmt_stat) & ET_MAC_MIIMGMT_STAT_PHYCRTL_MASK; + +out: + /* Stop the read operation */ + writel(0, &mac->mii_mgmt_cmd); + + /* set the registers we touched back to the state at which we entered + * this function + */ + writel(mii_addr, &mac->mii_mgmt_addr); + writel(mii_cmd, &mac->mii_mgmt_cmd); + + return status; +} + +static int et131x_mii_read(struct et131x_adapter *adapter, u8 reg, u16 *value) +{ + struct phy_device *phydev = adapter->phydev; + + if (!phydev) + return -EIO; + + return et131x_phy_mii_read(adapter, phydev->addr, reg, value); +} + +static int et131x_mii_write(struct et131x_adapter *adapter, u8 addr, u8 reg, + u16 value) +{ + struct mac_regs __iomem *mac = &adapter->regs->mac; + int status = 0; + u32 delay = 0; + u32 mii_addr; + u32 mii_cmd; + u32 mii_indicator; + + /* Save a local copy of the registers we are dealing with so we can + * set them back + */ + mii_addr = readl(&mac->mii_mgmt_addr); + mii_cmd = readl(&mac->mii_mgmt_cmd); + + /* Stop the current operation */ + writel(0, &mac->mii_mgmt_cmd); + + /* Set up the register we need to write to on the correct PHY */ + writel(ET_MAC_MII_ADDR(addr, reg), &mac->mii_mgmt_addr); + + /* Add the value to write to the registers to the mac */ + writel(value, &mac->mii_mgmt_ctrl); + + do { + udelay(50); + delay++; + mii_indicator = readl(&mac->mii_mgmt_indicator); + } while ((mii_indicator & ET_MAC_MGMT_BUSY) && delay < 100); + + /* If we hit the max delay, we could not write the register */ + if (delay == 100) { + u16 tmp; + + dev_warn(&adapter->pdev->dev, + "reg 0x%08x could not be written", reg); + dev_warn(&adapter->pdev->dev, "status is 0x%08x\n", + mii_indicator); + dev_warn(&adapter->pdev->dev, "command is 0x%08x\n", + readl(&mac->mii_mgmt_cmd)); + + et131x_mii_read(adapter, reg, &tmp); + + status = -EIO; + } + /* Stop the write operation */ + writel(0, &mac->mii_mgmt_cmd); + + /* set the registers we touched back to the state at which we entered + * this function + */ + writel(mii_addr, &mac->mii_mgmt_addr); + writel(mii_cmd, &mac->mii_mgmt_cmd); + + return status; +} + +static void et1310_phy_read_mii_bit(struct et131x_adapter *adapter, + u16 regnum, + u16 bitnum, + u8 *value) +{ + u16 reg; + u16 mask = 1 << bitnum; + + et131x_mii_read(adapter, regnum, ®); + + *value = (reg & mask) >> bitnum; +} + +static void et1310_config_flow_control(struct et131x_adapter *adapter) +{ + struct phy_device *phydev = adapter->phydev; + + if (phydev->duplex == DUPLEX_HALF) { + adapter->flow = FLOW_NONE; + } else { + char remote_pause, remote_async_pause; + + et1310_phy_read_mii_bit(adapter, 5, 10, &remote_pause); + et1310_phy_read_mii_bit(adapter, 5, 11, &remote_async_pause); + + if (remote_pause && remote_async_pause) { + adapter->flow = adapter->wanted_flow; + } else if (remote_pause && !remote_async_pause) { + if (adapter->wanted_flow == FLOW_BOTH) + adapter->flow = FLOW_BOTH; + else + adapter->flow = FLOW_NONE; + } else if (!remote_pause && !remote_async_pause) { + adapter->flow = FLOW_NONE; + } else { + if (adapter->wanted_flow == FLOW_BOTH) + adapter->flow = FLOW_RXONLY; + else + adapter->flow = FLOW_NONE; + } + } +} + +/* et1310_update_macstat_host_counters - Update local copy of the statistics */ +static void et1310_update_macstat_host_counters(struct et131x_adapter *adapter) +{ + struct ce_stats *stats = &adapter->stats; + struct macstat_regs __iomem *macstat = + &adapter->regs->macstat; + + stats->tx_collisions += readl(&macstat->tx_total_collisions); + stats->tx_first_collisions += readl(&macstat->tx_single_collisions); + stats->tx_deferred += readl(&macstat->tx_deferred); + stats->tx_excessive_collisions += + readl(&macstat->tx_multiple_collisions); + stats->tx_late_collisions += readl(&macstat->tx_late_collisions); + stats->tx_underflows += readl(&macstat->tx_undersize_frames); + stats->tx_max_pkt_errs += readl(&macstat->tx_oversize_frames); + + stats->rx_align_errs += readl(&macstat->rx_align_errs); + stats->rx_crc_errs += readl(&macstat->rx_code_errs); + stats->rcvd_pkts_dropped += readl(&macstat->rx_drops); + stats->rx_overflows += readl(&macstat->rx_oversize_packets); + stats->rx_code_violations += readl(&macstat->rx_fcs_errs); + stats->rx_length_errs += readl(&macstat->rx_frame_len_errs); + stats->rx_other_errs += readl(&macstat->rx_fragment_packets); +} + +/* et1310_handle_macstat_interrupt + * + * One of the MACSTAT counters has wrapped. Update the local copy of + * the statistics held in the adapter structure, checking the "wrap" + * bit for each counter. + */ +static void et1310_handle_macstat_interrupt(struct et131x_adapter *adapter) +{ + u32 carry_reg1; + u32 carry_reg2; + + /* Read the interrupt bits from the register(s). These are Clear On + * Write. + */ + carry_reg1 = readl(&adapter->regs->macstat.carry_reg1); + carry_reg2 = readl(&adapter->regs->macstat.carry_reg2); + + writel(carry_reg1, &adapter->regs->macstat.carry_reg1); + writel(carry_reg2, &adapter->regs->macstat.carry_reg2); + + /* We need to do update the host copy of all the MAC_STAT counters. + * For each counter, check it's overflow bit. If the overflow bit is + * set, then increment the host version of the count by one complete + * revolution of the counter. This routine is called when the counter + * block indicates that one of the counters has wrapped. + */ + if (carry_reg1 & (1 << 14)) + adapter->stats.rx_code_violations += COUNTER_WRAP_16_BIT; + if (carry_reg1 & (1 << 8)) + adapter->stats.rx_align_errs += COUNTER_WRAP_12_BIT; + if (carry_reg1 & (1 << 7)) + adapter->stats.rx_length_errs += COUNTER_WRAP_16_BIT; + if (carry_reg1 & (1 << 2)) + adapter->stats.rx_other_errs += COUNTER_WRAP_16_BIT; + if (carry_reg1 & (1 << 6)) + adapter->stats.rx_crc_errs += COUNTER_WRAP_16_BIT; + if (carry_reg1 & (1 << 3)) + adapter->stats.rx_overflows += COUNTER_WRAP_16_BIT; + if (carry_reg1 & (1 << 0)) + adapter->stats.rcvd_pkts_dropped += COUNTER_WRAP_16_BIT; + if (carry_reg2 & (1 << 16)) + adapter->stats.tx_max_pkt_errs += COUNTER_WRAP_12_BIT; + if (carry_reg2 & (1 << 15)) + adapter->stats.tx_underflows += COUNTER_WRAP_12_BIT; + if (carry_reg2 & (1 << 6)) + adapter->stats.tx_first_collisions += COUNTER_WRAP_12_BIT; + if (carry_reg2 & (1 << 8)) + adapter->stats.tx_deferred += COUNTER_WRAP_12_BIT; + if (carry_reg2 & (1 << 5)) + adapter->stats.tx_excessive_collisions += COUNTER_WRAP_12_BIT; + if (carry_reg2 & (1 << 4)) + adapter->stats.tx_late_collisions += COUNTER_WRAP_12_BIT; + if (carry_reg2 & (1 << 2)) + adapter->stats.tx_collisions += COUNTER_WRAP_12_BIT; +} + +static int et131x_mdio_read(struct mii_bus *bus, int phy_addr, int reg) +{ + struct net_device *netdev = bus->priv; + struct et131x_adapter *adapter = netdev_priv(netdev); + u16 value; + int ret; + + ret = et131x_phy_mii_read(adapter, phy_addr, reg, &value); + + if (ret < 0) + return ret; + + return value; +} + +static int et131x_mdio_write(struct mii_bus *bus, int phy_addr, + int reg, u16 value) +{ + struct net_device *netdev = bus->priv; + struct et131x_adapter *adapter = netdev_priv(netdev); + + return et131x_mii_write(adapter, phy_addr, reg, value); +} + +/* et1310_phy_power_switch - PHY power control + * @adapter: device to control + * @down: true for off/false for back on + * + * one hundred, ten, one thousand megs + * How would you like to have your LAN accessed + * Can't you see that this code processed + * Phy power, phy power.. + */ +static void et1310_phy_power_switch(struct et131x_adapter *adapter, bool down) +{ + u16 data; + struct phy_device *phydev = adapter->phydev; + + et131x_mii_read(adapter, MII_BMCR, &data); + data &= ~BMCR_PDOWN; + if (down) + data |= BMCR_PDOWN; + et131x_mii_write(adapter, phydev->addr, MII_BMCR, data); +} + +/* et131x_xcvr_init - Init the phy if we are setting it into force mode */ +static void et131x_xcvr_init(struct et131x_adapter *adapter) +{ + u16 lcr2; + struct phy_device *phydev = adapter->phydev; + + /* Set the LED behavior such that LED 1 indicates speed (off = + * 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates + * link and activity (on for link, blink off for activity). + * + * NOTE: Some customizations have been added here for specific + * vendors; The LED behavior is now determined by vendor data in the + * EEPROM. However, the above description is the default. + */ + if ((adapter->eeprom_data[1] & 0x4) == 0) { + et131x_mii_read(adapter, PHY_LED_2, &lcr2); + + lcr2 &= (ET_LED2_LED_100TX | ET_LED2_LED_1000T); + lcr2 |= (LED_VAL_LINKON_ACTIVE << LED_LINK_SHIFT); + + if ((adapter->eeprom_data[1] & 0x8) == 0) + lcr2 |= (LED_VAL_1000BT_100BTX << LED_TXRX_SHIFT); + else + lcr2 |= (LED_VAL_LINKON << LED_TXRX_SHIFT); + + et131x_mii_write(adapter, phydev->addr, PHY_LED_2, lcr2); + } +} + +/* et131x_configure_global_regs - configure JAGCore global regs */ +static void et131x_configure_global_regs(struct et131x_adapter *adapter) +{ + struct global_regs __iomem *regs = &adapter->regs->global; + + writel(0, ®s->rxq_start_addr); + writel(INTERNAL_MEM_SIZE - 1, ®s->txq_end_addr); + + if (adapter->registry_jumbo_packet < 2048) { + /* Tx / RxDMA and Tx/Rx MAC interfaces have a 1k word + * block of RAM that the driver can split between Tx + * and Rx as it desires. Our default is to split it + * 50/50: + */ + writel(PARM_RX_MEM_END_DEF, ®s->rxq_end_addr); + writel(PARM_RX_MEM_END_DEF + 1, ®s->txq_start_addr); + } else if (adapter->registry_jumbo_packet < 8192) { + /* For jumbo packets > 2k but < 8k, split 50-50. */ + writel(INTERNAL_MEM_RX_OFFSET, ®s->rxq_end_addr); + writel(INTERNAL_MEM_RX_OFFSET + 1, ®s->txq_start_addr); + } else { + /* 9216 is the only packet size greater than 8k that + * is available. The Tx buffer has to be big enough + * for one whole packet on the Tx side. We'll make + * the Tx 9408, and give the rest to Rx + */ + writel(0x01b3, ®s->rxq_end_addr); + writel(0x01b4, ®s->txq_start_addr); + } + + /* Initialize the loopback register. Disable all loopbacks. */ + writel(0, ®s->loopback); + + writel(0, ®s->msi_config); + + /* By default, disable the watchdog timer. It will be enabled when + * a packet is queued. + */ + writel(0, ®s->watchdog_timer); +} + +/* et131x_config_rx_dma_regs - Start of Rx_DMA init sequence */ +static void et131x_config_rx_dma_regs(struct et131x_adapter *adapter) +{ + struct rxdma_regs __iomem *rx_dma = &adapter->regs->rxdma; + struct rx_ring *rx_local = &adapter->rx_ring; + struct fbr_desc *fbr_entry; + u32 entry; + u32 psr_num_des; + unsigned long flags; + u8 id; + + et131x_rx_dma_disable(adapter); + + /* Load the completion writeback physical address */ + writel(upper_32_bits(rx_local->rx_status_bus), &rx_dma->dma_wb_base_hi); + writel(lower_32_bits(rx_local->rx_status_bus), &rx_dma->dma_wb_base_lo); + + memset(rx_local->rx_status_block, 0, sizeof(struct rx_status_block)); + + /* Set the address and parameters of the packet status ring */ + writel(upper_32_bits(rx_local->ps_ring_physaddr), &rx_dma->psr_base_hi); + writel(lower_32_bits(rx_local->ps_ring_physaddr), &rx_dma->psr_base_lo); + writel(rx_local->psr_entries - 1, &rx_dma->psr_num_des); + writel(0, &rx_dma->psr_full_offset); + + psr_num_des = readl(&rx_dma->psr_num_des) & ET_RXDMA_PSR_NUM_DES_MASK; + writel((psr_num_des * LO_MARK_PERCENT_FOR_PSR) / 100, + &rx_dma->psr_min_des); + + spin_lock_irqsave(&adapter->rcv_lock, flags); + + /* These local variables track the PSR in the adapter structure */ + rx_local->local_psr_full = 0; + + for (id = 0; id < NUM_FBRS; id++) { + u32 __iomem *num_des; + u32 __iomem *full_offset; + u32 __iomem *min_des; + u32 __iomem *base_hi; + u32 __iomem *base_lo; + struct fbr_lookup *fbr = rx_local->fbr[id]; + + if (id == 0) { + num_des = &rx_dma->fbr0_num_des; + full_offset = &rx_dma->fbr0_full_offset; + min_des = &rx_dma->fbr0_min_des; + base_hi = &rx_dma->fbr0_base_hi; + base_lo = &rx_dma->fbr0_base_lo; + } else { + num_des = &rx_dma->fbr1_num_des; + full_offset = &rx_dma->fbr1_full_offset; + min_des = &rx_dma->fbr1_min_des; + base_hi = &rx_dma->fbr1_base_hi; + base_lo = &rx_dma->fbr1_base_lo; + } + + /* Now's the best time to initialize FBR contents */ + fbr_entry = fbr->ring_virtaddr; + for (entry = 0; entry < fbr->num_entries; entry++) { + fbr_entry->addr_hi = fbr->bus_high[entry]; + fbr_entry->addr_lo = fbr->bus_low[entry]; + fbr_entry->word2 = entry; + fbr_entry++; + } + + /* Set the address and parameters of Free buffer ring 1 and 0 */ + writel(upper_32_bits(fbr->ring_physaddr), base_hi); + writel(lower_32_bits(fbr->ring_physaddr), base_lo); + writel(fbr->num_entries - 1, num_des); + writel(ET_DMA10_WRAP, full_offset); + + /* This variable tracks the free buffer ring 1 full position, + * so it has to match the above. + */ + fbr->local_full = ET_DMA10_WRAP; + writel(((fbr->num_entries * LO_MARK_PERCENT_FOR_RX) / 100) - 1, + min_des); + } + + /* Program the number of packets we will receive before generating an + * interrupt. + * For version B silicon, this value gets updated once autoneg is + *complete. + */ + writel(PARM_RX_NUM_BUFS_DEF, &rx_dma->num_pkt_done); + + /* The "time_done" is not working correctly to coalesce interrupts + * after a given time period, but rather is giving us an interrupt + * regardless of whether we have received packets. + * This value gets updated once autoneg is complete. + */ + writel(PARM_RX_TIME_INT_DEF, &rx_dma->max_pkt_time); + + spin_unlock_irqrestore(&adapter->rcv_lock, flags); +} + +/* et131x_config_tx_dma_regs - Set up the tx dma section of the JAGCore. + * + * Configure the transmit engine with the ring buffers we have created + * and prepare it for use. + */ +static void et131x_config_tx_dma_regs(struct et131x_adapter *adapter) +{ + struct txdma_regs __iomem *txdma = &adapter->regs->txdma; + struct tx_ring *tx_ring = &adapter->tx_ring; + + /* Load the hardware with the start of the transmit descriptor ring. */ + writel(upper_32_bits(tx_ring->tx_desc_ring_pa), &txdma->pr_base_hi); + writel(lower_32_bits(tx_ring->tx_desc_ring_pa), &txdma->pr_base_lo); + + /* Initialise the transmit DMA engine */ + writel(NUM_DESC_PER_RING_TX - 1, &txdma->pr_num_des); + + /* Load the completion writeback physical address */ + writel(upper_32_bits(tx_ring->tx_status_pa), &txdma->dma_wb_base_hi); + writel(lower_32_bits(tx_ring->tx_status_pa), &txdma->dma_wb_base_lo); + + *tx_ring->tx_status = 0; + + writel(0, &txdma->service_request); + tx_ring->send_idx = 0; +} + +/* et131x_adapter_setup - Set the adapter up as per cassini+ documentation */ +static void et131x_adapter_setup(struct et131x_adapter *adapter) +{ + et131x_configure_global_regs(adapter); + et1310_config_mac_regs1(adapter); + + /* Configure the MMC registers */ + /* All we need to do is initialize the Memory Control Register */ + writel(ET_MMC_ENABLE, &adapter->regs->mmc.mmc_ctrl); + + et1310_config_rxmac_regs(adapter); + et1310_config_txmac_regs(adapter); + + et131x_config_rx_dma_regs(adapter); + et131x_config_tx_dma_regs(adapter); + + et1310_config_macstat_regs(adapter); + + et1310_phy_power_switch(adapter, 0); + et131x_xcvr_init(adapter); +} + +/* et131x_soft_reset - Issue soft reset to the hardware, complete for ET1310 */ +static void et131x_soft_reset(struct et131x_adapter *adapter) +{ + u32 reg; + + /* Disable MAC Core */ + reg = ET_MAC_CFG1_SOFT_RESET | ET_MAC_CFG1_SIM_RESET | + ET_MAC_CFG1_RESET_RXMC | ET_MAC_CFG1_RESET_TXMC | + ET_MAC_CFG1_RESET_RXFUNC | ET_MAC_CFG1_RESET_TXFUNC; + writel(reg, &adapter->regs->mac.cfg1); + + reg = ET_RESET_ALL; + writel(reg, &adapter->regs->global.sw_reset); + + reg = ET_MAC_CFG1_RESET_RXMC | ET_MAC_CFG1_RESET_TXMC | + ET_MAC_CFG1_RESET_RXFUNC | ET_MAC_CFG1_RESET_TXFUNC; + writel(reg, &adapter->regs->mac.cfg1); + writel(0, &adapter->regs->mac.cfg1); +} + +static void et131x_enable_interrupts(struct et131x_adapter *adapter) +{ + u32 mask; + + if (adapter->flow == FLOW_TXONLY || adapter->flow == FLOW_BOTH) + mask = INT_MASK_ENABLE; + else + mask = INT_MASK_ENABLE_NO_FLOW; + + writel(mask, &adapter->regs->global.int_mask); +} + +static void et131x_disable_interrupts(struct et131x_adapter *adapter) +{ + writel(INT_MASK_DISABLE, &adapter->regs->global.int_mask); +} + +static void et131x_tx_dma_disable(struct et131x_adapter *adapter) +{ + /* Setup the transmit dma configuration register */ + writel(ET_TXDMA_CSR_HALT | ET_TXDMA_SNGL_EPKT, + &adapter->regs->txdma.csr); +} + +static void et131x_enable_txrx(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + et131x_rx_dma_enable(adapter); + et131x_tx_dma_enable(adapter); + + if (adapter->flags & FMP_ADAPTER_INTERRUPT_IN_USE) + et131x_enable_interrupts(adapter); + + netif_start_queue(netdev); +} + +static void et131x_disable_txrx(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + netif_stop_queue(netdev); + + et131x_rx_dma_disable(adapter); + et131x_tx_dma_disable(adapter); + + et131x_disable_interrupts(adapter); +} + +static void et131x_init_send(struct et131x_adapter *adapter) +{ + int i; + struct tx_ring *tx_ring = &adapter->tx_ring; + struct tcb *tcb = tx_ring->tcb_ring; + + tx_ring->tcb_qhead = tcb; + + memset(tcb, 0, sizeof(struct tcb) * NUM_TCB); + + for (i = 0; i < NUM_TCB; i++) { + tcb->next = tcb + 1; + tcb++; + } + + tcb--; + tx_ring->tcb_qtail = tcb; + tcb->next = NULL; + /* Curr send queue should now be empty */ + tx_ring->send_head = NULL; + tx_ring->send_tail = NULL; +} + +/* et1310_enable_phy_coma + * + * driver receive an phy status change interrupt while in D0 and check that + * phy_status is down. + * + * -- gate off JAGCore; + * -- set gigE PHY in Coma mode + * -- wake on phy_interrupt; Perform software reset JAGCore, + * re-initialize jagcore and gigE PHY + */ +static void et1310_enable_phy_coma(struct et131x_adapter *adapter) +{ + u32 pmcsr = readl(&adapter->regs->global.pm_csr); + + /* Stop sending packets. */ + adapter->flags |= FMP_ADAPTER_LOWER_POWER; + + /* Wait for outstanding Receive packets */ + et131x_disable_txrx(adapter->netdev); + + /* Gate off JAGCore 3 clock domains */ + pmcsr &= ~ET_PMCSR_INIT; + writel(pmcsr, &adapter->regs->global.pm_csr); + + /* Program gigE PHY in to Coma mode */ + pmcsr |= ET_PM_PHY_SW_COMA; + writel(pmcsr, &adapter->regs->global.pm_csr); +} + +static void et1310_disable_phy_coma(struct et131x_adapter *adapter) +{ + u32 pmcsr; + + pmcsr = readl(&adapter->regs->global.pm_csr); + + /* Disable phy_sw_coma register and re-enable JAGCore clocks */ + pmcsr |= ET_PMCSR_INIT; + pmcsr &= ~ET_PM_PHY_SW_COMA; + writel(pmcsr, &adapter->regs->global.pm_csr); + + /* Restore the GbE PHY speed and duplex modes; + * Reset JAGCore; re-configure and initialize JAGCore and gigE PHY + */ + + /* Re-initialize the send structures */ + et131x_init_send(adapter); + + /* Bring the device back to the state it was during init prior to + * autonegotiation being complete. This way, when we get the auto-neg + * complete interrupt, we can complete init by calling ConfigMacREGS2. + */ + et131x_soft_reset(adapter); + + et131x_adapter_setup(adapter); + + /* Allow Tx to restart */ + adapter->flags &= ~FMP_ADAPTER_LOWER_POWER; + + et131x_enable_txrx(adapter->netdev); +} + +static inline u32 bump_free_buff_ring(u32 *free_buff_ring, u32 limit) +{ + u32 tmp_free_buff_ring = *free_buff_ring; + + tmp_free_buff_ring++; + /* This works for all cases where limit < 1024. The 1023 case + * works because 1023++ is 1024 which means the if condition is not + * taken but the carry of the bit into the wrap bit toggles the wrap + * value correctly + */ + if ((tmp_free_buff_ring & ET_DMA10_MASK) > limit) { + tmp_free_buff_ring &= ~ET_DMA10_MASK; + tmp_free_buff_ring ^= ET_DMA10_WRAP; + } + /* For the 1023 case */ + tmp_free_buff_ring &= (ET_DMA10_MASK | ET_DMA10_WRAP); + *free_buff_ring = tmp_free_buff_ring; + return tmp_free_buff_ring; +} + +/* et131x_rx_dma_memory_alloc + * + * Allocates Free buffer ring 1 for sure, free buffer ring 0 if required, + * and the Packet Status Ring. + */ +static int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) +{ + u8 id; + u32 i, j; + u32 bufsize; + u32 psr_size; + u32 fbr_chunksize; + struct rx_ring *rx_ring = &adapter->rx_ring; + struct fbr_lookup *fbr; + + /* Alloc memory for the lookup table */ + rx_ring->fbr[0] = kzalloc(sizeof(*fbr), GFP_KERNEL); + if (rx_ring->fbr[0] == NULL) + return -ENOMEM; + rx_ring->fbr[1] = kzalloc(sizeof(*fbr), GFP_KERNEL); + if (rx_ring->fbr[1] == NULL) + return -ENOMEM; + + /* The first thing we will do is configure the sizes of the buffer + * rings. These will change based on jumbo packet support. Larger + * jumbo packets increases the size of each entry in FBR0, and the + * number of entries in FBR0, while at the same time decreasing the + * number of entries in FBR1. + * + * FBR1 holds "large" frames, FBR0 holds "small" frames. If FBR1 + * entries are huge in order to accommodate a "jumbo" frame, then it + * will have less entries. Conversely, FBR1 will now be relied upon + * to carry more "normal" frames, thus it's entry size also increases + * and the number of entries goes up too (since it now carries + * "small" + "regular" packets. + * + * In this scheme, we try to maintain 512 entries between the two + * rings. Also, FBR1 remains a constant size - when it's size doubles + * the number of entries halves. FBR0 increases in size, however. + */ + if (adapter->registry_jumbo_packet < 2048) { + rx_ring->fbr[0]->buffsize = 256; + rx_ring->fbr[0]->num_entries = 512; + rx_ring->fbr[1]->buffsize = 2048; + rx_ring->fbr[1]->num_entries = 512; + } else if (adapter->registry_jumbo_packet < 4096) { + rx_ring->fbr[0]->buffsize = 512; + rx_ring->fbr[0]->num_entries = 1024; + rx_ring->fbr[1]->buffsize = 4096; + rx_ring->fbr[1]->num_entries = 512; + } else { + rx_ring->fbr[0]->buffsize = 1024; + rx_ring->fbr[0]->num_entries = 768; + rx_ring->fbr[1]->buffsize = 16384; + rx_ring->fbr[1]->num_entries = 128; + } + + rx_ring->psr_entries = rx_ring->fbr[0]->num_entries + + rx_ring->fbr[1]->num_entries; + + for (id = 0; id < NUM_FBRS; id++) { + fbr = rx_ring->fbr[id]; + /* Allocate an area of memory for Free Buffer Ring */ + bufsize = sizeof(struct fbr_desc) * fbr->num_entries; + fbr->ring_virtaddr = dma_alloc_coherent(&adapter->pdev->dev, + bufsize, + &fbr->ring_physaddr, + GFP_KERNEL); + if (!fbr->ring_virtaddr) { + dev_err(&adapter->pdev->dev, + "Cannot alloc memory for Free Buffer Ring %d\n", + id); + return -ENOMEM; + } + } + + for (id = 0; id < NUM_FBRS; id++) { + fbr = rx_ring->fbr[id]; + fbr_chunksize = (FBR_CHUNKS * fbr->buffsize); + + for (i = 0; i < fbr->num_entries / FBR_CHUNKS; i++) { + dma_addr_t fbr_physaddr; + + fbr->mem_virtaddrs[i] = dma_alloc_coherent( + &adapter->pdev->dev, fbr_chunksize, + &fbr->mem_physaddrs[i], + GFP_KERNEL); + + if (!fbr->mem_virtaddrs[i]) { + dev_err(&adapter->pdev->dev, + "Could not alloc memory\n"); + return -ENOMEM; + } + + /* See NOTE in "Save Physical Address" comment above */ + fbr_physaddr = fbr->mem_physaddrs[i]; + + for (j = 0; j < FBR_CHUNKS; j++) { + u32 k = (i * FBR_CHUNKS) + j; + + /* Save the Virtual address of this index for + * quick access later + */ + fbr->virt[k] = (u8 *)fbr->mem_virtaddrs[i] + + (j * fbr->buffsize); + + /* now store the physical address in the + * descriptor so the device can access it + */ + fbr->bus_high[k] = upper_32_bits(fbr_physaddr); + fbr->bus_low[k] = lower_32_bits(fbr_physaddr); + fbr_physaddr += fbr->buffsize; + } + } + } + + /* Allocate an area of memory for FIFO of Packet Status ring entries */ + psr_size = sizeof(struct pkt_stat_desc) * rx_ring->psr_entries; + + rx_ring->ps_ring_virtaddr = dma_alloc_coherent(&adapter->pdev->dev, + psr_size, + &rx_ring->ps_ring_physaddr, + GFP_KERNEL); + + if (!rx_ring->ps_ring_virtaddr) { + dev_err(&adapter->pdev->dev, + "Cannot alloc memory for Packet Status Ring\n"); + return -ENOMEM; + } + + /* Allocate an area of memory for writeback of status information */ + rx_ring->rx_status_block = dma_alloc_coherent(&adapter->pdev->dev, + sizeof(struct rx_status_block), + &rx_ring->rx_status_bus, + GFP_KERNEL); + if (!rx_ring->rx_status_block) { + dev_err(&adapter->pdev->dev, + "Cannot alloc memory for Status Block\n"); + return -ENOMEM; + } + rx_ring->num_rfd = NIC_DEFAULT_NUM_RFD; + + /* The RFDs are going to be put on lists later on, so initialize the + * lists now. + */ + INIT_LIST_HEAD(&rx_ring->recv_list); + return 0; +} + +static void et131x_rx_dma_memory_free(struct et131x_adapter *adapter) +{ + u8 id; + u32 ii; + u32 bufsize; + u32 psr_size; + struct rfd *rfd; + struct rx_ring *rx_ring = &adapter->rx_ring; + struct fbr_lookup *fbr; + + /* Free RFDs and associated packet descriptors */ + WARN_ON(rx_ring->num_ready_recv != rx_ring->num_rfd); + + while (!list_empty(&rx_ring->recv_list)) { + rfd = list_entry(rx_ring->recv_list.next, + struct rfd, list_node); + + list_del(&rfd->list_node); + rfd->skb = NULL; + kfree(rfd); + } + + /* Free Free Buffer Rings */ + for (id = 0; id < NUM_FBRS; id++) { + fbr = rx_ring->fbr[id]; + + if (!fbr || !fbr->ring_virtaddr) + continue; + + /* First the packet memory */ + for (ii = 0; ii < fbr->num_entries / FBR_CHUNKS; ii++) { + if (fbr->mem_virtaddrs[ii]) { + bufsize = fbr->buffsize * FBR_CHUNKS; + + dma_free_coherent(&adapter->pdev->dev, + bufsize, + fbr->mem_virtaddrs[ii], + fbr->mem_physaddrs[ii]); + + fbr->mem_virtaddrs[ii] = NULL; + } + } + + bufsize = sizeof(struct fbr_desc) * fbr->num_entries; + + dma_free_coherent(&adapter->pdev->dev, + bufsize, + fbr->ring_virtaddr, + fbr->ring_physaddr); + + fbr->ring_virtaddr = NULL; + } + + /* Free Packet Status Ring */ + if (rx_ring->ps_ring_virtaddr) { + psr_size = sizeof(struct pkt_stat_desc) * rx_ring->psr_entries; + + dma_free_coherent(&adapter->pdev->dev, psr_size, + rx_ring->ps_ring_virtaddr, + rx_ring->ps_ring_physaddr); + + rx_ring->ps_ring_virtaddr = NULL; + } + + /* Free area of memory for the writeback of status information */ + if (rx_ring->rx_status_block) { + dma_free_coherent(&adapter->pdev->dev, + sizeof(struct rx_status_block), + rx_ring->rx_status_block, + rx_ring->rx_status_bus); + rx_ring->rx_status_block = NULL; + } + + /* Free the FBR Lookup Table */ + kfree(rx_ring->fbr[0]); + kfree(rx_ring->fbr[1]); + + /* Reset Counters */ + rx_ring->num_ready_recv = 0; +} + +/* et131x_init_recv - Initialize receive data structures */ +static int et131x_init_recv(struct et131x_adapter *adapter) +{ + struct rfd *rfd; + u32 rfdct; + struct rx_ring *rx_ring = &adapter->rx_ring; + + /* Setup each RFD */ + for (rfdct = 0; rfdct < rx_ring->num_rfd; rfdct++) { + rfd = kzalloc(sizeof(*rfd), GFP_ATOMIC | GFP_DMA); + if (!rfd) + return -ENOMEM; + + rfd->skb = NULL; + + /* Add this RFD to the recv_list */ + list_add_tail(&rfd->list_node, &rx_ring->recv_list); + + /* Increment the available RFD's */ + rx_ring->num_ready_recv++; + } + + return 0; +} + +/* et131x_set_rx_dma_timer - Set the heartbeat timer according to line rate */ +static void et131x_set_rx_dma_timer(struct et131x_adapter *adapter) +{ + struct phy_device *phydev = adapter->phydev; + + /* For version B silicon, we do not use the RxDMA timer for 10 and 100 + * Mbits/s line rates. We do not enable and RxDMA interrupt coalescing. + */ + if ((phydev->speed == SPEED_100) || (phydev->speed == SPEED_10)) { + writel(0, &adapter->regs->rxdma.max_pkt_time); + writel(1, &adapter->regs->rxdma.num_pkt_done); + } +} + +/* nic_return_rfd - Recycle a RFD and put it back onto the receive list */ +static void nic_return_rfd(struct et131x_adapter *adapter, struct rfd *rfd) +{ + struct rx_ring *rx_local = &adapter->rx_ring; + struct rxdma_regs __iomem *rx_dma = &adapter->regs->rxdma; + u16 buff_index = rfd->bufferindex; + u8 ring_index = rfd->ringindex; + unsigned long flags; + struct fbr_lookup *fbr = rx_local->fbr[ring_index]; + + /* We don't use any of the OOB data besides status. Otherwise, we + * need to clean up OOB data + */ + if (buff_index < fbr->num_entries) { + u32 free_buff_ring; + u32 __iomem *offset; + struct fbr_desc *next; + + if (ring_index == 0) + offset = &rx_dma->fbr0_full_offset; + else + offset = &rx_dma->fbr1_full_offset; + + next = (struct fbr_desc *)(fbr->ring_virtaddr) + + INDEX10(fbr->local_full); + + /* Handle the Free Buffer Ring advancement here. Write + * the PA / Buffer Index for the returned buffer into + * the oldest (next to be freed)FBR entry + */ + next->addr_hi = fbr->bus_high[buff_index]; + next->addr_lo = fbr->bus_low[buff_index]; + next->word2 = buff_index; + + free_buff_ring = bump_free_buff_ring(&fbr->local_full, + fbr->num_entries - 1); + writel(free_buff_ring, offset); + } else { + dev_err(&adapter->pdev->dev, + "%s illegal Buffer Index returned\n", __func__); + } + + /* The processing on this RFD is done, so put it back on the tail of + * our list + */ + spin_lock_irqsave(&adapter->rcv_lock, flags); + list_add_tail(&rfd->list_node, &rx_local->recv_list); + rx_local->num_ready_recv++; + spin_unlock_irqrestore(&adapter->rcv_lock, flags); + + WARN_ON(rx_local->num_ready_recv > rx_local->num_rfd); +} + +/* nic_rx_pkts - Checks the hardware for available packets + * + * Checks the hardware for available packets, using completion ring + * If packets are available, it gets an RFD from the recv_list, attaches + * the packet to it, puts the RFD in the RecvPendList, and also returns + * the pointer to the RFD. + */ +static struct rfd *nic_rx_pkts(struct et131x_adapter *adapter) +{ + struct rx_ring *rx_local = &adapter->rx_ring; + struct rx_status_block *status; + struct pkt_stat_desc *psr; + struct rfd *rfd; + unsigned long flags; + struct list_head *element; + u8 ring_index; + u16 buff_index; + u32 len; + u32 word0; + u32 word1; + struct sk_buff *skb; + struct fbr_lookup *fbr; + + /* RX Status block is written by the DMA engine prior to every + * interrupt. It contains the next to be used entry in the Packet + * Status Ring, and also the two Free Buffer rings. + */ + status = rx_local->rx_status_block; + word1 = status->word1 >> 16; + + /* Check the PSR and wrap bits do not match */ + if ((word1 & 0x1FFF) == (rx_local->local_psr_full & 0x1FFF)) + return NULL; /* Looks like this ring is not updated yet */ + + /* The packet status ring indicates that data is available. */ + psr = (struct pkt_stat_desc *)(rx_local->ps_ring_virtaddr) + + (rx_local->local_psr_full & 0xFFF); + + /* Grab any information that is required once the PSR is advanced, + * since we can no longer rely on the memory being accurate + */ + len = psr->word1 & 0xFFFF; + ring_index = (psr->word1 >> 26) & 0x03; + fbr = rx_local->fbr[ring_index]; + buff_index = (psr->word1 >> 16) & 0x3FF; + word0 = psr->word0; + + /* Indicate that we have used this PSR entry. */ + /* FIXME wrap 12 */ + add_12bit(&rx_local->local_psr_full, 1); + if ((rx_local->local_psr_full & 0xFFF) > rx_local->psr_entries - 1) { + /* Clear psr full and toggle the wrap bit */ + rx_local->local_psr_full &= ~0xFFF; + rx_local->local_psr_full ^= 0x1000; + } + + writel(rx_local->local_psr_full, &adapter->regs->rxdma.psr_full_offset); + + if (ring_index > 1 || buff_index > fbr->num_entries - 1) { + /* Illegal buffer or ring index cannot be used by S/W*/ + dev_err(&adapter->pdev->dev, + "NICRxPkts PSR Entry %d indicates length of %d and/or bad bi(%d)\n", + rx_local->local_psr_full & 0xFFF, len, buff_index); + return NULL; + } + + /* Get and fill the RFD. */ + spin_lock_irqsave(&adapter->rcv_lock, flags); + + element = rx_local->recv_list.next; + rfd = list_entry(element, struct rfd, list_node); + + if (!rfd) { + spin_unlock_irqrestore(&adapter->rcv_lock, flags); + return NULL; + } + + list_del(&rfd->list_node); + rx_local->num_ready_recv--; + + spin_unlock_irqrestore(&adapter->rcv_lock, flags); + + rfd->bufferindex = buff_index; + rfd->ringindex = ring_index; + + /* In V1 silicon, there is a bug which screws up filtering of runt + * packets. Therefore runt packet filtering is disabled in the MAC and + * the packets are dropped here. They are also counted here. + */ + if (len < (NIC_MIN_PACKET_SIZE + 4)) { + adapter->stats.rx_other_errs++; + rfd->len = 0; + goto out; + } + + if ((word0 & ALCATEL_MULTICAST_PKT) && !(word0 & ALCATEL_BROADCAST_PKT)) + adapter->stats.multicast_pkts_rcvd++; + + rfd->len = len; + + skb = dev_alloc_skb(rfd->len + 2); + if (!skb) + return NULL; + + adapter->netdev->stats.rx_bytes += rfd->len; + + memcpy(skb_put(skb, rfd->len), fbr->virt[buff_index], rfd->len); + + skb->protocol = eth_type_trans(skb, adapter->netdev); + skb->ip_summed = CHECKSUM_NONE; + netif_receive_skb(skb); + +out: + nic_return_rfd(adapter, rfd); + return rfd; +} + +static int et131x_handle_recv_pkts(struct et131x_adapter *adapter, int budget) +{ + struct rfd *rfd = NULL; + int count = 0; + int limit = budget; + bool done = true; + struct rx_ring *rx_ring = &adapter->rx_ring; + + if (budget > MAX_PACKETS_HANDLED) + limit = MAX_PACKETS_HANDLED; + + /* Process up to available RFD's */ + while (count < limit) { + if (list_empty(&rx_ring->recv_list)) { + WARN_ON(rx_ring->num_ready_recv != 0); + done = false; + break; + } + + rfd = nic_rx_pkts(adapter); + + if (rfd == NULL) + break; + + /* Do not receive any packets until a filter has been set. + * Do not receive any packets until we have link. + * If length is zero, return the RFD in order to advance the + * Free buffer ring. + */ + if (!adapter->packet_filter || + !netif_carrier_ok(adapter->netdev) || + rfd->len == 0) + continue; + + adapter->netdev->stats.rx_packets++; + + if (rx_ring->num_ready_recv < RFD_LOW_WATER_MARK) + dev_warn(&adapter->pdev->dev, "RFD's are running out\n"); + + count++; + } + + if (count == limit || !done) { + rx_ring->unfinished_receives = true; + writel(PARM_TX_TIME_INT_DEF * NANO_IN_A_MICRO, + &adapter->regs->global.watchdog_timer); + } else { + /* Watchdog timer will disable itself if appropriate. */ + rx_ring->unfinished_receives = false; + } + + return count; +} + +/* et131x_tx_dma_memory_alloc + * + * Allocates memory that will be visible both to the device and to the CPU. + * The OS will pass us packets, pointers to which we will insert in the Tx + * Descriptor queue. The device will read this queue to find the packets in + * memory. The device will update the "status" in memory each time it xmits a + * packet. + */ +static int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter) +{ + int desc_size = 0; + struct tx_ring *tx_ring = &adapter->tx_ring; + + /* Allocate memory for the TCB's (Transmit Control Block) */ + tx_ring->tcb_ring = kcalloc(NUM_TCB, sizeof(struct tcb), + GFP_ATOMIC | GFP_DMA); + if (!tx_ring->tcb_ring) + return -ENOMEM; + + desc_size = (sizeof(struct tx_desc) * NUM_DESC_PER_RING_TX); + tx_ring->tx_desc_ring = dma_alloc_coherent(&adapter->pdev->dev, + desc_size, + &tx_ring->tx_desc_ring_pa, + GFP_KERNEL); + if (!tx_ring->tx_desc_ring) { + dev_err(&adapter->pdev->dev, + "Cannot alloc memory for Tx Ring\n"); + return -ENOMEM; + } + + tx_ring->tx_status = dma_alloc_coherent(&adapter->pdev->dev, + sizeof(u32), + &tx_ring->tx_status_pa, + GFP_KERNEL); + if (!tx_ring->tx_status_pa) { + dev_err(&adapter->pdev->dev, + "Cannot alloc memory for Tx status block\n"); + return -ENOMEM; + } + return 0; +} + +static void et131x_tx_dma_memory_free(struct et131x_adapter *adapter) +{ + int desc_size = 0; + struct tx_ring *tx_ring = &adapter->tx_ring; + + if (tx_ring->tx_desc_ring) { + /* Free memory relating to Tx rings here */ + desc_size = (sizeof(struct tx_desc) * NUM_DESC_PER_RING_TX); + dma_free_coherent(&adapter->pdev->dev, + desc_size, + tx_ring->tx_desc_ring, + tx_ring->tx_desc_ring_pa); + tx_ring->tx_desc_ring = NULL; + } + + /* Free memory for the Tx status block */ + if (tx_ring->tx_status) { + dma_free_coherent(&adapter->pdev->dev, + sizeof(u32), + tx_ring->tx_status, + tx_ring->tx_status_pa); + + tx_ring->tx_status = NULL; + } + /* Free the memory for the tcb structures */ + kfree(tx_ring->tcb_ring); +} + +/* nic_send_packet - NIC specific send handler for version B silicon. */ +static int nic_send_packet(struct et131x_adapter *adapter, struct tcb *tcb) +{ + u32 i; + struct tx_desc desc[24]; + u32 frag = 0; + u32 thiscopy, remainder; + struct sk_buff *skb = tcb->skb; + u32 nr_frags = skb_shinfo(skb)->nr_frags + 1; + struct skb_frag_struct *frags = &skb_shinfo(skb)->frags[0]; + struct phy_device *phydev = adapter->phydev; + dma_addr_t dma_addr; + struct tx_ring *tx_ring = &adapter->tx_ring; + + /* Part of the optimizations of this send routine restrict us to + * sending 24 fragments at a pass. In practice we should never see + * more than 5 fragments. + */ + + /* nr_frags should be no more than 18. */ + BUILD_BUG_ON(MAX_SKB_FRAGS + 1 > 23); + + memset(desc, 0, sizeof(struct tx_desc) * (nr_frags + 1)); + + for (i = 0; i < nr_frags; i++) { + /* If there is something in this element, lets get a + * descriptor from the ring and get the necessary data + */ + if (i == 0) { + /* If the fragments are smaller than a standard MTU, + * then map them to a single descriptor in the Tx + * Desc ring. However, if they're larger, as is + * possible with support for jumbo packets, then + * split them each across 2 descriptors. + * + * This will work until we determine why the hardware + * doesn't seem to like large fragments. + */ + if (skb_headlen(skb) <= 1514) { + /* Low 16bits are length, high is vlan and + * unused currently so zero + */ + desc[frag].len_vlan = skb_headlen(skb); + dma_addr = dma_map_single(&adapter->pdev->dev, + skb->data, + skb_headlen(skb), + DMA_TO_DEVICE); + desc[frag].addr_lo = lower_32_bits(dma_addr); + desc[frag].addr_hi = upper_32_bits(dma_addr); + frag++; + } else { + desc[frag].len_vlan = skb_headlen(skb) / 2; + dma_addr = dma_map_single(&adapter->pdev->dev, + skb->data, + skb_headlen(skb) / 2, + DMA_TO_DEVICE); + desc[frag].addr_lo = lower_32_bits(dma_addr); + desc[frag].addr_hi = upper_32_bits(dma_addr); + frag++; + + desc[frag].len_vlan = skb_headlen(skb) / 2; + dma_addr = dma_map_single(&adapter->pdev->dev, + skb->data + + skb_headlen(skb) / 2, + skb_headlen(skb) / 2, + DMA_TO_DEVICE); + desc[frag].addr_lo = lower_32_bits(dma_addr); + desc[frag].addr_hi = upper_32_bits(dma_addr); + frag++; + } + } else { + desc[frag].len_vlan = frags[i - 1].size; + dma_addr = skb_frag_dma_map(&adapter->pdev->dev, + &frags[i - 1], + 0, + frags[i - 1].size, + DMA_TO_DEVICE); + desc[frag].addr_lo = lower_32_bits(dma_addr); + desc[frag].addr_hi = upper_32_bits(dma_addr); + frag++; + } + } + + if (phydev && phydev->speed == SPEED_1000) { + if (++tx_ring->since_irq == PARM_TX_NUM_BUFS_DEF) { + /* Last element & Interrupt flag */ + desc[frag - 1].flags = + TXDESC_FLAG_INTPROC | TXDESC_FLAG_LASTPKT; + tx_ring->since_irq = 0; + } else { /* Last element */ + desc[frag - 1].flags = TXDESC_FLAG_LASTPKT; + } + } else { + desc[frag - 1].flags = + TXDESC_FLAG_INTPROC | TXDESC_FLAG_LASTPKT; + } + + desc[0].flags |= TXDESC_FLAG_FIRSTPKT; + + tcb->index_start = tx_ring->send_idx; + tcb->stale = 0; + + thiscopy = NUM_DESC_PER_RING_TX - INDEX10(tx_ring->send_idx); + + if (thiscopy >= frag) { + remainder = 0; + thiscopy = frag; + } else { + remainder = frag - thiscopy; + } + + memcpy(tx_ring->tx_desc_ring + INDEX10(tx_ring->send_idx), + desc, + sizeof(struct tx_desc) * thiscopy); + + add_10bit(&tx_ring->send_idx, thiscopy); + + if (INDEX10(tx_ring->send_idx) == 0 || + INDEX10(tx_ring->send_idx) == NUM_DESC_PER_RING_TX) { + tx_ring->send_idx &= ~ET_DMA10_MASK; + tx_ring->send_idx ^= ET_DMA10_WRAP; + } + + if (remainder) { + memcpy(tx_ring->tx_desc_ring, + desc + thiscopy, + sizeof(struct tx_desc) * remainder); + + add_10bit(&tx_ring->send_idx, remainder); + } + + if (INDEX10(tx_ring->send_idx) == 0) { + if (tx_ring->send_idx) + tcb->index = NUM_DESC_PER_RING_TX - 1; + else + tcb->index = ET_DMA10_WRAP|(NUM_DESC_PER_RING_TX - 1); + } else { + tcb->index = tx_ring->send_idx - 1; + } + + spin_lock(&adapter->tcb_send_qlock); + + if (tx_ring->send_tail) + tx_ring->send_tail->next = tcb; + else + tx_ring->send_head = tcb; + + tx_ring->send_tail = tcb; + + WARN_ON(tcb->next != NULL); + + tx_ring->used++; + + spin_unlock(&adapter->tcb_send_qlock); + + /* Write the new write pointer back to the device. */ + writel(tx_ring->send_idx, &adapter->regs->txdma.service_request); + + /* For Gig only, we use Tx Interrupt coalescing. Enable the software + * timer to wake us up if this packet isn't followed by N more. + */ + if (phydev && phydev->speed == SPEED_1000) { + writel(PARM_TX_TIME_INT_DEF * NANO_IN_A_MICRO, + &adapter->regs->global.watchdog_timer); + } + return 0; +} + +static int send_packet(struct sk_buff *skb, struct et131x_adapter *adapter) +{ + int status; + struct tcb *tcb; + unsigned long flags; + struct tx_ring *tx_ring = &adapter->tx_ring; + + /* All packets must have at least a MAC address and a protocol type */ + if (skb->len < ETH_HLEN) + return -EIO; + + spin_lock_irqsave(&adapter->tcb_ready_qlock, flags); + + tcb = tx_ring->tcb_qhead; + + if (tcb == NULL) { + spin_unlock_irqrestore(&adapter->tcb_ready_qlock, flags); + return -ENOMEM; + } + + tx_ring->tcb_qhead = tcb->next; + + if (tx_ring->tcb_qhead == NULL) + tx_ring->tcb_qtail = NULL; + + spin_unlock_irqrestore(&adapter->tcb_ready_qlock, flags); + + tcb->skb = skb; + tcb->next = NULL; + + status = nic_send_packet(adapter, tcb); + + if (status != 0) { + spin_lock_irqsave(&adapter->tcb_ready_qlock, flags); + + if (tx_ring->tcb_qtail) + tx_ring->tcb_qtail->next = tcb; + else + /* Apparently ready Q is empty. */ + tx_ring->tcb_qhead = tcb; + + tx_ring->tcb_qtail = tcb; + spin_unlock_irqrestore(&adapter->tcb_ready_qlock, flags); + return status; + } + WARN_ON(tx_ring->used > NUM_TCB); + return 0; +} + +/* free_send_packet - Recycle a struct tcb */ +static inline void free_send_packet(struct et131x_adapter *adapter, + struct tcb *tcb) +{ + unsigned long flags; + struct tx_desc *desc = NULL; + struct net_device_stats *stats = &adapter->netdev->stats; + struct tx_ring *tx_ring = &adapter->tx_ring; + u64 dma_addr; + + if (tcb->skb) { + stats->tx_bytes += tcb->skb->len; + + /* Iterate through the TX descriptors on the ring + * corresponding to this packet and umap the fragments + * they point to + */ + do { + desc = tx_ring->tx_desc_ring + + INDEX10(tcb->index_start); + + dma_addr = desc->addr_lo; + dma_addr |= (u64)desc->addr_hi << 32; + + dma_unmap_single(&adapter->pdev->dev, + dma_addr, + desc->len_vlan, DMA_TO_DEVICE); + + add_10bit(&tcb->index_start, 1); + if (INDEX10(tcb->index_start) >= + NUM_DESC_PER_RING_TX) { + tcb->index_start &= ~ET_DMA10_MASK; + tcb->index_start ^= ET_DMA10_WRAP; + } + } while (desc != tx_ring->tx_desc_ring + INDEX10(tcb->index)); + + dev_kfree_skb_any(tcb->skb); + } + + memset(tcb, 0, sizeof(struct tcb)); + + /* Add the TCB to the Ready Q */ + spin_lock_irqsave(&adapter->tcb_ready_qlock, flags); + + stats->tx_packets++; + + if (tx_ring->tcb_qtail) + tx_ring->tcb_qtail->next = tcb; + else /* Apparently ready Q is empty. */ + tx_ring->tcb_qhead = tcb; + + tx_ring->tcb_qtail = tcb; + + spin_unlock_irqrestore(&adapter->tcb_ready_qlock, flags); + WARN_ON(tx_ring->used < 0); +} + +/* et131x_free_busy_send_packets - Free and complete the stopped active sends */ +static void et131x_free_busy_send_packets(struct et131x_adapter *adapter) +{ + struct tcb *tcb; + unsigned long flags; + u32 freed = 0; + struct tx_ring *tx_ring = &adapter->tx_ring; + + /* Any packets being sent? Check the first TCB on the send list */ + spin_lock_irqsave(&adapter->tcb_send_qlock, flags); + + tcb = tx_ring->send_head; + + while (tcb != NULL && freed < NUM_TCB) { + struct tcb *next = tcb->next; + + tx_ring->send_head = next; + + if (next == NULL) + tx_ring->send_tail = NULL; + + tx_ring->used--; + + spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); + + freed++; + free_send_packet(adapter, tcb); + + spin_lock_irqsave(&adapter->tcb_send_qlock, flags); + + tcb = tx_ring->send_head; + } + + WARN_ON(freed == NUM_TCB); + + spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); + + tx_ring->used = 0; +} + +/* et131x_handle_send_pkts + * + * Re-claim the send resources, complete sends and get more to send from + * the send wait queue. + */ +static void et131x_handle_send_pkts(struct et131x_adapter *adapter) +{ + unsigned long flags; + u32 serviced; + struct tcb *tcb; + u32 index; + struct tx_ring *tx_ring = &adapter->tx_ring; + + serviced = readl(&adapter->regs->txdma.new_service_complete); + index = INDEX10(serviced); + + /* Has the ring wrapped? Process any descriptors that do not have + * the same "wrap" indicator as the current completion indicator + */ + spin_lock_irqsave(&adapter->tcb_send_qlock, flags); + + tcb = tx_ring->send_head; + + while (tcb && + ((serviced ^ tcb->index) & ET_DMA10_WRAP) && + index < INDEX10(tcb->index)) { + tx_ring->used--; + tx_ring->send_head = tcb->next; + if (tcb->next == NULL) + tx_ring->send_tail = NULL; + + spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); + free_send_packet(adapter, tcb); + spin_lock_irqsave(&adapter->tcb_send_qlock, flags); + + /* Goto the next packet */ + tcb = tx_ring->send_head; + } + while (tcb && + !((serviced ^ tcb->index) & ET_DMA10_WRAP) && + index > (tcb->index & ET_DMA10_MASK)) { + tx_ring->used--; + tx_ring->send_head = tcb->next; + if (tcb->next == NULL) + tx_ring->send_tail = NULL; + + spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); + free_send_packet(adapter, tcb); + spin_lock_irqsave(&adapter->tcb_send_qlock, flags); + + /* Goto the next packet */ + tcb = tx_ring->send_head; + } + + /* Wake up the queue when we hit a low-water mark */ + if (tx_ring->used <= NUM_TCB / 3) + netif_wake_queue(adapter->netdev); + + spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); +} + +static int et131x_get_settings(struct net_device *netdev, + struct ethtool_cmd *cmd) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + return phy_ethtool_gset(adapter->phydev, cmd); +} + +static int et131x_set_settings(struct net_device *netdev, + struct ethtool_cmd *cmd) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + return phy_ethtool_sset(adapter->phydev, cmd); +} + +static int et131x_get_regs_len(struct net_device *netdev) +{ +#define ET131X_REGS_LEN 256 + return ET131X_REGS_LEN * sizeof(u32); +} + +static void et131x_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *regs_data) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + struct address_map __iomem *aregs = adapter->regs; + u32 *regs_buff = regs_data; + u32 num = 0; + u16 tmp; + + memset(regs_data, 0, et131x_get_regs_len(netdev)); + + regs->version = (1 << 24) | (adapter->pdev->revision << 16) | + adapter->pdev->device; + + /* PHY regs */ + et131x_mii_read(adapter, MII_BMCR, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_BMSR, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_PHYSID1, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_PHYSID2, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_ADVERTISE, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_LPA, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_EXPANSION, &tmp); + regs_buff[num++] = tmp; + /* Autoneg next page transmit reg */ + et131x_mii_read(adapter, 0x07, &tmp); + regs_buff[num++] = tmp; + /* Link partner next page reg */ + et131x_mii_read(adapter, 0x08, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_CTRL1000, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_STAT1000, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, 0x0b, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, 0x0c, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_MMD_CTRL, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_MMD_DATA, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, MII_ESTATUS, &tmp); + regs_buff[num++] = tmp; + + et131x_mii_read(adapter, PHY_INDEX_REG, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_DATA_REG, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_LOOPBACK_CONTROL, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_LOOPBACK_CONTROL + 1, &tmp); + regs_buff[num++] = tmp; + + et131x_mii_read(adapter, PHY_REGISTER_MGMT_CONTROL, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_CONFIG, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_PHY_CONTROL, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_INTERRUPT_MASK, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_INTERRUPT_STATUS, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_PHY_STATUS, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_LED_1, &tmp); + regs_buff[num++] = tmp; + et131x_mii_read(adapter, PHY_LED_2, &tmp); + regs_buff[num++] = tmp; + + /* Global regs */ + regs_buff[num++] = readl(&aregs->global.txq_start_addr); + regs_buff[num++] = readl(&aregs->global.txq_end_addr); + regs_buff[num++] = readl(&aregs->global.rxq_start_addr); + regs_buff[num++] = readl(&aregs->global.rxq_end_addr); + regs_buff[num++] = readl(&aregs->global.pm_csr); + regs_buff[num++] = adapter->stats.interrupt_status; + regs_buff[num++] = readl(&aregs->global.int_mask); + regs_buff[num++] = readl(&aregs->global.int_alias_clr_en); + regs_buff[num++] = readl(&aregs->global.int_status_alias); + regs_buff[num++] = readl(&aregs->global.sw_reset); + regs_buff[num++] = readl(&aregs->global.slv_timer); + regs_buff[num++] = readl(&aregs->global.msi_config); + regs_buff[num++] = readl(&aregs->global.loopback); + regs_buff[num++] = readl(&aregs->global.watchdog_timer); + + /* TXDMA regs */ + regs_buff[num++] = readl(&aregs->txdma.csr); + regs_buff[num++] = readl(&aregs->txdma.pr_base_hi); + regs_buff[num++] = readl(&aregs->txdma.pr_base_lo); + regs_buff[num++] = readl(&aregs->txdma.pr_num_des); + regs_buff[num++] = readl(&aregs->txdma.txq_wr_addr); + regs_buff[num++] = readl(&aregs->txdma.txq_wr_addr_ext); + regs_buff[num++] = readl(&aregs->txdma.txq_rd_addr); + regs_buff[num++] = readl(&aregs->txdma.dma_wb_base_hi); + regs_buff[num++] = readl(&aregs->txdma.dma_wb_base_lo); + regs_buff[num++] = readl(&aregs->txdma.service_request); + regs_buff[num++] = readl(&aregs->txdma.service_complete); + regs_buff[num++] = readl(&aregs->txdma.cache_rd_index); + regs_buff[num++] = readl(&aregs->txdma.cache_wr_index); + regs_buff[num++] = readl(&aregs->txdma.tx_dma_error); + regs_buff[num++] = readl(&aregs->txdma.desc_abort_cnt); + regs_buff[num++] = readl(&aregs->txdma.payload_abort_cnt); + regs_buff[num++] = readl(&aregs->txdma.writeback_abort_cnt); + regs_buff[num++] = readl(&aregs->txdma.desc_timeout_cnt); + regs_buff[num++] = readl(&aregs->txdma.payload_timeout_cnt); + regs_buff[num++] = readl(&aregs->txdma.writeback_timeout_cnt); + regs_buff[num++] = readl(&aregs->txdma.desc_error_cnt); + regs_buff[num++] = readl(&aregs->txdma.payload_error_cnt); + regs_buff[num++] = readl(&aregs->txdma.writeback_error_cnt); + regs_buff[num++] = readl(&aregs->txdma.dropped_tlp_cnt); + regs_buff[num++] = readl(&aregs->txdma.new_service_complete); + regs_buff[num++] = readl(&aregs->txdma.ethernet_packet_cnt); + + /* RXDMA regs */ + regs_buff[num++] = readl(&aregs->rxdma.csr); + regs_buff[num++] = readl(&aregs->rxdma.dma_wb_base_hi); + regs_buff[num++] = readl(&aregs->rxdma.dma_wb_base_lo); + regs_buff[num++] = readl(&aregs->rxdma.num_pkt_done); + regs_buff[num++] = readl(&aregs->rxdma.max_pkt_time); + regs_buff[num++] = readl(&aregs->rxdma.rxq_rd_addr); + regs_buff[num++] = readl(&aregs->rxdma.rxq_rd_addr_ext); + regs_buff[num++] = readl(&aregs->rxdma.rxq_wr_addr); + regs_buff[num++] = readl(&aregs->rxdma.psr_base_hi); + regs_buff[num++] = readl(&aregs->rxdma.psr_base_lo); + regs_buff[num++] = readl(&aregs->rxdma.psr_num_des); + regs_buff[num++] = readl(&aregs->rxdma.psr_avail_offset); + regs_buff[num++] = readl(&aregs->rxdma.psr_full_offset); + regs_buff[num++] = readl(&aregs->rxdma.psr_access_index); + regs_buff[num++] = readl(&aregs->rxdma.psr_min_des); + regs_buff[num++] = readl(&aregs->rxdma.fbr0_base_lo); + regs_buff[num++] = readl(&aregs->rxdma.fbr0_base_hi); + regs_buff[num++] = readl(&aregs->rxdma.fbr0_num_des); + regs_buff[num++] = readl(&aregs->rxdma.fbr0_avail_offset); + regs_buff[num++] = readl(&aregs->rxdma.fbr0_full_offset); + regs_buff[num++] = readl(&aregs->rxdma.fbr0_rd_index); + regs_buff[num++] = readl(&aregs->rxdma.fbr0_min_des); + regs_buff[num++] = readl(&aregs->rxdma.fbr1_base_lo); + regs_buff[num++] = readl(&aregs->rxdma.fbr1_base_hi); + regs_buff[num++] = readl(&aregs->rxdma.fbr1_num_des); + regs_buff[num++] = readl(&aregs->rxdma.fbr1_avail_offset); + regs_buff[num++] = readl(&aregs->rxdma.fbr1_full_offset); + regs_buff[num++] = readl(&aregs->rxdma.fbr1_rd_index); + regs_buff[num++] = readl(&aregs->rxdma.fbr1_min_des); +} + +static void et131x_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); + strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, pci_name(adapter->pdev), + sizeof(info->bus_info)); +} + +static struct ethtool_ops et131x_ethtool_ops = { + .get_settings = et131x_get_settings, + .set_settings = et131x_set_settings, + .get_drvinfo = et131x_get_drvinfo, + .get_regs_len = et131x_get_regs_len, + .get_regs = et131x_get_regs, + .get_link = ethtool_op_get_link, +}; + +/* et131x_hwaddr_init - set up the MAC Address */ +static void et131x_hwaddr_init(struct et131x_adapter *adapter) +{ + /* If have our default mac from init and no mac address from + * EEPROM then we need to generate the last octet and set it on the + * device + */ + if (is_zero_ether_addr(adapter->rom_addr)) { + /* We need to randomly generate the last octet so we + * decrease our chances of setting the mac address to + * same as another one of our cards in the system + */ + get_random_bytes(&adapter->addr[5], 1); + /* We have the default value in the register we are + * working with so we need to copy the current + * address into the permanent address + */ + ether_addr_copy(adapter->rom_addr, adapter->addr); + } else { + /* We do not have an override address, so set the + * current address to the permanent address and add + * it to the device + */ + ether_addr_copy(adapter->addr, adapter->rom_addr); + } +} + +static int et131x_pci_init(struct et131x_adapter *adapter, + struct pci_dev *pdev) +{ + u16 max_payload; + int i, rc; + + rc = et131x_init_eeprom(adapter); + if (rc < 0) + goto out; + + if (!pci_is_pcie(pdev)) { + dev_err(&pdev->dev, "Missing PCIe capabilities\n"); + goto err_out; + } + + /* Program the Ack/Nak latency and replay timers */ + max_payload = pdev->pcie_mpss; + + if (max_payload < 2) { + static const u16 acknak[2] = { 0x76, 0xD0 }; + static const u16 replay[2] = { 0x1E0, 0x2ED }; + + if (pci_write_config_word(pdev, ET1310_PCI_ACK_NACK, + acknak[max_payload])) { + dev_err(&pdev->dev, + "Could not write PCI config space for ACK/NAK\n"); + goto err_out; + } + if (pci_write_config_word(pdev, ET1310_PCI_REPLAY, + replay[max_payload])) { + dev_err(&pdev->dev, + "Could not write PCI config space for Replay Timer\n"); + goto err_out; + } + } + + /* l0s and l1 latency timers. We are using default values. + * Representing 001 for L0s and 010 for L1 + */ + if (pci_write_config_byte(pdev, ET1310_PCI_L0L1LATENCY, 0x11)) { + dev_err(&pdev->dev, + "Could not write PCI config space for Latency Timers\n"); + goto err_out; + } + + /* Change the max read size to 2k */ + if (pcie_set_readrq(pdev, 2048)) { + dev_err(&pdev->dev, + "Couldn't change PCI config space for Max read size\n"); + goto err_out; + } + + /* Get MAC address from config space if an eeprom exists, otherwise + * the MAC address there will not be valid + */ + if (!adapter->has_eeprom) { + et131x_hwaddr_init(adapter); + return 0; + } + + for (i = 0; i < ETH_ALEN; i++) { + if (pci_read_config_byte(pdev, ET1310_PCI_MAC_ADDRESS + i, + adapter->rom_addr + i)) { + dev_err(&pdev->dev, "Could not read PCI config space for MAC address\n"); + goto err_out; + } + } + ether_addr_copy(adapter->addr, adapter->rom_addr); +out: + return rc; +err_out: + rc = -EIO; + goto out; +} + +/* et131x_error_timer_handler + * @data: timer-specific variable; here a pointer to our adapter structure + * + * The routine called when the error timer expires, to track the number of + * recurring errors. + */ +static void et131x_error_timer_handler(unsigned long data) +{ + struct et131x_adapter *adapter = (struct et131x_adapter *)data; + struct phy_device *phydev = adapter->phydev; + + if (et1310_in_phy_coma(adapter)) { + /* Bring the device immediately out of coma, to + * prevent it from sleeping indefinitely, this + * mechanism could be improved! + */ + et1310_disable_phy_coma(adapter); + adapter->boot_coma = 20; + } else { + et1310_update_macstat_host_counters(adapter); + } + + if (!phydev->link && adapter->boot_coma < 11) + adapter->boot_coma++; + + if (adapter->boot_coma == 10) { + if (!phydev->link) { + if (!et1310_in_phy_coma(adapter)) { + /* NOTE - This was originally a 'sync with + * interrupt'. How to do that under Linux? + */ + et131x_enable_interrupts(adapter); + et1310_enable_phy_coma(adapter); + } + } + } + + /* This is a periodic timer, so reschedule */ + mod_timer(&adapter->error_timer, jiffies + TX_ERROR_PERIOD * HZ / 1000); +} + +static void et131x_adapter_memory_free(struct et131x_adapter *adapter) +{ + et131x_tx_dma_memory_free(adapter); + et131x_rx_dma_memory_free(adapter); +} + +static int et131x_adapter_memory_alloc(struct et131x_adapter *adapter) +{ + int status; + + status = et131x_tx_dma_memory_alloc(adapter); + if (status) { + dev_err(&adapter->pdev->dev, + "et131x_tx_dma_memory_alloc FAILED\n"); + et131x_tx_dma_memory_free(adapter); + return status; + } + + status = et131x_rx_dma_memory_alloc(adapter); + if (status) { + dev_err(&adapter->pdev->dev, + "et131x_rx_dma_memory_alloc FAILED\n"); + et131x_adapter_memory_free(adapter); + return status; + } + + status = et131x_init_recv(adapter); + if (status) { + dev_err(&adapter->pdev->dev, "et131x_init_recv FAILED\n"); + et131x_adapter_memory_free(adapter); + } + return status; +} + +static void et131x_adjust_link(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + struct phy_device *phydev = adapter->phydev; + + if (!phydev) + return; + if (phydev->link == adapter->link) + return; + + /* Check to see if we are in coma mode and if + * so, disable it because we will not be able + * to read PHY values until we are out. + */ + if (et1310_in_phy_coma(adapter)) + et1310_disable_phy_coma(adapter); + + adapter->link = phydev->link; + phy_print_status(phydev); + + if (phydev->link) { + adapter->boot_coma = 20; + if (phydev->speed == SPEED_10) { + u16 register18; + + et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG, + ®ister18); + et131x_mii_write(adapter, phydev->addr, + PHY_MPHY_CONTROL_REG, + register18 | 0x4); + et131x_mii_write(adapter, phydev->addr, PHY_INDEX_REG, + register18 | 0x8402); + et131x_mii_write(adapter, phydev->addr, PHY_DATA_REG, + register18 | 511); + et131x_mii_write(adapter, phydev->addr, + PHY_MPHY_CONTROL_REG, register18); + } + + et1310_config_flow_control(adapter); + + if (phydev->speed == SPEED_1000 && + adapter->registry_jumbo_packet > 2048) { + u16 reg; + + et131x_mii_read(adapter, PHY_CONFIG, ®); + reg &= ~ET_PHY_CONFIG_TX_FIFO_DEPTH; + reg |= ET_PHY_CONFIG_FIFO_DEPTH_32; + et131x_mii_write(adapter, phydev->addr, PHY_CONFIG, + reg); + } + + et131x_set_rx_dma_timer(adapter); + et1310_config_mac_regs2(adapter); + } else { + adapter->boot_coma = 0; + + if (phydev->speed == SPEED_10) { + u16 register18; + + et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG, + ®ister18); + et131x_mii_write(adapter, phydev->addr, + PHY_MPHY_CONTROL_REG, + register18 | 0x4); + et131x_mii_write(adapter, phydev->addr, + PHY_INDEX_REG, register18 | 0x8402); + et131x_mii_write(adapter, phydev->addr, + PHY_DATA_REG, register18 | 511); + et131x_mii_write(adapter, phydev->addr, + PHY_MPHY_CONTROL_REG, register18); + } + + et131x_free_busy_send_packets(adapter); + et131x_init_send(adapter); + + /* Bring the device back to the state it was during + * init prior to autonegotiation being complete. This + * way, when we get the auto-neg complete interrupt, + * we can complete init by calling config_mac_regs2. + */ + et131x_soft_reset(adapter); + + et131x_adapter_setup(adapter); + + et131x_disable_txrx(netdev); + et131x_enable_txrx(netdev); + } +} + +static int et131x_mii_probe(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + struct phy_device *phydev = NULL; + + phydev = phy_find_first(adapter->mii_bus); + if (!phydev) { + dev_err(&adapter->pdev->dev, "no PHY found\n"); + return -ENODEV; + } + + phydev = phy_connect(netdev, dev_name(&phydev->dev), + &et131x_adjust_link, PHY_INTERFACE_MODE_MII); + + if (IS_ERR(phydev)) { + dev_err(&adapter->pdev->dev, "Could not attach to PHY\n"); + return PTR_ERR(phydev); + } + + phydev->supported &= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_MII | + SUPPORTED_TP); + + if (adapter->pdev->device != ET131X_PCI_DEVICE_ID_FAST) + phydev->supported |= SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full; + + phydev->advertising = phydev->supported; + phydev->autoneg = AUTONEG_ENABLE; + adapter->phydev = phydev; + + dev_info(&adapter->pdev->dev, + "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n", + phydev->drv->name, dev_name(&phydev->dev)); + + return 0; +} + +static struct et131x_adapter *et131x_adapter_init(struct net_device *netdev, + struct pci_dev *pdev) +{ + static const u8 default_mac[] = { 0x00, 0x05, 0x3d, 0x00, 0x02, 0x00 }; + + struct et131x_adapter *adapter; + + adapter = netdev_priv(netdev); + adapter->pdev = pci_dev_get(pdev); + adapter->netdev = netdev; + + spin_lock_init(&adapter->tcb_send_qlock); + spin_lock_init(&adapter->tcb_ready_qlock); + spin_lock_init(&adapter->rcv_lock); + + adapter->registry_jumbo_packet = 1514; /* 1514-9216 */ + + ether_addr_copy(adapter->addr, default_mac); + + return adapter; +} + +static void et131x_pci_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct et131x_adapter *adapter = netdev_priv(netdev); + + unregister_netdev(netdev); + netif_napi_del(&adapter->napi); + phy_disconnect(adapter->phydev); + mdiobus_unregister(adapter->mii_bus); + kfree(adapter->mii_bus->irq); + mdiobus_free(adapter->mii_bus); + + et131x_adapter_memory_free(adapter); + iounmap(adapter->regs); + pci_dev_put(pdev); + + free_netdev(netdev); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static void et131x_up(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + et131x_enable_txrx(netdev); + phy_start(adapter->phydev); +} + +static void et131x_down(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + /* Save the timestamp for the TX watchdog, prevent a timeout */ + netdev->trans_start = jiffies; + + phy_stop(adapter->phydev); + et131x_disable_txrx(netdev); +} + +#ifdef CONFIG_PM_SLEEP +static int et131x_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct net_device *netdev = pci_get_drvdata(pdev); + + if (netif_running(netdev)) { + netif_device_detach(netdev); + et131x_down(netdev); + pci_save_state(pdev); + } + + return 0; +} + +static int et131x_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct net_device *netdev = pci_get_drvdata(pdev); + + if (netif_running(netdev)) { + pci_restore_state(pdev); + et131x_up(netdev); + netif_device_attach(netdev); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(et131x_pm_ops, et131x_suspend, et131x_resume); + +static irqreturn_t et131x_isr(int irq, void *dev_id) +{ + bool handled = true; + bool enable_interrupts = true; + struct net_device *netdev = dev_id; + struct et131x_adapter *adapter = netdev_priv(netdev); + struct address_map __iomem *iomem = adapter->regs; + struct rx_ring *rx_ring = &adapter->rx_ring; + struct tx_ring *tx_ring = &adapter->tx_ring; + u32 status; + + if (!netif_device_present(netdev)) { + handled = false; + enable_interrupts = false; + goto out; + } + + et131x_disable_interrupts(adapter); + + status = readl(&adapter->regs->global.int_status); + + if (adapter->flow == FLOW_TXONLY || adapter->flow == FLOW_BOTH) + status &= ~INT_MASK_ENABLE; + else + status &= ~INT_MASK_ENABLE_NO_FLOW; + + /* Make sure this is our interrupt */ + if (!status) { + handled = false; + et131x_enable_interrupts(adapter); + goto out; + } + + /* This is our interrupt, so process accordingly */ + if (status & ET_INTR_WATCHDOG) { + struct tcb *tcb = tx_ring->send_head; + + if (tcb) + if (++tcb->stale > 1) + status |= ET_INTR_TXDMA_ISR; + + if (rx_ring->unfinished_receives) + status |= ET_INTR_RXDMA_XFR_DONE; + else if (tcb == NULL) + writel(0, &adapter->regs->global.watchdog_timer); + + status &= ~ET_INTR_WATCHDOG; + } + + if (status & (ET_INTR_RXDMA_XFR_DONE | ET_INTR_TXDMA_ISR)) { + enable_interrupts = false; + napi_schedule(&adapter->napi); + } + + status &= ~(ET_INTR_TXDMA_ISR | ET_INTR_RXDMA_XFR_DONE); + + if (!status) + goto out; + + if (status & ET_INTR_TXDMA_ERR) { + /* Following read also clears the register (COR) */ + u32 txdma_err = readl(&iomem->txdma.tx_dma_error); + + dev_warn(&adapter->pdev->dev, + "TXDMA_ERR interrupt, error = %d\n", + txdma_err); + } + + if (status & (ET_INTR_RXDMA_FB_R0_LOW | ET_INTR_RXDMA_FB_R1_LOW)) { + /* This indicates the number of unused buffers in RXDMA free + * buffer ring 0 is <= the limit you programmed. Free buffer + * resources need to be returned. Free buffers are consumed as + * packets are passed from the network to the host. The host + * becomes aware of the packets from the contents of the packet + * status ring. This ring is queried when the packet done + * interrupt occurs. Packets are then passed to the OS. When + * the OS is done with the packets the resources can be + * returned to the ET1310 for re-use. This interrupt is one + * method of returning resources. + */ + + /* If the user has flow control on, then we will + * send a pause packet, otherwise just exit + */ + if (adapter->flow == FLOW_TXONLY || adapter->flow == FLOW_BOTH) { + u32 pm_csr; + + /* Tell the device to send a pause packet via the back + * pressure register (bp req and bp xon/xoff) + */ + pm_csr = readl(&iomem->global.pm_csr); + if (!et1310_in_phy_coma(adapter)) + writel(3, &iomem->txmac.bp_ctrl); + } + } + + /* Handle Packet Status Ring Low Interrupt */ + if (status & ET_INTR_RXDMA_STAT_LOW) { + /* Same idea as with the two Free Buffer Rings. Packets going + * from the network to the host each consume a free buffer + * resource and a packet status resource. These resources are + * passed to the OS. When the OS is done with the resources, + * they need to be returned to the ET1310. This is one method + * of returning the resources. + */ + } + + if (status & ET_INTR_RXDMA_ERR) { + /* The rxdma_error interrupt is sent when a time-out on a + * request issued by the JAGCore has occurred or a completion is + * returned with an un-successful status. In both cases the + * request is considered complete. The JAGCore will + * automatically re-try the request in question. Normally + * information on events like these are sent to the host using + * the "Advanced Error Reporting" capability. This interrupt is + * another way of getting similar information. The only thing + * required is to clear the interrupt by reading the ISR in the + * global resources. The JAGCore will do a re-try on the + * request. Normally you should never see this interrupt. If + * you start to see this interrupt occurring frequently then + * something bad has occurred. A reset might be the thing to do. + */ + /* TRAP();*/ + + dev_warn(&adapter->pdev->dev, "RxDMA_ERR interrupt, error %x\n", + readl(&iomem->txmac.tx_test)); + } + + /* Handle the Wake on LAN Event */ + if (status & ET_INTR_WOL) { + /* This is a secondary interrupt for wake on LAN. The driver + * should never see this, if it does, something serious is + * wrong. + */ + dev_err(&adapter->pdev->dev, "WAKE_ON_LAN interrupt\n"); + } + + if (status & ET_INTR_TXMAC) { + u32 err = readl(&iomem->txmac.err); + + /* When any of the errors occur and TXMAC generates an + * interrupt to report these errors, it usually means that + * TXMAC has detected an error in the data stream retrieved + * from the on-chip Tx Q. All of these errors are catastrophic + * and TXMAC won't be able to recover data when these errors + * occur. In a nutshell, the whole Tx path will have to be reset + * and re-configured afterwards. + */ + dev_warn(&adapter->pdev->dev, "TXMAC interrupt, error 0x%08x\n", + err); + + /* If we are debugging, we want to see this error, otherwise we + * just want the device to be reset and continue + */ + } + + if (status & ET_INTR_RXMAC) { + /* These interrupts are catastrophic to the device, what we need + * to do is disable the interrupts and set the flag to cause us + * to reset so we can solve this issue. + */ + dev_warn(&adapter->pdev->dev, + "RXMAC interrupt, error 0x%08x. Requesting reset\n", + readl(&iomem->rxmac.err_reg)); + + dev_warn(&adapter->pdev->dev, + "Enable 0x%08x, Diag 0x%08x\n", + readl(&iomem->rxmac.ctrl), + readl(&iomem->rxmac.rxq_diag)); + + /* If we are debugging, we want to see this error, otherwise we + * just want the device to be reset and continue + */ + } + + if (status & ET_INTR_MAC_STAT) { + /* This means at least one of the un-masked counters in the + * MAC_STAT block has rolled over. Use this to maintain the top, + * software managed bits of the counter(s). + */ + et1310_handle_macstat_interrupt(adapter); + } + + if (status & ET_INTR_SLV_TIMEOUT) { + /* This means a timeout has occurred on a read or write request + * to one of the JAGCore registers. The Global Resources block + * has terminated the request and on a read request, returned a + * "fake" value. The most likely reasons are: Bad Address or the + * addressed module is in a power-down state and can't respond. + */ + } + +out: + if (enable_interrupts) + et131x_enable_interrupts(adapter); + + return IRQ_RETVAL(handled); +} + +static int et131x_poll(struct napi_struct *napi, int budget) +{ + struct et131x_adapter *adapter = + container_of(napi, struct et131x_adapter, napi); + int work_done = et131x_handle_recv_pkts(adapter, budget); + + et131x_handle_send_pkts(adapter); + + if (work_done < budget) { + napi_complete(&adapter->napi); + et131x_enable_interrupts(adapter); + } + + return work_done; +} + +/* et131x_stats - Return the current device statistics */ +static struct net_device_stats *et131x_stats(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + struct net_device_stats *stats = &adapter->netdev->stats; + struct ce_stats *devstat = &adapter->stats; + + stats->rx_errors = devstat->rx_length_errs + + devstat->rx_align_errs + + devstat->rx_crc_errs + + devstat->rx_code_violations + + devstat->rx_other_errs; + stats->tx_errors = devstat->tx_max_pkt_errs; + stats->multicast = devstat->multicast_pkts_rcvd; + stats->collisions = devstat->tx_collisions; + + stats->rx_length_errors = devstat->rx_length_errs; + stats->rx_over_errors = devstat->rx_overflows; + stats->rx_crc_errors = devstat->rx_crc_errs; + stats->rx_dropped = devstat->rcvd_pkts_dropped; + + /* NOTE: Not used, can't find analogous statistics */ + /* stats->rx_frame_errors = devstat->; */ + /* stats->rx_fifo_errors = devstat->; */ + /* stats->rx_missed_errors = devstat->; */ + + /* stats->tx_aborted_errors = devstat->; */ + /* stats->tx_carrier_errors = devstat->; */ + /* stats->tx_fifo_errors = devstat->; */ + /* stats->tx_heartbeat_errors = devstat->; */ + /* stats->tx_window_errors = devstat->; */ + return stats; +} + +static int et131x_open(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + struct pci_dev *pdev = adapter->pdev; + unsigned int irq = pdev->irq; + int result; + + /* Start the timer to track NIC errors */ + init_timer(&adapter->error_timer); + adapter->error_timer.expires = jiffies + TX_ERROR_PERIOD * HZ / 1000; + adapter->error_timer.function = et131x_error_timer_handler; + adapter->error_timer.data = (unsigned long)adapter; + add_timer(&adapter->error_timer); + + result = request_irq(irq, et131x_isr, + IRQF_SHARED, netdev->name, netdev); + if (result) { + dev_err(&pdev->dev, "could not register IRQ %d\n", irq); + return result; + } + + adapter->flags |= FMP_ADAPTER_INTERRUPT_IN_USE; + + napi_enable(&adapter->napi); + + et131x_up(netdev); + + return result; +} + +static int et131x_close(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + et131x_down(netdev); + napi_disable(&adapter->napi); + + adapter->flags &= ~FMP_ADAPTER_INTERRUPT_IN_USE; + free_irq(adapter->pdev->irq, netdev); + + /* Stop the error timer */ + return del_timer_sync(&adapter->error_timer); +} + +static int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, + int cmd) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + if (!adapter->phydev) + return -EINVAL; + + return phy_mii_ioctl(adapter->phydev, reqbuf, cmd); +} + +/* et131x_set_packet_filter - Configures the Rx Packet filtering */ +static int et131x_set_packet_filter(struct et131x_adapter *adapter) +{ + int filter = adapter->packet_filter; + u32 ctrl; + u32 pf_ctrl; + + ctrl = readl(&adapter->regs->rxmac.ctrl); + pf_ctrl = readl(&adapter->regs->rxmac.pf_ctrl); + + /* Default to disabled packet filtering */ + ctrl |= 0x04; + + /* Set us to be in promiscuous mode so we receive everything, this + * is also true when we get a packet filter of 0 + */ + if ((filter & ET131X_PACKET_TYPE_PROMISCUOUS) || filter == 0) + pf_ctrl &= ~7; /* Clear filter bits */ + else { + /* Set us up with Multicast packet filtering. Three cases are + * possible - (1) we have a multi-cast list, (2) we receive ALL + * multicast entries or (3) we receive none. + */ + if (filter & ET131X_PACKET_TYPE_ALL_MULTICAST) + pf_ctrl &= ~2; /* Multicast filter bit */ + else { + et1310_setup_device_for_multicast(adapter); + pf_ctrl |= 2; + ctrl &= ~0x04; + } + + /* Set us up with Unicast packet filtering */ + if (filter & ET131X_PACKET_TYPE_DIRECTED) { + et1310_setup_device_for_unicast(adapter); + pf_ctrl |= 4; + ctrl &= ~0x04; + } + + /* Set us up with Broadcast packet filtering */ + if (filter & ET131X_PACKET_TYPE_BROADCAST) { + pf_ctrl |= 1; /* Broadcast filter bit */ + ctrl &= ~0x04; + } else { + pf_ctrl &= ~1; + } + + /* Setup the receive mac configuration registers - Packet + * Filter control + the enable / disable for packet filter + * in the control reg. + */ + writel(pf_ctrl, &adapter->regs->rxmac.pf_ctrl); + writel(ctrl, &adapter->regs->rxmac.ctrl); + } + return 0; +} + +static void et131x_multicast(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + int packet_filter; + struct netdev_hw_addr *ha; + int i; + + /* Before we modify the platform-independent filter flags, store them + * locally. This allows us to determine if anything's changed and if + * we even need to bother the hardware + */ + packet_filter = adapter->packet_filter; + + /* Clear the 'multicast' flag locally; because we only have a single + * flag to check multicast, and multiple multicast addresses can be + * set, this is the easiest way to determine if more than one + * multicast address is being set. + */ + packet_filter &= ~ET131X_PACKET_TYPE_MULTICAST; + + /* Check the net_device flags and set the device independent flags + * accordingly + */ + if (netdev->flags & IFF_PROMISC) + adapter->packet_filter |= ET131X_PACKET_TYPE_PROMISCUOUS; + else + adapter->packet_filter &= ~ET131X_PACKET_TYPE_PROMISCUOUS; + + if ((netdev->flags & IFF_ALLMULTI) || + (netdev_mc_count(netdev) > NIC_MAX_MCAST_LIST)) + adapter->packet_filter |= ET131X_PACKET_TYPE_ALL_MULTICAST; + + if (netdev_mc_count(netdev) < 1) { + adapter->packet_filter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; + adapter->packet_filter &= ~ET131X_PACKET_TYPE_MULTICAST; + } else { + adapter->packet_filter |= ET131X_PACKET_TYPE_MULTICAST; + } + + /* Set values in the private adapter struct */ + i = 0; + netdev_for_each_mc_addr(ha, netdev) { + if (i == NIC_MAX_MCAST_LIST) + break; + ether_addr_copy(adapter->multicast_list[i++], ha->addr); + } + adapter->multicast_addr_count = i; + + /* Are the new flags different from the previous ones? If not, then no + * action is required + * + * NOTE - This block will always update the multicast_list with the + * hardware, even if the addresses aren't the same. + */ + if (packet_filter != adapter->packet_filter) + et131x_set_packet_filter(adapter); +} + +static netdev_tx_t et131x_tx(struct sk_buff *skb, struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + struct tx_ring *tx_ring = &adapter->tx_ring; + + /* stop the queue if it's getting full */ + if (tx_ring->used >= NUM_TCB - 1 && !netif_queue_stopped(netdev)) + netif_stop_queue(netdev); + + /* Save the timestamp for the TX timeout watchdog */ + netdev->trans_start = jiffies; + + /* TCB is not available */ + if (tx_ring->used >= NUM_TCB) + goto drop_err; + + if ((adapter->flags & FMP_ADAPTER_FAIL_SEND_MASK) || + !netif_carrier_ok(netdev)) + goto drop_err; + + if (send_packet(skb, adapter)) + goto drop_err; + + return NETDEV_TX_OK; + +drop_err: + dev_kfree_skb_any(skb); + adapter->netdev->stats.tx_dropped++; + return NETDEV_TX_OK; +} + +/* et131x_tx_timeout - Timeout handler + * + * The handler called when a Tx request times out. The timeout period is + * specified by the 'tx_timeo" element in the net_device structure (see + * et131x_alloc_device() to see how this value is set). + */ +static void et131x_tx_timeout(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + struct tx_ring *tx_ring = &adapter->tx_ring; + struct tcb *tcb; + unsigned long flags; + + /* If the device is closed, ignore the timeout */ + if (~(adapter->flags & FMP_ADAPTER_INTERRUPT_IN_USE)) + return; + + /* Any nonrecoverable hardware error? + * Checks adapter->flags for any failure in phy reading + */ + if (adapter->flags & FMP_ADAPTER_NON_RECOVER_ERROR) + return; + + /* Hardware failure? */ + if (adapter->flags & FMP_ADAPTER_HARDWARE_ERROR) { + dev_err(&adapter->pdev->dev, "hardware error - reset\n"); + return; + } + + /* Is send stuck? */ + spin_lock_irqsave(&adapter->tcb_send_qlock, flags); + tcb = tx_ring->send_head; + spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); + + if (tcb) { + tcb->count++; + + if (tcb->count > NIC_SEND_HANG_THRESHOLD) { + dev_warn(&adapter->pdev->dev, + "Send stuck - reset. tcb->WrIndex %x\n", + tcb->index); + + adapter->netdev->stats.tx_errors++; + + /* perform reset of tx/rx */ + et131x_disable_txrx(netdev); + et131x_enable_txrx(netdev); + } + } +} + +static int et131x_change_mtu(struct net_device *netdev, int new_mtu) +{ + int result = 0; + struct et131x_adapter *adapter = netdev_priv(netdev); + + if (new_mtu < 64 || new_mtu > 9216) + return -EINVAL; + + et131x_disable_txrx(netdev); + + netdev->mtu = new_mtu; + + et131x_adapter_memory_free(adapter); + + /* Set the config parameter for Jumbo Packet support */ + adapter->registry_jumbo_packet = new_mtu + 14; + et131x_soft_reset(adapter); + + result = et131x_adapter_memory_alloc(adapter); + if (result != 0) { + dev_warn(&adapter->pdev->dev, + "Change MTU failed; couldn't re-alloc DMA memory\n"); + return result; + } + + et131x_init_send(adapter); + et131x_hwaddr_init(adapter); + ether_addr_copy(netdev->dev_addr, adapter->addr); + + /* Init the device with the new settings */ + et131x_adapter_setup(adapter); + et131x_enable_txrx(netdev); + + return result; +} + +static const struct net_device_ops et131x_netdev_ops = { + .ndo_open = et131x_open, + .ndo_stop = et131x_close, + .ndo_start_xmit = et131x_tx, + .ndo_set_rx_mode = et131x_multicast, + .ndo_tx_timeout = et131x_tx_timeout, + .ndo_change_mtu = et131x_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_get_stats = et131x_stats, + .ndo_do_ioctl = et131x_ioctl, +}; + +static int et131x_pci_setup(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct et131x_adapter *adapter; + int rc; + int ii; + + rc = pci_enable_device(pdev); + if (rc < 0) { + dev_err(&pdev->dev, "pci_enable_device() failed\n"); + goto out; + } + + /* Perform some basic PCI checks */ + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + dev_err(&pdev->dev, "Can't find PCI device's base address\n"); + rc = -ENODEV; + goto err_disable; + } + + rc = pci_request_regions(pdev, DRIVER_NAME); + if (rc < 0) { + dev_err(&pdev->dev, "Can't get PCI resources\n"); + goto err_disable; + } + + pci_set_master(pdev); + + /* Check the DMA addressing support of this device */ + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) && + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { + dev_err(&pdev->dev, "No usable DMA addressing method\n"); + rc = -EIO; + goto err_release_res; + } + + netdev = alloc_etherdev(sizeof(struct et131x_adapter)); + if (!netdev) { + dev_err(&pdev->dev, "Couldn't alloc netdev struct\n"); + rc = -ENOMEM; + goto err_release_res; + } + + netdev->watchdog_timeo = ET131X_TX_TIMEOUT; + netdev->netdev_ops = &et131x_netdev_ops; + + SET_NETDEV_DEV(netdev, &pdev->dev); + netdev->ethtool_ops = &et131x_ethtool_ops; + + adapter = et131x_adapter_init(netdev, pdev); + + rc = et131x_pci_init(adapter, pdev); + if (rc < 0) + goto err_free_dev; + + /* Map the bus-relative registers to system virtual memory */ + adapter->regs = pci_ioremap_bar(pdev, 0); + if (!adapter->regs) { + dev_err(&pdev->dev, "Cannot map device registers\n"); + rc = -ENOMEM; + goto err_free_dev; + } + + /* If Phy COMA mode was enabled when we went down, disable it here. */ + writel(ET_PMCSR_INIT, &adapter->regs->global.pm_csr); + + et131x_soft_reset(adapter); + et131x_disable_interrupts(adapter); + + rc = et131x_adapter_memory_alloc(adapter); + if (rc < 0) { + dev_err(&pdev->dev, "Could not alloc adapter memory (DMA)\n"); + goto err_iounmap; + } + + et131x_init_send(adapter); + + netif_napi_add(netdev, &adapter->napi, et131x_poll, 64); + + ether_addr_copy(netdev->dev_addr, adapter->addr); + + rc = -ENOMEM; + + adapter->mii_bus = mdiobus_alloc(); + if (!adapter->mii_bus) { + dev_err(&pdev->dev, "Alloc of mii_bus struct failed\n"); + goto err_mem_free; + } + + adapter->mii_bus->name = "et131x_eth_mii"; + snprintf(adapter->mii_bus->id, MII_BUS_ID_SIZE, "%x", + (adapter->pdev->bus->number << 8) | adapter->pdev->devfn); + adapter->mii_bus->priv = netdev; + adapter->mii_bus->read = et131x_mdio_read; + adapter->mii_bus->write = et131x_mdio_write; + adapter->mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), + GFP_KERNEL); + if (!adapter->mii_bus->irq) + goto err_mdio_free; + + for (ii = 0; ii < PHY_MAX_ADDR; ii++) + adapter->mii_bus->irq[ii] = PHY_POLL; + + rc = mdiobus_register(adapter->mii_bus); + if (rc < 0) { + dev_err(&pdev->dev, "failed to register MII bus\n"); + goto err_mdio_free_irq; + } + + rc = et131x_mii_probe(netdev); + if (rc < 0) { + dev_err(&pdev->dev, "failed to probe MII bus\n"); + goto err_mdio_unregister; + } + + et131x_adapter_setup(adapter); + + /* Init variable for counting how long we do not have link status */ + adapter->boot_coma = 0; + et1310_disable_phy_coma(adapter); + + /* We can enable interrupts now + * + * NOTE - Because registration of interrupt handler is done in the + * device's open(), defer enabling device interrupts to that + * point + */ + + rc = register_netdev(netdev); + if (rc < 0) { + dev_err(&pdev->dev, "register_netdev() failed\n"); + goto err_phy_disconnect; + } + + /* Register the net_device struct with the PCI subsystem. Save a copy + * of the PCI config space for this device now that the device has + * been initialized, just in case it needs to be quickly restored. + */ + pci_set_drvdata(pdev, netdev); +out: + return rc; + +err_phy_disconnect: + phy_disconnect(adapter->phydev); +err_mdio_unregister: + mdiobus_unregister(adapter->mii_bus); +err_mdio_free_irq: + kfree(adapter->mii_bus->irq); +err_mdio_free: + mdiobus_free(adapter->mii_bus); +err_mem_free: + et131x_adapter_memory_free(adapter); +err_iounmap: + iounmap(adapter->regs); +err_free_dev: + pci_dev_put(pdev); + free_netdev(netdev); +err_release_res: + pci_release_regions(pdev); +err_disable: + pci_disable_device(pdev); + goto out; +} + +static const struct pci_device_id et131x_pci_table[] = { + { PCI_VDEVICE(ATT, ET131X_PCI_DEVICE_ID_GIG), 0UL}, + { PCI_VDEVICE(ATT, ET131X_PCI_DEVICE_ID_FAST), 0UL}, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, et131x_pci_table); + +static struct pci_driver et131x_driver = { + .name = DRIVER_NAME, + .id_table = et131x_pci_table, + .probe = et131x_pci_setup, + .remove = et131x_pci_remove, + .driver.pm = &et131x_pm_ops, +}; + +module_pci_driver(et131x_driver); diff --git a/drivers/net/ethernet/agere/et131x.h b/drivers/net/ethernet/agere/et131x.h new file mode 100644 index 000000000000..be9a11c02526 --- /dev/null +++ b/drivers/net/ethernet/agere/et131x.h @@ -0,0 +1,1433 @@ +/* Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#define DRIVER_NAME "et131x" +#define DRIVER_VERSION "v2.0" + +/* EEPROM registers */ + +/* LBCIF Register Groups (addressed via 32-bit offsets) */ +#define LBCIF_DWORD0_GROUP 0xAC +#define LBCIF_DWORD1_GROUP 0xB0 + +/* LBCIF Registers (addressed via 8-bit offsets) */ +#define LBCIF_ADDRESS_REGISTER 0xAC +#define LBCIF_DATA_REGISTER 0xB0 +#define LBCIF_CONTROL_REGISTER 0xB1 +#define LBCIF_STATUS_REGISTER 0xB2 + +/* LBCIF Control Register Bits */ +#define LBCIF_CONTROL_SEQUENTIAL_READ 0x01 +#define LBCIF_CONTROL_PAGE_WRITE 0x02 +#define LBCIF_CONTROL_EEPROM_RELOAD 0x08 +#define LBCIF_CONTROL_TWO_BYTE_ADDR 0x20 +#define LBCIF_CONTROL_I2C_WRITE 0x40 +#define LBCIF_CONTROL_LBCIF_ENABLE 0x80 + +/* LBCIF Status Register Bits */ +#define LBCIF_STATUS_PHY_QUEUE_AVAIL 0x01 +#define LBCIF_STATUS_I2C_IDLE 0x02 +#define LBCIF_STATUS_ACK_ERROR 0x04 +#define LBCIF_STATUS_GENERAL_ERROR 0x08 +#define LBCIF_STATUS_CHECKSUM_ERROR 0x40 +#define LBCIF_STATUS_EEPROM_PRESENT 0x80 + +/* START OF GLOBAL REGISTER ADDRESS MAP */ +/* 10bit registers + * + * Tx queue start address reg in global address map at address 0x0000 + * tx queue end address reg in global address map at address 0x0004 + * rx queue start address reg in global address map at address 0x0008 + * rx queue end address reg in global address map at address 0x000C + */ + +/* structure for power management control status reg in global address map + * located at address 0x0010 + * jagcore_rx_rdy bit 9 + * jagcore_tx_rdy bit 8 + * phy_lped_en bit 7 + * phy_sw_coma bit 6 + * rxclk_gate bit 5 + * txclk_gate bit 4 + * sysclk_gate bit 3 + * jagcore_rx_en bit 2 + * jagcore_tx_en bit 1 + * gigephy_en bit 0 + */ +#define ET_PM_PHY_SW_COMA 0x40 +#define ET_PMCSR_INIT 0x38 + +/* Interrupt status reg at address 0x0018 + */ +#define ET_INTR_TXDMA_ISR 0x00000008 +#define ET_INTR_TXDMA_ERR 0x00000010 +#define ET_INTR_RXDMA_XFR_DONE 0x00000020 +#define ET_INTR_RXDMA_FB_R0_LOW 0x00000040 +#define ET_INTR_RXDMA_FB_R1_LOW 0x00000080 +#define ET_INTR_RXDMA_STAT_LOW 0x00000100 +#define ET_INTR_RXDMA_ERR 0x00000200 +#define ET_INTR_WATCHDOG 0x00004000 +#define ET_INTR_WOL 0x00008000 +#define ET_INTR_PHY 0x00010000 +#define ET_INTR_TXMAC 0x00020000 +#define ET_INTR_RXMAC 0x00040000 +#define ET_INTR_MAC_STAT 0x00080000 +#define ET_INTR_SLV_TIMEOUT 0x00100000 + +/* Interrupt mask register at address 0x001C + * Interrupt alias clear mask reg at address 0x0020 + * Interrupt status alias reg at address 0x0024 + * + * Same masks as above + */ + +/* Software reset reg at address 0x0028 + * 0: txdma_sw_reset + * 1: rxdma_sw_reset + * 2: txmac_sw_reset + * 3: rxmac_sw_reset + * 4: mac_sw_reset + * 5: mac_stat_sw_reset + * 6: mmc_sw_reset + *31: selfclr_disable + */ +#define ET_RESET_ALL 0x007F + +/* SLV Timer reg at address 0x002C (low 24 bits) + */ + +/* MSI Configuration reg at address 0x0030 + */ +#define ET_MSI_VECTOR 0x0000001F +#define ET_MSI_TC 0x00070000 + +/* Loopback reg located at address 0x0034 + */ +#define ET_LOOP_MAC 0x00000001 +#define ET_LOOP_DMA 0x00000002 + +/* GLOBAL Module of JAGCore Address Mapping + * Located at address 0x0000 + */ +struct global_regs { /* Location: */ + u32 txq_start_addr; /* 0x0000 */ + u32 txq_end_addr; /* 0x0004 */ + u32 rxq_start_addr; /* 0x0008 */ + u32 rxq_end_addr; /* 0x000C */ + u32 pm_csr; /* 0x0010 */ + u32 unused; /* 0x0014 */ + u32 int_status; /* 0x0018 */ + u32 int_mask; /* 0x001C */ + u32 int_alias_clr_en; /* 0x0020 */ + u32 int_status_alias; /* 0x0024 */ + u32 sw_reset; /* 0x0028 */ + u32 slv_timer; /* 0x002C */ + u32 msi_config; /* 0x0030 */ + u32 loopback; /* 0x0034 */ + u32 watchdog_timer; /* 0x0038 */ +}; + +/* START OF TXDMA REGISTER ADDRESS MAP */ +/* txdma control status reg at address 0x1000 + */ +#define ET_TXDMA_CSR_HALT 0x00000001 +#define ET_TXDMA_DROP_TLP 0x00000002 +#define ET_TXDMA_CACHE_THRS 0x000000F0 +#define ET_TXDMA_CACHE_SHIFT 4 +#define ET_TXDMA_SNGL_EPKT 0x00000100 +#define ET_TXDMA_CLASS 0x00001E00 + +/* structure for txdma packet ring base address hi reg in txdma address map + * located at address 0x1004 + * Defined earlier (u32) + */ + +/* structure for txdma packet ring base address low reg in txdma address map + * located at address 0x1008 + * Defined earlier (u32) + */ + +/* structure for txdma packet ring number of descriptor reg in txdma address + * map. Located at address 0x100C + * + * 31-10: unused + * 9-0: pr ndes + */ +#define ET_DMA12_MASK 0x0FFF /* 12 bit mask for DMA12W types */ +#define ET_DMA12_WRAP 0x1000 +#define ET_DMA10_MASK 0x03FF /* 10 bit mask for DMA10W types */ +#define ET_DMA10_WRAP 0x0400 +#define ET_DMA4_MASK 0x000F /* 4 bit mask for DMA4W types */ +#define ET_DMA4_WRAP 0x0010 + +#define INDEX12(x) ((x) & ET_DMA12_MASK) +#define INDEX10(x) ((x) & ET_DMA10_MASK) +#define INDEX4(x) ((x) & ET_DMA4_MASK) + +/* 10bit DMA with wrap + * txdma tx queue write address reg in txdma address map at 0x1010 + * txdma tx queue write address external reg in txdma address map at 0x1014 + * txdma tx queue read address reg in txdma address map at 0x1018 + * + * u32 + * txdma status writeback address hi reg in txdma address map at0x101C + * txdma status writeback address lo reg in txdma address map at 0x1020 + * + * 10bit DMA with wrap + * txdma service request reg in txdma address map at 0x1024 + * structure for txdma service complete reg in txdma address map at 0x1028 + * + * 4bit DMA with wrap + * txdma tx descriptor cache read index reg in txdma address map at 0x102C + * txdma tx descriptor cache write index reg in txdma address map at 0x1030 + * + * txdma error reg in txdma address map at address 0x1034 + * 0: PyldResend + * 1: PyldRewind + * 4: DescrResend + * 5: DescrRewind + * 8: WrbkResend + * 9: WrbkRewind + */ + +/* Tx DMA Module of JAGCore Address Mapping + * Located at address 0x1000 + */ +struct txdma_regs { /* Location: */ + u32 csr; /* 0x1000 */ + u32 pr_base_hi; /* 0x1004 */ + u32 pr_base_lo; /* 0x1008 */ + u32 pr_num_des; /* 0x100C */ + u32 txq_wr_addr; /* 0x1010 */ + u32 txq_wr_addr_ext; /* 0x1014 */ + u32 txq_rd_addr; /* 0x1018 */ + u32 dma_wb_base_hi; /* 0x101C */ + u32 dma_wb_base_lo; /* 0x1020 */ + u32 service_request; /* 0x1024 */ + u32 service_complete; /* 0x1028 */ + u32 cache_rd_index; /* 0x102C */ + u32 cache_wr_index; /* 0x1030 */ + u32 tx_dma_error; /* 0x1034 */ + u32 desc_abort_cnt; /* 0x1038 */ + u32 payload_abort_cnt; /* 0x103c */ + u32 writeback_abort_cnt; /* 0x1040 */ + u32 desc_timeout_cnt; /* 0x1044 */ + u32 payload_timeout_cnt; /* 0x1048 */ + u32 writeback_timeout_cnt; /* 0x104c */ + u32 desc_error_cnt; /* 0x1050 */ + u32 payload_error_cnt; /* 0x1054 */ + u32 writeback_error_cnt; /* 0x1058 */ + u32 dropped_tlp_cnt; /* 0x105c */ + u32 new_service_complete; /* 0x1060 */ + u32 ethernet_packet_cnt; /* 0x1064 */ +}; + +/* END OF TXDMA REGISTER ADDRESS MAP */ + +/* START OF RXDMA REGISTER ADDRESS MAP */ +/* structure for control status reg in rxdma address map + * Located at address 0x2000 + * + * CSR + * 0: halt + * 1-3: tc + * 4: fbr_big_endian + * 5: psr_big_endian + * 6: pkt_big_endian + * 7: dma_big_endian + * 8-9: fbr0_size + * 10: fbr0_enable + * 11-12: fbr1_size + * 13: fbr1_enable + * 14: unused + * 15: pkt_drop_disable + * 16: pkt_done_flush + * 17: halt_status + * 18-31: unused + */ +#define ET_RXDMA_CSR_HALT 0x0001 +#define ET_RXDMA_CSR_FBR0_SIZE_LO 0x0100 +#define ET_RXDMA_CSR_FBR0_SIZE_HI 0x0200 +#define ET_RXDMA_CSR_FBR0_ENABLE 0x0400 +#define ET_RXDMA_CSR_FBR1_SIZE_LO 0x0800 +#define ET_RXDMA_CSR_FBR1_SIZE_HI 0x1000 +#define ET_RXDMA_CSR_FBR1_ENABLE 0x2000 +#define ET_RXDMA_CSR_HALT_STATUS 0x00020000 + +/* structure for dma writeback lo reg in rxdma address map + * located at address 0x2004 + * Defined earlier (u32) + */ + +/* structure for dma writeback hi reg in rxdma address map + * located at address 0x2008 + * Defined earlier (u32) + */ + +/* structure for number of packets done reg in rxdma address map + * located at address 0x200C + * + * 31-8: unused + * 7-0: num done + */ + +/* structure for max packet time reg in rxdma address map + * located at address 0x2010 + * + * 31-18: unused + * 17-0: time done + */ + +/* structure for rx queue read address reg in rxdma address map + * located at address 0x2014 + * Defined earlier (u32) + */ + +/* structure for rx queue read address external reg in rxdma address map + * located at address 0x2018 + * Defined earlier (u32) + */ + +/* structure for rx queue write address reg in rxdma address map + * located at address 0x201C + * Defined earlier (u32) + */ + +/* structure for packet status ring base address lo reg in rxdma address map + * located at address 0x2020 + * Defined earlier (u32) + */ + +/* structure for packet status ring base address hi reg in rxdma address map + * located at address 0x2024 + * Defined earlier (u32) + */ + +/* structure for packet status ring number of descriptors reg in rxdma address + * map. Located at address 0x2028 + * + * 31-12: unused + * 11-0: psr ndes + */ +#define ET_RXDMA_PSR_NUM_DES_MASK 0xFFF + +/* structure for packet status ring available offset reg in rxdma address map + * located at address 0x202C + * + * 31-13: unused + * 12: psr avail wrap + * 11-0: psr avail + */ + +/* structure for packet status ring full offset reg in rxdma address map + * located at address 0x2030 + * + * 31-13: unused + * 12: psr full wrap + * 11-0: psr full + */ + +/* structure for packet status ring access index reg in rxdma address map + * located at address 0x2034 + * + * 31-5: unused + * 4-0: psr_ai + */ + +/* structure for packet status ring minimum descriptors reg in rxdma address + * map. Located at address 0x2038 + * + * 31-12: unused + * 11-0: psr_min + */ + +/* structure for free buffer ring base lo address reg in rxdma address map + * located at address 0x203C + * Defined earlier (u32) + */ + +/* structure for free buffer ring base hi address reg in rxdma address map + * located at address 0x2040 + * Defined earlier (u32) + */ + +/* structure for free buffer ring number of descriptors reg in rxdma address + * map. Located at address 0x2044 + * + * 31-10: unused + * 9-0: fbr ndesc + */ + +/* structure for free buffer ring 0 available offset reg in rxdma address map + * located at address 0x2048 + * Defined earlier (u32) + */ + +/* structure for free buffer ring 0 full offset reg in rxdma address map + * located at address 0x204C + * Defined earlier (u32) + */ + +/* structure for free buffer cache 0 full offset reg in rxdma address map + * located at address 0x2050 + * + * 31-5: unused + * 4-0: fbc rdi + */ + +/* structure for free buffer ring 0 minimum descriptor reg in rxdma address map + * located at address 0x2054 + * + * 31-10: unused + * 9-0: fbr min + */ + +/* structure for free buffer ring 1 base address lo reg in rxdma address map + * located at address 0x2058 - 0x205C + * Defined earlier (RXDMA_FBR_BASE_LO_t and RXDMA_FBR_BASE_HI_t) + */ + +/* structure for free buffer ring 1 number of descriptors reg in rxdma address + * map. Located at address 0x2060 + * Defined earlier (RXDMA_FBR_NUM_DES_t) + */ + +/* structure for free buffer ring 1 available offset reg in rxdma address map + * located at address 0x2064 + * Defined Earlier (RXDMA_FBR_AVAIL_OFFSET_t) + */ + +/* structure for free buffer ring 1 full offset reg in rxdma address map + * located at address 0x2068 + * Defined Earlier (RXDMA_FBR_FULL_OFFSET_t) + */ + +/* structure for free buffer cache 1 read index reg in rxdma address map + * located at address 0x206C + * Defined Earlier (RXDMA_FBC_RD_INDEX_t) + */ + +/* structure for free buffer ring 1 minimum descriptor reg in rxdma address map + * located at address 0x2070 + * Defined Earlier (RXDMA_FBR_MIN_DES_t) + */ + +/* Rx DMA Module of JAGCore Address Mapping + * Located at address 0x2000 + */ +struct rxdma_regs { /* Location: */ + u32 csr; /* 0x2000 */ + u32 dma_wb_base_lo; /* 0x2004 */ + u32 dma_wb_base_hi; /* 0x2008 */ + u32 num_pkt_done; /* 0x200C */ + u32 max_pkt_time; /* 0x2010 */ + u32 rxq_rd_addr; /* 0x2014 */ + u32 rxq_rd_addr_ext; /* 0x2018 */ + u32 rxq_wr_addr; /* 0x201C */ + u32 psr_base_lo; /* 0x2020 */ + u32 psr_base_hi; /* 0x2024 */ + u32 psr_num_des; /* 0x2028 */ + u32 psr_avail_offset; /* 0x202C */ + u32 psr_full_offset; /* 0x2030 */ + u32 psr_access_index; /* 0x2034 */ + u32 psr_min_des; /* 0x2038 */ + u32 fbr0_base_lo; /* 0x203C */ + u32 fbr0_base_hi; /* 0x2040 */ + u32 fbr0_num_des; /* 0x2044 */ + u32 fbr0_avail_offset; /* 0x2048 */ + u32 fbr0_full_offset; /* 0x204C */ + u32 fbr0_rd_index; /* 0x2050 */ + u32 fbr0_min_des; /* 0x2054 */ + u32 fbr1_base_lo; /* 0x2058 */ + u32 fbr1_base_hi; /* 0x205C */ + u32 fbr1_num_des; /* 0x2060 */ + u32 fbr1_avail_offset; /* 0x2064 */ + u32 fbr1_full_offset; /* 0x2068 */ + u32 fbr1_rd_index; /* 0x206C */ + u32 fbr1_min_des; /* 0x2070 */ +}; + +/* END OF RXDMA REGISTER ADDRESS MAP */ + +/* START OF TXMAC REGISTER ADDRESS MAP */ +/* structure for control reg in txmac address map + * located at address 0x3000 + * + * bits + * 31-8: unused + * 7: cklseg_disable + * 6: ckbcnt_disable + * 5: cksegnum + * 4: async_disable + * 3: fc_disable + * 2: mcif_disable + * 1: mif_disable + * 0: txmac_en + */ +#define ET_TX_CTRL_FC_DISABLE 0x0008 +#define ET_TX_CTRL_TXMAC_ENABLE 0x0001 + +/* structure for shadow pointer reg in txmac address map + * located at address 0x3004 + * 31-27: reserved + * 26-16: txq rd ptr + * 15-11: reserved + * 10-0: txq wr ptr + */ + +/* structure for error count reg in txmac address map + * located at address 0x3008 + * + * 31-12: unused + * 11-8: reserved + * 7-4: txq_underrun + * 3-0: fifo_underrun + */ + +/* structure for max fill reg in txmac address map + * located at address 0x300C + * 31-12: unused + * 11-0: max fill + */ + +/* structure for cf parameter reg in txmac address map + * located at address 0x3010 + * 31-16: cfep + * 15-0: cfpt + */ + +/* structure for tx test reg in txmac address map + * located at address 0x3014 + * 31-17: unused + * 16: reserved + * 15: txtest_en + * 14-11: unused + * 10-0: txq test pointer + */ + +/* structure for error reg in txmac address map + * located at address 0x3018 + * + * 31-9: unused + * 8: fifo_underrun + * 7-6: unused + * 5: ctrl2_err + * 4: txq_underrun + * 3: bcnt_err + * 2: lseg_err + * 1: segnum_err + * 0: seg0_err + */ + +/* structure for error interrupt reg in txmac address map + * located at address 0x301C + * + * 31-9: unused + * 8: fifo_underrun + * 7-6: unused + * 5: ctrl2_err + * 4: txq_underrun + * 3: bcnt_err + * 2: lseg_err + * 1: segnum_err + * 0: seg0_err + */ + +/* structure for error interrupt reg in txmac address map + * located at address 0x3020 + * + * 31-2: unused + * 1: bp_req + * 0: bp_xonxoff + */ + +/* Tx MAC Module of JAGCore Address Mapping + */ +struct txmac_regs { /* Location: */ + u32 ctl; /* 0x3000 */ + u32 shadow_ptr; /* 0x3004 */ + u32 err_cnt; /* 0x3008 */ + u32 max_fill; /* 0x300C */ + u32 cf_param; /* 0x3010 */ + u32 tx_test; /* 0x3014 */ + u32 err; /* 0x3018 */ + u32 err_int; /* 0x301C */ + u32 bp_ctrl; /* 0x3020 */ +}; + +/* END OF TXMAC REGISTER ADDRESS MAP */ + +/* START OF RXMAC REGISTER ADDRESS MAP */ + +/* structure for rxmac control reg in rxmac address map + * located at address 0x4000 + * + * 31-7: reserved + * 6: rxmac_int_disable + * 5: async_disable + * 4: mif_disable + * 3: wol_disable + * 2: pkt_filter_disable + * 1: mcif_disable + * 0: rxmac_en + */ +#define ET_RX_CTRL_WOL_DISABLE 0x0008 +#define ET_RX_CTRL_RXMAC_ENABLE 0x0001 + +/* structure for Wake On Lan Control and CRC 0 reg in rxmac address map + * located at address 0x4004 + * 31-16: crc + * 15-12: reserved + * 11: ignore_pp + * 10: ignore_mp + * 9: clr_intr + * 8: ignore_link_chg + * 7: ignore_uni + * 6: ignore_multi + * 5: ignore_broad + * 4-0: valid_crc 4-0 + */ + +/* structure for CRC 1 and CRC 2 reg in rxmac address map + * located at address 0x4008 + * + * 31-16: crc2 + * 15-0: crc1 + */ + +/* structure for CRC 3 and CRC 4 reg in rxmac address map + * located at address 0x400C + * + * 31-16: crc4 + * 15-0: crc3 + */ + +/* structure for Wake On Lan Source Address Lo reg in rxmac address map + * located at address 0x4010 + * + * 31-24: sa3 + * 23-16: sa4 + * 15-8: sa5 + * 7-0: sa6 + */ +#define ET_RX_WOL_LO_SA3_SHIFT 24 +#define ET_RX_WOL_LO_SA4_SHIFT 16 +#define ET_RX_WOL_LO_SA5_SHIFT 8 + +/* structure for Wake On Lan Source Address Hi reg in rxmac address map + * located at address 0x4014 + * + * 31-16: reserved + * 15-8: sa1 + * 7-0: sa2 + */ +#define ET_RX_WOL_HI_SA1_SHIFT 8 + +/* structure for Wake On Lan mask reg in rxmac address map + * located at address 0x4018 - 0x4064 + * Defined earlier (u32) + */ + +/* structure for Unicast Packet Filter Address 1 reg in rxmac address map + * located at address 0x4068 + * + * 31-24: addr1_3 + * 23-16: addr1_4 + * 15-8: addr1_5 + * 7-0: addr1_6 + */ +#define ET_RX_UNI_PF_ADDR1_3_SHIFT 24 +#define ET_RX_UNI_PF_ADDR1_4_SHIFT 16 +#define ET_RX_UNI_PF_ADDR1_5_SHIFT 8 + +/* structure for Unicast Packet Filter Address 2 reg in rxmac address map + * located at address 0x406C + * + * 31-24: addr2_3 + * 23-16: addr2_4 + * 15-8: addr2_5 + * 7-0: addr2_6 + */ +#define ET_RX_UNI_PF_ADDR2_3_SHIFT 24 +#define ET_RX_UNI_PF_ADDR2_4_SHIFT 16 +#define ET_RX_UNI_PF_ADDR2_5_SHIFT 8 + +/* structure for Unicast Packet Filter Address 1 & 2 reg in rxmac address map + * located at address 0x4070 + * + * 31-24: addr2_1 + * 23-16: addr2_2 + * 15-8: addr1_1 + * 7-0: addr1_2 + */ +#define ET_RX_UNI_PF_ADDR2_1_SHIFT 24 +#define ET_RX_UNI_PF_ADDR2_2_SHIFT 16 +#define ET_RX_UNI_PF_ADDR1_1_SHIFT 8 + +/* structure for Multicast Hash reg in rxmac address map + * located at address 0x4074 - 0x4080 + * Defined earlier (u32) + */ + +/* structure for Packet Filter Control reg in rxmac address map + * located at address 0x4084 + * + * 31-23: unused + * 22-16: min_pkt_size + * 15-4: unused + * 3: filter_frag_en + * 2: filter_uni_en + * 1: filter_multi_en + * 0: filter_broad_en + */ +#define ET_RX_PFCTRL_MIN_PKT_SZ_SHIFT 16 +#define ET_RX_PFCTRL_FRAG_FILTER_ENABLE 0x0008 +#define ET_RX_PFCTRL_UNICST_FILTER_ENABLE 0x0004 +#define ET_RX_PFCTRL_MLTCST_FILTER_ENABLE 0x0002 +#define ET_RX_PFCTRL_BRDCST_FILTER_ENABLE 0x0001 + +/* structure for Memory Controller Interface Control Max Segment reg in rxmac + * address map. Located at address 0x4088 + * + * 31-10: reserved + * 9-2: max_size + * 1: fc_en + * 0: seg_en + */ +#define ET_RX_MCIF_CTRL_MAX_SEG_SIZE_SHIFT 2 +#define ET_RX_MCIF_CTRL_MAX_SEG_FC_ENABLE 0x0002 +#define ET_RX_MCIF_CTRL_MAX_SEG_ENABLE 0x0001 + +/* structure for Memory Controller Interface Water Mark reg in rxmac address + * map. Located at address 0x408C + * + * 31-26: unused + * 25-16: mark_hi + * 15-10: unused + * 9-0: mark_lo + */ + +/* structure for Rx Queue Dialog reg in rxmac address map. + * located at address 0x4090 + * + * 31-26: reserved + * 25-16: rd_ptr + * 15-10: reserved + * 9-0: wr_ptr + */ + +/* structure for space available reg in rxmac address map. + * located at address 0x4094 + * + * 31-17: reserved + * 16: space_avail_en + * 15-10: reserved + * 9-0: space_avail + */ + +/* structure for management interface reg in rxmac address map. + * located at address 0x4098 + * + * 31-18: reserved + * 17: drop_pkt_en + * 16-0: drop_pkt_mask + */ + +/* structure for Error reg in rxmac address map. + * located at address 0x409C + * + * 31-4: unused + * 3: mif + * 2: async + * 1: pkt_filter + * 0: mcif + */ + +/* Rx MAC Module of JAGCore Address Mapping + */ +struct rxmac_regs { /* Location: */ + u32 ctrl; /* 0x4000 */ + u32 crc0; /* 0x4004 */ + u32 crc12; /* 0x4008 */ + u32 crc34; /* 0x400C */ + u32 sa_lo; /* 0x4010 */ + u32 sa_hi; /* 0x4014 */ + u32 mask0_word0; /* 0x4018 */ + u32 mask0_word1; /* 0x401C */ + u32 mask0_word2; /* 0x4020 */ + u32 mask0_word3; /* 0x4024 */ + u32 mask1_word0; /* 0x4028 */ + u32 mask1_word1; /* 0x402C */ + u32 mask1_word2; /* 0x4030 */ + u32 mask1_word3; /* 0x4034 */ + u32 mask2_word0; /* 0x4038 */ + u32 mask2_word1; /* 0x403C */ + u32 mask2_word2; /* 0x4040 */ + u32 mask2_word3; /* 0x4044 */ + u32 mask3_word0; /* 0x4048 */ + u32 mask3_word1; /* 0x404C */ + u32 mask3_word2; /* 0x4050 */ + u32 mask3_word3; /* 0x4054 */ + u32 mask4_word0; /* 0x4058 */ + u32 mask4_word1; /* 0x405C */ + u32 mask4_word2; /* 0x4060 */ + u32 mask4_word3; /* 0x4064 */ + u32 uni_pf_addr1; /* 0x4068 */ + u32 uni_pf_addr2; /* 0x406C */ + u32 uni_pf_addr3; /* 0x4070 */ + u32 multi_hash1; /* 0x4074 */ + u32 multi_hash2; /* 0x4078 */ + u32 multi_hash3; /* 0x407C */ + u32 multi_hash4; /* 0x4080 */ + u32 pf_ctrl; /* 0x4084 */ + u32 mcif_ctrl_max_seg; /* 0x4088 */ + u32 mcif_water_mark; /* 0x408C */ + u32 rxq_diag; /* 0x4090 */ + u32 space_avail; /* 0x4094 */ + + u32 mif_ctrl; /* 0x4098 */ + u32 err_reg; /* 0x409C */ +}; + +/* END OF RXMAC REGISTER ADDRESS MAP */ + +/* START OF MAC REGISTER ADDRESS MAP */ +/* structure for configuration #1 reg in mac address map. + * located at address 0x5000 + * + * 31: soft reset + * 30: sim reset + * 29-20: reserved + * 19: reset rx mc + * 18: reset tx mc + * 17: reset rx func + * 16: reset tx fnc + * 15-9: reserved + * 8: loopback + * 7-6: reserved + * 5: rx flow + * 4: tx flow + * 3: syncd rx en + * 2: rx enable + * 1: syncd tx en + * 0: tx enable + */ +#define ET_MAC_CFG1_SOFT_RESET 0x80000000 +#define ET_MAC_CFG1_SIM_RESET 0x40000000 +#define ET_MAC_CFG1_RESET_RXMC 0x00080000 +#define ET_MAC_CFG1_RESET_TXMC 0x00040000 +#define ET_MAC_CFG1_RESET_RXFUNC 0x00020000 +#define ET_MAC_CFG1_RESET_TXFUNC 0x00010000 +#define ET_MAC_CFG1_LOOPBACK 0x00000100 +#define ET_MAC_CFG1_RX_FLOW 0x00000020 +#define ET_MAC_CFG1_TX_FLOW 0x00000010 +#define ET_MAC_CFG1_RX_ENABLE 0x00000004 +#define ET_MAC_CFG1_TX_ENABLE 0x00000001 +#define ET_MAC_CFG1_WAIT 0x0000000A /* RX & TX syncd */ + +/* structure for configuration #2 reg in mac address map. + * located at address 0x5004 + * 31-16: reserved + * 15-12: preamble + * 11-10: reserved + * 9-8: if mode + * 7-6: reserved + * 5: huge frame + * 4: length check + * 3: undefined + * 2: pad crc + * 1: crc enable + * 0: full duplex + */ +#define ET_MAC_CFG2_PREAMBLE_SHIFT 12 +#define ET_MAC_CFG2_IFMODE_MASK 0x0300 +#define ET_MAC_CFG2_IFMODE_1000 0x0200 +#define ET_MAC_CFG2_IFMODE_100 0x0100 +#define ET_MAC_CFG2_IFMODE_HUGE_FRAME 0x0020 +#define ET_MAC_CFG2_IFMODE_LEN_CHECK 0x0010 +#define ET_MAC_CFG2_IFMODE_PAD_CRC 0x0004 +#define ET_MAC_CFG2_IFMODE_CRC_ENABLE 0x0002 +#define ET_MAC_CFG2_IFMODE_FULL_DPLX 0x0001 + +/* structure for Interpacket gap reg in mac address map. + * located at address 0x5008 + * + * 31: reserved + * 30-24: non B2B ipg 1 + * 23: undefined + * 22-16: non B2B ipg 2 + * 15-8: Min ifg enforce + * 7-0: B2B ipg + * + * structure for half duplex reg in mac address map. + * located at address 0x500C + * 31-24: reserved + * 23-20: Alt BEB trunc + * 19: Alt BEB enable + * 18: BP no backoff + * 17: no backoff + * 16: excess defer + * 15-12: re-xmit max + * 11-10: reserved + * 9-0: collision window + */ + +/* structure for Maximum Frame Length reg in mac address map. + * located at address 0x5010: bits 0-15 hold the length. + */ + +/* structure for Reserve 1 reg in mac address map. + * located at address 0x5014 - 0x5018 + * Defined earlier (u32) + */ + +/* structure for Test reg in mac address map. + * located at address 0x501C + * test: bits 0-2, rest unused + */ + +/* structure for MII Management Configuration reg in mac address map. + * located at address 0x5020 + * + * 31: reset MII mgmt + * 30-6: unused + * 5: scan auto increment + * 4: preamble suppress + * 3: undefined + * 2-0: mgmt clock reset + */ +#define ET_MAC_MIIMGMT_CLK_RST 0x0007 + +/* structure for MII Management Command reg in mac address map. + * located at address 0x5024 + * bit 1: scan cycle + * bit 0: read cycle + */ + +/* structure for MII Management Address reg in mac address map. + * located at address 0x5028 + * 31-13: reserved + * 12-8: phy addr + * 7-5: reserved + * 4-0: register + */ +#define ET_MAC_MII_ADDR(phy, reg) ((phy) << 8 | (reg)) + +/* structure for MII Management Control reg in mac address map. + * located at address 0x502C + * 31-16: reserved + * 15-0: phy control + */ + +/* structure for MII Management Status reg in mac address map. + * located at address 0x5030 + * 31-16: reserved + * 15-0: phy control + */ +#define ET_MAC_MIIMGMT_STAT_PHYCRTL_MASK 0xFFFF + +/* structure for MII Management Indicators reg in mac address map. + * located at address 0x5034 + * 31-3: reserved + * 2: not valid + * 1: scanning + * 0: busy + */ +#define ET_MAC_MGMT_BUSY 0x00000001 /* busy */ +#define ET_MAC_MGMT_WAIT 0x00000005 /* busy | not valid */ + +/* structure for Interface Control reg in mac address map. + * located at address 0x5038 + * + * 31: reset if module + * 30-28: reserved + * 27: tbi mode + * 26: ghd mode + * 25: lhd mode + * 24: phy mode + * 23: reset per mii + * 22-17: reserved + * 16: speed + * 15: reset pe100x + * 14-11: reserved + * 10: force quiet + * 9: no cipher + * 8: disable link fail + * 7: reset gpsi + * 6-1: reserved + * 0: enable jabber protection + */ +#define ET_MAC_IFCTRL_GHDMODE (1 << 26) +#define ET_MAC_IFCTRL_PHYMODE (1 << 24) + +/* structure for Interface Status reg in mac address map. + * located at address 0x503C + * + * 31-10: reserved + * 9: excess_defer + * 8: clash + * 7: phy_jabber + * 6: phy_link_ok + * 5: phy_full_duplex + * 4: phy_speed + * 3: pe100x_link_fail + * 2: pe10t_loss_carrier + * 1: pe10t_sqe_error + * 0: pe10t_jabber + */ + +/* structure for Mac Station Address, Part 1 reg in mac address map. + * located at address 0x5040 + * + * 31-24: Octet6 + * 23-16: Octet5 + * 15-8: Octet4 + * 7-0: Octet3 + */ +#define ET_MAC_STATION_ADDR1_OC6_SHIFT 24 +#define ET_MAC_STATION_ADDR1_OC5_SHIFT 16 +#define ET_MAC_STATION_ADDR1_OC4_SHIFT 8 + +/* structure for Mac Station Address, Part 2 reg in mac address map. + * located at address 0x5044 + * + * 31-24: Octet2 + * 23-16: Octet1 + * 15-0: reserved + */ +#define ET_MAC_STATION_ADDR2_OC2_SHIFT 24 +#define ET_MAC_STATION_ADDR2_OC1_SHIFT 16 + +/* MAC Module of JAGCore Address Mapping + */ +struct mac_regs { /* Location: */ + u32 cfg1; /* 0x5000 */ + u32 cfg2; /* 0x5004 */ + u32 ipg; /* 0x5008 */ + u32 hfdp; /* 0x500C */ + u32 max_fm_len; /* 0x5010 */ + u32 rsv1; /* 0x5014 */ + u32 rsv2; /* 0x5018 */ + u32 mac_test; /* 0x501C */ + u32 mii_mgmt_cfg; /* 0x5020 */ + u32 mii_mgmt_cmd; /* 0x5024 */ + u32 mii_mgmt_addr; /* 0x5028 */ + u32 mii_mgmt_ctrl; /* 0x502C */ + u32 mii_mgmt_stat; /* 0x5030 */ + u32 mii_mgmt_indicator; /* 0x5034 */ + u32 if_ctrl; /* 0x5038 */ + u32 if_stat; /* 0x503C */ + u32 station_addr_1; /* 0x5040 */ + u32 station_addr_2; /* 0x5044 */ +}; + +/* END OF MAC REGISTER ADDRESS MAP */ + +/* START OF MAC STAT REGISTER ADDRESS MAP */ +/* structure for Carry Register One and it's Mask Register reg located in mac + * stat address map address 0x6130 and 0x6138. + * + * 31: tr64 + * 30: tr127 + * 29: tr255 + * 28: tr511 + * 27: tr1k + * 26: trmax + * 25: trmgv + * 24-17: unused + * 16: rbyt + * 15: rpkt + * 14: rfcs + * 13: rmca + * 12: rbca + * 11: rxcf + * 10: rxpf + * 9: rxuo + * 8: raln + * 7: rflr + * 6: rcde + * 5: rcse + * 4: rund + * 3: rovr + * 2: rfrg + * 1: rjbr + * 0: rdrp + */ + +/* structure for Carry Register Two Mask Register reg in mac stat address map. + * located at address 0x613C + * + * 31-20: unused + * 19: tjbr + * 18: tfcs + * 17: txcf + * 16: tovr + * 15: tund + * 14: trfg + * 13: tbyt + * 12: tpkt + * 11: tmca + * 10: tbca + * 9: txpf + * 8: tdfr + * 7: tedf + * 6: tscl + * 5: tmcl + * 4: tlcl + * 3: txcl + * 2: tncl + * 1: tpfh + * 0: tdrp + */ + +/* MAC STATS Module of JAGCore Address Mapping + */ +struct macstat_regs { /* Location: */ + u32 pad[32]; /* 0x6000 - 607C */ + + /* counters */ + u32 txrx_0_64_byte_frames; /* 0x6080 */ + u32 txrx_65_127_byte_frames; /* 0x6084 */ + u32 txrx_128_255_byte_frames; /* 0x6088 */ + u32 txrx_256_511_byte_frames; /* 0x608C */ + u32 txrx_512_1023_byte_frames; /* 0x6090 */ + u32 txrx_1024_1518_byte_frames; /* 0x6094 */ + u32 txrx_1519_1522_gvln_frames; /* 0x6098 */ + u32 rx_bytes; /* 0x609C */ + u32 rx_packets; /* 0x60A0 */ + u32 rx_fcs_errs; /* 0x60A4 */ + u32 rx_multicast_packets; /* 0x60A8 */ + u32 rx_broadcast_packets; /* 0x60AC */ + u32 rx_control_frames; /* 0x60B0 */ + u32 rx_pause_frames; /* 0x60B4 */ + u32 rx_unknown_opcodes; /* 0x60B8 */ + u32 rx_align_errs; /* 0x60BC */ + u32 rx_frame_len_errs; /* 0x60C0 */ + u32 rx_code_errs; /* 0x60C4 */ + u32 rx_carrier_sense_errs; /* 0x60C8 */ + u32 rx_undersize_packets; /* 0x60CC */ + u32 rx_oversize_packets; /* 0x60D0 */ + u32 rx_fragment_packets; /* 0x60D4 */ + u32 rx_jabbers; /* 0x60D8 */ + u32 rx_drops; /* 0x60DC */ + u32 tx_bytes; /* 0x60E0 */ + u32 tx_packets; /* 0x60E4 */ + u32 tx_multicast_packets; /* 0x60E8 */ + u32 tx_broadcast_packets; /* 0x60EC */ + u32 tx_pause_frames; /* 0x60F0 */ + u32 tx_deferred; /* 0x60F4 */ + u32 tx_excessive_deferred; /* 0x60F8 */ + u32 tx_single_collisions; /* 0x60FC */ + u32 tx_multiple_collisions; /* 0x6100 */ + u32 tx_late_collisions; /* 0x6104 */ + u32 tx_excessive_collisions; /* 0x6108 */ + u32 tx_total_collisions; /* 0x610C */ + u32 tx_pause_honored_frames; /* 0x6110 */ + u32 tx_drops; /* 0x6114 */ + u32 tx_jabbers; /* 0x6118 */ + u32 tx_fcs_errs; /* 0x611C */ + u32 tx_control_frames; /* 0x6120 */ + u32 tx_oversize_frames; /* 0x6124 */ + u32 tx_undersize_frames; /* 0x6128 */ + u32 tx_fragments; /* 0x612C */ + u32 carry_reg1; /* 0x6130 */ + u32 carry_reg2; /* 0x6134 */ + u32 carry_reg1_mask; /* 0x6138 */ + u32 carry_reg2_mask; /* 0x613C */ +}; + +/* END OF MAC STAT REGISTER ADDRESS MAP */ + +/* START OF MMC REGISTER ADDRESS MAP */ +/* Main Memory Controller Control reg in mmc address map. + * located at address 0x7000 + */ +#define ET_MMC_ENABLE 1 +#define ET_MMC_ARB_DISABLE 2 +#define ET_MMC_RXMAC_DISABLE 4 +#define ET_MMC_TXMAC_DISABLE 8 +#define ET_MMC_TXDMA_DISABLE 16 +#define ET_MMC_RXDMA_DISABLE 32 +#define ET_MMC_FORCE_CE 64 + +/* Main Memory Controller Host Memory Access Address reg in mmc + * address map. Located at address 0x7004. Top 16 bits hold the address bits + */ +#define ET_SRAM_REQ_ACCESS 1 +#define ET_SRAM_WR_ACCESS 2 +#define ET_SRAM_IS_CTRL 4 + +/* structure for Main Memory Controller Host Memory Access Data reg in mmc + * address map. Located at address 0x7008 - 0x7014 + * Defined earlier (u32) + */ + +/* Memory Control Module of JAGCore Address Mapping + */ +struct mmc_regs { /* Location: */ + u32 mmc_ctrl; /* 0x7000 */ + u32 sram_access; /* 0x7004 */ + u32 sram_word1; /* 0x7008 */ + u32 sram_word2; /* 0x700C */ + u32 sram_word3; /* 0x7010 */ + u32 sram_word4; /* 0x7014 */ +}; + +/* END OF MMC REGISTER ADDRESS MAP */ + +/* JAGCore Address Mapping + */ +struct address_map { + struct global_regs global; + /* unused section of global address map */ + u8 unused_global[4096 - sizeof(struct global_regs)]; + struct txdma_regs txdma; + /* unused section of txdma address map */ + u8 unused_txdma[4096 - sizeof(struct txdma_regs)]; + struct rxdma_regs rxdma; + /* unused section of rxdma address map */ + u8 unused_rxdma[4096 - sizeof(struct rxdma_regs)]; + struct txmac_regs txmac; + /* unused section of txmac address map */ + u8 unused_txmac[4096 - sizeof(struct txmac_regs)]; + struct rxmac_regs rxmac; + /* unused section of rxmac address map */ + u8 unused_rxmac[4096 - sizeof(struct rxmac_regs)]; + struct mac_regs mac; + /* unused section of mac address map */ + u8 unused_mac[4096 - sizeof(struct mac_regs)]; + struct macstat_regs macstat; + /* unused section of mac stat address map */ + u8 unused_mac_stat[4096 - sizeof(struct macstat_regs)]; + struct mmc_regs mmc; + /* unused section of mmc address map */ + u8 unused_mmc[4096 - sizeof(struct mmc_regs)]; + /* unused section of address map */ + u8 unused_[1015808]; + u8 unused_exp_rom[4096]; /* MGS-size TBD */ + u8 unused__[524288]; /* unused section of address map */ +}; + +/* Defines for generic MII registers 0x00 -> 0x0F can be found in + * include/linux/mii.h + */ +/* some defines for modem registers that seem to be 'reserved' */ +#define PHY_INDEX_REG 0x10 +#define PHY_DATA_REG 0x11 +#define PHY_MPHY_CONTROL_REG 0x12 + +/* defines for specified registers */ +#define PHY_LOOPBACK_CONTROL 0x13 /* TRU_VMI_LOOPBACK_CONTROL_1_REG 19 */ + /* TRU_VMI_LOOPBACK_CONTROL_2_REG 20 */ +#define PHY_REGISTER_MGMT_CONTROL 0x15 /* TRU_VMI_MI_SEQ_CONTROL_REG 21 */ +#define PHY_CONFIG 0x16 /* TRU_VMI_CONFIGURATION_REG 22 */ +#define PHY_PHY_CONTROL 0x17 /* TRU_VMI_PHY_CONTROL_REG 23 */ +#define PHY_INTERRUPT_MASK 0x18 /* TRU_VMI_INTERRUPT_MASK_REG 24 */ +#define PHY_INTERRUPT_STATUS 0x19 /* TRU_VMI_INTERRUPT_STATUS_REG 25 */ +#define PHY_PHY_STATUS 0x1A /* TRU_VMI_PHY_STATUS_REG 26 */ +#define PHY_LED_1 0x1B /* TRU_VMI_LED_CONTROL_1_REG 27 */ +#define PHY_LED_2 0x1C /* TRU_VMI_LED_CONTROL_2_REG 28 */ + /* TRU_VMI_LINK_CONTROL_REG 29 */ + /* TRU_VMI_TIMING_CONTROL_REG */ + +/* MI Register 10: Gigabit basic mode status reg(Reg 0x0A) */ +#define ET_1000BT_MSTR_SLV 0x4000 + +/* MI Register 16 - 18: Reserved Reg(0x10-0x12) */ + +/* MI Register 19: Loopback Control Reg(0x13) + * 15: mii_en + * 14: pcs_en + * 13: pmd_en + * 12: all_digital_en + * 11: replica_en + * 10: line_driver_en + * 9-0: reserved + */ + +/* MI Register 20: Reserved Reg(0x14) */ + +/* MI Register 21: Management Interface Control Reg(0x15) + * 15-11: reserved + * 10-4: mi_error_count + * 3: reserved + * 2: ignore_10g_fr + * 1: reserved + * 0: preamble_suppress_en + */ + +/* MI Register 22: PHY Configuration Reg(0x16) + * 15: crs_tx_en + * 14: reserved + * 13-12: tx_fifo_depth + * 11-10: speed_downshift + * 9: pbi_detect + * 8: tbi_rate + * 7: alternate_np + * 6: group_mdio_en + * 5: tx_clock_en + * 4: sys_clock_en + * 3: reserved + * 2-0: mac_if_mode + */ +#define ET_PHY_CONFIG_TX_FIFO_DEPTH 0x3000 + +#define ET_PHY_CONFIG_FIFO_DEPTH_8 0x0000 +#define ET_PHY_CONFIG_FIFO_DEPTH_16 0x1000 +#define ET_PHY_CONFIG_FIFO_DEPTH_32 0x2000 +#define ET_PHY_CONFIG_FIFO_DEPTH_64 0x3000 + +/* MI Register 23: PHY CONTROL Reg(0x17) + * 15: reserved + * 14: tdr_en + * 13: reserved + * 12-11: downshift_attempts + * 10-6: reserved + * 5: jabber_10baseT + * 4: sqe_10baseT + * 3: tp_loopback_10baseT + * 2: preamble_gen_en + * 1: reserved + * 0: force_int + */ + +/* MI Register 24: Interrupt Mask Reg(0x18) + * 15-10: reserved + * 9: mdio_sync_lost + * 8: autoneg_status + * 7: hi_bit_err + * 6: np_rx + * 5: err_counter_full + * 4: fifo_over_underflow + * 3: rx_status + * 2: link_status + * 1: automatic_speed + * 0: int_en + */ + +/* MI Register 25: Interrupt Status Reg(0x19) + * 15-10: reserved + * 9: mdio_sync_lost + * 8: autoneg_status + * 7: hi_bit_err + * 6: np_rx + * 5: err_counter_full + * 4: fifo_over_underflow + * 3: rx_status + * 2: link_status + * 1: automatic_speed + * 0: int_en + */ + +/* MI Register 26: PHY Status Reg(0x1A) + * 15: reserved + * 14-13: autoneg_fault + * 12: autoneg_status + * 11: mdi_x_status + * 10: polarity_status + * 9-8: speed_status + * 7: duplex_status + * 6: link_status + * 5: tx_status + * 4: rx_status + * 3: collision_status + * 2: autoneg_en + * 1: pause_en + * 0: asymmetric_dir + */ +#define ET_PHY_AUTONEG_STATUS 0x1000 +#define ET_PHY_POLARITY_STATUS 0x0400 +#define ET_PHY_SPEED_STATUS 0x0300 +#define ET_PHY_DUPLEX_STATUS 0x0080 +#define ET_PHY_LSTATUS 0x0040 +#define ET_PHY_AUTONEG_ENABLE 0x0020 + +/* MI Register 27: LED Control Reg 1(0x1B) + * 15-14: reserved + * 13-12: led_dup_indicate + * 11-10: led_10baseT + * 9-8: led_collision + * 7-4: reserved + * 3-2: pulse_dur + * 1: pulse_stretch1 + * 0: pulse_stretch0 + */ + +/* MI Register 28: LED Control Reg 2(0x1C) + * 15-12: led_link + * 11-8: led_tx_rx + * 7-4: led_100BaseTX + * 3-0: led_1000BaseT + */ +#define ET_LED2_LED_LINK 0xF000 +#define ET_LED2_LED_TXRX 0x0F00 +#define ET_LED2_LED_100TX 0x00F0 +#define ET_LED2_LED_1000T 0x000F + +/* defines for LED control reg 2 values */ +#define LED_VAL_1000BT 0x0 +#define LED_VAL_100BTX 0x1 +#define LED_VAL_10BT 0x2 +#define LED_VAL_1000BT_100BTX 0x3 /* 1000BT on, 100BTX blink */ +#define LED_VAL_LINKON 0x4 +#define LED_VAL_TX 0x5 +#define LED_VAL_RX 0x6 +#define LED_VAL_TXRX 0x7 /* TX or RX */ +#define LED_VAL_DUPLEXFULL 0x8 +#define LED_VAL_COLLISION 0x9 +#define LED_VAL_LINKON_ACTIVE 0xA /* Link on, activity blink */ +#define LED_VAL_LINKON_RECV 0xB /* Link on, receive blink */ +#define LED_VAL_DUPLEXFULL_COLLISION 0xC /* Duplex on, collision blink */ +#define LED_VAL_BLINK 0xD +#define LED_VAL_ON 0xE +#define LED_VAL_OFF 0xF + +#define LED_LINK_SHIFT 12 +#define LED_TXRX_SHIFT 8 +#define LED_100TX_SHIFT 4 + +/* MI Register 29 - 31: Reserved Reg(0x1D - 0x1E) */ diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index 29b9f082475d..1fcd5568a352 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -878,8 +878,6 @@ static int emac_probe(struct platform_device *pdev) emac_powerup(ndev); emac_reset(db); - ether_setup(ndev); - ndev->netdev_ops = &emac_netdev_ops; ndev->watchdog_timeo = msecs_to_jiffies(watchdog); ndev->ethtool_ops = &emac_ethtool_ops; diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 7330681574d2..fc2d5556b715 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -1433,7 +1433,6 @@ static int altera_tse_probe(struct platform_device *pdev) goto err_free_netdev; /* initialize netdev */ - ether_setup(ndev); ndev->mem_start = control_port->start; ndev->mem_end = control_port->end; ndev->netdev_ops = &altera_tse_netdev_ops; diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 2fee73b878c2..823d01c5684c 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -3236,8 +3236,9 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) skb->protocol = eth_type_trans(skb, bp->dev); - if ((len > (bp->dev->mtu + ETH_HLEN)) && - (ntohs(skb->protocol) != 0x8100)) { + if (len > (bp->dev->mtu + ETH_HLEN) && + skb->protocol != htons(0x8100) && + skb->protocol != htons(ETH_P_8021AD)) { dev_kfree_skb(skb); goto next_rx; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 77cb7555e794..d51729c619c0 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1054,7 +1054,8 @@ static int bcmgenet_xmit_frag(struct net_device *dev, /* Reallocate the SKB to put enough headroom in front of it and insert * the transmit checksum offsets in the descriptors */ -static int bcmgenet_put_tx_csum(struct net_device *dev, struct sk_buff *skb) +static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev, + struct sk_buff *skb) { struct status_64 *status = NULL; struct sk_buff *new_skb; @@ -1072,7 +1073,7 @@ static int bcmgenet_put_tx_csum(struct net_device *dev, struct sk_buff *skb) if (!new_skb) { dev->stats.tx_errors++; dev->stats.tx_dropped++; - return -ENOMEM; + return NULL; } skb = new_skb; } @@ -1090,7 +1091,7 @@ static int bcmgenet_put_tx_csum(struct net_device *dev, struct sk_buff *skb) ip_proto = ipv6_hdr(skb)->nexthdr; break; default: - return 0; + return skb; } offset = skb_checksum_start_offset(skb) - sizeof(*status); @@ -1111,7 +1112,7 @@ static int bcmgenet_put_tx_csum(struct net_device *dev, struct sk_buff *skb) status->tx_csum_info = tx_csum_info; } - return 0; + return skb; } static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) @@ -1158,8 +1159,8 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) /* set the SKB transmit checksum */ if (priv->desc_64b_en) { - ret = bcmgenet_put_tx_csum(dev, skb); - if (ret) { + skb = bcmgenet_put_tx_csum(dev, skb); + if (!skb) { ret = NETDEV_TX_OK; goto out; } diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index e7d3a620d96a..ba499489969a 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6918,7 +6918,8 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) skb->protocol = eth_type_trans(skb, tp->dev); if (len > (tp->dev->mtu + ETH_HLEN) && - skb->protocol != htons(ETH_P_8021Q)) { + skb->protocol != htons(ETH_P_8021Q) && + skb->protocol != htons(ETH_P_8021AD)) { dev_kfree_skb_any(skb); goto drop_it_no_recycle; } diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c index 4a79edaf3885..4a24b9a6ad75 100644 --- a/drivers/net/ethernet/cadence/at91_ether.c +++ b/drivers/net/ethernet/cadence/at91_ether.c @@ -351,7 +351,6 @@ static int __init at91ether_probe(struct platform_device *pdev) if (res) goto err_disable_clock; - ether_setup(dev); dev->netdev_ops = &at91ether_netdev_ops; dev->ethtool_ops = &macb_ethtool_ops; platform_set_drvdata(pdev, dev); diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index d9b8e94b805f..4d9fc0509af6 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -30,7 +30,6 @@ #include <linux/of_device.h> #include <linux/of_mdio.h> #include <linux/of_net.h> -#include <linux/pinctrl/consumer.h> #include "macb.h" @@ -2071,7 +2070,6 @@ static int __init macb_probe(struct platform_device *pdev) struct phy_device *phydev; u32 config; int err = -ENXIO; - struct pinctrl *pinctrl; const char *mac; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -2080,15 +2078,6 @@ static int __init macb_probe(struct platform_device *pdev) goto err_out; } - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - err = PTR_ERR(pinctrl); - if (err == -EPROBE_DEFER) - goto err_out; - - dev_warn(&pdev->dev, "No pinctrl provided\n"); - } - err = -ENOMEM; dev = alloc_etherdev(sizeof(*bp)); if (!dev) diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index 25d6b2a10e4e..47bfea24b9e1 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -1735,7 +1735,6 @@ static int xgmac_probe(struct platform_device *pdev) SET_NETDEV_DEV(ndev, &pdev->dev); priv = netdev_priv(ndev); platform_set_drvdata(pdev, ndev); - ether_setup(ndev); ndev->netdev_ops = &xgmac_netdev_ops; ndev->ethtool_ops = &xgmac_ethtool_ops; spin_lock_init(&priv->stats_lock); diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 70089c29d307..f3ba840cbf7b 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -1613,9 +1613,6 @@ dm9000_probe(struct platform_device *pdev) /* from this point we assume that we have found a DM9000 */ - /* driver system function */ - ether_setup(ndev); - ndev->netdev_ops = &dm9000_netdev_ops; ndev->watchdog_timeo = msecs_to_jiffies(watchdog); ndev->ethtool_ops = &dm9000_ethtool_ops; diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index f3658bdb64cc..0bc6c102f3ac 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1222,8 +1222,6 @@ static int ethoc_probe(struct platform_device *pdev) goto error; } - ether_setup(netdev); - /* setup the net_device structure */ netdev->netdev_ops = ðoc_netdev_ops; netdev->watchdog_timeo = ETHOC_TIMEOUT; diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 354a30954fb1..1d5e1822bb2c 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -482,6 +482,8 @@ struct fec_enet_private { unsigned int tx_pkts_itr; unsigned int tx_time_itr; unsigned int itr_clk_rate; + + u32 rx_copybreak; }; void fec_ptp_init(struct platform_device *pdev); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 2c7343473e1c..1f07db891ee8 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -236,6 +236,8 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_PAUSE_FLAG_AUTONEG 0x1 #define FEC_PAUSE_FLAG_ENABLE 0x2 +#define COPYBREAK_DEFAULT 256 + #define TSO_HEADER_SIZE 128 /* Max number of allowed TCP segments for software TSO */ #define FEC_MAX_TSO_SEGS 100 @@ -1322,6 +1324,50 @@ fec_enet_tx(struct net_device *ndev) return; } +static int +fec_enet_new_rxbdp(struct net_device *ndev, struct bufdesc *bdp, struct sk_buff *skb) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + int off; + + off = ((unsigned long)skb->data) & fep->rx_align; + if (off) + skb_reserve(skb, fep->rx_align + 1 - off); + + bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, + FEC_ENET_RX_FRSIZE - fep->rx_align, + DMA_FROM_DEVICE); + if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) { + if (net_ratelimit()) + netdev_err(ndev, "Rx DMA memory map failed\n"); + return -ENOMEM; + } + + return 0; +} + +static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb, + struct bufdesc *bdp, u32 length) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + struct sk_buff *new_skb; + + if (length > fep->rx_copybreak) + return false; + + new_skb = netdev_alloc_skb(ndev, length); + if (!new_skb) + return false; + + dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr, + FEC_ENET_RX_FRSIZE - fep->rx_align, + DMA_FROM_DEVICE); + memcpy(new_skb->data, (*skb)->data, length); + *skb = new_skb; + + return true; +} + /* During a receive, the cur_rx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator, @@ -1336,7 +1382,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) struct fec_enet_priv_rx_q *rxq; struct bufdesc *bdp; unsigned short status; - struct sk_buff *skb; + struct sk_buff *skb_new = NULL; + struct sk_buff *skb; ushort pkt_len; __u8 *data; int pkt_received = 0; @@ -1344,6 +1391,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) bool vlan_packet_rcvd = false; u16 vlan_tag; int index = 0; + bool is_copybreak; #ifdef CONFIG_M532x flush_cache_all(); @@ -1401,11 +1449,27 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) ndev->stats.rx_bytes += pkt_len; index = fec_enet_get_bd_index(rxq->rx_bd_base, bdp, fep); - data = rxq->rx_skbuff[index]->data; - dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr, - FEC_ENET_RX_FRSIZE - fep->rx_align, - DMA_FROM_DEVICE); + skb = rxq->rx_skbuff[index]; + /* The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, pkt_len - 4); + if (!is_copybreak) { + skb_new = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); + if (unlikely(!skb_new)) { + ndev->stats.rx_dropped++; + goto rx_processing_done; + } + dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, + FEC_ENET_RX_FRSIZE - fep->rx_align, + DMA_FROM_DEVICE); + } + + prefetch(skb->data - NET_IP_ALIGN); + skb_put(skb, pkt_len - 4); + data = skb->data; if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) swap_buffer(data, pkt_len); @@ -1422,62 +1486,48 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) struct vlan_hdr *vlan_header = (struct vlan_hdr *) (data + ETH_HLEN); vlan_tag = ntohs(vlan_header->h_vlan_TCI); - pkt_len -= VLAN_HLEN; vlan_packet_rcvd = true; + + skb_copy_to_linear_data_offset(skb, VLAN_HLEN, + data, (2 * ETH_ALEN)); + skb_pull(skb, VLAN_HLEN); } - /* This does 16 byte alignment, exactly what we need. - * The packet length includes FCS, but we don't want to - * include that when passing upstream as it messes up - * bridging applications. - */ - skb = netdev_alloc_skb(ndev, pkt_len - 4 + NET_IP_ALIGN); + skb->protocol = eth_type_trans(skb, ndev); - if (unlikely(!skb)) { - ndev->stats.rx_dropped++; - } else { - int payload_offset = (2 * ETH_ALEN); - skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, pkt_len - 4); /* Make room */ - - /* Extract the frame data without the VLAN header. */ - skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN)); - if (vlan_packet_rcvd) - payload_offset = (2 * ETH_ALEN) + VLAN_HLEN; - skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN), - data + payload_offset, - pkt_len - 4 - (2 * ETH_ALEN)); - - skb->protocol = eth_type_trans(skb, ndev); - - /* Get receive timestamp from the skb */ - if (fep->hwts_rx_en && fep->bufdesc_ex) - fec_enet_hwtstamp(fep, ebdp->ts, - skb_hwtstamps(skb)); - - if (fep->bufdesc_ex && - (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { - if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) { - /* don't check it */ - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { - skb_checksum_none_assert(skb); - } + /* Get receive timestamp from the skb */ + if (fep->hwts_rx_en && fep->bufdesc_ex) + fec_enet_hwtstamp(fep, ebdp->ts, + skb_hwtstamps(skb)); + + if (fep->bufdesc_ex && + (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { + if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) { + /* don't check it */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + skb_checksum_none_assert(skb); } + } - /* Handle received VLAN packets */ - if (vlan_packet_rcvd) - __vlan_hwaccel_put_tag(skb, - htons(ETH_P_8021Q), - vlan_tag); + /* Handle received VLAN packets */ + if (vlan_packet_rcvd) + __vlan_hwaccel_put_tag(skb, + htons(ETH_P_8021Q), + vlan_tag); - napi_gro_receive(&fep->napi, skb); + napi_gro_receive(&fep->napi, skb); + + if (is_copybreak) { + dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr, + FEC_ENET_RX_FRSIZE - fep->rx_align, + DMA_FROM_DEVICE); + } else { + rxq->rx_skbuff[index] = skb_new; + fec_enet_new_rxbdp(ndev, bdp, skb_new); } - dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr, - FEC_ENET_RX_FRSIZE - fep->rx_align, - DMA_FROM_DEVICE); rx_processing_done: /* Clear the status flags for this buffer */ status &= ~BD_ENET_RX_STATS; @@ -2392,6 +2442,44 @@ static void fec_enet_itr_coal_init(struct net_device *ndev) fec_enet_set_coalesce(ndev, &ec); } +static int fec_enet_get_tunable(struct net_device *netdev, + const struct ethtool_tunable *tuna, + void *data) +{ + struct fec_enet_private *fep = netdev_priv(netdev); + int ret = 0; + + switch (tuna->id) { + case ETHTOOL_RX_COPYBREAK: + *(u32 *)data = fep->rx_copybreak; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int fec_enet_set_tunable(struct net_device *netdev, + const struct ethtool_tunable *tuna, + const void *data) +{ + struct fec_enet_private *fep = netdev_priv(netdev); + int ret = 0; + + switch (tuna->id) { + case ETHTOOL_RX_COPYBREAK: + fep->rx_copybreak = *(u32 *)data; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + static const struct ethtool_ops fec_enet_ethtool_ops = { .get_settings = fec_enet_get_settings, .set_settings = fec_enet_set_settings, @@ -2408,6 +2496,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = { .get_sset_count = fec_enet_get_sset_count, #endif .get_ts_info = fec_enet_get_ts_info, + .get_tunable = fec_enet_get_tunable, + .set_tunable = fec_enet_set_tunable, }; static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) @@ -2553,33 +2643,20 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue) struct sk_buff *skb; struct bufdesc *bdp; struct fec_enet_priv_rx_q *rxq; - unsigned int off; rxq = fep->rx_queue[queue]; bdp = rxq->rx_bd_base; for (i = 0; i < rxq->rx_ring_size; i++) { - dma_addr_t addr; - skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); if (!skb) goto err_alloc; - off = ((unsigned long)skb->data) & fep->rx_align; - if (off) - skb_reserve(skb, fep->rx_align + 1 - off); - - addr = dma_map_single(&fep->pdev->dev, skb->data, - FEC_ENET_RX_FRSIZE - fep->rx_align, DMA_FROM_DEVICE); - - if (dma_mapping_error(&fep->pdev->dev, addr)) { + if (fec_enet_new_rxbdp(ndev, bdp, skb)) { dev_kfree_skb(skb); - if (net_ratelimit()) - netdev_err(ndev, "Rx DMA memory map failed\n"); goto err_alloc; } rxq->rx_skbuff[i] = skb; - bdp->cbd_bufaddr = addr; bdp->cbd_sc = BD_ENET_RX_EMPTY; if (fep->bufdesc_ex) { @@ -3240,6 +3317,7 @@ fec_probe(struct platform_device *pdev) if (fep->bufdesc_ex && fep->ptp_clock) netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); + fep->rx_copybreak = COPYBREAK_DEFAULT; INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work); return 0; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k.h b/drivers/net/ethernet/intel/fm10k/fm10k.h index 05658275ba17..42eb4344a9dc 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k.h @@ -47,13 +47,9 @@ #define FM10K_DEFAULT_TX_WORK 256 #define FM10K_RXBUFFER_256 256 -#define FM10K_RXBUFFER_16384 16384 #define FM10K_RX_HDR_LEN FM10K_RXBUFFER_256 -#if PAGE_SIZE <= FM10K_RXBUFFER_16384 -#define FM10K_RX_BUFSZ (PAGE_SIZE / 2) -#else -#define FM10K_RX_BUFSZ FM10K_RXBUFFER_16384 -#endif +#define FM10K_RXBUFFER_2048 2048 +#define FM10K_RX_BUFSZ FM10K_RXBUFFER_2048 /* How many Rx Buffers do we bundle into one write to the hardware ? */ #define FM10K_RX_BUFFER_WRITE 16 /* Must be power of 2 */ diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index dcec000bdb68..bf44a8fe711f 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -546,6 +546,10 @@ int fm10k_open(struct net_device *netdev) fm10k_request_glort_range(interface); /* Notify the stack of the actual queue counts */ + err = netif_set_real_num_tx_queues(netdev, + interface->num_tx_queues); + if (err) + goto err_set_queues; err = netif_set_real_num_rx_queues(netdev, interface->num_rx_queues); @@ -601,7 +605,7 @@ int fm10k_close(struct net_device *netdev) static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev) { struct fm10k_intfc *interface = netdev_priv(dev); - unsigned int r_idx = 0; + unsigned int r_idx = skb->queue_mapping; int err; if ((skb->protocol == htons(ETH_P_8021Q)) && diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index be039dd6114d..267992b3de8a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -702,7 +702,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) total_packets += tx_buf->gso_segs; /* free the skb */ - dev_kfree_skb_any(tx_buf->skb); + dev_consume_skb_any(tx_buf->skb); /* unmap skb header data */ dma_unmap_single(tx_ring->dev, diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index ce55ea5d750c..2003b3756ba2 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -265,11 +265,6 @@ struct e1000_hw_stats { u64 b2ogprc; }; -struct e1000_phy_stats { - u32 idle_errors; - u32 receive_errors; -}; - struct e1000_host_mng_dhcp_cookie { u32 signature; u8 status; diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 06102d1f7c03..82d891e183b1 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -403,7 +403,6 @@ struct igb_adapter { struct e1000_hw hw; struct e1000_hw_stats stats; struct e1000_phy_info phy_info; - struct e1000_phy_stats phy_stats; u32 test_icr; struct igb_ring test_tx_ring; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6cf0c17ad9c4..ae59c0b108c5 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -58,7 +58,7 @@ #define MAJ 5 #define MIN 2 -#define BUILD 13 +#define BUILD 15 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) "-k" char igb_driver_name[] = "igb"; @@ -5206,14 +5206,11 @@ void igb_update_stats(struct igb_adapter *adapter, struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; u32 reg, mpc; - u16 phy_tmp; int i; u64 bytes, packets; unsigned int start; u64 _bytes, _packets; -#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF - /* Prevent stats update while adapter is being reset, or if the pci * connection is down. */ @@ -5374,15 +5371,6 @@ void igb_update_stats(struct igb_adapter *adapter, /* Tx Dropped needs to be maintained elsewhere */ - /* Phy Stats */ - if (hw->phy.media_type == e1000_media_type_copper) { - if ((adapter->link_speed == SPEED_1000) && - (!igb_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { - phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; - adapter->phy_stats.idle_errors += phy_tmp; - } - } - /* Management Stats */ adapter->stats.mgptc += rd32(E1000_MGTPTC); adapter->stats.mgprc += rd32(E1000_MGTPRC); @@ -6386,7 +6374,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) total_packets += tx_buffer->gso_segs; /* free the skb */ - dev_kfree_skb_any(tx_buffer->skb); + dev_consume_skb_any(tx_buffer->skb); /* unmap skb header data */ dma_unmap_single(tx_ring->dev, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 673d82095779..5032a602d5c9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -307,7 +307,6 @@ enum ixgbe_ring_f_enum { #define MAX_RX_QUEUES (IXGBE_MAX_FDIR_INDICES + 1) #define MAX_TX_QUEUES (IXGBE_MAX_FDIR_INDICES + 1) #define IXGBE_MAX_L2A_QUEUES 4 -#define IXGBE_MAX_L2A_QUEUES 4 #define IXGBE_BAD_L2A_QUEUE 3 #define IXGBE_MAX_MACVLANS 31 #define IXGBE_MAX_DCBMACVLANS 8 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index cff383b1cbb0..3ce4a258f945 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2267,7 +2267,6 @@ static int ixgbe_set_coalesce(struct net_device *netdev, if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) adapter->tx_itr_setting = adapter->rx_itr_setting; -#if IS_ENABLED(CONFIG_BQL) /* detect ITR changes that require update of TXDCTL.WTHRESH */ if ((adapter->tx_itr_setting != 1) && (adapter->tx_itr_setting < IXGBE_100K_ITR)) { @@ -2279,7 +2278,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev, (tx_itr_prev < IXGBE_100K_ITR)) need_reset = true; } -#endif + /* check the old value and enable RSC if necessary */ need_reset |= ixgbe_update_rsc(adapter); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 06ef5a32a893..d677b5a23b58 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1094,7 +1094,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, total_packets += tx_buffer->gso_segs; /* free the skb */ - dev_kfree_skb_any(tx_buffer->skb); + dev_consume_skb_any(tx_buffer->skb); /* unmap skb header data */ dma_unmap_single(tx_ring->dev, @@ -2982,11 +2982,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, * to or less than the number of on chip descriptors, which is * currently 40. */ -#if IS_ENABLED(CONFIG_BQL) if (!ring->q_vector || (ring->q_vector->itr < IXGBE_100K_ITR)) -#else - if (!ring->q_vector || (ring->q_vector->itr < 8)) -#endif txdctl |= (1 << 16); /* WTHRESH = 1 */ else txdctl |= (8 << 16); /* WTHRESH = 8 */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 11f02ea78c4a..d47b19f27c35 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -445,8 +445,6 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) { s32 status = 0; - u32 time_out; - u32 max_time_out = 10; u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; bool autoneg = false; ixgbe_link_speed speed; @@ -514,25 +512,6 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_AN, autoneg_reg); - /* Wait for autonegotiation to finish */ - for (time_out = 0; time_out < max_time_out; time_out++) { - udelay(10); - /* Restart PHY autonegotiation and wait for completion */ - status = hw->phy.ops.read_reg(hw, MDIO_STAT1, - MDIO_MMD_AN, - &autoneg_reg); - - autoneg_reg &= MDIO_AN_STAT1_COMPLETE; - if (autoneg_reg == MDIO_AN_STAT1_COMPLETE) { - break; - } - } - - if (time_out == max_time_out) { - hw_dbg(hw, "ixgbe_setup_phy_link_generic: time out\n"); - return IXGBE_ERR_LINK_SETUP; - } - return status; } @@ -657,8 +636,6 @@ s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) { s32 status; - u32 time_out; - u32 max_time_out = 10; u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; bool autoneg = false; ixgbe_link_speed speed; @@ -724,24 +701,6 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_AN, autoneg_reg); - /* Wait for autonegotiation to finish */ - for (time_out = 0; time_out < max_time_out; time_out++) { - udelay(10); - /* Restart PHY autonegotiation and wait for completion */ - status = hw->phy.ops.read_reg(hw, MDIO_STAT1, - MDIO_MMD_AN, - &autoneg_reg); - - autoneg_reg &= MDIO_AN_STAT1_COMPLETE; - if (autoneg_reg == MDIO_AN_STAT1_COMPLETE) - break; - } - - if (time_out == max_time_out) { - hw_dbg(hw, "ixgbe_setup_phy_link_tnx: time out\n"); - return IXGBE_ERR_LINK_SETUP; - } - return status; } diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index fd4b6aecf6ee..2dad4d5047ba 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -633,7 +633,6 @@ ltq_etop_init(struct net_device *dev) int err; bool random_mac = false; - ether_setup(dev); dev->watchdog_timeo = 10 * HZ; err = ltq_etop_hw_init(dev); if (err) diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index bed8fbb3edc5..b3b72ad92d4a 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -64,7 +64,7 @@ config MVPP2 config PXA168_ETH tristate "Marvell pxa168 ethernet support" - depends on CPU_PXA168 || ARCH_BERLIN || COMPILE_TEST + depends on (CPU_PXA168 || ARCH_BERLIN || COMPILE_TEST) && HAS_IOMEM select PHYLIB ---help--- This driver supports the pxa168 Ethernet ports. diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 24de41231593..c3b209cd0660 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -634,12 +634,12 @@ static int pxa168_eth_set_mac_address(struct net_device *dev, void *addr) memcpy(oldMac, dev->dev_addr, ETH_ALEN); memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); - mac_h = sa->sa_data[0] << 24; - mac_h |= sa->sa_data[1] << 16; - mac_h |= sa->sa_data[2] << 8; - mac_h |= sa->sa_data[3]; - mac_l = sa->sa_data[4] << 8; - mac_l |= sa->sa_data[5]; + mac_h = dev->dev_addr[0] << 24; + mac_h |= dev->dev_addr[1] << 16; + mac_h |= dev->dev_addr[2] << 8; + mac_h |= dev->dev_addr[3]; + mac_l = dev->dev_addr[4] << 8; + mac_l |= dev->dev_addr[5]; wrl(pep, MAC_ADDR_HIGH, mac_h); wrl(pep, MAC_ADDR_LOW, mac_l); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 35ff2925110a..42c9f8b09a6e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -112,6 +112,7 @@ static const char main_strings[][ETH_GSTRING_LEN] = { /* port statistics */ "tso_packets", + "xmit_more", "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed", "rx_csum_good", "rx_csum_none", "tx_chksum_offload", diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c index c2cfb05e7290..0a0261d128b9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_port.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c @@ -150,14 +150,19 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) priv->port_stats.tx_chksum_offload = 0; priv->port_stats.queue_stopped = 0; priv->port_stats.wake_queue = 0; + priv->port_stats.tso_packets = 0; + priv->port_stats.xmit_more = 0; for (i = 0; i < priv->tx_ring_num; i++) { - stats->tx_packets += priv->tx_ring[i]->packets; - stats->tx_bytes += priv->tx_ring[i]->bytes; - priv->port_stats.tx_chksum_offload += priv->tx_ring[i]->tx_csum; - priv->port_stats.queue_stopped += - priv->tx_ring[i]->queue_stopped; - priv->port_stats.wake_queue += priv->tx_ring[i]->wake_queue; + const struct mlx4_en_tx_ring *ring = priv->tx_ring[i]; + + stats->tx_packets += ring->packets; + stats->tx_bytes += ring->bytes; + priv->port_stats.tx_chksum_offload += ring->tx_csum; + priv->port_stats.queue_stopped += ring->queue_stopped; + priv->port_stats.wake_queue += ring->wake_queue; + priv->port_stats.tso_packets += ring->tso_packets; + priv->port_stats.xmit_more += ring->xmit_more; } stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) + diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index adedc47e947d..0c501253fdab 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -840,7 +840,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) * note that we already verified that it is linear */ memcpy(tx_desc->lso.header, skb->data, lso_header_size); - priv->port_stats.tso_packets++; + ring->tso_packets++; i = ((skb->len - lso_header_size) / skb_shinfo(skb)->gso_size) + !!((skb->len - lso_header_size) % skb_shinfo(skb)->gso_size); tx_info->nr_bytes = skb->len + (i - 1) * lso_header_size; @@ -910,6 +910,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) wmb(); iowrite32be(ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL); + } else { + ring->xmit_more++; } } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index f6c32a947185..90de6e1ad06e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -78,13 +78,13 @@ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); #endif /* CONFIG_PCI_MSI */ static uint8_t num_vfs[3] = {0, 0, 0}; -static int num_vfs_argc = 3; +static int num_vfs_argc; module_param_array(num_vfs, byte , &num_vfs_argc, 0444); MODULE_PARM_DESC(num_vfs, "enable #num_vfs functions if num_vfs > 0\n" "num_vfs=port1,port2,port1+2"); static uint8_t probe_vf[3] = {0, 0, 0}; -static int probe_vfs_argc = 3; +static int probe_vfs_argc; module_param_array(probe_vf, byte, &probe_vfs_argc, 0444); MODULE_PARM_DESC(probe_vf, "number of vfs to probe by pf driver (num_vfs > 0)\n" "probe_vf=port1,port2,port1+2"); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 6a4fc2394cf2..84c9d5dbfa4f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -279,6 +279,8 @@ struct mlx4_en_tx_ring { unsigned long tx_csum; unsigned long queue_stopped; unsigned long wake_queue; + unsigned long tso_packets; + unsigned long xmit_more; struct mlx4_bf bf; bool bf_enabled; bool bf_alloced; @@ -426,6 +428,7 @@ struct mlx4_en_pkt_stats { struct mlx4_en_port_stats { unsigned long tso_packets; + unsigned long xmit_more; unsigned long queue_stopped; unsigned long wake_queue; unsigned long tx_timeout; @@ -433,7 +436,7 @@ struct mlx4_en_port_stats { unsigned long rx_chksum_good; unsigned long rx_chksum_none; unsigned long tx_chksum_offload; -#define NUM_PORT_STATS 8 +#define NUM_PORT_STATS 9 }; struct mlx4_en_perf_stats { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 65a7da69e2ac..368c6c5ea014 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -357,60 +357,24 @@ const char *mlx5_command_str(int command) case MLX5_CMD_OP_2ERR_QP: return "2ERR_QP"; - case MLX5_CMD_OP_RTS2SQD_QP: - return "RTS2SQD_QP"; - - case MLX5_CMD_OP_SQD2RTS_QP: - return "SQD2RTS_QP"; - case MLX5_CMD_OP_2RST_QP: return "2RST_QP"; case MLX5_CMD_OP_QUERY_QP: return "QUERY_QP"; - case MLX5_CMD_OP_CONF_SQP: - return "CONF_SQP"; - case MLX5_CMD_OP_MAD_IFC: return "MAD_IFC"; case MLX5_CMD_OP_INIT2INIT_QP: return "INIT2INIT_QP"; - case MLX5_CMD_OP_SUSPEND_QP: - return "SUSPEND_QP"; - - case MLX5_CMD_OP_UNSUSPEND_QP: - return "UNSUSPEND_QP"; - - case MLX5_CMD_OP_SQD2SQD_QP: - return "SQD2SQD_QP"; - - case MLX5_CMD_OP_ALLOC_QP_COUNTER_SET: - return "ALLOC_QP_COUNTER_SET"; - - case MLX5_CMD_OP_DEALLOC_QP_COUNTER_SET: - return "DEALLOC_QP_COUNTER_SET"; - - case MLX5_CMD_OP_QUERY_QP_COUNTER_SET: - return "QUERY_QP_COUNTER_SET"; - case MLX5_CMD_OP_CREATE_PSV: return "CREATE_PSV"; case MLX5_CMD_OP_DESTROY_PSV: return "DESTROY_PSV"; - case MLX5_CMD_OP_QUERY_PSV: - return "QUERY_PSV"; - - case MLX5_CMD_OP_QUERY_SIG_RULE_TABLE: - return "QUERY_SIG_RULE_TABLE"; - - case MLX5_CMD_OP_QUERY_BLOCK_SIZE_TABLE: - return "QUERY_BLOCK_SIZE_TABLE"; - case MLX5_CMD_OP_CREATE_SRQ: return "CREATE_SRQ"; @@ -1538,16 +1502,9 @@ static const char *cmd_status_str(u8 status) } } -int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr) +static int cmd_status_to_err(u8 status) { - if (!hdr->status) - return 0; - - pr_warn("command failed, status %s(0x%x), syndrome 0x%x\n", - cmd_status_str(hdr->status), hdr->status, - be32_to_cpu(hdr->syndrome)); - - switch (hdr->status) { + switch (status) { case MLX5_CMD_STAT_OK: return 0; case MLX5_CMD_STAT_INT_ERR: return -EIO; case MLX5_CMD_STAT_BAD_OP_ERR: return -EINVAL; @@ -1567,3 +1524,33 @@ int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr) default: return -EIO; } } + +/* this will be available till all the commands use set/get macros */ +int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr) +{ + if (!hdr->status) + return 0; + + pr_warn("command failed, status %s(0x%x), syndrome 0x%x\n", + cmd_status_str(hdr->status), hdr->status, + be32_to_cpu(hdr->syndrome)); + + return cmd_status_to_err(hdr->status); +} + +int mlx5_cmd_status_to_err_v2(void *ptr) +{ + u32 syndrome; + u8 status; + + status = be32_to_cpu(*(__be32 *)ptr) >> 24; + if (!status) + return 0; + + syndrome = be32_to_cpu(*(__be32 *)(ptr + 4)); + + pr_warn("command failed, status %s(0x%x), syndrome 0x%x\n", + cmd_status_str(status), status, syndrome); + + return cmd_status_to_err(status); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 4e8bd0b34bb0..ed53291468f3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -198,7 +198,7 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) int eqes_found = 0; int set_ci = 0; u32 cqn; - u32 srqn; + u32 rsn; u8 port; while ((eqe = next_eqe_sw(eq))) { @@ -224,18 +224,18 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) case MLX5_EVENT_TYPE_PATH_MIG_FAILED: case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR: case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR: + rsn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff; mlx5_core_dbg(dev, "event %s(%d) arrived\n", eqe_type_str(eqe->type), eqe->type); - mlx5_qp_event(dev, be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff, - eqe->type); + mlx5_rsc_event(dev, rsn, eqe->type); break; case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT: case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR: - srqn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff; + rsn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff; mlx5_core_dbg(dev, "SRQ event %s(%d): srqn 0x%x\n", - eqe_type_str(eqe->type), eqe->type, srqn); - mlx5_srq_event(dev, srqn, eqe->type); + eqe_type_str(eqe->type), eqe->type, rsn); + mlx5_srq_event(dev, rsn, eqe->type); break; case MLX5_EVENT_TYPE_CMD: @@ -468,7 +468,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev) err = mlx5_create_map_eq(dev, &table->pages_eq, MLX5_EQ_VEC_PAGES, - dev->caps.max_vf + 1, + dev->caps.gen.max_vf + 1, 1 << MLX5_EVENT_TYPE_PAGE_REQUEST, "mlx5_pages_eq", &dev->priv.uuari.uars[0]); if (err) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index f012658b6a92..087c4c797deb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -64,86 +64,9 @@ out_out: return err; } -int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev, - struct mlx5_caps *caps) +int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev, struct mlx5_caps *caps) { - struct mlx5_cmd_query_hca_cap_mbox_out *out; - struct mlx5_cmd_query_hca_cap_mbox_in in; - struct mlx5_query_special_ctxs_mbox_out ctx_out; - struct mlx5_query_special_ctxs_mbox_in ctx_in; - int err; - u16 t16; - - out = kzalloc(sizeof(*out), GFP_KERNEL); - if (!out) - return -ENOMEM; - - memset(&in, 0, sizeof(in)); - in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_HCA_CAP); - in.hdr.opmod = cpu_to_be16(0x1); - err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out)); - if (err) - goto out_out; - - if (out->hdr.status) { - err = mlx5_cmd_status_to_err(&out->hdr); - goto out_out; - } - - - caps->log_max_eq = out->hca_cap.log_max_eq & 0xf; - caps->max_cqes = 1 << out->hca_cap.log_max_cq_sz; - caps->max_wqes = 1 << out->hca_cap.log_max_qp_sz; - caps->max_sq_desc_sz = be16_to_cpu(out->hca_cap.max_desc_sz_sq); - caps->max_rq_desc_sz = be16_to_cpu(out->hca_cap.max_desc_sz_rq); - caps->flags = be64_to_cpu(out->hca_cap.flags); - caps->stat_rate_support = be16_to_cpu(out->hca_cap.stat_rate_support); - caps->log_max_msg = out->hca_cap.log_max_msg & 0x1f; - caps->num_ports = out->hca_cap.num_ports & 0xf; - caps->log_max_cq = out->hca_cap.log_max_cq & 0x1f; - if (caps->num_ports > MLX5_MAX_PORTS) { - mlx5_core_err(dev, "device has %d ports while the driver supports max %d ports\n", - caps->num_ports, MLX5_MAX_PORTS); - err = -EINVAL; - goto out_out; - } - caps->log_max_qp = out->hca_cap.log_max_qp & 0x1f; - caps->log_max_mkey = out->hca_cap.log_max_mkey & 0x3f; - caps->log_max_pd = out->hca_cap.log_max_pd & 0x1f; - caps->log_max_srq = out->hca_cap.log_max_srqs & 0x1f; - caps->local_ca_ack_delay = out->hca_cap.local_ca_ack_delay & 0x1f; - caps->log_max_mcg = out->hca_cap.log_max_mcg; - caps->max_qp_mcg = be32_to_cpu(out->hca_cap.max_qp_mcg) & 0xffffff; - caps->max_ra_res_qp = 1 << (out->hca_cap.log_max_ra_res_qp & 0x3f); - caps->max_ra_req_qp = 1 << (out->hca_cap.log_max_ra_req_qp & 0x3f); - caps->max_srq_wqes = 1 << out->hca_cap.log_max_srq_sz; - t16 = be16_to_cpu(out->hca_cap.bf_log_bf_reg_size); - if (t16 & 0x8000) { - caps->bf_reg_size = 1 << (t16 & 0x1f); - caps->bf_regs_per_page = MLX5_BF_REGS_PER_PAGE; - } else { - caps->bf_reg_size = 0; - caps->bf_regs_per_page = 0; - } - caps->min_page_sz = ~(u32)((1 << out->hca_cap.log_pg_sz) - 1); - - memset(&ctx_in, 0, sizeof(ctx_in)); - memset(&ctx_out, 0, sizeof(ctx_out)); - ctx_in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS); - err = mlx5_cmd_exec(dev, &ctx_in, sizeof(ctx_in), - &ctx_out, sizeof(ctx_out)); - if (err) - goto out_out; - - if (ctx_out.hdr.status) - err = mlx5_cmd_status_to_err(&ctx_out.hdr); - - caps->reserved_lkey = be32_to_cpu(ctx_out.reserved_lkey); - -out_out: - kfree(out); - - return err; + return mlx5_core_get_caps(dev, caps, HCA_CAP_OPMOD_GET_CUR); } int mlx5_cmd_init_hca(struct mlx5_core_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index f2716cc1f51d..3d8e8e489b2d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -43,6 +43,7 @@ #include <linux/mlx5/qp.h> #include <linux/mlx5/srq.h> #include <linux/debugfs.h> +#include <linux/mlx5/mlx5_ifc.h> #include "mlx5_core.h" #define DRIVER_NAME "mlx5_core" @@ -207,11 +208,11 @@ static void release_bar(struct pci_dev *pdev) static int mlx5_enable_msix(struct mlx5_core_dev *dev) { struct mlx5_eq_table *table = &dev->priv.eq_table; - int num_eqs = 1 << dev->caps.log_max_eq; + int num_eqs = 1 << dev->caps.gen.log_max_eq; int nvec; int i; - nvec = dev->caps.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE; + nvec = dev->caps.gen.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE; nvec = min_t(int, nvec, num_eqs); if (nvec <= MLX5_EQ_VEC_COMP_BASE) return -ENOMEM; @@ -250,91 +251,205 @@ struct mlx5_reg_host_endianess { #define CAP_MASK(pos, size) ((u64)((1 << (size)) - 1) << (pos)) enum { - MLX5_CAP_BITS_RW_MASK = CAP_MASK(MLX5_CAP_OFF_CMDIF_CSUM, 2) | - CAP_MASK(MLX5_CAP_OFF_DCT, 1), + MLX5_CAP_BITS_RW_MASK = CAP_MASK(MLX5_CAP_OFF_CMDIF_CSUM, 2) | + MLX5_DEV_CAP_FLAG_DCT, }; +static u16 to_fw_pkey_sz(u32 size) +{ + switch (size) { + case 128: + return 0; + case 256: + return 1; + case 512: + return 2; + case 1024: + return 3; + case 2048: + return 4; + case 4096: + return 5; + default: + pr_warn("invalid pkey table size %d\n", size); + return 0; + } +} + /* selectively copy writable fields clearing any reserved area */ -static void copy_rw_fields(struct mlx5_hca_cap *to, struct mlx5_hca_cap *from) +static void copy_rw_fields(void *to, struct mlx5_caps *from) { + __be64 *flags_off = (__be64 *)MLX5_ADDR_OF(cmd_hca_cap, to, reserved_22); u64 v64; - to->log_max_qp = from->log_max_qp & 0x1f; - to->log_max_ra_req_dc = from->log_max_ra_req_dc & 0x3f; - to->log_max_ra_res_dc = from->log_max_ra_res_dc & 0x3f; - to->log_max_ra_req_qp = from->log_max_ra_req_qp & 0x3f; - to->log_max_ra_res_qp = from->log_max_ra_res_qp & 0x3f; - to->log_max_atomic_size_qp = from->log_max_atomic_size_qp; - to->log_max_atomic_size_dc = from->log_max_atomic_size_dc; - v64 = be64_to_cpu(from->flags) & MLX5_CAP_BITS_RW_MASK; - to->flags = cpu_to_be64(v64); + MLX5_SET(cmd_hca_cap, to, log_max_qp, from->gen.log_max_qp); + MLX5_SET(cmd_hca_cap, to, log_max_ra_req_qp, from->gen.log_max_ra_req_qp); + MLX5_SET(cmd_hca_cap, to, log_max_ra_res_qp, from->gen.log_max_ra_res_qp); + MLX5_SET(cmd_hca_cap, to, pkey_table_size, from->gen.pkey_table_size); + MLX5_SET(cmd_hca_cap, to, log_max_ra_req_dc, from->gen.log_max_ra_req_dc); + MLX5_SET(cmd_hca_cap, to, log_max_ra_res_dc, from->gen.log_max_ra_res_dc); + MLX5_SET(cmd_hca_cap, to, pkey_table_size, to_fw_pkey_sz(from->gen.pkey_table_size)); + v64 = from->gen.flags & MLX5_CAP_BITS_RW_MASK; + *flags_off = cpu_to_be64(v64); } -enum { - HCA_CAP_OPMOD_GET_MAX = 0, - HCA_CAP_OPMOD_GET_CUR = 1, -}; +static u16 get_pkey_table_size(int pkey) +{ + if (pkey > MLX5_MAX_LOG_PKEY_TABLE) + return 0; -static int handle_hca_cap(struct mlx5_core_dev *dev) + return MLX5_MIN_PKEY_TABLE_SIZE << pkey; +} + +static void fw2drv_caps(struct mlx5_caps *caps, void *out) +{ + struct mlx5_general_caps *gen = &caps->gen; + + gen->max_srq_wqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_srq_sz); + gen->max_wqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_qp_sz); + gen->log_max_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_qp); + gen->log_max_strq = MLX5_GET_PR(cmd_hca_cap, out, log_max_strq_sz); + gen->log_max_srq = MLX5_GET_PR(cmd_hca_cap, out, log_max_srqs); + gen->max_cqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_cq_sz); + gen->log_max_cq = MLX5_GET_PR(cmd_hca_cap, out, log_max_cq); + gen->max_eqes = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_max_eq_sz); + gen->log_max_mkey = MLX5_GET_PR(cmd_hca_cap, out, log_max_mkey); + gen->log_max_eq = MLX5_GET_PR(cmd_hca_cap, out, log_max_eq); + gen->max_indirection = MLX5_GET_PR(cmd_hca_cap, out, max_indirection); + gen->log_max_mrw_sz = MLX5_GET_PR(cmd_hca_cap, out, log_max_mrw_sz); + gen->log_max_bsf_list_size = MLX5_GET_PR(cmd_hca_cap, out, log_max_bsf_list_size); + gen->log_max_klm_list_size = MLX5_GET_PR(cmd_hca_cap, out, log_max_klm_list_size); + gen->log_max_ra_req_dc = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_req_dc); + gen->log_max_ra_res_dc = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_res_dc); + gen->log_max_ra_req_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_req_qp); + gen->log_max_ra_res_qp = MLX5_GET_PR(cmd_hca_cap, out, log_max_ra_res_qp); + gen->max_qp_counters = MLX5_GET_PR(cmd_hca_cap, out, max_qp_cnt); + gen->pkey_table_size = get_pkey_table_size(MLX5_GET_PR(cmd_hca_cap, out, pkey_table_size)); + gen->local_ca_ack_delay = MLX5_GET_PR(cmd_hca_cap, out, local_ca_ack_delay); + gen->num_ports = MLX5_GET_PR(cmd_hca_cap, out, num_ports); + gen->log_max_msg = MLX5_GET_PR(cmd_hca_cap, out, log_max_msg); + gen->stat_rate_support = MLX5_GET_PR(cmd_hca_cap, out, stat_rate_support); + gen->flags = be64_to_cpu(*(__be64 *)MLX5_ADDR_OF(cmd_hca_cap, out, reserved_22)); + pr_debug("flags = 0x%llx\n", gen->flags); + gen->uar_sz = MLX5_GET_PR(cmd_hca_cap, out, uar_sz); + gen->min_log_pg_sz = MLX5_GET_PR(cmd_hca_cap, out, log_pg_sz); + gen->bf_reg_size = MLX5_GET_PR(cmd_hca_cap, out, bf); + gen->bf_reg_size = 1 << MLX5_GET_PR(cmd_hca_cap, out, log_bf_reg_size); + gen->max_sq_desc_sz = MLX5_GET_PR(cmd_hca_cap, out, max_wqe_sz_sq); + gen->max_rq_desc_sz = MLX5_GET_PR(cmd_hca_cap, out, max_wqe_sz_rq); + gen->max_dc_sq_desc_sz = MLX5_GET_PR(cmd_hca_cap, out, max_wqe_sz_sq_dc); + gen->max_qp_mcg = MLX5_GET_PR(cmd_hca_cap, out, max_qp_mcg); + gen->log_max_pd = MLX5_GET_PR(cmd_hca_cap, out, log_max_pd); + gen->log_max_xrcd = MLX5_GET_PR(cmd_hca_cap, out, log_max_xrcd); + gen->log_uar_page_sz = MLX5_GET_PR(cmd_hca_cap, out, log_uar_page_sz); +} + +static const char *caps_opmod_str(u16 opmod) { - struct mlx5_cmd_query_hca_cap_mbox_out *query_out = NULL; - struct mlx5_cmd_set_hca_cap_mbox_in *set_ctx = NULL; - struct mlx5_cmd_query_hca_cap_mbox_in query_ctx; - struct mlx5_cmd_set_hca_cap_mbox_out set_out; - u64 flags; + switch (opmod) { + case HCA_CAP_OPMOD_GET_MAX: + return "GET_MAX"; + case HCA_CAP_OPMOD_GET_CUR: + return "GET_CUR"; + default: + return "Invalid"; + } +} + +int mlx5_core_get_caps(struct mlx5_core_dev *dev, struct mlx5_caps *caps, + u16 opmod) +{ + u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)]; + int out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out); + void *out; int err; - memset(&query_ctx, 0, sizeof(query_ctx)); - query_out = kzalloc(sizeof(*query_out), GFP_KERNEL); - if (!query_out) + memset(in, 0, sizeof(in)); + out = kzalloc(out_sz, GFP_KERNEL); + if (!out) return -ENOMEM; + MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); + MLX5_SET(query_hca_cap_in, in, op_mod, opmod); + err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz); + if (err) + goto query_ex; - set_ctx = kzalloc(sizeof(*set_ctx), GFP_KERNEL); - if (!set_ctx) { - err = -ENOMEM; + err = mlx5_cmd_status_to_err_v2(out); + if (err) { + mlx5_core_warn(dev, "query max hca cap failed, %d\n", err); goto query_ex; } + mlx5_core_dbg(dev, "%s\n", caps_opmod_str(opmod)); + fw2drv_caps(caps, MLX5_ADDR_OF(query_hca_cap_out, out, capability_struct)); + +query_ex: + kfree(out); + return err; +} - query_ctx.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_HCA_CAP); - query_ctx.hdr.opmod = cpu_to_be16(HCA_CAP_OPMOD_GET_CUR); - err = mlx5_cmd_exec(dev, &query_ctx, sizeof(query_ctx), - query_out, sizeof(*query_out)); +static int set_caps(struct mlx5_core_dev *dev, void *in, int in_sz) +{ + u32 out[MLX5_ST_SZ_DW(set_hca_cap_out)]; + int err; + + memset(out, 0, sizeof(out)); + + MLX5_SET(set_hca_cap_in, in, opcode, MLX5_CMD_OP_SET_HCA_CAP); + err = mlx5_cmd_exec(dev, in, in_sz, out, sizeof(out)); if (err) - goto query_ex; + return err; - err = mlx5_cmd_status_to_err(&query_out->hdr); - if (err) { - mlx5_core_warn(dev, "query hca cap failed, %d\n", err); + err = mlx5_cmd_status_to_err_v2(out); + + return err; +} + +static int handle_hca_cap(struct mlx5_core_dev *dev) +{ + void *set_ctx = NULL; + struct mlx5_profile *prof = dev->profile; + struct mlx5_caps *cur_caps = NULL; + struct mlx5_caps *max_caps = NULL; + int err = -ENOMEM; + int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in); + + set_ctx = kzalloc(set_sz, GFP_KERNEL); + if (!set_ctx) goto query_ex; - } - copy_rw_fields(&set_ctx->hca_cap, &query_out->hca_cap); + max_caps = kzalloc(sizeof(*max_caps), GFP_KERNEL); + if (!max_caps) + goto query_ex; - if (dev->profile && dev->profile->mask & MLX5_PROF_MASK_QP_SIZE) - set_ctx->hca_cap.log_max_qp = dev->profile->log_max_qp; + cur_caps = kzalloc(sizeof(*cur_caps), GFP_KERNEL); + if (!cur_caps) + goto query_ex; - flags = be64_to_cpu(query_out->hca_cap.flags); - /* disable checksum */ - flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM; - - set_ctx->hca_cap.flags = cpu_to_be64(flags); - memset(&set_out, 0, sizeof(set_out)); - set_ctx->hca_cap.log_uar_page_sz = cpu_to_be16(PAGE_SHIFT - 12); - set_ctx->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_SET_HCA_CAP); - err = mlx5_cmd_exec(dev, set_ctx, sizeof(*set_ctx), - &set_out, sizeof(set_out)); - if (err) { - mlx5_core_warn(dev, "set hca cap failed, %d\n", err); + err = mlx5_core_get_caps(dev, max_caps, HCA_CAP_OPMOD_GET_MAX); + if (err) goto query_ex; - } - err = mlx5_cmd_status_to_err(&set_out.hdr); + err = mlx5_core_get_caps(dev, cur_caps, HCA_CAP_OPMOD_GET_CUR); if (err) goto query_ex; + /* we limit the size of the pkey table to 128 entries for now */ + cur_caps->gen.pkey_table_size = 128; + + if (prof->mask & MLX5_PROF_MASK_QP_SIZE) + cur_caps->gen.log_max_qp = prof->log_max_qp; + + /* disable checksum */ + cur_caps->gen.flags &= ~MLX5_DEV_CAP_FLAG_CMDIF_CSUM; + + copy_rw_fields(MLX5_ADDR_OF(set_hca_cap_in, set_ctx, hca_capability_struct), + cur_caps); + err = set_caps(dev, set_ctx, set_sz); + query_ex: - kfree(query_out); + kfree(cur_caps); + kfree(max_caps); kfree(set_ctx); return err; @@ -782,6 +897,7 @@ static void remove_one(struct pci_dev *pdev) static const struct pci_device_id mlx5_core_pci_table[] = { { PCI_VDEVICE(MELLANOX, 4113) }, /* MT4113 Connect-IB */ + { PCI_VDEVICE(MELLANOX, 4115) }, /* ConnectX-4 */ { 0, } }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 8145b4668229..5261a2b0da43 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -39,28 +39,53 @@ #include "mlx5_core.h" -void mlx5_qp_event(struct mlx5_core_dev *dev, u32 qpn, int event_type) +static struct mlx5_core_rsc_common *mlx5_get_rsc(struct mlx5_core_dev *dev, + u32 rsn) { struct mlx5_qp_table *table = &dev->priv.qp_table; - struct mlx5_core_qp *qp; + struct mlx5_core_rsc_common *common; spin_lock(&table->lock); - qp = radix_tree_lookup(&table->tree, qpn); - if (qp) - atomic_inc(&qp->refcount); + common = radix_tree_lookup(&table->tree, rsn); + if (common) + atomic_inc(&common->refcount); spin_unlock(&table->lock); - if (!qp) { - mlx5_core_warn(dev, "Async event for bogus QP 0x%x\n", qpn); - return; + if (!common) { + mlx5_core_warn(dev, "Async event for bogus resource 0x%x\n", + rsn); + return NULL; } + return common; +} - qp->event(qp, event_type); +void mlx5_core_put_rsc(struct mlx5_core_rsc_common *common) +{ + if (atomic_dec_and_test(&common->refcount)) + complete(&common->free); +} + +void mlx5_rsc_event(struct mlx5_core_dev *dev, u32 rsn, int event_type) +{ + struct mlx5_core_rsc_common *common = mlx5_get_rsc(dev, rsn); + struct mlx5_core_qp *qp; + + if (!common) + return; + + switch (common->res) { + case MLX5_RES_QP: + qp = (struct mlx5_core_qp *)common; + qp->event(qp, event_type); + break; + + default: + mlx5_core_warn(dev, "invalid resource type for 0x%x\n", rsn); + } - if (atomic_dec_and_test(&qp->refcount)) - complete(&qp->free); + mlx5_core_put_rsc(common); } int mlx5_core_create_qp(struct mlx5_core_dev *dev, @@ -92,6 +117,7 @@ int mlx5_core_create_qp(struct mlx5_core_dev *dev, qp->qpn = be32_to_cpu(out.qpn) & 0xffffff; mlx5_core_dbg(dev, "qpn = 0x%x\n", qp->qpn); + qp->common.res = MLX5_RES_QP; spin_lock_irq(&table->lock); err = radix_tree_insert(&table->tree, qp->qpn, qp); spin_unlock_irq(&table->lock); @@ -106,9 +132,9 @@ int mlx5_core_create_qp(struct mlx5_core_dev *dev, qp->qpn); qp->pid = current->pid; - atomic_set(&qp->refcount, 1); + atomic_set(&qp->common.refcount, 1); atomic_inc(&dev->num_qps); - init_completion(&qp->free); + init_completion(&qp->common.free); return 0; @@ -138,9 +164,8 @@ int mlx5_core_destroy_qp(struct mlx5_core_dev *dev, radix_tree_delete(&table->tree, qp->qpn); spin_unlock_irqrestore(&table->lock, flags); - if (atomic_dec_and_test(&qp->refcount)) - complete(&qp->free); - wait_for_completion(&qp->free); + mlx5_core_put_rsc((struct mlx5_core_rsc_common *)qp); + wait_for_completion(&qp->common.free); memset(&in, 0, sizeof(in)); memset(&out, 0, sizeof(out)); @@ -184,13 +209,10 @@ int mlx5_core_qp_modify(struct mlx5_core_dev *dev, enum mlx5_qp_state cur_state, [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_RTS2RTS_QP, - [MLX5_QP_STATE_SQD] = MLX5_CMD_OP_RTS2SQD_QP, }, [MLX5_QP_STATE_SQD] = { [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, - [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_SQD2RTS_QP, - [MLX5_QP_STATE_SQD] = MLX5_CMD_OP_SQD2SQD_QP, }, [MLX5_QP_STATE_SQER] = { [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c index 68f5d9c77c7b..0a6348cefc01 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c @@ -174,11 +174,11 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari) for (i = 0; i < tot_uuars; i++) { bf = &uuari->bfs[i]; - bf->buf_size = dev->caps.bf_reg_size / 2; + bf->buf_size = dev->caps.gen.bf_reg_size / 2; bf->uar = &uuari->uars[i / MLX5_BF_REGS_PER_PAGE]; bf->regreg = uuari->uars[i / MLX5_BF_REGS_PER_PAGE].map; bf->reg = NULL; /* Add WC support */ - bf->offset = (i % MLX5_BF_REGS_PER_PAGE) * dev->caps.bf_reg_size + + bf->offset = (i % MLX5_BF_REGS_PER_PAGE) * dev->caps.gen.bf_reg_size + MLX5_BF_OFFSET; bf->need_lock = need_uuar_lock(i); spin_lock_init(&bf->lock); diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c index 2f12c88c66ab..bde1b70f473b 100644 --- a/drivers/net/ethernet/moxa/moxart_ether.c +++ b/drivers/net/ethernet/moxa/moxart_ether.c @@ -511,7 +511,6 @@ static int moxart_mac_probe(struct platform_device *pdev) goto init_fail; } - ether_setup(ndev); ndev->netdev_ops = &moxart_netdev_ops; netif_napi_add(ndev, &priv->napi, moxart_rx_poll, RX_DESC_NUM); ndev->priv_flags |= IFF_UNICAST_FLT; diff --git a/drivers/net/ethernet/netx-eth.c b/drivers/net/ethernet/netx-eth.c index 31eb911e4763..8176c8a1cc6a 100644 --- a/drivers/net/ethernet/netx-eth.c +++ b/drivers/net/ethernet/netx-eth.c @@ -315,8 +315,6 @@ static int netx_eth_enable(struct net_device *ndev) unsigned int mac4321, mac65; int running, i; - ether_setup(ndev); - ndev->netdev_ops = &netx_eth_netdev_ops; ndev->watchdog_timeo = msecs_to_jiffies(5000); diff --git a/drivers/net/ethernet/nuvoton/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c index 79645f74b3a8..379b7fbded78 100644 --- a/drivers/net/ethernet/nuvoton/w90p910_ether.c +++ b/drivers/net/ethernet/nuvoton/w90p910_ether.c @@ -943,7 +943,6 @@ static int w90p910_ether_setup(struct net_device *dev) { struct w90p910_ether *ether = netdev_priv(dev); - ether_setup(dev); dev->netdev_ops = &w90p910_ether_netdev_ops; dev->ethtool_ops = &w90p910_ether_ethtool_ops; diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index a44a03c45014..66fd868152e5 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1377,9 +1377,6 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) goto err_out_iounmap; } - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(ndev); - /* Setup driver functions */ ndev->netdev_ops = &lpc_netdev_ops; ndev->ethtool_ops = &lpc_eth_ethtool_ops; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index 32058614151a..5c4068353f66 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c @@ -135,6 +135,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter) int i, j; struct nx_host_tx_ring *tx_ring = adapter->tx_ring; + spin_lock(&adapter->tx_clean_lock); cmd_buf = tx_ring->cmd_buf_arr; for (i = 0; i < tx_ring->num_desc; i++) { buffrag = cmd_buf->frag_array; @@ -158,6 +159,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter) } cmd_buf++; } + spin_unlock(&adapter->tx_clean_lock); } void netxen_free_sw_resources(struct netxen_adapter *adapter) @@ -1792,9 +1794,9 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) break; } - if (count && netif_running(netdev)) { - tx_ring->sw_consumer = sw_consumer; + tx_ring->sw_consumer = sw_consumer; + if (count && netif_running(netdev)) { smp_mb(); if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 32456c79cc73..0b2a1ccd276d 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -1186,7 +1186,6 @@ __netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) return; smp_mb(); - spin_lock(&adapter->tx_clean_lock); netif_carrier_off(netdev); netif_tx_disable(netdev); @@ -1204,7 +1203,6 @@ __netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev) netxen_napi_disable(adapter); netxen_release_tx_buffers(adapter); - spin_unlock(&adapter->tx_clean_lock); } /* Usage: During suspend and firmware recovery module */ diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 9a2cfe4efac6..2bb48d57e7a5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -1177,9 +1177,8 @@ static void qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter *adapter) { u32 idc_params, val; - if (qlcnic_83xx_lockless_flash_read32(adapter, - QLC_83XX_IDC_FLASH_PARAM_ADDR, - (u8 *)&idc_params, 1)) { + if (qlcnic_83xx_flash_read32(adapter, QLC_83XX_IDC_FLASH_PARAM_ADDR, + (u8 *)&idc_params, 1)) { dev_info(&adapter->pdev->dev, "%s:failed to get IDC params from flash\n", __func__); adapter->dev_init_timeo = QLC_83XX_IDC_INIT_TIMEOUT_SECS; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 141f116eb868..494e8105adee 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -1333,21 +1333,21 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev, struct qlcnic_host_tx_ring *tx_ring; struct qlcnic_esw_statistics port_stats; struct qlcnic_mac_statistics mac_stats; - int index, ret, length, size, tx_size, ring; + int index, ret, length, size, ring; char *p; - tx_size = adapter->drv_tx_rings * QLCNIC_TX_STATS_LEN; + memset(data, 0, stats->n_stats * sizeof(u64)); - memset(data, 0, tx_size * sizeof(u64)); for (ring = 0, index = 0; ring < adapter->drv_tx_rings; ring++) { - if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { + if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) { tx_ring = &adapter->tx_ring[ring]; data = qlcnic_fill_tx_queue_stats(data, tx_ring); qlcnic_update_stats(adapter); + } else { + data += QLCNIC_TX_STATS_LEN; } } - memset(data, 0, stats->n_stats * sizeof(u64)); length = QLCNIC_STATS_LEN; for (index = 0; index < length; index++) { p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset; diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 74eb520e2649..2c811f66d5ac 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -810,8 +810,6 @@ qcaspi_netdev_setup(struct net_device *dev) { struct qcaspi *qca = NULL; - ether_setup(dev); - dev->netdev_ops = &qcaspi_netdev_ops; qcaspi_set_ethtool_ops(dev); dev->watchdog_timeo = QCASPI_TX_TIMEOUT; diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 1d81238fcb93..54476ba42477 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -969,59 +969,6 @@ DECLARE_RTL_COND(rtl_eriar_cond) return RTL_R32(ERIAR) & ERIAR_FLAG; } -static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd) -{ - void __iomem *ioaddr = tp->mmio_addr; - - RTL_W8(ERIDR, cmd); - RTL_W32(ERIAR, 0x800010e8); - msleep(2); - - if (!rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 5)) - return; - - ocp_write(tp, 0x1, 0x30, 0x00000001); -} - -#define OOB_CMD_RESET 0x00 -#define OOB_CMD_DRIVER_START 0x05 -#define OOB_CMD_DRIVER_STOP 0x06 - -static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp) -{ - return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10; -} - -DECLARE_RTL_COND(rtl_ocp_read_cond) -{ - u16 reg; - - reg = rtl8168_get_ocp_reg(tp); - - return ocp_read(tp, 0x0f, reg) & 0x00000800; -} - -static void rtl8168_driver_start(struct rtl8169_private *tp) -{ - rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START); - - rtl_msleep_loop_wait_high(tp, &rtl_ocp_read_cond, 10, 10); -} - -static void rtl8168_driver_stop(struct rtl8169_private *tp) -{ - rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP); - - rtl_msleep_loop_wait_low(tp, &rtl_ocp_read_cond, 10, 10); -} - -static int r8168dp_check_dash(struct rtl8169_private *tp) -{ - u16 reg = rtl8168_get_ocp_reg(tp); - - return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0; -} - static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg) { if (reg & 0xffff0001) { @@ -1246,12 +1193,12 @@ static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value) rtl_writephy(tp, reg_addr, rtl_readphy(tp, reg_addr) | value); } -static void rtl_w1w0_phy(struct rtl8169_private *tp, int reg_addr, int p, int m) +static void rtl_w0w1_phy(struct rtl8169_private *tp, int reg_addr, int p, int m) { int val; val = rtl_readphy(tp, reg_addr); - rtl_writephy(tp, reg_addr, (val | p) & ~m); + rtl_writephy(tp, reg_addr, (val & ~m) | p); } static void rtl_mdio_write(struct net_device *dev, int phy_id, int location, @@ -1320,7 +1267,7 @@ static u32 rtl_eri_read(struct rtl8169_private *tp, int addr, int type) RTL_R32(ERIDR) : ~0; } -static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p, +static void rtl_w0w1_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p, u32 m, int type) { u32 val; @@ -1329,6 +1276,52 @@ static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p, rtl_eri_write(tp, addr, mask, (val & ~m) | p, type); } +static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd) +{ + rtl_eri_write(tp, 0xe8, ERIAR_MASK_0001, cmd, ERIAR_EXGMAC); + + ocp_write(tp, 0x1, 0x30, 0x00000001); +} + +#define OOB_CMD_RESET 0x00 +#define OOB_CMD_DRIVER_START 0x05 +#define OOB_CMD_DRIVER_STOP 0x06 + +static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp) +{ + return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10; +} + +DECLARE_RTL_COND(rtl_ocp_read_cond) +{ + u16 reg; + + reg = rtl8168_get_ocp_reg(tp); + + return ocp_read(tp, 0x0f, reg) & 0x00000800; +} + +static void rtl8168_driver_start(struct rtl8169_private *tp) +{ + rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START); + + rtl_msleep_loop_wait_high(tp, &rtl_ocp_read_cond, 10, 10); +} + +static void rtl8168_driver_stop(struct rtl8169_private *tp) +{ + rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP); + + rtl_msleep_loop_wait_low(tp, &rtl_ocp_read_cond, 10, 10); +} + +static int r8168_check_dash(struct rtl8169_private *tp) +{ + u16 reg = rtl8168_get_ocp_reg(tp); + + return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0; +} + struct exgmac_reg { u16 addr; u16 mask; @@ -1473,9 +1466,9 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp) ERIAR_EXGMAC); } /* Reset packet filter */ - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 || tp->mac_version == RTL_GIGA_MAC_VER_36) { @@ -1546,8 +1539,20 @@ static u32 __rtl8169_get_wol(struct rtl8169_private *tp) if (options & LinkUp) wolopts |= WAKE_PHY; switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_35: + case RTL_GIGA_MAC_VER_36: + case RTL_GIGA_MAC_VER_37: + case RTL_GIGA_MAC_VER_38: + case RTL_GIGA_MAC_VER_40: + case RTL_GIGA_MAC_VER_41: + case RTL_GIGA_MAC_VER_42: + case RTL_GIGA_MAC_VER_43: + case RTL_GIGA_MAC_VER_44: case RTL_GIGA_MAC_VER_45: case RTL_GIGA_MAC_VER_46: + case RTL_GIGA_MAC_VER_47: + case RTL_GIGA_MAC_VER_48: if (rtl_eri_read(tp, 0xdc, ERIAR_EXGMAC) & MagicPacket_v2) wolopts |= WAKE_MAGIC; break; @@ -1601,18 +1606,30 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) RTL_W8(Cfg9346, Cfg9346_Unlock); switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_35: + case RTL_GIGA_MAC_VER_36: + case RTL_GIGA_MAC_VER_37: + case RTL_GIGA_MAC_VER_38: + case RTL_GIGA_MAC_VER_40: + case RTL_GIGA_MAC_VER_41: + case RTL_GIGA_MAC_VER_42: + case RTL_GIGA_MAC_VER_43: + case RTL_GIGA_MAC_VER_44: case RTL_GIGA_MAC_VER_45: case RTL_GIGA_MAC_VER_46: + case RTL_GIGA_MAC_VER_47: + case RTL_GIGA_MAC_VER_48: tmp = ARRAY_SIZE(cfg) - 1; if (wolopts & WAKE_MAGIC) - rtl_w1w0_eri(tp, + rtl_w0w1_eri(tp, 0x0dc, ERIAR_MASK_0100, MagicPacket_v2, 0x0000, ERIAR_EXGMAC); else - rtl_w1w0_eri(tp, + rtl_w0w1_eri(tp, 0x0dc, ERIAR_MASK_0100, 0x0000, @@ -2877,8 +2894,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) * Fine Tune Switching regulator parameter */ rtl_writephy(tp, 0x1f, 0x0002); - rtl_w1w0_phy(tp, 0x0b, 0x0010, 0x00ef); - rtl_w1w0_phy(tp, 0x0c, 0xa200, 0x5d00); + rtl_w0w1_phy(tp, 0x0b, 0x0010, 0x00ef); + rtl_w0w1_phy(tp, 0x0c, 0xa200, 0x5d00); if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) { static const struct phy_reg phy_reg_init[] = { @@ -2927,8 +2944,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) /* Fine tune PLL performance */ rtl_writephy(tp, 0x1f, 0x0002); - rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600); - rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000); + rtl_w0w1_phy(tp, 0x02, 0x0100, 0x0600); + rtl_w0w1_phy(tp, 0x03, 0x0000, 0xe000); rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x001b); @@ -3025,8 +3042,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) /* Fine tune PLL performance */ rtl_writephy(tp, 0x1f, 0x0002); - rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600); - rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000); + rtl_w0w1_phy(tp, 0x02, 0x0100, 0x0600); + rtl_w0w1_phy(tp, 0x03, 0x0000, 0xe000); /* Switching regulator Slew rate */ rtl_writephy(tp, 0x1f, 0x0002); @@ -3154,32 +3171,32 @@ static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) /* DCO enable for 10M IDLE Power */ rtl_writephy(tp, 0x1f, 0x0007); rtl_writephy(tp, 0x1e, 0x0023); - rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000); + rtl_w0w1_phy(tp, 0x17, 0x0006, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); /* For impedance matching */ rtl_writephy(tp, 0x1f, 0x0002); - rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00); + rtl_w0w1_phy(tp, 0x08, 0x8000, 0x7f00); rtl_writephy(tp, 0x1f, 0x0000); /* PHY auto speed down */ rtl_writephy(tp, 0x1f, 0x0007); rtl_writephy(tp, 0x1e, 0x002d); - rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000); + rtl_w0w1_phy(tp, 0x18, 0x0050, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); - rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); + rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b86); - rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000); + rtl_w0w1_phy(tp, 0x06, 0x0001, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b85); - rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000); + rtl_w0w1_phy(tp, 0x06, 0x0000, 0x2000); rtl_writephy(tp, 0x1f, 0x0007); rtl_writephy(tp, 0x1e, 0x0020); - rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100); + rtl_w0w1_phy(tp, 0x15, 0x0000, 0x1100); rtl_writephy(tp, 0x1f, 0x0006); rtl_writephy(tp, 0x00, 0x5a00); rtl_writephy(tp, 0x1f, 0x0000); @@ -3243,39 +3260,39 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) /* For 4-corner performance improve */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b80); - rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000); + rtl_w0w1_phy(tp, 0x17, 0x0006, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); /* PHY auto speed down */ rtl_writephy(tp, 0x1f, 0x0004); rtl_writephy(tp, 0x1f, 0x0007); rtl_writephy(tp, 0x1e, 0x002d); - rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000); + rtl_w0w1_phy(tp, 0x18, 0x0010, 0x0000); rtl_writephy(tp, 0x1f, 0x0002); rtl_writephy(tp, 0x1f, 0x0000); - rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); + rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); /* improve 10M EEE waveform */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b86); - rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000); + rtl_w0w1_phy(tp, 0x06, 0x0001, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); /* Improve 2-pair detection performance */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b85); - rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000); + rtl_w0w1_phy(tp, 0x06, 0x4000, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); /* EEE setting */ - rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0000, 0x0003, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0000, 0x0003, ERIAR_EXGMAC); rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b85); - rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000); + rtl_w0w1_phy(tp, 0x06, 0x0000, 0x2000); rtl_writephy(tp, 0x1f, 0x0004); rtl_writephy(tp, 0x1f, 0x0007); rtl_writephy(tp, 0x1e, 0x0020); - rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100); + rtl_w0w1_phy(tp, 0x15, 0x0000, 0x0100); rtl_writephy(tp, 0x1f, 0x0002); rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, 0x0d, 0x0007); @@ -3286,8 +3303,8 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) /* Green feature */ rtl_writephy(tp, 0x1f, 0x0003); - rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001); - rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400); + rtl_w0w1_phy(tp, 0x19, 0x0000, 0x0001); + rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0400); rtl_writephy(tp, 0x1f, 0x0000); /* Broken BIOS workaround: feed GigaMAC registers with MAC address. */ @@ -3299,20 +3316,20 @@ static void rtl8168f_hw_phy_config(struct rtl8169_private *tp) /* For 4-corner performance improve */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b80); - rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000); + rtl_w0w1_phy(tp, 0x06, 0x0006, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); /* PHY auto speed down */ rtl_writephy(tp, 0x1f, 0x0007); rtl_writephy(tp, 0x1e, 0x002d); - rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000); + rtl_w0w1_phy(tp, 0x18, 0x0010, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); - rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); + rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); /* Improve 10M EEE waveform */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b86); - rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000); + rtl_w0w1_phy(tp, 0x06, 0x0001, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); } @@ -3362,7 +3379,7 @@ static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp) /* Improve 2-pair detection performance */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b85); - rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000); + rtl_w0w1_phy(tp, 0x06, 0x4000, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); } @@ -3418,7 +3435,7 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp) /* Improve 2-pair detection performance */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b85); - rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000); + rtl_w0w1_phy(tp, 0x06, 0x4000, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); @@ -3426,36 +3443,36 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp) /* Modify green table for giga */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b54); - rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800); + rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0800); rtl_writephy(tp, 0x05, 0x8b5d); - rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800); + rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0800); rtl_writephy(tp, 0x05, 0x8a7c); - rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100); + rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0100); rtl_writephy(tp, 0x05, 0x8a7f); - rtl_w1w0_phy(tp, 0x06, 0x0100, 0x0000); + rtl_w0w1_phy(tp, 0x06, 0x0100, 0x0000); rtl_writephy(tp, 0x05, 0x8a82); - rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100); + rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0100); rtl_writephy(tp, 0x05, 0x8a85); - rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100); + rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0100); rtl_writephy(tp, 0x05, 0x8a88); - rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100); + rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0100); rtl_writephy(tp, 0x1f, 0x0000); /* uc same-seed solution */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b85); - rtl_w1w0_phy(tp, 0x06, 0x8000, 0x0000); + rtl_w0w1_phy(tp, 0x06, 0x8000, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); /* eee setting */ - rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC); rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b85); - rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000); + rtl_w0w1_phy(tp, 0x06, 0x0000, 0x2000); rtl_writephy(tp, 0x1f, 0x0004); rtl_writephy(tp, 0x1f, 0x0007); rtl_writephy(tp, 0x1e, 0x0020); - rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100); + rtl_w0w1_phy(tp, 0x15, 0x0000, 0x0100); rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, 0x0d, 0x0007); rtl_writephy(tp, 0x0e, 0x003c); @@ -3465,8 +3482,8 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp) /* Green feature */ rtl_writephy(tp, 0x1f, 0x0003); - rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001); - rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400); + rtl_w0w1_phy(tp, 0x19, 0x0000, 0x0001); + rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0400); rtl_writephy(tp, 0x1f, 0x0000); } @@ -3477,45 +3494,45 @@ static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0a46); if (rtl_readphy(tp, 0x10) & 0x0100) { rtl_writephy(tp, 0x1f, 0x0bcc); - rtl_w1w0_phy(tp, 0x12, 0x0000, 0x8000); + rtl_w0w1_phy(tp, 0x12, 0x0000, 0x8000); } else { rtl_writephy(tp, 0x1f, 0x0bcc); - rtl_w1w0_phy(tp, 0x12, 0x8000, 0x0000); + rtl_w0w1_phy(tp, 0x12, 0x8000, 0x0000); } rtl_writephy(tp, 0x1f, 0x0a46); if (rtl_readphy(tp, 0x13) & 0x0100) { rtl_writephy(tp, 0x1f, 0x0c41); - rtl_w1w0_phy(tp, 0x15, 0x0002, 0x0000); + rtl_w0w1_phy(tp, 0x15, 0x0002, 0x0000); } else { rtl_writephy(tp, 0x1f, 0x0c41); - rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0002); + rtl_w0w1_phy(tp, 0x15, 0x0000, 0x0002); } /* Enable PHY auto speed down */ rtl_writephy(tp, 0x1f, 0x0a44); - rtl_w1w0_phy(tp, 0x11, 0x000c, 0x0000); + rtl_w0w1_phy(tp, 0x11, 0x000c, 0x0000); rtl_writephy(tp, 0x1f, 0x0bcc); - rtl_w1w0_phy(tp, 0x14, 0x0100, 0x0000); + rtl_w0w1_phy(tp, 0x14, 0x0100, 0x0000); rtl_writephy(tp, 0x1f, 0x0a44); - rtl_w1w0_phy(tp, 0x11, 0x00c0, 0x0000); + rtl_w0w1_phy(tp, 0x11, 0x00c0, 0x0000); rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x8084); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x6000); - rtl_w1w0_phy(tp, 0x10, 0x1003, 0x0000); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x6000); + rtl_w0w1_phy(tp, 0x10, 0x1003, 0x0000); /* EEE auto-fallback function */ rtl_writephy(tp, 0x1f, 0x0a4b); - rtl_w1w0_phy(tp, 0x11, 0x0004, 0x0000); + rtl_w0w1_phy(tp, 0x11, 0x0004, 0x0000); /* Enable UC LPF tune function */ rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x8012); - rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); + rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); rtl_writephy(tp, 0x1f, 0x0c42); - rtl_w1w0_phy(tp, 0x11, 0x4000, 0x2000); + rtl_w0w1_phy(tp, 0x11, 0x4000, 0x2000); /* Improve SWR Efficiency */ rtl_writephy(tp, 0x1f, 0x0bcd); @@ -3531,7 +3548,7 @@ static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp) /* Check ALDPS bit, disable it if enabled */ rtl_writephy(tp, 0x1f, 0x0a43); if (rtl_readphy(tp, 0x10) & 0x0004) - rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0004); + rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0004); rtl_writephy(tp, 0x1f, 0x0000); } @@ -3551,33 +3568,33 @@ static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp) /* CHN EST parameters adjust - giga master */ rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x809b); - rtl_w1w0_phy(tp, 0x14, 0x8000, 0xf800); + rtl_w0w1_phy(tp, 0x14, 0x8000, 0xf800); rtl_writephy(tp, 0x13, 0x80a2); - rtl_w1w0_phy(tp, 0x14, 0x8000, 0xff00); + rtl_w0w1_phy(tp, 0x14, 0x8000, 0xff00); rtl_writephy(tp, 0x13, 0x80a4); - rtl_w1w0_phy(tp, 0x14, 0x8500, 0xff00); + rtl_w0w1_phy(tp, 0x14, 0x8500, 0xff00); rtl_writephy(tp, 0x13, 0x809c); - rtl_w1w0_phy(tp, 0x14, 0xbd00, 0xff00); + rtl_w0w1_phy(tp, 0x14, 0xbd00, 0xff00); rtl_writephy(tp, 0x1f, 0x0000); /* CHN EST parameters adjust - giga slave */ rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x80ad); - rtl_w1w0_phy(tp, 0x14, 0x7000, 0xf800); + rtl_w0w1_phy(tp, 0x14, 0x7000, 0xf800); rtl_writephy(tp, 0x13, 0x80b4); - rtl_w1w0_phy(tp, 0x14, 0x5000, 0xff00); + rtl_w0w1_phy(tp, 0x14, 0x5000, 0xff00); rtl_writephy(tp, 0x13, 0x80ac); - rtl_w1w0_phy(tp, 0x14, 0x4000, 0xff00); + rtl_w0w1_phy(tp, 0x14, 0x4000, 0xff00); rtl_writephy(tp, 0x1f, 0x0000); /* CHN EST parameters adjust - fnet */ rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x808e); - rtl_w1w0_phy(tp, 0x14, 0x1200, 0xff00); + rtl_w0w1_phy(tp, 0x14, 0x1200, 0xff00); rtl_writephy(tp, 0x13, 0x8090); - rtl_w1w0_phy(tp, 0x14, 0xe500, 0xff00); + rtl_w0w1_phy(tp, 0x14, 0xe500, 0xff00); rtl_writephy(tp, 0x13, 0x8092); - rtl_w1w0_phy(tp, 0x14, 0x9f00, 0xff00); + rtl_w0w1_phy(tp, 0x14, 0x9f00, 0xff00); rtl_writephy(tp, 0x1f, 0x0000); /* enable R-tune & PGA-retune function */ @@ -3596,57 +3613,57 @@ static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp) dout_tapbin &= 0xf000; rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x827a); - rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000); + rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000); rtl_writephy(tp, 0x13, 0x827b); - rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000); + rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000); rtl_writephy(tp, 0x13, 0x827c); - rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000); + rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000); rtl_writephy(tp, 0x13, 0x827d); - rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000); + rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000); rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x0811); - rtl_w1w0_phy(tp, 0x14, 0x0800, 0x0000); + rtl_w0w1_phy(tp, 0x14, 0x0800, 0x0000); rtl_writephy(tp, 0x1f, 0x0a42); - rtl_w1w0_phy(tp, 0x16, 0x0002, 0x0000); + rtl_w0w1_phy(tp, 0x16, 0x0002, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); /* enable GPHY 10M */ rtl_writephy(tp, 0x1f, 0x0a44); - rtl_w1w0_phy(tp, 0x11, 0x0800, 0x0000); + rtl_w0w1_phy(tp, 0x11, 0x0800, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); /* SAR ADC performance */ rtl_writephy(tp, 0x1f, 0x0bca); - rtl_w1w0_phy(tp, 0x17, 0x4000, 0x3000); + rtl_w0w1_phy(tp, 0x17, 0x4000, 0x3000); rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x803f); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); rtl_writephy(tp, 0x13, 0x8047); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); rtl_writephy(tp, 0x13, 0x804f); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); rtl_writephy(tp, 0x13, 0x8057); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); rtl_writephy(tp, 0x13, 0x805f); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); rtl_writephy(tp, 0x13, 0x8067); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); rtl_writephy(tp, 0x13, 0x806f); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); rtl_writephy(tp, 0x1f, 0x0000); /* disable phy pfm mode */ rtl_writephy(tp, 0x1f, 0x0a44); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x0080); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x0080); rtl_writephy(tp, 0x1f, 0x0000); /* Check ALDPS bit, disable it if enabled */ rtl_writephy(tp, 0x1f, 0x0a43); if (rtl_readphy(tp, 0x10) & 0x0004) - rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0004); + rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0004); rtl_writephy(tp, 0x1f, 0x0000); } @@ -3662,20 +3679,20 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp) /* CHIN EST parameter update */ rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x808a); - rtl_w1w0_phy(tp, 0x14, 0x000a, 0x003f); + rtl_w0w1_phy(tp, 0x14, 0x000a, 0x003f); rtl_writephy(tp, 0x1f, 0x0000); /* enable R-tune & PGA-retune function */ rtl_writephy(tp, 0x1f, 0x0a43); rtl_writephy(tp, 0x13, 0x0811); - rtl_w1w0_phy(tp, 0x14, 0x0800, 0x0000); + rtl_w0w1_phy(tp, 0x14, 0x0800, 0x0000); rtl_writephy(tp, 0x1f, 0x0a42); - rtl_w1w0_phy(tp, 0x16, 0x0002, 0x0000); + rtl_w0w1_phy(tp, 0x16, 0x0002, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); /* enable GPHY 10M */ rtl_writephy(tp, 0x1f, 0x0a44); - rtl_w1w0_phy(tp, 0x11, 0x0800, 0x0000); + rtl_w0w1_phy(tp, 0x11, 0x0800, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); r8168_mac_ocp_write(tp, 0xdd02, 0x807d); @@ -3692,8 +3709,8 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp) ioffset_p0 |= (data & (0x07)); data = (ioffset_p3<<12)|(ioffset_p2<<8)|(ioffset_p1<<4)|(ioffset_p0); - if ((ioffset_p3 != 0x0F) || (ioffset_p2 != 0x0F) || - (ioffset_p1 != 0x0F) || (ioffset_p0 == 0x0F)) { + if ((ioffset_p3 != 0x0f) || (ioffset_p2 != 0x0f) || + (ioffset_p1 != 0x0f) || (ioffset_p0 == 0x0f)) { rtl_writephy(tp, 0x1f, 0x0bcf); rtl_writephy(tp, 0x16, data); rtl_writephy(tp, 0x1f, 0x0000); @@ -3713,13 +3730,13 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp) /* disable phy pfm mode */ rtl_writephy(tp, 0x1f, 0x0a44); - rtl_w1w0_phy(tp, 0x14, 0x0000, 0x0080); + rtl_w0w1_phy(tp, 0x14, 0x0000, 0x0080); rtl_writephy(tp, 0x1f, 0x0000); /* Check ALDPS bit, disable it if enabled */ rtl_writephy(tp, 0x1f, 0x0a43); if (rtl_readphy(tp, 0x10) & 0x0004) - rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0004); + rtl_w0w1_phy(tp, 0x10, 0x0000, 0x0004); rtl_writephy(tp, 0x1f, 0x0000); } @@ -4265,7 +4282,7 @@ static void r810x_pll_power_up(struct rtl8169_private *tp) break; case RTL_GIGA_MAC_VER_47: case RTL_GIGA_MAC_VER_48: - RTL_W8(PMCH, RTL_R8(PMCH) | 0xC0); + RTL_W8(PMCH, RTL_R8(PMCH) | 0xc0); break; default: RTL_W8(PMCH, RTL_R8(PMCH) | 0x80); @@ -4340,7 +4357,7 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) if ((tp->mac_version == RTL_GIGA_MAC_VER_27 || tp->mac_version == RTL_GIGA_MAC_VER_28 || tp->mac_version == RTL_GIGA_MAC_VER_31) && - r8168dp_check_dash(tp)) { + r8168_check_dash(tp)) { return; } @@ -4367,14 +4384,16 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_31: case RTL_GIGA_MAC_VER_32: case RTL_GIGA_MAC_VER_33: + case RTL_GIGA_MAC_VER_44: case RTL_GIGA_MAC_VER_45: case RTL_GIGA_MAC_VER_46: RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80); break; case RTL_GIGA_MAC_VER_40: case RTL_GIGA_MAC_VER_41: - rtl_w1w0_eri(tp, 0x1a8, ERIAR_MASK_1111, 0x00000000, + rtl_w0w1_eri(tp, 0x1a8, ERIAR_MASK_1111, 0x00000000, 0xfc000000, ERIAR_EXGMAC); + RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80); break; } } @@ -4393,13 +4412,15 @@ static void r8168_pll_power_up(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_33: RTL_W8(PMCH, RTL_R8(PMCH) | 0x80); break; + case RTL_GIGA_MAC_VER_44: case RTL_GIGA_MAC_VER_45: case RTL_GIGA_MAC_VER_46: - RTL_W8(PMCH, RTL_R8(PMCH) | 0xC0); + RTL_W8(PMCH, RTL_R8(PMCH) | 0xc0); break; case RTL_GIGA_MAC_VER_40: case RTL_GIGA_MAC_VER_41: - rtl_w1w0_eri(tp, 0x1a8, ERIAR_MASK_1111, 0xfc000000, + RTL_W8(PMCH, RTL_R8(PMCH) | 0xc0); + rtl_w0w1_eri(tp, 0x1a8, ERIAR_MASK_1111, 0xfc000000, 0x00000000, ERIAR_EXGMAC); break; } @@ -4712,6 +4733,8 @@ static void rtl_hw_reset(struct rtl8169_private *tp) RTL_W8(ChipCmd, CmdReset); rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); + + netdev_reset_queue(tp->dev); } static void rtl_request_uncached_firmware(struct rtl8169_private *tp) @@ -4975,7 +4998,7 @@ static void rtl_hw_start_8169(struct net_device *dev) if (tp->mac_version == RTL_GIGA_MAC_VER_02 || tp->mac_version == RTL_GIGA_MAC_VER_03) { - dprintk("Set MAC Reg C+CR Offset 0xE0. " + dprintk("Set MAC Reg C+CR Offset 0xe0. " "Bit-3 and bit-14 MUST be 1\n"); tp->cp_cmd |= (1 << 14); } @@ -5010,7 +5033,7 @@ static void rtl_hw_start_8169(struct net_device *dev) rtl_set_rx_mode(dev); /* no early-rx interrupts */ - RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000); } static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value) @@ -5473,8 +5496,8 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp) rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC); rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC); rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x07ff0060, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC); RTL_W8(MaxTxPacketSize, EarlySize); @@ -5504,10 +5527,10 @@ static void rtl_hw_start_8168f(struct rtl8169_private *tp) rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC); rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC); rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC); rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC); @@ -5536,7 +5559,7 @@ static void rtl_hw_start_8168f_1(struct rtl8169_private *tp) rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1)); - rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC); /* Adjust EEE LED frequency */ RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07); @@ -5556,7 +5579,7 @@ static void rtl_hw_start_8411(struct rtl8169_private *tp) rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1)); - rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0x0000, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0x0000, ERIAR_EXGMAC); } static void rtl_hw_start_8168g_1(struct rtl8169_private *tp) @@ -5575,8 +5598,8 @@ static void rtl_hw_start_8168g_1(struct rtl8169_private *tp) rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); rtl_eri_write(tp, 0x2f8, ERIAR_MASK_0011, 0x1d8f, ERIAR_EXGMAC); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); @@ -5589,8 +5612,8 @@ static void rtl_hw_start_8168g_1(struct rtl8169_private *tp) /* Adjust EEE LED frequency */ RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07); - rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x06, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x06, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC); rtl_pcie_state_l2l3_enable(tp, false); } @@ -5663,12 +5686,12 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp) rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_1111, 0x0010, 0x00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_1111, 0x0010, 0x00, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0xd4, ERIAR_MASK_1111, 0x1f00, 0x00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xd4, ERIAR_MASK_1111, 0x1f00, 0x00, ERIAR_EXGMAC); rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87, ERIAR_EXGMAC); @@ -5687,7 +5710,7 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp) RTL_W8(DLLPR, RTL_R8(DLLPR) & ~TX_10M_PS_EN); - rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC); rtl_pcie_state_l2l3_enable(tp, false); @@ -5858,7 +5881,7 @@ static void rtl_hw_start_8168(struct net_device *dev) rtl_set_rx_mode(dev); - RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); + RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000); } #define R810X_CPCMD_QUIRK_MASK (\ @@ -5981,11 +6004,11 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp) rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00000002, ERIAR_EXGMAC); rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00000006, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); - rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, ERIAR_EXGMAC); + rtl_w0w1_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, ERIAR_EXGMAC); rtl_pcie_state_l2l3_enable(tp, false); } @@ -6592,6 +6615,8 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, txd->opts2 = cpu_to_le32(opts[1]); + netdev_sent_queue(dev, skb->len); + skb_tx_timestamp(skb); wmb(); @@ -6691,6 +6716,7 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev) static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) { unsigned int dirty_tx, tx_left; + unsigned int bytes_compl = 0, pkts_compl = 0; dirty_tx = tp->dirty_tx; smp_rmb(); @@ -6709,10 +6735,8 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb, tp->TxDescArray + entry); if (status & LastFrag) { - u64_stats_update_begin(&tp->tx_stats.syncp); - tp->tx_stats.packets++; - tp->tx_stats.bytes += tx_skb->skb->len; - u64_stats_update_end(&tp->tx_stats.syncp); + pkts_compl++; + bytes_compl += tx_skb->skb->len; dev_kfree_skb_any(tx_skb->skb); tx_skb->skb = NULL; } @@ -6721,6 +6745,13 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) } if (tp->dirty_tx != dirty_tx) { + netdev_completed_queue(tp->dev, pkts_compl, bytes_compl); + + u64_stats_update_begin(&tp->tx_stats.syncp); + tp->tx_stats.packets += pkts_compl; + tp->tx_stats.bytes += bytes_compl; + u64_stats_update_end(&tp->tx_stats.syncp); + tp->dirty_tx = dirty_tx; /* Sync with rtl8169_start_xmit: * - publish dirty_tx ring index (write barrier) @@ -7366,9 +7397,10 @@ static void rtl_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct rtl8169_private *tp = netdev_priv(dev); - if (tp->mac_version == RTL_GIGA_MAC_VER_27 || - tp->mac_version == RTL_GIGA_MAC_VER_28 || - tp->mac_version == RTL_GIGA_MAC_VER_31) { + if ((tp->mac_version == RTL_GIGA_MAC_VER_27 || + tp->mac_version == RTL_GIGA_MAC_VER_28 || + tp->mac_version == RTL_GIGA_MAC_VER_31) && + r8168_check_dash(tp)) { rtl8168_driver_stop(tp); } @@ -7662,8 +7694,20 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) RTL_W8(Config1, RTL_R8(Config1) | PMEnable); RTL_W8(Config5, RTL_R8(Config5) & (BWF | MWF | UWF | LanWake | PMEStatus)); switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_35: + case RTL_GIGA_MAC_VER_36: + case RTL_GIGA_MAC_VER_37: + case RTL_GIGA_MAC_VER_38: + case RTL_GIGA_MAC_VER_40: + case RTL_GIGA_MAC_VER_41: + case RTL_GIGA_MAC_VER_42: + case RTL_GIGA_MAC_VER_43: + case RTL_GIGA_MAC_VER_44: case RTL_GIGA_MAC_VER_45: case RTL_GIGA_MAC_VER_46: + case RTL_GIGA_MAC_VER_47: + case RTL_GIGA_MAC_VER_48: if (rtl_eri_read(tp, 0xdc, ERIAR_EXGMAC) & MagicPacket_v2) tp->features |= RTL_FEATURE_WOL; if ((RTL_R8(Config3) & LinkUp) != 0) @@ -7700,14 +7744,23 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) u64_stats_init(&tp->tx_stats.syncp); /* Get MAC address */ - if (tp->mac_version == RTL_GIGA_MAC_VER_45 || + if (tp->mac_version == RTL_GIGA_MAC_VER_35 || + tp->mac_version == RTL_GIGA_MAC_VER_36 || + tp->mac_version == RTL_GIGA_MAC_VER_37 || + tp->mac_version == RTL_GIGA_MAC_VER_38 || + tp->mac_version == RTL_GIGA_MAC_VER_40 || + tp->mac_version == RTL_GIGA_MAC_VER_41 || + tp->mac_version == RTL_GIGA_MAC_VER_42 || + tp->mac_version == RTL_GIGA_MAC_VER_43 || + tp->mac_version == RTL_GIGA_MAC_VER_44 || + tp->mac_version == RTL_GIGA_MAC_VER_45 || tp->mac_version == RTL_GIGA_MAC_VER_46 || tp->mac_version == RTL_GIGA_MAC_VER_47 || tp->mac_version == RTL_GIGA_MAC_VER_48) { u16 mac_addr[3]; - *(u32 *)&mac_addr[0] = rtl_eri_read(tp, 0xE0, ERIAR_EXGMAC); - *(u16 *)&mac_addr[2] = rtl_eri_read(tp, 0xE4, ERIAR_EXGMAC); + *(u32 *)&mac_addr[0] = rtl_eri_read(tp, 0xe0, ERIAR_EXGMAC); + *(u16 *)&mac_addr[2] = rtl_eri_read(tp, 0xe4, ERIAR_EXGMAC); if (is_valid_ether_addr((u8 *)mac_addr)) rtl_rar_set(tp, (u8 *)mac_addr); @@ -7780,9 +7833,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_chip_infos[chipset].jumbo_tx_csum ? "ok" : "ko"); } - if (tp->mac_version == RTL_GIGA_MAC_VER_27 || - tp->mac_version == RTL_GIGA_MAC_VER_28 || - tp->mac_version == RTL_GIGA_MAC_VER_31) { + if ((tp->mac_version == RTL_GIGA_MAC_VER_27 || + tp->mac_version == RTL_GIGA_MAC_VER_28 || + tp->mac_version == RTL_GIGA_MAC_VER_31) && + r8168_check_dash(tp)) { rtl8168_driver_start(tp); } diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index 9778cba9fc74..e88df9c7f1c0 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -1927,9 +1927,6 @@ static int smc911x_probe(struct net_device *dev) } dev->irq = irq_canonicalize(dev->irq); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - dev->netdev_ops = &smc911x_netdev_ops; dev->watchdog_timeo = msecs_to_jiffies(watchdog); dev->ethtool_ops = &smc911x_ethtool_ops; diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index bcaa41af1e62..5e94d00b96b3 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -1967,9 +1967,6 @@ static int smc_probe(struct net_device *dev, void __iomem *ioaddr, } dev->irq = irq_canonicalize(dev->irq); - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - dev->watchdog_timeo = msecs_to_jiffies(watchdog); dev->netdev_ops = &smc_netdev_ops; dev->ethtool_ops = &smc_ethtool_ops; diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 5e13fa5524ae..affb29da353e 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -2255,7 +2255,6 @@ static int smsc911x_init(struct net_device *dev) if (smsc911x_soft_reset(pdata)) return -ENODEV; - ether_setup(dev); dev->flags |= IFF_MULTICAST; netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT); dev->netdev_ops = &smsc911x_netdev_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9dbb02d9d9c2..6f77a46c7e2c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2765,8 +2765,6 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, priv->device = device; priv->dev = ndev; - ether_setup(ndev); - stmmac_set_ethtool_ops(ndev); priv->pause = pause; priv->plat = plat_dat; @@ -2786,8 +2784,15 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, if (IS_ERR(priv->stmmac_clk)) { dev_warn(priv->device, "%s: warning: cannot get CSR clock\n", __func__); - ret = PTR_ERR(priv->stmmac_clk); - goto error_clk_get; + /* If failed to obtain stmmac_clk and specific clk_csr value + * is NOT passed from the platform, probe fail. + */ + if (!priv->plat->clk_csr) { + ret = PTR_ERR(priv->stmmac_clk); + goto error_clk_get; + } else { + priv->stmmac_clk = NULL; + } } clk_prepare_enable(priv->stmmac_clk); diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 126269762ee7..15396720f489 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -1073,7 +1073,7 @@ out_dropped: if (pending) (void)mod_timer(&port->clean_timer, jiffies + VNET_CLEAN_TIMEOUT); - else + else if (port) del_timer(&port->clean_timer); dev->stats.tx_dropped++; return NETDEV_TX_OK; diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c index 104d46f37969..0f56b1c0e082 100644 --- a/drivers/net/ethernet/wiznet/w5100.c +++ b/drivers/net/ethernet/wiznet/w5100.c @@ -708,7 +708,6 @@ static int w5100_probe(struct platform_device *pdev) priv = netdev_priv(ndev); priv->ndev = ndev; - ether_setup(ndev); ndev->netdev_ops = &w5100_netdev_ops; ndev->ethtool_ops = &w5100_ethtool_ops; ndev->watchdog_timeo = HZ; diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c index 1f33c4c86c20..f961f14a0473 100644 --- a/drivers/net/ethernet/wiznet/w5300.c +++ b/drivers/net/ethernet/wiznet/w5300.c @@ -620,7 +620,6 @@ static int w5300_probe(struct platform_device *pdev) priv = netdev_priv(ndev); priv->ndev = ndev; - ether_setup(ndev); ndev->netdev_ops = &w5300_netdev_ops; ndev->ethtool_ops = &w5300_ethtool_ops; ndev->watchdog_timeo = HZ; diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index fda5891835d4..629077050fce 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -1012,7 +1012,6 @@ static int temac_of_probe(struct platform_device *op) if (!ndev) return -ENOMEM; - ether_setup(ndev); platform_set_drvdata(op, ndev); SET_NETDEV_DEV(ndev, &op->dev); ndev->flags &= ~IFF_MULTICAST; /* clear multicast */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index a9c5eaadc426..0fcb5e7eb073 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -387,6 +387,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) int hdr_offset; u32 net_trans_info; u32 hash; + u32 skb_length = skb->len; /* We will atmost need two pages to describe the rndis @@ -562,7 +563,7 @@ do_send: drop: if (ret == 0) { - net->stats.tx_bytes += skb->len; + net->stats.tx_bytes += skb_length; net->stats.tx_packets++; } else { kfree(packet); diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 8d101d63abca..a2c227bfb687 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -397,7 +397,7 @@ config MCS_FIR config SH_IRDA tristate "SuperH IrDA driver" depends on IRDA - depends on ARCH_SHMOBILE || COMPILE_TEST + depends on (ARCH_SHMOBILE || COMPILE_TEST) && HAS_IOMEM help Say Y here if your want to enable SuperH IrDA devices. diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 3381c4f91a8c..0c6adaaf898c 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -112,17 +112,15 @@ out: return err; } +/* Requires RTNL */ static int macvtap_set_queue(struct net_device *dev, struct file *file, struct macvtap_queue *q) { struct macvlan_dev *vlan = netdev_priv(dev); - int err = -EBUSY; - rtnl_lock(); if (vlan->numqueues == MAX_MACVTAP_QUEUES) - goto out; + return -EBUSY; - err = 0; rcu_assign_pointer(q->vlan, vlan); rcu_assign_pointer(vlan->taps[vlan->numvtaps], q); sock_hold(&q->sk); @@ -136,9 +134,7 @@ static int macvtap_set_queue(struct net_device *dev, struct file *file, vlan->numvtaps++; vlan->numqueues++; -out: - rtnl_unlock(); - return err; + return 0; } static int macvtap_disable_queue(struct macvtap_queue *q) @@ -454,11 +450,12 @@ static void macvtap_sock_destruct(struct sock *sk) static int macvtap_open(struct inode *inode, struct file *file) { struct net *net = current->nsproxy->net_ns; - struct net_device *dev = dev_get_by_macvtap_minor(iminor(inode)); + struct net_device *dev; struct macvtap_queue *q; - int err; + int err = -ENODEV; - err = -ENODEV; + rtnl_lock(); + dev = dev_get_by_macvtap_minor(iminor(inode)); if (!dev) goto out; @@ -498,6 +495,7 @@ out: if (dev) dev_put(dev); + rtnl_unlock(); return err; } diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index daae69950925..1d211d369039 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -350,6 +350,32 @@ static struct phy_driver bcm7xxx_driver[] = { BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"), BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"), { + .phy_id = PHY_ID_BCM7425, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM7425", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = 0, + .config_init = bcm7xxx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = bcm7xxx_suspend, + .resume = bcm7xxx_config_init, + .driver = { .owner = THIS_MODULE }, +}, { + .phy_id = PHY_ID_BCM7429, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM7429", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_IS_INTERNAL, + .config_init = bcm7xxx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = bcm7xxx_suspend, + .resume = bcm7xxx_config_init, + .driver = { .owner = THIS_MODULE }, +}, { .phy_id = PHY_BCM_OUI_4, .phy_id_mask = 0xffff0000, .name = "Broadcom BCM7XXX 40nm", @@ -381,6 +407,8 @@ static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { { PHY_ID_BCM7250, 0xfffffff0, }, { PHY_ID_BCM7364, 0xfffffff0, }, { PHY_ID_BCM7366, 0xfffffff0, }, + { PHY_ID_BCM7425, 0xfffffff0, }, + { PHY_ID_BCM7429, 0xfffffff0, }, { PHY_ID_BCM7439, 0xfffffff0, }, { PHY_ID_BCM7445, 0xfffffff0, }, { PHY_BCM_OUI_4, 0xffff0000 }, diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index a4d4c4a1354f..b9a98152815b 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -26,7 +26,7 @@ #include <linux/mdio.h> /* Version Information */ -#define DRIVER_VERSION "v1.06.0 (2014/03/03)" +#define DRIVER_VERSION "v1.06.1 (2014/10/01)" #define DRIVER_AUTHOR "Realtek linux nic maintainers <[email protected]>" #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" @@ -1979,10 +1979,34 @@ static void rxdy_gated_en(struct r8152 *tp, bool enable) ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); } +static int rtl_start_rx(struct r8152 *tp) +{ + int i, ret = 0; + + INIT_LIST_HEAD(&tp->rx_done); + for (i = 0; i < RTL8152_MAX_RX; i++) { + INIT_LIST_HEAD(&tp->rx_info[i].list); + ret = r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL); + if (ret) + break; + } + + return ret; +} + +static int rtl_stop_rx(struct r8152 *tp) +{ + int i; + + for (i = 0; i < RTL8152_MAX_RX; i++) + usb_kill_urb(tp->rx_info[i].urb); + + return 0; +} + static int rtl_enable(struct r8152 *tp) { u32 ocp_data; - int i, ret; r8152b_reset_packet_filter(tp); @@ -1992,14 +2016,7 @@ static int rtl_enable(struct r8152 *tp) rxdy_gated_en(tp, false); - INIT_LIST_HEAD(&tp->rx_done); - ret = 0; - for (i = 0; i < RTL8152_MAX_RX; i++) { - INIT_LIST_HEAD(&tp->rx_info[i].list); - ret |= r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL); - } - - return ret; + return rtl_start_rx(tp); } static int rtl8152_enable(struct r8152 *tp) @@ -2083,8 +2100,7 @@ static void rtl_disable(struct r8152 *tp) usleep_range(1000, 2000); } - for (i = 0; i < RTL8152_MAX_RX; i++) - usb_kill_urb(tp->rx_info[i].urb); + rtl_stop_rx(tp); rtl8152_nic_reset(tp); } @@ -2243,28 +2259,6 @@ static void rtl_phy_reset(struct r8152 *tp) } } -static void rtl_clear_bp(struct r8152 *tp) -{ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0); - usleep_range(3000, 6000); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0); - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0); -} - -static void r8153_clear_bp(struct r8152 *tp) -{ - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); - ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0); - rtl_clear_bp(tp); -} - static void r8153_teredo_off(struct r8152 *tp) { u32 ocp_data; @@ -2307,8 +2301,6 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp) r8152_mdio_write(tp, MII_BMCR, data); } - rtl_clear_bp(tp); - set_bit(PHY_RESET, &tp->flags); } @@ -2455,8 +2447,6 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) r8152_mdio_write(tp, MII_BMCR, data); } - r8153_clear_bp(tp); - if (tp->version == RTL_VER_03) { data = ocp_reg_read(tp, OCP_EEE_CFG); data &= ~CTAP_SHORT_EN; @@ -3181,13 +3171,14 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); + tasklet_disable(&tp->tl); if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + rtl_stop_rx(tp); rtl_runtime_suspend_enable(tp, true); } else { - tasklet_disable(&tp->tl); tp->rtl_ops.down(tp); - tasklet_enable(&tp->tl); } + tasklet_enable(&tp->tl); } return 0; @@ -3206,18 +3197,19 @@ static int rtl8152_resume(struct usb_interface *intf) if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { rtl_runtime_suspend_enable(tp, false); clear_bit(SELECTIVE_SUSPEND, &tp->flags); + set_bit(WORK_ENABLE, &tp->flags); if (tp->speed & LINK_STATUS) - tp->rtl_ops.disable(tp); + rtl_start_rx(tp); } else { tp->rtl_ops.up(tp); rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); + tp->speed = 0; + netif_carrier_off(tp->netdev); + set_bit(WORK_ENABLE, &tp->flags); } - tp->speed = 0; - netif_carrier_off(tp->netdev); - set_bit(WORK_ENABLE, &tp->flags); usb_submit_urb(tp->intr_urb, GFP_KERNEL); } @@ -3623,7 +3615,7 @@ static void rtl8153_unload(struct r8152 *tp) if (test_bit(RTL8152_UNPLUG, &tp->flags)) return; - r8153_power_cut_en(tp, true); + r8153_power_cut_en(tp, false); } static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) @@ -3788,7 +3780,11 @@ static void rtl8152_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (tp) { - set_bit(RTL8152_UNPLUG, &tp->flags); + struct usb_device *udev = tp->udev; + + if (udev->state == USB_STATE_NOTATTACHED) + set_bit(RTL8152_UNPLUG, &tp->flags); + tasklet_kill(&tp->tl); unregister_netdev(tp->netdev); tp->rtl_ops.unload(tp); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 34e102ec95c2..2af795d6ba05 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1610,6 +1610,8 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, vxh->vx_flags = htonl(VXLAN_FLAGS); vxh->vx_vni = vni; + skb_set_inner_protocol(skb, htons(ETH_P_TEB)); + udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio, ttl, src_port, dst_port); return 0; @@ -1652,6 +1654,8 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, vxh->vx_flags = htonl(VXLAN_FLAGS); vxh->vx_vni = vni; + skb_set_inner_protocol(skb, htons(ETH_P_TEB)); + return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos, ttl, df, src_port, dst_port, xnet); } diff --git a/drivers/of/base.c b/drivers/of/base.c index d8574adf0d62..293ed4b687ba 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -138,6 +138,9 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp) /* Important: Don't leak passwords */ bool secure = strncmp(pp->name, "security-", 9) == 0; + if (!IS_ENABLED(CONFIG_SYSFS)) + return 0; + if (!of_kset || !of_node_is_attached(np)) return 0; @@ -158,6 +161,9 @@ int __of_attach_node_sysfs(struct device_node *np) struct property *pp; int rc; + if (!IS_ENABLED(CONFIG_SYSFS)) + return 0; + if (!of_kset) return 0; @@ -1713,6 +1719,9 @@ int __of_remove_property(struct device_node *np, struct property *prop) void __of_remove_property_sysfs(struct device_node *np, struct property *prop) { + if (!IS_ENABLED(CONFIG_SYSFS)) + return; + /* at early boot, bail here and defer setup to of_init() */ if (of_kset && of_node_is_attached(np)) sysfs_remove_bin_file(&np->kobj, &prop->attr); @@ -1777,6 +1786,9 @@ int __of_update_property(struct device_node *np, struct property *newprop, void __of_update_property_sysfs(struct device_node *np, struct property *newprop, struct property *oldprop) { + if (!IS_ENABLED(CONFIG_SYSFS)) + return; + /* At early boot, bail out and defer setup to of_init() */ if (!of_kset) return; @@ -1847,6 +1859,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) { struct property *pp; + of_aliases = of_find_node_by_path("/aliases"); of_chosen = of_find_node_by_path("/chosen"); if (of_chosen == NULL) of_chosen = of_find_node_by_path("/chosen@0"); @@ -1862,7 +1875,6 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) of_stdout = of_find_node_by_path(name); } - of_aliases = of_find_node_by_path("/aliases"); if (!of_aliases) return; @@ -1986,7 +1998,7 @@ bool of_console_check(struct device_node *dn, char *name, int index) { if (!dn || dn != of_stdout || console_set_on_cmdline) return false; - return add_preferred_console(name, index, NULL); + return !add_preferred_console(name, index, NULL); } EXPORT_SYMBOL_GPL(of_console_check); diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 54fecc49a1fe..f297891d8529 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -45,6 +45,9 @@ void __of_detach_node_sysfs(struct device_node *np) { struct property *pp; + if (!IS_ENABLED(CONFIG_SYSFS)) + return; + BUG_ON(!of_node_is_initialized(np)); if (!of_kset) return; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 79cb8313c7d8..d1ffca8b34ea 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -928,7 +928,11 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) { const u64 phys_offset = __pa(PAGE_OFFSET); - base &= PAGE_MASK; + + if (!PAGE_ALIGNED(base)) { + size -= PAGE_SIZE - (base & ~PAGE_MASK); + base = PAGE_ALIGN(base); + } size &= PAGE_MASK; if (base > MAX_PHYS_ADDR) { @@ -937,10 +941,10 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) return; } - if (base + size > MAX_PHYS_ADDR) { - pr_warning("Ignoring memory range 0x%lx - 0x%llx\n", - ULONG_MAX, base + size); - size = MAX_PHYS_ADDR - base; + if (base + size - 1 > MAX_PHYS_ADDR) { + pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", + ((u64)MAX_PHYS_ADDR) + 1, base + size); + size = MAX_PHYS_ADDR - base + 1; } if (base + size < phys_offset) { diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 8225b89de810..c384fec6d173 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -232,6 +232,7 @@ static struct platform_driver efi_rtc_driver = { module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe); +MODULE_ALIAS("platform:rtc-efi"); MODULE_AUTHOR("dann frazier <[email protected]>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("EFI RTC driver"); diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c index 447458e696a9..7e1f120f2b32 100644 --- a/drivers/soc/qcom/qcom_gsbi.c +++ b/drivers/soc/qcom/qcom_gsbi.c @@ -22,44 +22,63 @@ #define GSBI_CTRL_REG 0x0000 #define GSBI_PROTOCOL_SHIFT 4 +struct gsbi_info { + struct clk *hclk; + u32 mode; + u32 crci; +}; + static int gsbi_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct resource *res; void __iomem *base; - struct clk *hclk; - u32 mode, crci = 0; + struct gsbi_info *gsbi; + + gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL); + + if (!gsbi) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); - if (of_property_read_u32(node, "qcom,mode", &mode)) { + if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) { dev_err(&pdev->dev, "missing mode configuration\n"); return -EINVAL; } /* not required, so default to 0 if not present */ - of_property_read_u32(node, "qcom,crci", &crci); + of_property_read_u32(node, "qcom,crci", &gsbi->crci); - dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n", mode, crci); + dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n", + gsbi->mode, gsbi->crci); + gsbi->hclk = devm_clk_get(&pdev->dev, "iface"); + if (IS_ERR(gsbi->hclk)) + return PTR_ERR(gsbi->hclk); - hclk = devm_clk_get(&pdev->dev, "iface"); - if (IS_ERR(hclk)) - return PTR_ERR(hclk); + clk_prepare_enable(gsbi->hclk); - clk_prepare_enable(hclk); - - writel_relaxed((mode << GSBI_PROTOCOL_SHIFT) | crci, + writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci, base + GSBI_CTRL_REG); /* make sure the gsbi control write is not reordered */ wmb(); - clk_disable_unprepare(hclk); + platform_set_drvdata(pdev, gsbi); + + return of_platform_populate(node, NULL, NULL, &pdev->dev); +} + +static int gsbi_remove(struct platform_device *pdev) +{ + struct gsbi_info *gsbi = platform_get_drvdata(pdev); + + clk_disable_unprepare(gsbi->hclk); - return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + return 0; } static const struct of_device_id gsbi_dt_match[] = { @@ -76,6 +95,7 @@ static struct platform_driver gsbi_driver = { .of_match_table = gsbi_dt_match, }, .probe = gsbi_probe, + .remove = gsbi_remove, }; module_platform_driver(gsbi_driver); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 35b494f5667f..ee256138b2c4 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -24,8 +24,6 @@ menuconfig STAGING if STAGING -source "drivers/staging/et131x/Kconfig" - source "drivers/staging/slicoss/Kconfig" source "drivers/staging/wlan-ng/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index e66a5dbd9b02..64bf31200c88 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_STAGING) += staging.o obj-y += media/ -obj-$(CONFIG_ET131X) += et131x/ obj-$(CONFIG_SLICOSS) += slicoss/ obj-$(CONFIG_PRISM2_USB) += wlan-ng/ obj-$(CONFIG_COMEDI) += comedi/ diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c index d749731dc0ee..fbb08e97438d 100644 --- a/fs/cachefiles/bind.c +++ b/fs/cachefiles/bind.c @@ -50,18 +50,18 @@ int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args) cache->brun_percent < 100); if (*args) { - pr_err("'bind' command doesn't take an argument"); + pr_err("'bind' command doesn't take an argument\n"); return -EINVAL; } if (!cache->rootdirname) { - pr_err("No cache directory specified"); + pr_err("No cache directory specified\n"); return -EINVAL; } /* don't permit already bound caches to be re-bound */ if (test_bit(CACHEFILES_READY, &cache->flags)) { - pr_err("Cache already bound"); + pr_err("Cache already bound\n"); return -EBUSY; } @@ -248,7 +248,7 @@ error_open_root: kmem_cache_free(cachefiles_object_jar, fsdef); error_root_object: cachefiles_end_secure(cache, saved_cred); - pr_err("Failed to register: %d", ret); + pr_err("Failed to register: %d\n", ret); return ret; } diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c index b078d3081d6c..ce1b115dcc28 100644 --- a/fs/cachefiles/daemon.c +++ b/fs/cachefiles/daemon.c @@ -315,7 +315,7 @@ static unsigned int cachefiles_daemon_poll(struct file *file, static int cachefiles_daemon_range_error(struct cachefiles_cache *cache, char *args) { - pr_err("Free space limits must be in range 0%%<=stop<cull<run<100%%"); + pr_err("Free space limits must be in range 0%%<=stop<cull<run<100%%\n"); return -EINVAL; } @@ -475,12 +475,12 @@ static int cachefiles_daemon_dir(struct cachefiles_cache *cache, char *args) _enter(",%s", args); if (!*args) { - pr_err("Empty directory specified"); + pr_err("Empty directory specified\n"); return -EINVAL; } if (cache->rootdirname) { - pr_err("Second cache directory specified"); + pr_err("Second cache directory specified\n"); return -EEXIST; } @@ -503,12 +503,12 @@ static int cachefiles_daemon_secctx(struct cachefiles_cache *cache, char *args) _enter(",%s", args); if (!*args) { - pr_err("Empty security context specified"); + pr_err("Empty security context specified\n"); return -EINVAL; } if (cache->secctx) { - pr_err("Second security context specified"); + pr_err("Second security context specified\n"); return -EINVAL; } @@ -531,7 +531,7 @@ static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args) _enter(",%s", args); if (!*args) { - pr_err("Empty tag specified"); + pr_err("Empty tag specified\n"); return -EINVAL; } @@ -562,12 +562,12 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) goto inval; if (!test_bit(CACHEFILES_READY, &cache->flags)) { - pr_err("cull applied to unready cache"); + pr_err("cull applied to unready cache\n"); return -EIO; } if (test_bit(CACHEFILES_DEAD, &cache->flags)) { - pr_err("cull applied to dead cache"); + pr_err("cull applied to dead cache\n"); return -EIO; } @@ -587,11 +587,11 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) notdir: path_put(&path); - pr_err("cull command requires dirfd to be a directory"); + pr_err("cull command requires dirfd to be a directory\n"); return -ENOTDIR; inval: - pr_err("cull command requires dirfd and filename"); + pr_err("cull command requires dirfd and filename\n"); return -EINVAL; } @@ -614,7 +614,7 @@ static int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args) return 0; inval: - pr_err("debug command requires mask"); + pr_err("debug command requires mask\n"); return -EINVAL; } @@ -634,12 +634,12 @@ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) goto inval; if (!test_bit(CACHEFILES_READY, &cache->flags)) { - pr_err("inuse applied to unready cache"); + pr_err("inuse applied to unready cache\n"); return -EIO; } if (test_bit(CACHEFILES_DEAD, &cache->flags)) { - pr_err("inuse applied to dead cache"); + pr_err("inuse applied to dead cache\n"); return -EIO; } @@ -659,11 +659,11 @@ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) notdir: path_put(&path); - pr_err("inuse command requires dirfd to be a directory"); + pr_err("inuse command requires dirfd to be a directory\n"); return -ENOTDIR; inval: - pr_err("inuse command requires dirfd and filename"); + pr_err("inuse command requires dirfd and filename\n"); return -EINVAL; } diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index 3d50998abf57..8c52472d2efa 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h @@ -255,7 +255,7 @@ extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache, #define cachefiles_io_error(___cache, FMT, ...) \ do { \ - pr_err("I/O Error: " FMT, ##__VA_ARGS__); \ + pr_err("I/O Error: " FMT"\n", ##__VA_ARGS__); \ fscache_io_error(&(___cache)->cache); \ set_bit(CACHEFILES_DEAD, &(___cache)->flags); \ } while (0) diff --git a/fs/cachefiles/main.c b/fs/cachefiles/main.c index 180edfb45f66..711f13d8c2de 100644 --- a/fs/cachefiles/main.c +++ b/fs/cachefiles/main.c @@ -84,7 +84,7 @@ error_proc: error_object_jar: misc_deregister(&cachefiles_dev); error_dev: - pr_err("failed to register: %d", ret); + pr_err("failed to register: %d\n", ret); return ret; } diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 83e9c94ca2cf..dad7d9542a24 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -543,7 +543,7 @@ lookup_again: next, next->d_inode, next->d_inode->i_ino); } else if (!S_ISDIR(next->d_inode->i_mode)) { - pr_err("inode %lu is not a directory", + pr_err("inode %lu is not a directory\n", next->d_inode->i_ino); ret = -ENOBUFS; goto error; @@ -574,7 +574,7 @@ lookup_again: } else if (!S_ISDIR(next->d_inode->i_mode) && !S_ISREG(next->d_inode->i_mode) ) { - pr_err("inode %lu is not a file or directory", + pr_err("inode %lu is not a file or directory\n", next->d_inode->i_ino); ret = -ENOBUFS; goto error; @@ -768,7 +768,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, ASSERT(subdir->d_inode); if (!S_ISDIR(subdir->d_inode->i_mode)) { - pr_err("%s is not a directory", dirname); + pr_err("%s is not a directory\n", dirname); ret = -EIO; goto check_error; } @@ -796,13 +796,13 @@ check_error: mkdir_error: mutex_unlock(&dir->d_inode->i_mutex); dput(subdir); - pr_err("mkdir %s failed with error %d", dirname, ret); + pr_err("mkdir %s failed with error %d\n", dirname, ret); return ERR_PTR(ret); lookup_error: mutex_unlock(&dir->d_inode->i_mutex); ret = PTR_ERR(subdir); - pr_err("Lookup %s failed with error %d", dirname, ret); + pr_err("Lookup %s failed with error %d\n", dirname, ret); return ERR_PTR(ret); nomem_d_alloc: @@ -892,7 +892,7 @@ lookup_error: if (ret == -EIO) { cachefiles_io_error(cache, "Lookup failed"); } else if (ret != -ENOMEM) { - pr_err("Internal error: %d", ret); + pr_err("Internal error: %d\n", ret); ret = -EIO; } @@ -951,7 +951,7 @@ error: } if (ret != -ENOMEM) { - pr_err("Internal error: %d", ret); + pr_err("Internal error: %d\n", ret); ret = -EIO; } diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c index 1ad51ffbb275..acbc1f094fb1 100644 --- a/fs/cachefiles/xattr.c +++ b/fs/cachefiles/xattr.c @@ -51,7 +51,7 @@ int cachefiles_check_object_type(struct cachefiles_object *object) } if (ret != -EEXIST) { - pr_err("Can't set xattr on %*.*s [%lu] (err %d)", + pr_err("Can't set xattr on %*.*s [%lu] (err %d)\n", dentry->d_name.len, dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino, -ret); @@ -64,7 +64,7 @@ int cachefiles_check_object_type(struct cachefiles_object *object) if (ret == -ERANGE) goto bad_type_length; - pr_err("Can't read xattr on %*.*s [%lu] (err %d)", + pr_err("Can't read xattr on %*.*s [%lu] (err %d)\n", dentry->d_name.len, dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino, -ret); @@ -85,14 +85,14 @@ error: return ret; bad_type_length: - pr_err("Cache object %lu type xattr length incorrect", + pr_err("Cache object %lu type xattr length incorrect\n", dentry->d_inode->i_ino); ret = -EIO; goto error; bad_type: xtype[2] = 0; - pr_err("Cache object %*.*s [%lu] type %s not %s", + pr_err("Cache object %*.*s [%lu] type %s not %s\n", dentry->d_name.len, dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino, xtype, type); @@ -293,7 +293,7 @@ error: return ret; bad_type_length: - pr_err("Cache object %lu xattr length incorrect", + pr_err("Cache object %lu xattr length incorrect\n", dentry->d_inode->i_ino); ret = -EIO; goto error; diff --git a/fs/dcache.c b/fs/dcache.c index 7a5b51440afa..cb25a1a5e307 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2372,7 +2372,8 @@ void dentry_update_name_case(struct dentry *dentry, struct qstr *name) } EXPORT_SYMBOL(dentry_update_name_case); -static void switch_names(struct dentry *dentry, struct dentry *target) +static void switch_names(struct dentry *dentry, struct dentry *target, + bool exchange) { if (dname_external(target)) { if (dname_external(dentry)) { @@ -2406,13 +2407,19 @@ static void switch_names(struct dentry *dentry, struct dentry *target) */ unsigned int i; BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long))); + if (!exchange) { + memcpy(dentry->d_iname, target->d_name.name, + target->d_name.len + 1); + dentry->d_name.hash_len = target->d_name.hash_len; + return; + } for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) { swap(((long *) &dentry->d_iname)[i], ((long *) &target->d_iname)[i]); } } } - swap(dentry->d_name.len, target->d_name.len); + swap(dentry->d_name.hash_len, target->d_name.hash_len); } static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) @@ -2442,25 +2449,29 @@ static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) } } -static void dentry_unlock_parents_for_move(struct dentry *dentry, - struct dentry *target) +static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target) { if (target->d_parent != dentry->d_parent) spin_unlock(&dentry->d_parent->d_lock); if (target->d_parent != target) spin_unlock(&target->d_parent->d_lock); + spin_unlock(&target->d_lock); + spin_unlock(&dentry->d_lock); } /* * When switching names, the actual string doesn't strictly have to * be preserved in the target - because we're dropping the target * anyway. As such, we can just do a simple memcpy() to copy over - * the new name before we switch. - * - * Note that we have to be a lot more careful about getting the hash - * switched - we have to switch the hash value properly even if it - * then no longer matches the actual (corrupted) string of the target. - * The hash value has to match the hash queue that the dentry is on.. + * the new name before we switch, unless we are going to rehash + * it. Note that if we *do* unhash the target, we are not allowed + * to rehash it without giving it a new name/hash key - whether + * we swap or overwrite the names here, resulting name won't match + * the reality in filesystem; it's only there for d_path() purposes. + * Note that all of this is happening under rename_lock, so the + * any hash lookup seeing it in the middle of manipulations will + * be discarded anyway. So we do not care what happens to the hash + * key in that case. */ /* * __d_move - move a dentry @@ -2506,36 +2517,30 @@ static void __d_move(struct dentry *dentry, struct dentry *target, d_hash(dentry->d_parent, dentry->d_name.hash)); } - list_del(&dentry->d_u.d_child); - list_del(&target->d_u.d_child); - /* Switch the names.. */ - switch_names(dentry, target); - swap(dentry->d_name.hash, target->d_name.hash); + switch_names(dentry, target, exchange); - /* ... and switch the parents */ + /* ... and switch them in the tree */ if (IS_ROOT(dentry)) { + /* splicing a tree */ dentry->d_parent = target->d_parent; target->d_parent = target; - INIT_LIST_HEAD(&target->d_u.d_child); + list_del_init(&target->d_u.d_child); + list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); } else { + /* swapping two dentries */ swap(dentry->d_parent, target->d_parent); - - /* And add them back to the (new) parent lists */ - list_add(&target->d_u.d_child, &target->d_parent->d_subdirs); + list_move(&target->d_u.d_child, &target->d_parent->d_subdirs); + list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); + if (exchange) + fsnotify_d_move(target); + fsnotify_d_move(dentry); } - list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); - write_seqcount_end(&target->d_seq); write_seqcount_end(&dentry->d_seq); - dentry_unlock_parents_for_move(dentry, target); - if (exchange) - fsnotify_d_move(target); - spin_unlock(&target->d_lock); - fsnotify_d_move(dentry); - spin_unlock(&dentry->d_lock); + dentry_unlock_for_move(dentry, target); } /* @@ -2633,45 +2638,6 @@ out_err: return ret; } -/* - * Prepare an anonymous dentry for life in the superblock's dentry tree as a - * named dentry in place of the dentry to be replaced. - * returns with anon->d_lock held! - */ -static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) -{ - struct dentry *dparent; - - dentry_lock_for_move(anon, dentry); - - write_seqcount_begin(&dentry->d_seq); - write_seqcount_begin_nested(&anon->d_seq, DENTRY_D_LOCK_NESTED); - - dparent = dentry->d_parent; - - switch_names(dentry, anon); - swap(dentry->d_name.hash, anon->d_name.hash); - - dentry->d_parent = dentry; - list_del_init(&dentry->d_u.d_child); - anon->d_parent = dparent; - if (likely(!d_unhashed(anon))) { - hlist_bl_lock(&anon->d_sb->s_anon); - __hlist_bl_del(&anon->d_hash); - anon->d_hash.pprev = NULL; - hlist_bl_unlock(&anon->d_sb->s_anon); - } - list_move(&anon->d_u.d_child, &dparent->d_subdirs); - - write_seqcount_end(&dentry->d_seq); - write_seqcount_end(&anon->d_seq); - - dentry_unlock_parents_for_move(anon, dentry); - spin_unlock(&dentry->d_lock); - - /* anon->d_lock still locked, returns locked */ -} - /** * d_splice_alias - splice a disconnected dentry into the tree if one exists * @inode: the inode which may have a disconnected dentry @@ -2717,10 +2683,8 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) return ERR_PTR(-EIO); } write_seqlock(&rename_lock); - __d_materialise_dentry(dentry, new); + __d_move(new, dentry, false); write_sequnlock(&rename_lock); - _d_rehash(new); - spin_unlock(&new->d_lock); spin_unlock(&inode->i_lock); security_d_instantiate(new, inode); iput(inode); @@ -2780,7 +2744,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) } else if (IS_ROOT(alias)) { /* Is this an anonymous mountpoint that we * could splice into our tree? */ - __d_materialise_dentry(dentry, alias); + __d_move(alias, dentry, false); write_sequnlock(&rename_lock); goto found; } else { @@ -2807,13 +2771,9 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) actual = __d_instantiate_unique(dentry, inode); if (!actual) actual = dentry; - else - BUG_ON(!d_unhashed(actual)); - spin_lock(&actual->d_lock); + d_rehash(actual); found: - _d_rehash(actual); - spin_unlock(&actual->d_lock); spin_unlock(&inode->i_lock); out_nolock: if (actual == dentry) { diff --git a/fs/direct-io.c b/fs/direct-io.c index c3116404ab49..e181b6b2e297 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -158,7 +158,7 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio) { ssize_t ret; - ret = iov_iter_get_pages(sdio->iter, dio->pages, DIO_PAGES, + ret = iov_iter_get_pages(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES, &sdio->from); if (ret < 0 && sdio->blocks_available && (dio->rw & WRITE)) { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 912061ac4baf..caa8d95b24e8 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1305,6 +1305,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, size_t start; ssize_t ret = iov_iter_get_pages(ii, &req->pages[req->num_pages], + *nbytesp - nbytes, req->max_pages - req->num_pages, &start); if (ret < 0) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index e94457c33ad6..b01f6e100ee8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3104,7 +3104,8 @@ static __be32 nfsd4_encode_splice_read( buf->page_len = maxcount; buf->len += maxcount; - xdr->page_ptr += (maxcount + PAGE_SIZE - 1) / PAGE_SIZE; + xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1) + / PAGE_SIZE; /* Use rest of head for padding and remaining ops: */ buf->tail[0].iov_base = xdr->p; diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 6252b173a465..d071e7f23de2 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -24,6 +24,7 @@ #include <linux/buffer_head.h> #include <linux/gfp.h> #include <linux/mpage.h> +#include <linux/pagemap.h> #include <linux/writeback.h> #include <linux/aio.h> #include "nilfs.h" @@ -219,10 +220,10 @@ static int nilfs_writepage(struct page *page, struct writeback_control *wbc) static int nilfs_set_page_dirty(struct page *page) { + struct inode *inode = page->mapping->host; int ret = __set_page_dirty_nobuffers(page); if (page_has_buffers(page)) { - struct inode *inode = page->mapping->host; unsigned nr_dirty = 0; struct buffer_head *bh, *head; @@ -245,6 +246,10 @@ static int nilfs_set_page_dirty(struct page *page) if (nr_dirty) nilfs_set_file_dirty(inode, nr_dirty); + } else if (ret) { + unsigned nr_dirty = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits); + + nilfs_set_file_dirty(inode, nr_dirty); } return ret; } diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 3ec906ef5d9a..e3cfa0227026 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -655,12 +655,9 @@ void dlm_lockres_clear_refmap_bit(struct dlm_ctxt *dlm, clear_bit(bit, res->refmap); } - -void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, +static void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) { - assert_spin_locked(&res->spinlock); - res->inflight_locks++; mlog(0, "%s: res %.*s, inflight++: now %u, %ps()\n", dlm->name, @@ -668,6 +665,13 @@ void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, __builtin_return_address(0)); } +void dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res) +{ + assert_spin_locked(&res->spinlock); + __dlm_lockres_grab_inflight_ref(dlm, res); +} + void dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) { @@ -894,10 +898,8 @@ lookup: /* finally add the lockres to its hash bucket */ __dlm_insert_lockres(dlm, res); - /* Grab inflight ref to pin the resource */ - spin_lock(&res->spinlock); - dlm_lockres_grab_inflight_ref(dlm, res); - spin_unlock(&res->spinlock); + /* since this lockres is new it doesn't not require the spinlock */ + __dlm_lockres_grab_inflight_ref(dlm, res); /* get an extra ref on the mle in case this is a BLOCK * if so, the creator of the BLOCK may try to put the last diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index ddb662b32447..4142546aedae 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -2532,6 +2532,7 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb) kfree(osb->journal); kfree(osb->local_alloc_copy); kfree(osb->uuid_str); + kfree(osb->vol_label); ocfs2_put_dlm_debug(osb->osb_dlm_debug); memset(osb, 0, sizeof(struct ocfs2_super)); } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index dfc791c42d64..c34156888d70 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -931,23 +931,32 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, while (addr < end) { struct vm_area_struct *vma = find_vma(walk->mm, addr); pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); - unsigned long vm_end; + /* End of address space hole, which we mark as non-present. */ + unsigned long hole_end; - if (!vma) { - vm_end = end; - } else { - vm_end = min(end, vma->vm_end); - if (vma->vm_flags & VM_SOFTDIRTY) - pme.pme |= PM_STATUS2(pm->v2, __PM_SOFT_DIRTY); + if (vma) + hole_end = min(end, vma->vm_start); + else + hole_end = end; + + for (; addr < hole_end; addr += PAGE_SIZE) { + err = add_to_pagemap(addr, &pme, pm); + if (err) + goto out; } - for (; addr < vm_end; addr += PAGE_SIZE) { + if (!vma) + break; + + /* Addresses in the VMA. */ + if (vma->vm_flags & VM_SOFTDIRTY) + pme.pme |= PM_STATUS2(pm->v2, __PM_SOFT_DIRTY); + for (; addr < min(end, vma->vm_end); addr += PAGE_SIZE) { err = add_to_pagemap(addr, &pme, pm); if (err) goto out; } } - out: return err; } diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index a9cc75ffa925..7caa01652888 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -298,7 +298,10 @@ cg_found: ufsi->i_oeftflag = 0; ufsi->i_dir_start_lookup = 0; memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1)); - insert_inode_hash(inode); + if (insert_inode_locked(inode) < 0) { + err = -EIO; + goto failed; + } mark_inode_dirty(inode); if (uspi->fs_magic == UFS2_MAGIC) { @@ -337,6 +340,7 @@ cg_found: fail_remove_inode: unlock_ufs(sb); clear_nlink(inode); + unlock_new_inode(inode); iput(inode); UFSD("EXIT (FAILED): err %d\n", err); return ERR_PTR(err); diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 2df62a73f20c..fd65deb4b5f0 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -38,10 +38,12 @@ static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode) { int err = ufs_add_link(dentry, inode); if (!err) { + unlock_new_inode(inode); d_instantiate(dentry, inode); return 0; } inode_dec_link_count(inode); + unlock_new_inode(inode); iput(inode); return err; } @@ -155,6 +157,7 @@ out_notlocked: out_fail: inode_dec_link_count(inode); + unlock_new_inode(inode); iput(inode); goto out; } @@ -210,6 +213,7 @@ out: out_fail: inode_dec_link_count(inode); inode_dec_link_count(inode); + unlock_new_inode(inode); iput (inode); inode_dec_link_count(dir); unlock_ufs(dir->i_sb); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index d91e59b79f0d..57ee0528aacb 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -118,6 +118,7 @@ struct acpi_device; struct acpi_hotplug_profile { struct kobject kobj; int (*scan_dependent)(struct acpi_device *adev); + void (*notify_online)(struct acpi_device *adev); bool enabled:1; bool demand_offline:1; }; diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index 3f626fe48c9a..7ccd928cc1f2 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -16,6 +16,8 @@ #define PHY_ID_BCM7250 0xae025280 #define PHY_ID_BCM7364 0xae025260 #define PHY_ID_BCM7366 0x600d8490 +#define PHY_ID_BCM7425 0x03625e60 +#define PHY_ID_BCM7429 0x600d8730 #define PHY_ID_BCM7439 0x600d8480 #define PHY_ID_BCM7445 0x600d8510 diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index ade2390ffe92..6e39c9bb0dae 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -93,12 +93,12 @@ extern int cpuset_slab_spread_node(void); static inline int cpuset_do_page_mem_spread(void) { - return current->flags & PF_SPREAD_PAGE; + return task_spread_page(current); } static inline int cpuset_do_slab_mem_spread(void) { - return current->flags & PF_SPREAD_SLAB; + return task_spread_slab(current); } extern int current_cpuset_is_being_rebound(void); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index a95efeb53a8b..b556e0ab946f 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -577,20 +577,4 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node } #endif /* CONFIG_OF */ -#ifdef CONFIG_ACPI -void acpi_i2c_register_devices(struct i2c_adapter *adap); -#else -static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } -#endif /* CONFIG_ACPI */ - -#ifdef CONFIG_ACPI_I2C_OPREGION -int acpi_i2c_install_space_handler(struct i2c_adapter *adapter); -void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter); -#else -static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) -{ } -static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) -{ return 0; } -#endif /* CONFIG_ACPI_I2C_OPREGION */ - #endif /* _LINUX_I2C_H */ diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 334947151dfc..1d67fd32e71c 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -44,6 +44,50 @@ #error Host endianness not defined #endif +/* helper macros */ +#define __mlx5_nullp(typ) ((struct mlx5_ifc_##typ##_bits *)0) +#define __mlx5_bit_sz(typ, fld) sizeof(__mlx5_nullp(typ)->fld) +#define __mlx5_bit_off(typ, fld) ((unsigned)(unsigned long)(&(__mlx5_nullp(typ)->fld))) +#define __mlx5_dw_off(typ, fld) (__mlx5_bit_off(typ, fld) / 32) +#define __mlx5_64_off(typ, fld) (__mlx5_bit_off(typ, fld) / 64) +#define __mlx5_dw_bit_off(typ, fld) (32 - __mlx5_bit_sz(typ, fld) - (__mlx5_bit_off(typ, fld) & 0x1f)) +#define __mlx5_mask(typ, fld) ((u32)((1ull << __mlx5_bit_sz(typ, fld)) - 1)) +#define __mlx5_dw_mask(typ, fld) (__mlx5_mask(typ, fld) << __mlx5_dw_bit_off(typ, fld)) +#define __mlx5_st_sz_bits(typ) sizeof(struct mlx5_ifc_##typ##_bits) + +#define MLX5_FLD_SZ_BYTES(typ, fld) (__mlx5_bit_sz(typ, fld) / 8) +#define MLX5_ST_SZ_BYTES(typ) (sizeof(struct mlx5_ifc_##typ##_bits) / 8) +#define MLX5_ST_SZ_DW(typ) (sizeof(struct mlx5_ifc_##typ##_bits) / 32) +#define MLX5_BYTE_OFF(typ, fld) (__mlx5_bit_off(typ, fld) / 8) +#define MLX5_ADDR_OF(typ, p, fld) ((char *)(p) + MLX5_BYTE_OFF(typ, fld)) + +/* insert a value to a struct */ +#define MLX5_SET(typ, p, fld, v) do { \ + BUILD_BUG_ON(__mlx5_st_sz_bits(typ) % 32); \ + *((__be32 *)(p) + __mlx5_dw_off(typ, fld)) = \ + cpu_to_be32((be32_to_cpu(*((__be32 *)(p) + __mlx5_dw_off(typ, fld))) & \ + (~__mlx5_dw_mask(typ, fld))) | (((v) & __mlx5_mask(typ, fld)) \ + << __mlx5_dw_bit_off(typ, fld))); \ +} while (0) + +#define MLX5_GET(typ, p, fld) ((be32_to_cpu(*((__be32 *)(p) +\ +__mlx5_dw_off(typ, fld))) >> __mlx5_dw_bit_off(typ, fld)) & \ +__mlx5_mask(typ, fld)) + +#define MLX5_GET_PR(typ, p, fld) ({ \ + u32 ___t = MLX5_GET(typ, p, fld); \ + pr_debug(#fld " = 0x%x\n", ___t); \ + ___t; \ +}) + +#define MLX5_SET64(typ, p, fld, v) do { \ + BUILD_BUG_ON(__mlx5_bit_sz(typ, fld) != 64); \ + BUILD_BUG_ON(__mlx5_bit_off(typ, fld) % 64); \ + *((__be64 *)(p) + __mlx5_64_off(typ, fld)) = cpu_to_be64(v); \ +} while (0) + +#define MLX5_GET64(typ, p, fld) be64_to_cpu(*((__be64 *)(p) + __mlx5_64_off(typ, fld))) + enum { MLX5_MAX_COMMANDS = 32, MLX5_CMD_DATA_BLOCK_SIZE = 512, @@ -71,6 +115,11 @@ enum { }; enum { + MLX5_MIN_PKEY_TABLE_SIZE = 128, + MLX5_MAX_LOG_PKEY_TABLE = 5, +}; + +enum { MLX5_PERM_LOCAL_READ = 1 << 2, MLX5_PERM_LOCAL_WRITE = 1 << 3, MLX5_PERM_REMOTE_READ = 1 << 4, @@ -184,10 +233,10 @@ enum { MLX5_DEV_CAP_FLAG_CQ_MODER = 1LL << 29, MLX5_DEV_CAP_FLAG_RESIZE_CQ = 1LL << 30, MLX5_DEV_CAP_FLAG_RESIZE_SRQ = 1LL << 32, + MLX5_DEV_CAP_FLAG_DCT = 1LL << 37, MLX5_DEV_CAP_FLAG_REMOTE_FENCE = 1LL << 38, MLX5_DEV_CAP_FLAG_TLP_HINTS = 1LL << 39, MLX5_DEV_CAP_FLAG_SIG_HAND_OVER = 1LL << 40, - MLX5_DEV_CAP_FLAG_DCT = 1LL << 41, MLX5_DEV_CAP_FLAG_CMDIF_CSUM = 3LL << 46, }; @@ -243,10 +292,14 @@ enum { }; enum { - MLX5_CAP_OFF_DCT = 41, MLX5_CAP_OFF_CMDIF_CSUM = 46, }; +enum { + HCA_CAP_OPMOD_GET_MAX = 0, + HCA_CAP_OPMOD_GET_CUR = 1, +}; + struct mlx5_inbox_hdr { __be16 opcode; u8 rsvd[4]; @@ -274,101 +327,6 @@ struct mlx5_cmd_query_adapter_mbox_out { u8 vsd_psid[16]; }; -struct mlx5_hca_cap { - u8 rsvd1[16]; - u8 log_max_srq_sz; - u8 log_max_qp_sz; - u8 rsvd2; - u8 log_max_qp; - u8 log_max_strq_sz; - u8 log_max_srqs; - u8 rsvd4[2]; - u8 rsvd5; - u8 log_max_cq_sz; - u8 rsvd6; - u8 log_max_cq; - u8 log_max_eq_sz; - u8 log_max_mkey; - u8 rsvd7; - u8 log_max_eq; - u8 max_indirection; - u8 log_max_mrw_sz; - u8 log_max_bsf_list_sz; - u8 log_max_klm_list_sz; - u8 rsvd_8_0; - u8 log_max_ra_req_dc; - u8 rsvd_8_1; - u8 log_max_ra_res_dc; - u8 rsvd9; - u8 log_max_ra_req_qp; - u8 rsvd10; - u8 log_max_ra_res_qp; - u8 rsvd11[4]; - __be16 max_qp_count; - __be16 rsvd12; - u8 rsvd13; - u8 local_ca_ack_delay; - u8 rsvd14; - u8 num_ports; - u8 log_max_msg; - u8 rsvd15[3]; - __be16 stat_rate_support; - u8 rsvd16[2]; - __be64 flags; - u8 rsvd17; - u8 uar_sz; - u8 rsvd18; - u8 log_pg_sz; - __be16 bf_log_bf_reg_size; - u8 rsvd19[4]; - __be16 max_desc_sz_sq; - u8 rsvd20[2]; - __be16 max_desc_sz_rq; - u8 rsvd21[2]; - __be16 max_desc_sz_sq_dc; - __be32 max_qp_mcg; - u8 rsvd22[3]; - u8 log_max_mcg; - u8 rsvd23; - u8 log_max_pd; - u8 rsvd24; - u8 log_max_xrcd; - u8 rsvd25[42]; - __be16 log_uar_page_sz; - u8 rsvd26[28]; - u8 log_max_atomic_size_qp; - u8 rsvd27[2]; - u8 log_max_atomic_size_dc; - u8 rsvd28[76]; -}; - - -struct mlx5_cmd_query_hca_cap_mbox_in { - struct mlx5_inbox_hdr hdr; - u8 rsvd[8]; -}; - - -struct mlx5_cmd_query_hca_cap_mbox_out { - struct mlx5_outbox_hdr hdr; - u8 rsvd0[8]; - struct mlx5_hca_cap hca_cap; -}; - - -struct mlx5_cmd_set_hca_cap_mbox_in { - struct mlx5_inbox_hdr hdr; - u8 rsvd[8]; - struct mlx5_hca_cap hca_cap; -}; - - -struct mlx5_cmd_set_hca_cap_mbox_out { - struct mlx5_outbox_hdr hdr; - u8 rsvd0[8]; -}; - - struct mlx5_cmd_init_hca_mbox_in { struct mlx5_inbox_hdr hdr; u8 rsvd0[2]; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index b88e9b46d957..246310dc8bef 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -44,6 +44,7 @@ #include <linux/mlx5/device.h> #include <linux/mlx5/doorbell.h> +#include <linux/mlx5/mlx5_ifc.h> enum { MLX5_BOARD_ID_LEN = 64, @@ -99,81 +100,6 @@ enum { }; enum { - MLX5_CMD_OP_QUERY_HCA_CAP = 0x100, - MLX5_CMD_OP_QUERY_ADAPTER = 0x101, - MLX5_CMD_OP_INIT_HCA = 0x102, - MLX5_CMD_OP_TEARDOWN_HCA = 0x103, - MLX5_CMD_OP_ENABLE_HCA = 0x104, - MLX5_CMD_OP_DISABLE_HCA = 0x105, - MLX5_CMD_OP_QUERY_PAGES = 0x107, - MLX5_CMD_OP_MANAGE_PAGES = 0x108, - MLX5_CMD_OP_SET_HCA_CAP = 0x109, - - MLX5_CMD_OP_CREATE_MKEY = 0x200, - MLX5_CMD_OP_QUERY_MKEY = 0x201, - MLX5_CMD_OP_DESTROY_MKEY = 0x202, - MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS = 0x203, - - MLX5_CMD_OP_CREATE_EQ = 0x301, - MLX5_CMD_OP_DESTROY_EQ = 0x302, - MLX5_CMD_OP_QUERY_EQ = 0x303, - - MLX5_CMD_OP_CREATE_CQ = 0x400, - MLX5_CMD_OP_DESTROY_CQ = 0x401, - MLX5_CMD_OP_QUERY_CQ = 0x402, - MLX5_CMD_OP_MODIFY_CQ = 0x403, - - MLX5_CMD_OP_CREATE_QP = 0x500, - MLX5_CMD_OP_DESTROY_QP = 0x501, - MLX5_CMD_OP_RST2INIT_QP = 0x502, - MLX5_CMD_OP_INIT2RTR_QP = 0x503, - MLX5_CMD_OP_RTR2RTS_QP = 0x504, - MLX5_CMD_OP_RTS2RTS_QP = 0x505, - MLX5_CMD_OP_SQERR2RTS_QP = 0x506, - MLX5_CMD_OP_2ERR_QP = 0x507, - MLX5_CMD_OP_RTS2SQD_QP = 0x508, - MLX5_CMD_OP_SQD2RTS_QP = 0x509, - MLX5_CMD_OP_2RST_QP = 0x50a, - MLX5_CMD_OP_QUERY_QP = 0x50b, - MLX5_CMD_OP_CONF_SQP = 0x50c, - MLX5_CMD_OP_MAD_IFC = 0x50d, - MLX5_CMD_OP_INIT2INIT_QP = 0x50e, - MLX5_CMD_OP_SUSPEND_QP = 0x50f, - MLX5_CMD_OP_UNSUSPEND_QP = 0x510, - MLX5_CMD_OP_SQD2SQD_QP = 0x511, - MLX5_CMD_OP_ALLOC_QP_COUNTER_SET = 0x512, - MLX5_CMD_OP_DEALLOC_QP_COUNTER_SET = 0x513, - MLX5_CMD_OP_QUERY_QP_COUNTER_SET = 0x514, - - MLX5_CMD_OP_CREATE_PSV = 0x600, - MLX5_CMD_OP_DESTROY_PSV = 0x601, - MLX5_CMD_OP_QUERY_PSV = 0x602, - MLX5_CMD_OP_QUERY_SIG_RULE_TABLE = 0x603, - MLX5_CMD_OP_QUERY_BLOCK_SIZE_TABLE = 0x604, - - MLX5_CMD_OP_CREATE_SRQ = 0x700, - MLX5_CMD_OP_DESTROY_SRQ = 0x701, - MLX5_CMD_OP_QUERY_SRQ = 0x702, - MLX5_CMD_OP_ARM_RQ = 0x703, - MLX5_CMD_OP_RESIZE_SRQ = 0x704, - - MLX5_CMD_OP_ALLOC_PD = 0x800, - MLX5_CMD_OP_DEALLOC_PD = 0x801, - MLX5_CMD_OP_ALLOC_UAR = 0x802, - MLX5_CMD_OP_DEALLOC_UAR = 0x803, - - MLX5_CMD_OP_ATTACH_TO_MCG = 0x806, - MLX5_CMD_OP_DETACH_FROM_MCG = 0x807, - - - MLX5_CMD_OP_ALLOC_XRCD = 0x80e, - MLX5_CMD_OP_DEALLOC_XRCD = 0x80f, - - MLX5_CMD_OP_ACCESS_REG = 0x805, - MLX5_CMD_OP_MAX = 0x810, -}; - -enum { MLX5_REG_PCAP = 0x5001, MLX5_REG_PMTU = 0x5003, MLX5_REG_PTYS = 0x5004, @@ -335,23 +261,30 @@ struct mlx5_port_caps { int pkey_table_len; }; -struct mlx5_caps { +struct mlx5_general_caps { u8 log_max_eq; u8 log_max_cq; u8 log_max_qp; u8 log_max_mkey; u8 log_max_pd; u8 log_max_srq; + u8 log_max_strq; + u8 log_max_mrw_sz; + u8 log_max_bsf_list_size; + u8 log_max_klm_list_size; u32 max_cqes; int max_wqes; + u32 max_eqes; + u32 max_indirection; int max_sq_desc_sz; int max_rq_desc_sz; + int max_dc_sq_desc_sz; u64 flags; u16 stat_rate_support; int log_max_msg; int num_ports; - int max_ra_res_qp; - int max_ra_req_qp; + u8 log_max_ra_res_qp; + u8 log_max_ra_req_qp; int max_srq_wqes; int bf_reg_size; int bf_regs_per_page; @@ -363,6 +296,19 @@ struct mlx5_caps { u8 log_max_mcg; u32 max_qp_mcg; int min_page_sz; + int pd_cap; + u32 max_qp_counters; + u32 pkey_table_size; + u8 log_max_ra_req_dc; + u8 log_max_ra_res_dc; + u32 uar_sz; + u8 min_log_pg_sz; + u8 log_max_xrcd; + u16 log_uar_page_sz; +}; + +struct mlx5_caps { + struct mlx5_general_caps gen; }; struct mlx5_cmd_mailbox { @@ -429,6 +375,16 @@ struct mlx5_core_mr { u32 pd; }; +enum mlx5_res_type { + MLX5_RES_QP, +}; + +struct mlx5_core_rsc_common { + enum mlx5_res_type res; + atomic_t refcount; + struct completion free; +}; + struct mlx5_core_srq { u32 srqn; int max; @@ -695,6 +651,9 @@ void mlx5_cmd_cleanup(struct mlx5_core_dev *dev); void mlx5_cmd_use_events(struct mlx5_core_dev *dev); void mlx5_cmd_use_polling(struct mlx5_core_dev *dev); int mlx5_cmd_status_to_err(struct mlx5_outbox_hdr *hdr); +int mlx5_cmd_status_to_err_v2(void *ptr); +int mlx5_core_get_caps(struct mlx5_core_dev *dev, struct mlx5_caps *caps, + u16 opmod); int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, int out_size); int mlx5_cmd_exec_cb(struct mlx5_core_dev *dev, void *in, int in_size, @@ -751,7 +710,7 @@ int mlx5_eq_init(struct mlx5_core_dev *dev); void mlx5_eq_cleanup(struct mlx5_core_dev *dev); void mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas); void mlx5_cq_completion(struct mlx5_core_dev *dev, u32 cqn); -void mlx5_qp_event(struct mlx5_core_dev *dev, u32 qpn, int event_type); +void mlx5_rsc_event(struct mlx5_core_dev *dev, u32 rsn, int event_type); void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type); struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn); void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector); @@ -788,6 +747,7 @@ void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev); int mlx5_core_create_psv(struct mlx5_core_dev *dev, u32 pdn, int npsvs, u32 *sig_index); int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num); +void mlx5_core_put_rsc(struct mlx5_core_rsc_common *common); static inline u32 mlx5_mkey_to_idx(u32 mkey) { diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h new file mode 100644 index 000000000000..5f48b8f592c5 --- /dev/null +++ b/include/linux/mlx5/mlx5_ifc.h @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2014, Mellanox Technologies inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX5_IFC_H +#define MLX5_IFC_H + +enum { + MLX5_CMD_OP_QUERY_HCA_CAP = 0x100, + MLX5_CMD_OP_QUERY_ADAPTER = 0x101, + MLX5_CMD_OP_INIT_HCA = 0x102, + MLX5_CMD_OP_TEARDOWN_HCA = 0x103, + MLX5_CMD_OP_ENABLE_HCA = 0x104, + MLX5_CMD_OP_DISABLE_HCA = 0x105, + MLX5_CMD_OP_QUERY_PAGES = 0x107, + MLX5_CMD_OP_MANAGE_PAGES = 0x108, + MLX5_CMD_OP_SET_HCA_CAP = 0x109, + MLX5_CMD_OP_CREATE_MKEY = 0x200, + MLX5_CMD_OP_QUERY_MKEY = 0x201, + MLX5_CMD_OP_DESTROY_MKEY = 0x202, + MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS = 0x203, + MLX5_CMD_OP_PAGE_FAULT_RESUME = 0x204, + MLX5_CMD_OP_CREATE_EQ = 0x301, + MLX5_CMD_OP_DESTROY_EQ = 0x302, + MLX5_CMD_OP_QUERY_EQ = 0x303, + MLX5_CMD_OP_GEN_EQE = 0x304, + MLX5_CMD_OP_CREATE_CQ = 0x400, + MLX5_CMD_OP_DESTROY_CQ = 0x401, + MLX5_CMD_OP_QUERY_CQ = 0x402, + MLX5_CMD_OP_MODIFY_CQ = 0x403, + MLX5_CMD_OP_CREATE_QP = 0x500, + MLX5_CMD_OP_DESTROY_QP = 0x501, + MLX5_CMD_OP_RST2INIT_QP = 0x502, + MLX5_CMD_OP_INIT2RTR_QP = 0x503, + MLX5_CMD_OP_RTR2RTS_QP = 0x504, + MLX5_CMD_OP_RTS2RTS_QP = 0x505, + MLX5_CMD_OP_SQERR2RTS_QP = 0x506, + MLX5_CMD_OP_2ERR_QP = 0x507, + MLX5_CMD_OP_2RST_QP = 0x50a, + MLX5_CMD_OP_QUERY_QP = 0x50b, + MLX5_CMD_OP_INIT2INIT_QP = 0x50e, + MLX5_CMD_OP_CREATE_PSV = 0x600, + MLX5_CMD_OP_DESTROY_PSV = 0x601, + MLX5_CMD_OP_CREATE_SRQ = 0x700, + MLX5_CMD_OP_DESTROY_SRQ = 0x701, + MLX5_CMD_OP_QUERY_SRQ = 0x702, + MLX5_CMD_OP_ARM_RQ = 0x703, + MLX5_CMD_OP_RESIZE_SRQ = 0x704, + MLX5_CMD_OP_CREATE_DCT = 0x710, + MLX5_CMD_OP_DESTROY_DCT = 0x711, + MLX5_CMD_OP_DRAIN_DCT = 0x712, + MLX5_CMD_OP_QUERY_DCT = 0x713, + MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION = 0x714, + MLX5_CMD_OP_QUERY_VPORT_STATE = 0x750, + MLX5_CMD_OP_MODIFY_VPORT_STATE = 0x751, + MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT = 0x752, + MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT = 0x753, + MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT = 0x754, + MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT = 0x755, + MLX5_CMD_OP_QUERY_RCOE_ADDRESS = 0x760, + MLX5_CMD_OP_SET_ROCE_ADDRESS = 0x761, + MLX5_CMD_OP_QUERY_VPORT_COUNTER = 0x770, + MLX5_CMD_OP_ALLOC_Q_COUNTER = 0x771, + MLX5_CMD_OP_DEALLOC_Q_COUNTER = 0x772, + MLX5_CMD_OP_QUERY_Q_COUNTER = 0x773, + MLX5_CMD_OP_ALLOC_PD = 0x800, + MLX5_CMD_OP_DEALLOC_PD = 0x801, + MLX5_CMD_OP_ALLOC_UAR = 0x802, + MLX5_CMD_OP_DEALLOC_UAR = 0x803, + MLX5_CMD_OP_CONFIG_INT_MODERATION = 0x804, + MLX5_CMD_OP_ACCESS_REG = 0x805, + MLX5_CMD_OP_ATTACH_TO_MCG = 0x806, + MLX5_CMD_OP_DETACH_FROM_MCG = 0x807, + MLX5_CMD_OP_GET_DROPPED_PACKET_LOG = 0x80a, + MLX5_CMD_OP_MAD_IFC = 0x50d, + MLX5_CMD_OP_QUERY_MAD_DEMUX = 0x80b, + MLX5_CMD_OP_SET_MAD_DEMUX = 0x80c, + MLX5_CMD_OP_NOP = 0x80d, + MLX5_CMD_OP_ALLOC_XRCD = 0x80e, + MLX5_CMD_OP_DEALLOC_XRCD = 0x80f, + MLX5_CMD_OP_SET_BURST_SIZE = 0x812, + MLX5_CMD_OP_QUERY_BURST_SZIE = 0x813, + MLX5_CMD_OP_ACTIVATE_TRACER = 0x814, + MLX5_CMD_OP_DEACTIVATE_TRACER = 0x815, + MLX5_CMD_OP_CREATE_SNIFFER_RULE = 0x820, + MLX5_CMD_OP_DESTROY_SNIFFER_RULE = 0x821, + MLX5_CMD_OP_QUERY_CONG_PARAMS = 0x822, + MLX5_CMD_OP_MODIFY_CONG_PARAMS = 0x823, + MLX5_CMD_OP_QUERY_CONG_STATISTICS = 0x824, + MLX5_CMD_OP_CREATE_TIR = 0x900, + MLX5_CMD_OP_MODIFY_TIR = 0x901, + MLX5_CMD_OP_DESTROY_TIR = 0x902, + MLX5_CMD_OP_QUERY_TIR = 0x903, + MLX5_CMD_OP_CREATE_TIS = 0x912, + MLX5_CMD_OP_MODIFY_TIS = 0x913, + MLX5_CMD_OP_DESTROY_TIS = 0x914, + MLX5_CMD_OP_QUERY_TIS = 0x915, + MLX5_CMD_OP_CREATE_SQ = 0x904, + MLX5_CMD_OP_MODIFY_SQ = 0x905, + MLX5_CMD_OP_DESTROY_SQ = 0x906, + MLX5_CMD_OP_QUERY_SQ = 0x907, + MLX5_CMD_OP_CREATE_RQ = 0x908, + MLX5_CMD_OP_MODIFY_RQ = 0x909, + MLX5_CMD_OP_DESTROY_RQ = 0x90a, + MLX5_CMD_OP_QUERY_RQ = 0x90b, + MLX5_CMD_OP_CREATE_RMP = 0x90c, + MLX5_CMD_OP_MODIFY_RMP = 0x90d, + MLX5_CMD_OP_DESTROY_RMP = 0x90e, + MLX5_CMD_OP_QUERY_RMP = 0x90f, + MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY = 0x910, + MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY = 0x911, + MLX5_CMD_OP_MAX = 0x911 +}; + +struct mlx5_ifc_cmd_hca_cap_bits { + u8 reserved_0[0x80]; + + u8 log_max_srq_sz[0x8]; + u8 log_max_qp_sz[0x8]; + u8 reserved_1[0xb]; + u8 log_max_qp[0x5]; + + u8 log_max_strq_sz[0x8]; + u8 reserved_2[0x3]; + u8 log_max_srqs[0x5]; + u8 reserved_3[0x10]; + + u8 reserved_4[0x8]; + u8 log_max_cq_sz[0x8]; + u8 reserved_5[0xb]; + u8 log_max_cq[0x5]; + + u8 log_max_eq_sz[0x8]; + u8 reserved_6[0x2]; + u8 log_max_mkey[0x6]; + u8 reserved_7[0xc]; + u8 log_max_eq[0x4]; + + u8 max_indirection[0x8]; + u8 reserved_8[0x1]; + u8 log_max_mrw_sz[0x7]; + u8 reserved_9[0x2]; + u8 log_max_bsf_list_size[0x6]; + u8 reserved_10[0x2]; + u8 log_max_klm_list_size[0x6]; + + u8 reserved_11[0xa]; + u8 log_max_ra_req_dc[0x6]; + u8 reserved_12[0xa]; + u8 log_max_ra_res_dc[0x6]; + + u8 reserved_13[0xa]; + u8 log_max_ra_req_qp[0x6]; + u8 reserved_14[0xa]; + u8 log_max_ra_res_qp[0x6]; + + u8 pad_cap[0x1]; + u8 cc_query_allowed[0x1]; + u8 cc_modify_allowed[0x1]; + u8 reserved_15[0x1d]; + + u8 reserved_16[0x6]; + u8 max_qp_cnt[0xa]; + u8 pkey_table_size[0x10]; + + u8 eswitch_owner[0x1]; + u8 reserved_17[0xa]; + u8 local_ca_ack_delay[0x5]; + u8 reserved_18[0x8]; + u8 num_ports[0x8]; + + u8 reserved_19[0x3]; + u8 log_max_msg[0x5]; + u8 reserved_20[0x18]; + + u8 stat_rate_support[0x10]; + u8 reserved_21[0x10]; + + u8 reserved_22[0x10]; + u8 cmdif_checksum[0x2]; + u8 sigerr_cqe[0x1]; + u8 reserved_23[0x1]; + u8 wq_signature[0x1]; + u8 sctr_data_cqe[0x1]; + u8 reserved_24[0x1]; + u8 sho[0x1]; + u8 tph[0x1]; + u8 rf[0x1]; + u8 dc[0x1]; + u8 reserved_25[0x2]; + u8 roce[0x1]; + u8 atomic[0x1]; + u8 rsz_srq[0x1]; + + u8 cq_oi[0x1]; + u8 cq_resize[0x1]; + u8 cq_moderation[0x1]; + u8 sniffer_rule_flow[0x1]; + u8 sniffer_rule_vport[0x1]; + u8 sniffer_rule_phy[0x1]; + u8 reserved_26[0x1]; + u8 pg[0x1]; + u8 block_lb_mc[0x1]; + u8 reserved_27[0x3]; + u8 cd[0x1]; + u8 reserved_28[0x1]; + u8 apm[0x1]; + u8 reserved_29[0x7]; + u8 qkv[0x1]; + u8 pkv[0x1]; + u8 reserved_30[0x4]; + u8 xrc[0x1]; + u8 ud[0x1]; + u8 uc[0x1]; + u8 rc[0x1]; + + u8 reserved_31[0xa]; + u8 uar_sz[0x6]; + u8 reserved_32[0x8]; + u8 log_pg_sz[0x8]; + + u8 bf[0x1]; + u8 reserved_33[0xa]; + u8 log_bf_reg_size[0x5]; + u8 reserved_34[0x10]; + + u8 reserved_35[0x10]; + u8 max_wqe_sz_sq[0x10]; + + u8 reserved_36[0x10]; + u8 max_wqe_sz_rq[0x10]; + + u8 reserved_37[0x10]; + u8 max_wqe_sz_sq_dc[0x10]; + + u8 reserved_38[0x7]; + u8 max_qp_mcg[0x19]; + + u8 reserved_39[0x18]; + u8 log_max_mcg[0x8]; + + u8 reserved_40[0xb]; + u8 log_max_pd[0x5]; + u8 reserved_41[0xb]; + u8 log_max_xrcd[0x5]; + + u8 reserved_42[0x20]; + + u8 reserved_43[0x3]; + u8 log_max_rq[0x5]; + u8 reserved_44[0x3]; + u8 log_max_sq[0x5]; + u8 reserved_45[0x3]; + u8 log_max_tir[0x5]; + u8 reserved_46[0x3]; + u8 log_max_tis[0x5]; + + u8 reserved_47[0x13]; + u8 log_max_rq_per_tir[0x5]; + u8 reserved_48[0x3]; + u8 log_max_tis_per_sq[0x5]; + + u8 reserved_49[0xe0]; + + u8 reserved_50[0x10]; + u8 log_uar_page_sz[0x10]; + + u8 reserved_51[0x100]; + + u8 reserved_52[0x1f]; + u8 cqe_zip[0x1]; + + u8 cqe_zip_timeout[0x10]; + u8 cqe_zip_max_num[0x10]; + + u8 reserved_53[0x220]; +}; + +struct mlx5_ifc_set_hca_cap_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; + + struct mlx5_ifc_cmd_hca_cap_bits hca_capability_struct; +}; + +struct mlx5_ifc_query_hca_cap_in_bits { + u8 opcode[0x10]; + u8 reserved_0[0x10]; + + u8 reserved_1[0x10]; + u8 op_mod[0x10]; + + u8 reserved_2[0x40]; +}; + +struct mlx5_ifc_query_hca_cap_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; + + u8 capability_struct[256][0x8]; +}; + +struct mlx5_ifc_set_hca_cap_out_bits { + u8 status[0x8]; + u8 reserved_0[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_1[0x40]; +}; + +#endif /* MLX5_IFC_H */ diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h index 9709b30e2d69..7c4c0f1f5805 100644 --- a/include/linux/mlx5/qp.h +++ b/include/linux/mlx5/qp.h @@ -342,10 +342,9 @@ struct mlx5_stride_block_ctrl_seg { }; struct mlx5_core_qp { + struct mlx5_core_rsc_common common; /* must be first */ void (*event) (struct mlx5_core_qp *, int); int qpn; - atomic_t refcount; - struct completion free; struct mlx5_rsc_debug *dbg; int pid; }; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9b7fbacb6296..22d54b9b700d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1886,6 +1886,9 @@ struct napi_gro_cb { /* Number of checksums via CHECKSUM_UNNECESSARY */ u8 csum_cnt:3; + /* Used in foo-over-udp, set in udp[46]_gro_receive */ + u8 is_ipv6:1; + /* used to support CHECKSUM_COMPLETE for tunneling protocols */ __wsum csum; @@ -2821,7 +2824,7 @@ int dev_set_mac_address(struct net_device *, struct sockaddr *); int dev_change_carrier(struct net_device *, bool new_carrier); int dev_get_phys_port_id(struct net_device *dev, struct netdev_phys_port_id *ppid); -struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev); +struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev); struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, int *ret); int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb); diff --git a/include/linux/sched.h b/include/linux/sched.h index 5c2c885ee52b..b867a4dab38a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1903,8 +1903,6 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, #define PF_KTHREAD 0x00200000 /* I am a kernel thread */ #define PF_RANDOMIZE 0x00400000 /* randomize virtual address space */ #define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */ -#define PF_SPREAD_PAGE 0x01000000 /* Spread page cache over cpuset */ -#define PF_SPREAD_SLAB 0x02000000 /* Spread some slab caches over cpuset */ #define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */ #define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */ #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ @@ -1957,17 +1955,31 @@ static inline void memalloc_noio_restore(unsigned int flags) } /* Per-process atomic flags. */ -#define PFA_NO_NEW_PRIVS 0x00000001 /* May not gain new privileges. */ +#define PFA_NO_NEW_PRIVS 0 /* May not gain new privileges. */ +#define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */ +#define PFA_SPREAD_SLAB 2 /* Spread some slab caches over cpuset */ -static inline bool task_no_new_privs(struct task_struct *p) -{ - return test_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags); -} -static inline void task_set_no_new_privs(struct task_struct *p) -{ - set_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags); -} +#define TASK_PFA_TEST(name, func) \ + static inline bool task_##func(struct task_struct *p) \ + { return test_bit(PFA_##name, &p->atomic_flags); } +#define TASK_PFA_SET(name, func) \ + static inline void task_set_##func(struct task_struct *p) \ + { set_bit(PFA_##name, &p->atomic_flags); } +#define TASK_PFA_CLEAR(name, func) \ + static inline void task_clear_##func(struct task_struct *p) \ + { clear_bit(PFA_##name, &p->atomic_flags); } + +TASK_PFA_TEST(NO_NEW_PRIVS, no_new_privs) +TASK_PFA_SET(NO_NEW_PRIVS, no_new_privs) + +TASK_PFA_TEST(SPREAD_PAGE, spread_page) +TASK_PFA_SET(SPREAD_PAGE, spread_page) +TASK_PFA_CLEAR(SPREAD_PAGE, spread_page) + +TASK_PFA_TEST(SPREAD_SLAB, spread_slab) +TASK_PFA_SET(SPREAD_SLAB, spread_slab) +TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab) /* * task->jobctl flags @@ -2608,9 +2620,22 @@ static inline void setup_thread_stack(struct task_struct *p, struct task_struct task_thread_info(p)->task = p; } +/* + * Return the address of the last usable long on the stack. + * + * When the stack grows down, this is just above the thread + * info struct. Going any lower will corrupt the threadinfo. + * + * When the stack grows up, this is the highest address. + * Beyond that position, we corrupt data on the next page. + */ static inline unsigned long *end_of_stack(struct task_struct *p) { +#ifdef CONFIG_STACK_GROWSUP + return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1; +#else return (unsigned long *)(task_thread_info(p) + 1); +#endif } #endif diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 262efdbc346b..3a5ec7638627 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -339,9 +339,10 @@ struct skb_shared_info { enum { - SKB_FCLONE_UNAVAILABLE, - SKB_FCLONE_ORIG, - SKB_FCLONE_CLONE, + SKB_FCLONE_UNAVAILABLE, /* skb has no fclone (from head_cache) */ + SKB_FCLONE_ORIG, /* orig skb (from fclone_cache) */ + SKB_FCLONE_CLONE, /* companion fclone skb (from fclone_cache) */ + SKB_FCLONE_FREE, /* this companion fclone skb is available */ }; enum { @@ -596,7 +597,8 @@ struct sk_buff { __u8 ndisc_nodetype:2; #endif __u8 ipvs_property:1; - /* 5 or 7 bit hole */ + __u8 inner_protocol_type:1; + /* 4 or 6 bit hole */ #ifdef CONFIG_NET_SCHED __u16 tc_index; /* traffic control index */ @@ -632,7 +634,11 @@ struct sk_buff { __u32 reserved_tailroom; }; - __be16 inner_protocol; + union { + __be16 inner_protocol; + __u8 inner_ipproto; + }; + __u16 inner_transport_header; __u16 inner_network_header; __u16 inner_mac_header; @@ -781,6 +787,31 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len, int *errcode, gfp_t gfp_mask); +/* Layout of fast clones : [skb1][skb2][fclone_ref] */ +struct sk_buff_fclones { + struct sk_buff skb1; + + struct sk_buff skb2; + + atomic_t fclone_ref; +}; + +/** + * skb_fclone_busy - check if fclone is busy + * @skb: buffer + * + * Returns true is skb is a fast clone, and its clone is not freed. + */ +static inline bool skb_fclone_busy(const struct sk_buff *skb) +{ + const struct sk_buff_fclones *fclones; + + fclones = container_of(skb, struct sk_buff_fclones, skb1); + + return skb->fclone == SKB_FCLONE_ORIG && + fclones->skb2.fclone == SKB_FCLONE_CLONE; +} + static inline struct sk_buff *alloc_skb_fclone(unsigned int size, gfp_t priority) { @@ -1737,6 +1768,23 @@ static inline void skb_reserve(struct sk_buff *skb, int len) skb->tail += len; } +#define ENCAP_TYPE_ETHER 0 +#define ENCAP_TYPE_IPPROTO 1 + +static inline void skb_set_inner_protocol(struct sk_buff *skb, + __be16 protocol) +{ + skb->inner_protocol = protocol; + skb->inner_protocol_type = ENCAP_TYPE_ETHER; +} + +static inline void skb_set_inner_ipproto(struct sk_buff *skb, + __u8 ipproto) +{ + skb->inner_ipproto = ipproto; + skb->inner_protocol_type = ENCAP_TYPE_IPPROTO; +} + static inline void skb_reset_inner_headers(struct sk_buff *skb) { skb->inner_mac_header = skb->mac_header; diff --git a/include/linux/uio.h b/include/linux/uio.h index 48d64e6ab292..290fbf0b6b8a 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -84,7 +84,7 @@ unsigned long iov_iter_alignment(const struct iov_iter *i); void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, unsigned long nr_segs, size_t count); ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, - unsigned maxpages, size_t *start); + size_t maxsize, unsigned maxpages, size_t *start); ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, size_t maxsize, size_t *start); int iov_iter_npages(const struct iov_iter *i, int maxpages); diff --git a/include/net/gue.h b/include/net/gue.h new file mode 100644 index 000000000000..b6c332788084 --- /dev/null +++ b/include/net/gue.h @@ -0,0 +1,23 @@ +#ifndef __NET_GUE_H +#define __NET_GUE_H + +struct guehdr { + union { + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 hlen:4, + version:4; +#elif defined (__BIG_ENDIAN_BITFIELD) + __u8 version:4, + hlen:4; +#else +#error "Please fix <asm/byteorder.h>" +#endif + __u8 next_hdr; + __u16 flags; + }; + __u32 word; + }; +}; + +#endif diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index d07b1a64b4e7..55a8d4056cc9 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -35,7 +35,6 @@ enum { INET6_IFADDR_STATE_DAD, INET6_IFADDR_STATE_POSTDAD, INET6_IFADDR_STATE_ERRDAD, - INET6_IFADDR_STATE_UP, INET6_IFADDR_STATE_DEAD, }; diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 9bcb220bd4ad..cf485f9aa563 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -114,16 +114,13 @@ struct rt6_info { u32 rt6i_flags; struct rt6key rt6i_src; struct rt6key rt6i_prefsrc; - u32 rt6i_metric; struct inet6_dev *rt6i_idev; unsigned long _rt6i_peer; - u32 rt6i_genid; - + u32 rt6i_metric; /* more non-fragment space at head required */ unsigned short rt6i_nfheader_len; - u8 rt6i_protocol; }; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 361d26077196..e0d64667a4b3 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -352,26 +352,12 @@ static inline void rt_genid_bump_ipv4(struct net *net) atomic_inc(&net->ipv4.rt_genid); } -#if IS_ENABLED(CONFIG_IPV6) -static inline int rt_genid_ipv6(struct net *net) -{ - return atomic_read(&net->ipv6.rt_genid); -} - -static inline void rt_genid_bump_ipv6(struct net *net) -{ - atomic_inc(&net->ipv6.rt_genid); -} -#else -static inline int rt_genid_ipv6(struct net *net) -{ - return 0; -} - +extern void (*__fib6_flush_trees)(struct net *net); static inline void rt_genid_bump_ipv6(struct net *net) { + if (__fib6_flush_trees) + __fib6_flush_trees(net); } -#endif #if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) static inline struct netns_ieee802154_lowpan * diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 73f9532ee581..ef44ad9a6426 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -20,11 +20,7 @@ int unregister_tcf_proto_ops(struct tcf_proto_ops *ops); static inline unsigned long __cls_set_class(unsigned long *clp, unsigned long cl) { - unsigned long old_cl; - - old_cl = *clp; - *clp = cl; - return old_cl; + return xchg(clp, cl); } static inline unsigned long diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 8bbe626e9ece..e4b3c828c1c2 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -99,7 +99,7 @@ void qdisc_put_stab(struct qdisc_size_table *tab); void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc); int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, struct net_device *dev, struct netdev_queue *txq, - spinlock_t *root_lock); + spinlock_t *root_lock, bool validate); void __qdisc_run(struct Qdisc *q); diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index f12669819d1a..d17ed6fb2f70 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -7,6 +7,7 @@ #include <linux/pkt_sched.h> #include <linux/pkt_cls.h> #include <linux/percpu.h> +#include <linux/dynamic_queue_limits.h> #include <net/gen_stats.h> #include <net/rtnetlink.h> @@ -119,6 +120,21 @@ static inline void qdisc_run_end(struct Qdisc *qdisc) qdisc->__state &= ~__QDISC___STATE_RUNNING; } +static inline bool qdisc_may_bulk(const struct Qdisc *qdisc) +{ + return qdisc->flags & TCQ_F_ONETXQUEUE; +} + +static inline int qdisc_avail_bulklimit(const struct netdev_queue *txq) +{ +#ifdef CONFIG_BQL + /* Non-BQL migrated drivers will return 0, too. */ + return dql_avail(&txq->dql); +#else + return 0; +#endif +} + static inline bool qdisc_is_throttled(const struct Qdisc *qdisc) { return test_bit(__QDISC_STATE_THROTTLED, &qdisc->state) ? true : false; diff --git a/include/net/udp.h b/include/net/udp.h index 16f4e80f0519..07f9b70962f6 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -239,7 +239,8 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); int udp_disconnect(struct sock *sk, int flags); unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait); struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, - netdev_features_t features); + netdev_features_t features, + bool is_ipv6); int udp_lib_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); int udp_lib_setsockopt(struct sock *sk, int level, int optname, diff --git a/include/uapi/linux/fou.h b/include/uapi/linux/fou.h index e03376de453d..8df06894da23 100644 --- a/include/uapi/linux/fou.h +++ b/include/uapi/linux/fou.h @@ -13,6 +13,7 @@ enum { FOU_ATTR_PORT, /* u16 */ FOU_ATTR_AF, /* u8 */ FOU_ATTR_IPPROTO, /* u8 */ + FOU_ATTR_TYPE, /* u8 */ __FOU_ATTR_MAX, }; @@ -27,6 +28,12 @@ enum { __FOU_CMD_MAX, }; +enum { + FOU_ENCAP_UNSPEC, + FOU_ENCAP_DIRECT, + FOU_ENCAP_GUE, +}; + #define FOU_CMD_MAX (__FOU_CMD_MAX - 1) #endif /* _UAPI_LINUX_FOU_H */ diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h index 7c832afdfa94..280d9e092283 100644 --- a/include/uapi/linux/if_tunnel.h +++ b/include/uapi/linux/if_tunnel.h @@ -64,6 +64,7 @@ enum { enum tunnel_encap_types { TUNNEL_ENCAP_NONE, TUNNEL_ENCAP_FOU, + TUNNEL_ENCAP_GUE, }; #define TUNNEL_ENCAP_FLAG_CSUM (1<<0) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a086dd3210a8..801f5f3b9307 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -199,6 +199,7 @@ struct verifier_env { struct verifier_stack_elem *head; /* stack of verifier states to be processed */ int stack_size; /* number of states to be processed */ struct verifier_state cur_state; /* current verifier state */ + struct verifier_state_list **explored_states; /* search pruning optimization */ struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */ u32 used_map_cnt; /* number of used maps */ }; @@ -1219,6 +1220,8 @@ enum { BRANCH = 2, }; +#define STATE_LIST_MARK ((struct verifier_state_list *) -1L) + static int *insn_stack; /* stack of insns to process */ static int cur_stack; /* current stack index */ static int *insn_state; @@ -1241,6 +1244,10 @@ static int push_insn(int t, int w, int e, struct verifier_env *env) return -EINVAL; } + if (e == BRANCH) + /* mark branch target for state pruning */ + env->explored_states[w] = STATE_LIST_MARK; + if (insn_state[w] == 0) { /* tree-edge */ insn_state[t] = DISCOVERED | e; @@ -1314,6 +1321,10 @@ peek_stack: goto peek_stack; else if (ret < 0) goto err_free; + /* tell verifier to check for equivalent states + * after every call and jump + */ + env->explored_states[t + 1] = STATE_LIST_MARK; } else { /* conditional jump with two edges */ ret = push_insn(t, t + 1, FALLTHROUGH, env); @@ -1364,6 +1375,95 @@ err_free: return ret; } +/* compare two verifier states + * + * all states stored in state_list are known to be valid, since + * verifier reached 'bpf_exit' instruction through them + * + * this function is called when verifier exploring different branches of + * execution popped from the state stack. If it sees an old state that has + * more strict register state and more strict stack state then this execution + * branch doesn't need to be explored further, since verifier already + * concluded that more strict state leads to valid finish. + * + * Therefore two states are equivalent if register state is more conservative + * and explored stack state is more conservative than the current one. + * Example: + * explored current + * (slot1=INV slot2=MISC) == (slot1=MISC slot2=MISC) + * (slot1=MISC slot2=MISC) != (slot1=INV slot2=MISC) + * + * In other words if current stack state (one being explored) has more + * valid slots than old one that already passed validation, it means + * the verifier can stop exploring and conclude that current state is valid too + * + * Similarly with registers. If explored state has register type as invalid + * whereas register type in current state is meaningful, it means that + * the current state will reach 'bpf_exit' instruction safely + */ +static bool states_equal(struct verifier_state *old, struct verifier_state *cur) +{ + int i; + + for (i = 0; i < MAX_BPF_REG; i++) { + if (memcmp(&old->regs[i], &cur->regs[i], + sizeof(old->regs[0])) != 0) { + if (old->regs[i].type == NOT_INIT || + old->regs[i].type == UNKNOWN_VALUE) + continue; + return false; + } + } + + for (i = 0; i < MAX_BPF_STACK; i++) { + if (memcmp(&old->stack[i], &cur->stack[i], + sizeof(old->stack[0])) != 0) { + if (old->stack[i].stype == STACK_INVALID) + continue; + return false; + } + } + return true; +} + +static int is_state_visited(struct verifier_env *env, int insn_idx) +{ + struct verifier_state_list *new_sl; + struct verifier_state_list *sl; + + sl = env->explored_states[insn_idx]; + if (!sl) + /* this 'insn_idx' instruction wasn't marked, so we will not + * be doing state search here + */ + return 0; + + while (sl != STATE_LIST_MARK) { + if (states_equal(&sl->state, &env->cur_state)) + /* reached equivalent register/stack state, + * prune the search + */ + return 1; + sl = sl->next; + } + + /* there were no equivalent states, remember current one. + * technically the current state is not proven to be safe yet, + * but it will either reach bpf_exit (which means it's safe) or + * it will be rejected. Since there are no loops, we won't be + * seeing this 'insn_idx' instruction again on the way to bpf_exit + */ + new_sl = kmalloc(sizeof(struct verifier_state_list), GFP_USER); + if (!new_sl) + return -ENOMEM; + + /* add new state to the head of linked list */ + memcpy(&new_sl->state, &env->cur_state, sizeof(env->cur_state)); + new_sl->next = env->explored_states[insn_idx]; + env->explored_states[insn_idx] = new_sl; + return 0; +} + static int do_check(struct verifier_env *env) { struct verifier_state *state = &env->cur_state; @@ -1396,6 +1496,21 @@ static int do_check(struct verifier_env *env) return -E2BIG; } + err = is_state_visited(env, insn_idx); + if (err < 0) + return err; + if (err == 1) { + /* found equivalent state, can prune the search */ + if (log_level) { + if (do_print_state) + verbose("\nfrom %d to %d: safe\n", + prev_insn_idx, insn_idx); + else + verbose("%d: safe\n", insn_idx); + } + goto process_bpf_exit; + } + if (log_level && do_print_state) { verbose("\nfrom %d to %d:", prev_insn_idx, insn_idx); print_verifier_state(env); @@ -1531,6 +1646,7 @@ static int do_check(struct verifier_env *env) if (err) return err; +process_bpf_exit: insn_idx = pop_stack(env, &prev_insn_idx); if (insn_idx < 0) { break; @@ -1671,6 +1787,28 @@ static void convert_pseudo_ld_imm64(struct verifier_env *env) insn->src_reg = 0; } +static void free_states(struct verifier_env *env) +{ + struct verifier_state_list *sl, *sln; + int i; + + if (!env->explored_states) + return; + + for (i = 0; i < env->prog->len; i++) { + sl = env->explored_states[i]; + + if (sl) + while (sl != STATE_LIST_MARK) { + sln = sl->next; + kfree(sl); + sl = sln; + } + } + + kfree(env->explored_states); +} + int bpf_check(struct bpf_prog *prog, union bpf_attr *attr) { char __user *log_ubuf = NULL; @@ -1719,6 +1857,13 @@ int bpf_check(struct bpf_prog *prog, union bpf_attr *attr) if (ret < 0) goto skip_full_check; + env->explored_states = kcalloc(prog->len, + sizeof(struct verifier_state_list *), + GFP_USER); + ret = -ENOMEM; + if (!env->explored_states) + goto skip_full_check; + ret = check_cfg(env); if (ret < 0) goto skip_full_check; @@ -1727,6 +1872,7 @@ int bpf_check(struct bpf_prog *prog, union bpf_attr *attr) skip_full_check: while (pop_stack(env, NULL) >= 0); + free_states(env); if (log_level && log_len >= log_size - 1) { BUG_ON(log_len >= log_size); diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 22874d7cf2c0..52cb04c993b7 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -365,13 +365,14 @@ static void cpuset_update_task_spread_flag(struct cpuset *cs, struct task_struct *tsk) { if (is_spread_page(cs)) - tsk->flags |= PF_SPREAD_PAGE; + task_set_spread_page(tsk); else - tsk->flags &= ~PF_SPREAD_PAGE; + task_clear_spread_page(tsk); + if (is_spread_slab(cs)) - tsk->flags |= PF_SPREAD_SLAB; + task_set_spread_slab(tsk); else - tsk->flags &= ~PF_SPREAD_SLAB; + task_clear_spread_slab(tsk); } /* diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index c4b8093c80b3..f1604d8cf489 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -725,14 +725,6 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn) clear_bit(bit, addr); } -static void memory_bm_clear_current(struct memory_bitmap *bm) -{ - int bit; - - bit = max(bm->cur.node_bit - 1, 0); - clear_bit(bit, bm->cur.node->data); -} - static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) { void *addr; @@ -1341,35 +1333,23 @@ static struct memory_bitmap copy_bm; void swsusp_free(void) { - unsigned long fb_pfn, fr_pfn; - - memory_bm_position_reset(forbidden_pages_map); - memory_bm_position_reset(free_pages_map); - -loop: - fr_pfn = memory_bm_next_pfn(free_pages_map); - fb_pfn = memory_bm_next_pfn(forbidden_pages_map); - - /* - * Find the next bit set in both bitmaps. This is guaranteed to - * terminate when fb_pfn == fr_pfn == BM_END_OF_MAP. - */ - do { - if (fb_pfn < fr_pfn) - fb_pfn = memory_bm_next_pfn(forbidden_pages_map); - if (fr_pfn < fb_pfn) - fr_pfn = memory_bm_next_pfn(free_pages_map); - } while (fb_pfn != fr_pfn); - - if (fr_pfn != BM_END_OF_MAP && pfn_valid(fr_pfn)) { - struct page *page = pfn_to_page(fr_pfn); + struct zone *zone; + unsigned long pfn, max_zone_pfn; - memory_bm_clear_current(forbidden_pages_map); - memory_bm_clear_current(free_pages_map); - __free_page(page); - goto loop; + for_each_populated_zone(zone) { + max_zone_pfn = zone_end_pfn(zone); + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) + if (pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); + + if (swsusp_page_is_forbidden(page) && + swsusp_page_is_free(page)) { + swsusp_unset_page_forbidden(page); + swsusp_unset_page_free(page); + __free_page(page); + } + } } - nr_copy_pages = 0; nr_meta_pages = 0; restore_pblist = NULL; diff --git a/lib/genalloc.c b/lib/genalloc.c index bdb9a456bcbb..38d2db82228c 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -588,6 +588,7 @@ struct gen_pool *of_get_named_gen_pool(struct device_node *np, if (!np_pool) return NULL; pdev = of_find_device_by_node(np_pool); + of_node_put(np_pool); if (!pdev) return NULL; return dev_get_gen_pool(&pdev->dev); diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 25f14c586ad7..3943e14da628 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -592,13 +592,13 @@ EXPORT_SYMBOL_GPL(rhashtable_init); * rhashtable_destroy - destroy hash table * @ht: the hash table to destroy * - * Frees the bucket array. + * Frees the bucket array. This function is not rcu safe, therefore the caller + * has to make sure that no resizing may happen by unpublishing the hashtable + * and waiting for the quiescent cycle before releasing the bucket array. */ void rhashtable_destroy(const struct rhashtable *ht) { - const struct bucket_table *tbl = rht_dereference(ht->tbl, ht); - - bucket_table_free(tbl); + bucket_table_free(ht->tbl); } EXPORT_SYMBOL_GPL(rhashtable_destroy); diff --git a/mm/iov_iter.c b/mm/iov_iter.c index ab88dc0ea1d3..9a09f2034fcc 100644 --- a/mm/iov_iter.c +++ b/mm/iov_iter.c @@ -310,7 +310,7 @@ void iov_iter_init(struct iov_iter *i, int direction, EXPORT_SYMBOL(iov_iter_init); static ssize_t get_pages_iovec(struct iov_iter *i, - struct page **pages, unsigned maxpages, + struct page **pages, size_t maxsize, unsigned maxpages, size_t *start) { size_t offset = i->iov_offset; @@ -323,6 +323,8 @@ static ssize_t get_pages_iovec(struct iov_iter *i, len = iov->iov_len - offset; if (len > i->count) len = i->count; + if (len > maxsize) + len = maxsize; addr = (unsigned long)iov->iov_base + offset; len += *start = addr & (PAGE_SIZE - 1); if (len > maxpages * PAGE_SIZE) @@ -588,13 +590,15 @@ static unsigned long alignment_bvec(const struct iov_iter *i) } static ssize_t get_pages_bvec(struct iov_iter *i, - struct page **pages, unsigned maxpages, + struct page **pages, size_t maxsize, unsigned maxpages, size_t *start) { const struct bio_vec *bvec = i->bvec; size_t len = bvec->bv_len - i->iov_offset; if (len > i->count) len = i->count; + if (len > maxsize) + len = maxsize; /* can't be more than PAGE_SIZE */ *start = bvec->bv_offset + i->iov_offset; @@ -711,13 +715,13 @@ unsigned long iov_iter_alignment(const struct iov_iter *i) EXPORT_SYMBOL(iov_iter_alignment); ssize_t iov_iter_get_pages(struct iov_iter *i, - struct page **pages, unsigned maxpages, + struct page **pages, size_t maxsize, unsigned maxpages, size_t *start) { if (i->type & ITER_BVEC) - return get_pages_bvec(i, pages, maxpages, start); + return get_pages_bvec(i, pages, maxsize, maxpages, start); else - return get_pages_iovec(i, pages, maxpages, start); + return get_pages_iovec(i, pages, maxsize, maxpages, start); } EXPORT_SYMBOL(iov_iter_get_pages); diff --git a/mm/memory.c b/mm/memory.c index d17f1bcd2a91..e229970e4223 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1127,7 +1127,7 @@ again: addr) != page->index) { pte_t ptfile = pgoff_to_pte(page->index); if (pte_soft_dirty(ptent)) - pte_file_mksoft_dirty(ptfile); + ptfile = pte_file_mksoft_dirty(ptfile); set_pte_at(mm, addr, pte, ptfile); } if (PageAnon(page)) diff --git a/mm/shmem.c b/mm/shmem.c index 0e5fb225007c..469f90d56051 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2367,8 +2367,10 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc if (new_dentry->d_inode) { (void) shmem_unlink(new_dir, new_dentry); - if (they_are_dirs) + if (they_are_dirs) { + drop_nlink(new_dentry->d_inode); drop_nlink(old_dir); + } } else if (they_are_dirs) { drop_nlink(old_dir); inc_nlink(new_dir); diff --git a/mm/slab.c b/mm/slab.c index a467b308c682..7c52b3890d25 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2124,7 +2124,8 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp) int __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) { - size_t left_over, freelist_size, ralign; + size_t left_over, freelist_size; + size_t ralign = BYTES_PER_WORD; gfp_t gfp; int err; size_t size = cachep->size; @@ -2157,14 +2158,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) size &= ~(BYTES_PER_WORD - 1); } - /* - * Redzoning and user store require word alignment or possibly larger. - * Note this will be overridden by architecture or caller mandated - * alignment if either is greater than BYTES_PER_WORD. - */ - if (flags & SLAB_STORE_USER) - ralign = BYTES_PER_WORD; - if (flags & SLAB_RED_ZONE) { ralign = REDZONE_ALIGN; /* If redzoning, ensure that the second redzone is suitably @@ -2994,7 +2987,7 @@ out: #ifdef CONFIG_NUMA /* - * Try allocating on another node if PF_SPREAD_SLAB is a mempolicy is set. + * Try allocating on another node if PFA_SPREAD_SLAB is a mempolicy is set. * * If we are in_interrupt, then process context, including cpusets and * mempolicy, may not apply and should not be used for allocation policy. @@ -3226,7 +3219,7 @@ __do_cache_alloc(struct kmem_cache *cache, gfp_t flags) { void *objp; - if (current->mempolicy || unlikely(current->flags & PF_SPREAD_SLAB)) { + if (current->mempolicy || cpuset_do_slab_mem_spread()) { objp = alternate_node_alloc(cache, flags); if (objp) goto out; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 659cac15c0df..ffd379db5938 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -88,12 +88,17 @@ out: static int br_dev_init(struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); + int err; br->stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!br->stats) return -ENOMEM; - return 0; + err = br_vlan_init(br); + if (err) + free_percpu(br->stats); + + return err; } static int br_dev_open(struct net_device *dev) @@ -389,5 +394,4 @@ void br_dev_setup(struct net_device *dev) br_netfilter_rtable_init(br); br_stp_timer_init(br); br_multicast_init(br); - br_vlan_init(br); } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index a9f54a9b6690..ed307db7a12b 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -332,7 +332,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, p->port_no = index; p->flags = BR_LEARNING | BR_FLOOD; br_init_port(p); - p->state = BR_STATE_DISABLED; + br_set_state(p, BR_STATE_DISABLED); br_stp_port_timer_init(p); br_multicast_add_port(p); @@ -500,6 +500,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) if (br_fdb_insert(br, p, dev->dev_addr, 0)) netdev_err(dev, "failed insert local address bridge forwarding table\n"); + if (nbp_vlan_init(p)) + netdev_err(dev, "failed to initialize vlan filtering on this port\n"); + spin_lock_bh(&br->lock); changed_addr = br_stp_recalculate_bridge_id(br); diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 0fa66b83685f..2ff9706647f2 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -301,7 +301,7 @@ static int br_set_port_state(struct net_bridge_port *p, u8 state) (!netif_oper_up(p->dev) && state != BR_STATE_DISABLED)) return -ENETDOWN; - p->state = state; + br_set_state(p, state); br_log_state(p); br_port_state_selection(p->br); return 0; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index f53592fc3ef9..d8cbaa694227 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -299,6 +299,7 @@ struct net_bridge #ifdef CONFIG_BRIDGE_VLAN_FILTERING u8 vlan_enabled; __be16 vlan_proto; + u16 default_pvid; struct net_port_vlans __rcu *vlan_info; #endif }; @@ -604,11 +605,13 @@ bool br_vlan_find(struct net_bridge *br, u16 vid); void br_recalculate_fwd_mask(struct net_bridge *br); int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); int br_vlan_set_proto(struct net_bridge *br, unsigned long val); -void br_vlan_init(struct net_bridge *br); +int br_vlan_init(struct net_bridge *br); +int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val); int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags); int nbp_vlan_delete(struct net_bridge_port *port, u16 vid); void nbp_vlan_flush(struct net_bridge_port *port); bool nbp_vlan_find(struct net_bridge_port *port, u16 vid); +int nbp_vlan_init(struct net_bridge_port *port); static inline struct net_port_vlans *br_get_vlan_info( const struct net_bridge *br) @@ -641,11 +644,11 @@ static inline int br_vlan_get_tag(const struct sk_buff *skb, u16 *vid) static inline u16 br_get_pvid(const struct net_port_vlans *v) { - /* Return just the VID if it is set, or VLAN_N_VID (invalid vid) if - * vid wasn't set - */ + if (!v) + return 0; + smp_rmb(); - return v->pvid ?: VLAN_N_VID; + return v->pvid; } static inline int br_vlan_enabled(struct net_bridge *br) @@ -704,8 +707,9 @@ static inline void br_recalculate_fwd_mask(struct net_bridge *br) { } -static inline void br_vlan_init(struct net_bridge *br) +static inline int br_vlan_init(struct net_bridge *br) { + return 0; } static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) @@ -738,13 +742,18 @@ static inline bool nbp_vlan_find(struct net_bridge_port *port, u16 vid) return false; } +static inline int nbp_vlan_init(struct net_bridge_port *port) +{ + return 0; +} + static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag) { return 0; } static inline u16 br_get_pvid(const struct net_port_vlans *v) { - return VLAN_N_VID; /* Returns invalid vid */ + return 0; } static inline int br_vlan_enabled(struct net_bridge *br) @@ -766,6 +775,7 @@ static inline void br_nf_core_fini(void) {} /* br_stp.c */ void br_log_state(const struct net_bridge_port *p); +void br_set_state(struct net_bridge_port *p, unsigned int state); struct net_bridge_port *br_get_port(struct net_bridge *br, u16 port_no); void br_init_port(struct net_bridge_port *p); void br_become_designated_port(struct net_bridge_port *p); diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 3c86f0538cbb..2b047bcf42a4 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -36,6 +36,11 @@ void br_log_state(const struct net_bridge_port *p) br_port_state_names[p->state]); } +void br_set_state(struct net_bridge_port *p, unsigned int state) +{ + p->state = state; +} + /* called under bridge lock */ struct net_bridge_port *br_get_port(struct net_bridge *br, u16 port_no) { @@ -107,7 +112,7 @@ static void br_root_port_block(const struct net_bridge *br, br_notice(br, "port %u(%s) tried to become root port (blocked)", (unsigned int) p->port_no, p->dev->name); - p->state = BR_STATE_LISTENING; + br_set_state(p, BR_STATE_LISTENING); br_log_state(p); br_ifinfo_notify(RTM_NEWLINK, p); @@ -387,7 +392,7 @@ static void br_make_blocking(struct net_bridge_port *p) p->state == BR_STATE_LEARNING) br_topology_change_detection(p->br); - p->state = BR_STATE_BLOCKING; + br_set_state(p, BR_STATE_BLOCKING); br_log_state(p); br_ifinfo_notify(RTM_NEWLINK, p); @@ -404,13 +409,13 @@ static void br_make_forwarding(struct net_bridge_port *p) return; if (br->stp_enabled == BR_NO_STP || br->forward_delay == 0) { - p->state = BR_STATE_FORWARDING; + br_set_state(p, BR_STATE_FORWARDING); br_topology_change_detection(br); del_timer(&p->forward_delay_timer); } else if (br->stp_enabled == BR_KERNEL_STP) - p->state = BR_STATE_LISTENING; + br_set_state(p, BR_STATE_LISTENING); else - p->state = BR_STATE_LEARNING; + br_set_state(p, BR_STATE_LEARNING); br_multicast_enable_port(p); br_log_state(p); diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 189ba1e7d851..41146872c1b4 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -37,7 +37,7 @@ void br_init_port(struct net_bridge_port *p) { p->port_id = br_make_port_id(p->priority, p->port_no); br_become_designated_port(p); - p->state = BR_STATE_BLOCKING; + br_set_state(p, BR_STATE_BLOCKING); p->topology_change_ack = 0; p->config_pending = 0; } @@ -100,7 +100,7 @@ void br_stp_disable_port(struct net_bridge_port *p) wasroot = br_is_root_bridge(br); br_become_designated_port(p); - p->state = BR_STATE_DISABLED; + br_set_state(p, BR_STATE_DISABLED); p->topology_change_ack = 0; p->config_pending = 0; diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c index 558c46d19e05..4fcaa67750fd 100644 --- a/net/bridge/br_stp_timer.c +++ b/net/bridge/br_stp_timer.c @@ -87,11 +87,11 @@ static void br_forward_delay_timer_expired(unsigned long arg) (unsigned int) p->port_no, p->dev->name); spin_lock(&br->lock); if (p->state == BR_STATE_LISTENING) { - p->state = BR_STATE_LEARNING; + br_set_state(p, BR_STATE_LEARNING); mod_timer(&p->forward_delay_timer, jiffies + br->forward_delay); } else if (p->state == BR_STATE_LEARNING) { - p->state = BR_STATE_FORWARDING; + br_set_state(p, BR_STATE_FORWARDING); if (br_is_designated_for_some_port(br)) br_topology_change_detection(br); netif_carrier_on(br->dev); diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index cb431c6016ee..4c97fc50fb70 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -725,6 +725,22 @@ static ssize_t vlan_protocol_store(struct device *d, return store_bridge_parm(d, buf, len, br_vlan_set_proto); } static DEVICE_ATTR_RW(vlan_protocol); + +static ssize_t default_pvid_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct net_bridge *br = to_bridge(d); + return sprintf(buf, "%d\n", br->default_pvid); +} + +static ssize_t default_pvid_store(struct device *d, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return store_bridge_parm(d, buf, len, br_vlan_set_default_pvid); +} +static DEVICE_ATTR_RW(default_pvid); #endif static struct attribute *bridge_attrs[] = { @@ -771,6 +787,7 @@ static struct attribute *bridge_attrs[] = { #ifdef CONFIG_BRIDGE_VLAN_FILTERING &dev_attr_vlan_filtering.attr, &dev_attr_vlan_protocol.attr, + &dev_attr_default_pvid.attr, #endif NULL }; diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 3ba57fcdcd13..150048fb99b0 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -223,7 +223,7 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, * See if pvid is set on this port. That tells us which * vlan untagged or priority-tagged traffic belongs to. */ - if (pvid == VLAN_N_VID) + if (!pvid) goto drop; /* PVID is set on this port. Any untagged or priority-tagged @@ -292,7 +292,7 @@ bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) if (!*vid) { *vid = br_get_pvid(v); - if (*vid == VLAN_N_VID) + if (!*vid) return false; return true; @@ -499,9 +499,141 @@ err_filt: goto unlock; } -void br_vlan_init(struct net_bridge *br) +static bool vlan_default_pvid(struct net_port_vlans *pv, u16 vid) +{ + return pv && vid == pv->pvid && test_bit(vid, pv->untagged_bitmap); +} + +static void br_vlan_disable_default_pvid(struct net_bridge *br) +{ + struct net_bridge_port *p; + u16 pvid = br->default_pvid; + + /* Disable default_pvid on all ports where it is still + * configured. + */ + if (vlan_default_pvid(br_get_vlan_info(br), pvid)) + br_vlan_delete(br, pvid); + + list_for_each_entry(p, &br->port_list, list) { + if (vlan_default_pvid(nbp_get_vlan_info(p), pvid)) + nbp_vlan_delete(p, pvid); + } + + br->default_pvid = 0; +} + +static int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid) +{ + struct net_bridge_port *p; + u16 old_pvid; + int err = 0; + unsigned long *changed; + + changed = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long), + GFP_KERNEL); + if (!changed) + return -ENOMEM; + + old_pvid = br->default_pvid; + + /* Update default_pvid config only if we do not conflict with + * user configuration. + */ + if ((!old_pvid || vlan_default_pvid(br_get_vlan_info(br), old_pvid)) && + !br_vlan_find(br, pvid)) { + err = br_vlan_add(br, pvid, + BRIDGE_VLAN_INFO_PVID | + BRIDGE_VLAN_INFO_UNTAGGED); + if (err) + goto out; + br_vlan_delete(br, old_pvid); + set_bit(0, changed); + } + + list_for_each_entry(p, &br->port_list, list) { + /* Update default_pvid config only if we do not conflict with + * user configuration. + */ + if ((old_pvid && + !vlan_default_pvid(nbp_get_vlan_info(p), old_pvid)) || + nbp_vlan_find(p, pvid)) + continue; + + err = nbp_vlan_add(p, pvid, + BRIDGE_VLAN_INFO_PVID | + BRIDGE_VLAN_INFO_UNTAGGED); + if (err) + goto err_port; + nbp_vlan_delete(p, old_pvid); + set_bit(p->port_no, changed); + } + + br->default_pvid = pvid; + +out: + kfree(changed); + return err; + +err_port: + list_for_each_entry_continue_reverse(p, &br->port_list, list) { + if (!test_bit(p->port_no, changed)) + continue; + + if (old_pvid) + nbp_vlan_add(p, old_pvid, + BRIDGE_VLAN_INFO_PVID | + BRIDGE_VLAN_INFO_UNTAGGED); + nbp_vlan_delete(p, pvid); + } + + if (test_bit(0, changed)) { + if (old_pvid) + br_vlan_add(br, old_pvid, + BRIDGE_VLAN_INFO_PVID | + BRIDGE_VLAN_INFO_UNTAGGED); + br_vlan_delete(br, pvid); + } + goto out; +} + +int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val) +{ + u16 pvid = val; + int err = 0; + + if (val >= VLAN_VID_MASK) + return -EINVAL; + + if (!rtnl_trylock()) + return restart_syscall(); + + if (pvid == br->default_pvid) + goto unlock; + + /* Only allow default pvid change when filtering is disabled */ + if (br->vlan_enabled) { + pr_info_once("Please disable vlan filtering to change default_pvid\n"); + err = -EPERM; + goto unlock; + } + + if (!pvid) + br_vlan_disable_default_pvid(br); + else + err = __br_vlan_set_default_pvid(br, pvid); + +unlock: + rtnl_unlock(); + return err; +} + +int br_vlan_init(struct net_bridge *br) { br->vlan_proto = htons(ETH_P_8021Q); + br->default_pvid = 1; + return br_vlan_add(br, 1, + BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED); } /* Must be protected by RTNL. @@ -593,3 +725,12 @@ out: rcu_read_unlock(); return found; } + +int nbp_vlan_init(struct net_bridge_port *p) +{ + return p->br->default_pvid ? + nbp_vlan_add(p, p->br->default_pvid, + BRIDGE_VLAN_INFO_PVID | + BRIDGE_VLAN_INFO_UNTAGGED) : + 0; +} diff --git a/net/core/dev.c b/net/core/dev.c index e55c546717d4..1a90530f83ff 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2655,7 +2655,7 @@ struct sk_buff *validate_xmit_vlan(struct sk_buff *skb, netdev_features_t featur return skb; } -struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev) +static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev) { netdev_features_t features; @@ -2720,6 +2720,30 @@ out_null: return NULL; } +struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev) +{ + struct sk_buff *next, *head = NULL, *tail; + + while (skb) { + next = skb->next; + skb->next = NULL; + skb = validate_xmit_skb(skb, dev); + if (skb) { + struct sk_buff *end = skb; + + while (end->next) + end = end->next; + if (!head) + head = skb; + else + tail->next = skb; + tail = end; + } + skb = next; + } + return head; +} + static void qdisc_pkt_len_init(struct sk_buff *skb) { const struct skb_shared_info *shinfo = skb_shinfo(skb); @@ -2786,8 +2810,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, qdisc_bstats_update(q, skb); - skb = validate_xmit_skb(skb, dev); - if (skb && sch_direct_xmit(skb, q, dev, txq, root_lock)) { + if (sch_direct_xmit(skb, q, dev, txq, root_lock, true)) { if (unlikely(contended)) { spin_unlock(&q->busylock); contended = false; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 5c728aaf8d6c..443256bdcddc 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -387,6 +387,7 @@ struct pktgen_dev { u16 queue_map_min; u16 queue_map_max; __u32 skb_priority; /* skb priority field */ + unsigned int burst; /* number of duplicated packets to burst */ int node; /* Memory node */ #ifdef CONFIG_XFRM @@ -613,6 +614,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v) if (pkt_dev->traffic_class) seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); + if (pkt_dev->burst > 1) + seq_printf(seq, " burst: %d\n", pkt_dev->burst); + if (pkt_dev->node >= 0) seq_printf(seq, " node: %d\n", pkt_dev->node); @@ -1124,6 +1128,16 @@ static ssize_t pktgen_if_write(struct file *file, pkt_dev->dst_mac_count); return count; } + if (!strcmp(name, "burst")) { + len = num_arg(&user_buffer[i], 10, &value); + if (len < 0) + return len; + + i += len; + pkt_dev->burst = value < 1 ? 1 : value; + sprintf(pg_result, "OK: burst=%d", pkt_dev->burst); + return count; + } if (!strcmp(name, "node")) { len = num_arg(&user_buffer[i], 10, &value); if (len < 0) @@ -3297,6 +3311,7 @@ static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) static void pktgen_xmit(struct pktgen_dev *pkt_dev) { + unsigned int burst = ACCESS_ONCE(pkt_dev->burst); struct net_device *odev = pkt_dev->odev; struct netdev_queue *txq; int ret; @@ -3347,8 +3362,10 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->last_ok = 0; goto unlock; } - atomic_inc(&(pkt_dev->skb->users)); - ret = netdev_start_xmit(pkt_dev->skb, odev, txq, false); + atomic_add(burst, &pkt_dev->skb->users); + +xmit_more: + ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0); switch (ret) { case NETDEV_TX_OK: @@ -3356,6 +3373,8 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) pkt_dev->sofar++; pkt_dev->seq_num++; pkt_dev->tx_bytes += pkt_dev->last_pkt_size; + if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq)) + goto xmit_more; break; case NET_XMIT_DROP: case NET_XMIT_CN: @@ -3374,6 +3393,8 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) atomic_dec(&(pkt_dev->skb->users)); pkt_dev->last_ok = 0; } + if (unlikely(burst)) + atomic_sub(burst, &pkt_dev->skb->users); unlock: HARD_TX_UNLOCK(odev, txq); @@ -3572,6 +3593,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) pkt_dev->svlan_p = 0; pkt_dev->svlan_cfi = 0; pkt_dev->svlan_id = 0xffff; + pkt_dev->burst = 1; pkt_dev->node = -1; err = pktgen_setup_dev(t->net, pkt_dev, ifname); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7de3d679f3e0..9a423e2c5766 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -257,15 +257,16 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, kmemcheck_annotate_variable(shinfo->destructor_arg); if (flags & SKB_ALLOC_FCLONE) { - struct sk_buff *child = skb + 1; - atomic_t *fclone_ref = (atomic_t *) (child + 1); + struct sk_buff_fclones *fclones; - kmemcheck_annotate_bitfield(child, flags1); + fclones = container_of(skb, struct sk_buff_fclones, skb1); + + kmemcheck_annotate_bitfield(&fclones->skb2, flags1); skb->fclone = SKB_FCLONE_ORIG; - atomic_set(fclone_ref, 1); + atomic_set(&fclones->fclone_ref, 1); - child->fclone = SKB_FCLONE_UNAVAILABLE; - child->pfmemalloc = pfmemalloc; + fclones->skb2.fclone = SKB_FCLONE_FREE; + fclones->skb2.pfmemalloc = pfmemalloc; } out: return skb; @@ -524,8 +525,7 @@ static void skb_release_data(struct sk_buff *skb) */ static void kfree_skbmem(struct sk_buff *skb) { - struct sk_buff *other; - atomic_t *fclone_ref; + struct sk_buff_fclones *fclones; switch (skb->fclone) { case SKB_FCLONE_UNAVAILABLE: @@ -533,22 +533,28 @@ static void kfree_skbmem(struct sk_buff *skb) break; case SKB_FCLONE_ORIG: - fclone_ref = (atomic_t *) (skb + 2); - if (atomic_dec_and_test(fclone_ref)) - kmem_cache_free(skbuff_fclone_cache, skb); + fclones = container_of(skb, struct sk_buff_fclones, skb1); + if (atomic_dec_and_test(&fclones->fclone_ref)) + kmem_cache_free(skbuff_fclone_cache, fclones); break; case SKB_FCLONE_CLONE: - fclone_ref = (atomic_t *) (skb + 1); - other = skb - 1; + fclones = container_of(skb, struct sk_buff_fclones, skb2); - /* The clone portion is available for - * fast-cloning again. + /* Warning : We must perform the atomic_dec_and_test() before + * setting skb->fclone back to SKB_FCLONE_FREE, otherwise + * skb_clone() could set clone_ref to 2 before our decrement. + * Anyway, if we are going to free the structure, no need to + * rewrite skb->fclone. */ - skb->fclone = SKB_FCLONE_UNAVAILABLE; - - if (atomic_dec_and_test(fclone_ref)) - kmem_cache_free(skbuff_fclone_cache, other); + if (atomic_dec_and_test(&fclones->fclone_ref)) { + kmem_cache_free(skbuff_fclone_cache, fclones); + } else { + /* The clone portion is available for + * fast-cloning again. + */ + skb->fclone = SKB_FCLONE_FREE; + } break; } } @@ -859,17 +865,22 @@ EXPORT_SYMBOL_GPL(skb_copy_ubufs); struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) { - struct sk_buff *n; + struct sk_buff_fclones *fclones = container_of(skb, + struct sk_buff_fclones, + skb1); + struct sk_buff *n = &fclones->skb2; if (skb_orphan_frags(skb, gfp_mask)) return NULL; - n = skb + 1; if (skb->fclone == SKB_FCLONE_ORIG && - n->fclone == SKB_FCLONE_UNAVAILABLE) { - atomic_t *fclone_ref = (atomic_t *) (n + 1); + n->fclone == SKB_FCLONE_FREE) { n->fclone = SKB_FCLONE_CLONE; - atomic_inc(fclone_ref); + /* As our fastclone was free, clone_ref must be 1 at this point. + * We could use atomic_inc() here, but it is faster + * to set the final value. + */ + atomic_set(&fclones->fclone_ref, 2); } else { if (skb_pfmemalloc(skb)) gfp_mask |= __GFP_MEMALLOC; @@ -3155,6 +3166,9 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD; goto done; } + /* switch back to head shinfo */ + pinfo = skb_shinfo(p); + if (pinfo->frag_list) goto merge; if (skb_gro_len(p) != pinfo->gso_size) @@ -3230,7 +3244,6 @@ done: NAPI_GRO_CB(skb)->same_flow = 1; return 0; } -EXPORT_SYMBOL_GPL(skb_gro_receive); void __init skb_init(void) { @@ -3240,8 +3253,7 @@ void __init skb_init(void) SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache", - (2*sizeof(struct sk_buff)) + - sizeof(atomic_t), + sizeof(struct sk_buff_fclones), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c index 597557254ddb..83498975165f 100644 --- a/net/dccp/ccid.c +++ b/net/dccp/ccid.c @@ -99,7 +99,7 @@ static void ccid_kmem_cache_destroy(struct kmem_cache *slab) kmem_cache_destroy(slab); } -static int ccid_activate(struct ccid_operations *ccid_ops) +static int __init ccid_activate(struct ccid_operations *ccid_ops) { int err = -ENOBUFS; diff --git a/net/dccp/proto.c b/net/dccp/proto.c index de2c1e719305..1ad150ed57cf 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -1082,7 +1082,7 @@ void dccp_shutdown(struct sock *sk, int how) EXPORT_SYMBOL_GPL(dccp_shutdown); -static inline int dccp_mib_init(void) +static inline int __init dccp_mib_init(void) { dccp_statistics = alloc_percpu(struct dccp_mib); if (!dccp_statistics) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 6905f2d84c44..22f34cf4cb27 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -238,6 +238,7 @@ static void dsa_switch_destroy(struct dsa_switch *ds) { } +#ifdef CONFIG_PM_SLEEP static int dsa_switch_suspend(struct dsa_switch *ds) { int i, ret = 0; @@ -280,6 +281,7 @@ static int dsa_switch_resume(struct dsa_switch *ds) return 0; } +#endif /* link polling *************************************************************/ diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 36953c84ff2d..8030489d9cbe 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -608,7 +608,6 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent, p->phy->speed = 0; p->phy->duplex = 0; p->phy->advertising = p->phy->supported | ADVERTISED_Autoneg; - phy_start_aneg(p->phy); } return slave_dev; diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 05b708bbdb0d..4715f25dfe03 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -246,7 +246,7 @@ static u32 cipso_v4_map_cache_hash(const unsigned char *key, u32 key_len) * success, negative values on error. * */ -static int cipso_v4_cache_init(void) +static int __init cipso_v4_cache_init(void) { u32 iter; diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index dced89fbe480..efa70ad44906 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -7,6 +7,7 @@ #include <linux/types.h> #include <linux/kernel.h> #include <net/genetlink.h> +#include <net/gue.h> #include <net/ip.h> #include <net/protocol.h> #include <net/udp.h> @@ -27,6 +28,7 @@ struct fou { }; struct fou_cfg { + u16 type; u8 protocol; struct udp_port_cfg udp_config; }; @@ -64,15 +66,51 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb) sizeof(struct udphdr)); } +static int gue_udp_recv(struct sock *sk, struct sk_buff *skb) +{ + struct fou *fou = fou_from_sock(sk); + size_t len; + struct guehdr *guehdr; + struct udphdr *uh; + + if (!fou) + return 1; + + len = sizeof(struct udphdr) + sizeof(struct guehdr); + if (!pskb_may_pull(skb, len)) + goto drop; + + uh = udp_hdr(skb); + guehdr = (struct guehdr *)&uh[1]; + + len += guehdr->hlen << 2; + if (!pskb_may_pull(skb, len)) + goto drop; + + if (guehdr->version != 0) + goto drop; + + if (guehdr->flags) { + /* No support yet */ + goto drop; + } + + return fou_udp_encap_recv_deliver(skb, guehdr->next_hdr, len); +drop: + kfree_skb(skb); + return 0; +} + static struct sk_buff **fou_gro_receive(struct sk_buff **head, - struct sk_buff *skb, - const struct net_offload **offloads) + struct sk_buff *skb) { const struct net_offload *ops; struct sk_buff **pp = NULL; u8 proto = NAPI_GRO_CB(skb)->proto; + const struct net_offload **offloads; rcu_read_lock(); + offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; ops = rcu_dereference(offloads[proto]); if (!ops || !ops->callbacks.gro_receive) goto out_unlock; @@ -85,14 +123,15 @@ out_unlock: return pp; } -static int fou_gro_complete(struct sk_buff *skb, int nhoff, - const struct net_offload **offloads) +static int fou_gro_complete(struct sk_buff *skb, int nhoff) { const struct net_offload *ops; u8 proto = NAPI_GRO_CB(skb)->proto; int err = -ENOSYS; + const struct net_offload **offloads; rcu_read_lock(); + offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; ops = rcu_dereference(offloads[proto]); if (WARN_ON(!ops || !ops->callbacks.gro_complete)) goto out_unlock; @@ -105,26 +144,110 @@ out_unlock: return err; } -static struct sk_buff **fou4_gro_receive(struct sk_buff **head, - struct sk_buff *skb) +static struct sk_buff **gue_gro_receive(struct sk_buff **head, + struct sk_buff *skb) { - return fou_gro_receive(head, skb, inet_offloads); -} + const struct net_offload **offloads; + const struct net_offload *ops; + struct sk_buff **pp = NULL; + struct sk_buff *p; + u8 proto; + struct guehdr *guehdr; + unsigned int hlen, guehlen; + unsigned int off; + int flush = 1; + + off = skb_gro_offset(skb); + hlen = off + sizeof(*guehdr); + guehdr = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, hlen)) { + guehdr = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!guehdr)) + goto out; + } -static int fou4_gro_complete(struct sk_buff *skb, int nhoff) -{ - return fou_gro_complete(skb, nhoff, inet_offloads); -} + proto = guehdr->next_hdr; -static struct sk_buff **fou6_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - return fou_gro_receive(head, skb, inet6_offloads); + rcu_read_lock(); + offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; + ops = rcu_dereference(offloads[proto]); + if (WARN_ON(!ops || !ops->callbacks.gro_receive)) + goto out_unlock; + + guehlen = sizeof(*guehdr) + (guehdr->hlen << 2); + + hlen = off + guehlen; + if (skb_gro_header_hard(skb, hlen)) { + guehdr = skb_gro_header_slow(skb, hlen, off); + if (unlikely(!guehdr)) + goto out_unlock; + } + + flush = 0; + + for (p = *head; p; p = p->next) { + const struct guehdr *guehdr2; + + if (!NAPI_GRO_CB(p)->same_flow) + continue; + + guehdr2 = (struct guehdr *)(p->data + off); + + /* Compare base GUE header to be equal (covers + * hlen, version, next_hdr, and flags. + */ + if (guehdr->word != guehdr2->word) { + NAPI_GRO_CB(p)->same_flow = 0; + continue; + } + + /* Compare optional fields are the same. */ + if (guehdr->hlen && memcmp(&guehdr[1], &guehdr2[1], + guehdr->hlen << 2)) { + NAPI_GRO_CB(p)->same_flow = 0; + continue; + } + } + + skb_gro_pull(skb, guehlen); + + /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/ + skb_gro_postpull_rcsum(skb, guehdr, guehlen); + + pp = ops->callbacks.gro_receive(head, skb); + +out_unlock: + rcu_read_unlock(); +out: + NAPI_GRO_CB(skb)->flush |= flush; + + return pp; } -static int fou6_gro_complete(struct sk_buff *skb, int nhoff) +static int gue_gro_complete(struct sk_buff *skb, int nhoff) { - return fou_gro_complete(skb, nhoff, inet6_offloads); + const struct net_offload **offloads; + struct guehdr *guehdr = (struct guehdr *)(skb->data + nhoff); + const struct net_offload *ops; + unsigned int guehlen; + u8 proto; + int err = -ENOENT; + + proto = guehdr->next_hdr; + + guehlen = sizeof(*guehdr) + (guehdr->hlen << 2); + + rcu_read_lock(); + offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; + ops = rcu_dereference(offloads[proto]); + if (WARN_ON(!ops || !ops->callbacks.gro_complete)) + goto out_unlock; + + err = ops->callbacks.gro_complete(skb, nhoff + guehlen); + +out_unlock: + rcu_read_unlock(); + return err; } static int fou_add_to_port_list(struct fou *fou) @@ -162,6 +285,28 @@ static void fou_release(struct fou *fou) kfree(fou); } +static int fou_encap_init(struct sock *sk, struct fou *fou, struct fou_cfg *cfg) +{ + udp_sk(sk)->encap_rcv = fou_udp_recv; + fou->protocol = cfg->protocol; + fou->udp_offloads.callbacks.gro_receive = fou_gro_receive; + fou->udp_offloads.callbacks.gro_complete = fou_gro_complete; + fou->udp_offloads.port = cfg->udp_config.local_udp_port; + fou->udp_offloads.ipproto = cfg->protocol; + + return 0; +} + +static int gue_encap_init(struct sock *sk, struct fou *fou, struct fou_cfg *cfg) +{ + udp_sk(sk)->encap_rcv = gue_udp_recv; + fou->udp_offloads.callbacks.gro_receive = gue_gro_receive; + fou->udp_offloads.callbacks.gro_complete = gue_gro_complete; + fou->udp_offloads.port = cfg->udp_config.local_udp_port; + + return 0; +} + static int fou_create(struct net *net, struct fou_cfg *cfg, struct socket **sockp) { @@ -184,10 +329,24 @@ static int fou_create(struct net *net, struct fou_cfg *cfg, sk = sock->sk; - /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ - fou->protocol = cfg->protocol; - fou->port = cfg->udp_config.local_udp_port; - udp_sk(sk)->encap_rcv = fou_udp_recv; + fou->port = cfg->udp_config.local_udp_port; + + /* Initial for fou type */ + switch (cfg->type) { + case FOU_ENCAP_DIRECT: + err = fou_encap_init(sk, fou, cfg); + if (err) + goto error; + break; + case FOU_ENCAP_GUE: + err = gue_encap_init(sk, fou, cfg); + if (err) + goto error; + break; + default: + err = -EINVAL; + goto error; + } udp_sk(sk)->encap_type = 1; udp_encap_enable(); @@ -199,23 +358,6 @@ static int fou_create(struct net *net, struct fou_cfg *cfg, sk->sk_allocation = GFP_ATOMIC; - switch (cfg->udp_config.family) { - case AF_INET: - fou->udp_offloads.callbacks.gro_receive = fou4_gro_receive; - fou->udp_offloads.callbacks.gro_complete = fou4_gro_complete; - break; - case AF_INET6: - fou->udp_offloads.callbacks.gro_receive = fou6_gro_receive; - fou->udp_offloads.callbacks.gro_complete = fou6_gro_complete; - break; - default: - err = -EPFNOSUPPORT; - goto error; - } - - fou->udp_offloads.port = cfg->udp_config.local_udp_port; - fou->udp_offloads.ipproto = cfg->protocol; - if (cfg->udp_config.family == AF_INET) { err = udp_add_offload(&fou->udp_offloads); if (err) @@ -272,6 +414,7 @@ static struct nla_policy fou_nl_policy[FOU_ATTR_MAX + 1] = { [FOU_ATTR_PORT] = { .type = NLA_U16, }, [FOU_ATTR_AF] = { .type = NLA_U8, }, [FOU_ATTR_IPPROTO] = { .type = NLA_U8, }, + [FOU_ATTR_TYPE] = { .type = NLA_U8, }, }; static int parse_nl_config(struct genl_info *info, @@ -299,6 +442,9 @@ static int parse_nl_config(struct genl_info *info, if (info->attrs[FOU_ATTR_IPPROTO]) cfg->protocol = nla_get_u8(info->attrs[FOU_ATTR_IPPROTO]); + if (info->attrs[FOU_ATTR_TYPE]) + cfg->type = nla_get_u8(info->attrs[FOU_ATTR_TYPE]); + return 0; } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 15f0e2bad7ad..2811cc18701a 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -790,7 +790,7 @@ static void __net_exit ip4_frags_ns_ctl_unregister(struct net *net) kfree(table); } -static void ip4_frags_ctl_register(void) +static void __init ip4_frags_ctl_register(void) { register_net_sysctl(&init_net, "net/ipv4", ip4_frags_ctl_table); } @@ -804,7 +804,7 @@ static inline void ip4_frags_ns_ctl_unregister(struct net *net) { } -static inline void ip4_frags_ctl_register(void) +static inline void __init ip4_frags_ctl_register(void) { } #endif diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 829aff8bf723..0485ef18d254 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -241,6 +241,8 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, /* Push GRE header. */ gre_build_header(skb, &tpi, tunnel->tun_hlen); + skb_set_inner_protocol(skb, tpi.proto); + ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol); } diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index b75b47b0a223..0bb8e141eacc 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -56,6 +56,7 @@ #include <net/netns/generic.h> #include <net/rtnetlink.h> #include <net/udp.h> +#include <net/gue.h> #if IS_ENABLED(CONFIG_IPV6) #include <net/ipv6.h> @@ -495,6 +496,8 @@ static int ip_encap_hlen(struct ip_tunnel_encap *e) return 0; case TUNNEL_ENCAP_FOU: return sizeof(struct udphdr); + case TUNNEL_ENCAP_GUE: + return sizeof(struct udphdr) + sizeof(struct guehdr); default: return -EINVAL; } @@ -546,6 +549,15 @@ static int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, skb_reset_transport_header(skb); uh = udp_hdr(skb); + if (e->type == TUNNEL_ENCAP_GUE) { + struct guehdr *guehdr = (struct guehdr *)&uh[1]; + + guehdr->version = 0; + guehdr->hlen = 0; + guehdr->flags = 0; + guehdr->next_hdr = *protocol; + } + uh->dest = e->dport; uh->source = sport; uh->len = htons(skb->len); @@ -565,6 +577,7 @@ int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t, case TUNNEL_ENCAP_NONE: return 0; case TUNNEL_ENCAP_FOU: + case TUNNEL_ENCAP_GUE: return fou_build_header(skb, &t->encap, t->encap_hlen, protocol, fl4); default: @@ -759,7 +772,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, df |= (inner_iph->frag_off&htons(IP_DF)); max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr) - + rt->dst.header_len; + + rt->dst.header_len + ip_encap_hlen(&tunnel->encap); if (max_headroom > dev->needed_headroom) dev->needed_headroom = max_headroom; @@ -853,9 +866,14 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); - if (!t && (cmd == SIOCADDTUNNEL)) { - t = ip_tunnel_create(net, itn, p); - err = PTR_ERR_OR_ZERO(t); + if (cmd == SIOCADDTUNNEL) { + if (!t) { + t = ip_tunnel_create(net, itn, p); + err = PTR_ERR_OR_ZERO(t); + break; + } + + err = -EEXIST; break; } if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index bfec31df8b21..ea88ab3102a8 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -224,6 +224,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (IS_ERR(skb)) goto out; + skb_set_inner_ipproto(skb, IPPROTO_IPIP); + ip_tunnel_xmit(skb, dev, tiph, tiph->protocol); return NETDEV_TX_OK; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d4bd68dcdc39..793c0bb8c4fd 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -746,7 +746,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow } n = ipv4_neigh_lookup(&rt->dst, NULL, &new_gw); - if (n) { + if (!IS_ERR(n)) { if (!(n->nud_state & NUD_VALID)) { neigh_event_send(n, NULL); } else { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index cf5e508e1ef5..26a6f113f00c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2693,7 +2693,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, break; #endif case TCP_USER_TIMEOUT: - /* Cap the max timeout in ms TCP will retry/retrans + /* Cap the max time in ms TCP will retry or probe the window * before giving up and aborting (ETIMEDOUT) a connection. */ if (val < 0) @@ -3172,7 +3172,7 @@ static int __init set_thash_entries(char *str) } __setup("thash_entries=", set_thash_entries); -static void tcp_init_mem(void) +static void __init tcp_init_mem(void) { unsigned long limit = nr_free_buffer_pages() / 8; limit = max(limit, 128UL); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ee567e9e98c3..8d4eac793700 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2110,10 +2110,7 @@ bool tcp_schedule_loss_probe(struct sock *sk) static bool skb_still_in_host_queue(const struct sock *sk, const struct sk_buff *skb) { - const struct sk_buff *fclone = skb + 1; - - if (unlikely(skb->fclone == SKB_FCLONE_ORIG && - fclone->fclone == SKB_FCLONE_CLONE)) { + if (unlikely(skb_fclone_busy(skb))) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES); return true; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index b24360f6e293..9b21ae8b2e31 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -52,7 +52,7 @@ static void tcp_write_err(struct sock *sk) * limit. * 2. If we have strong memory pressure. */ -static int tcp_out_of_resources(struct sock *sk, int do_reset) +static int tcp_out_of_resources(struct sock *sk, bool do_reset) { struct tcp_sock *tp = tcp_sk(sk); int shift = 0; @@ -72,7 +72,7 @@ static int tcp_out_of_resources(struct sock *sk, int do_reset) if ((s32)(tcp_time_stamp - tp->lsndtime) <= TCP_TIMEWAIT_LEN || /* 2. Window is closed. */ (!tp->snd_wnd && !tp->packets_out)) - do_reset = 1; + do_reset = true; if (do_reset) tcp_send_active_reset(sk, GFP_ATOMIC); tcp_done(sk); @@ -270,40 +270,41 @@ static void tcp_probe_timer(struct sock *sk) struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); int max_probes; + u32 start_ts; if (tp->packets_out || !tcp_send_head(sk)) { icsk->icsk_probes_out = 0; return; } - /* *WARNING* RFC 1122 forbids this - * - * It doesn't AFAIK, because we kill the retransmit timer -AK - * - * FIXME: We ought not to do it, Solaris 2.5 actually has fixing - * this behaviour in Solaris down as a bug fix. [AC] - * - * Let me to explain. icsk_probes_out is zeroed by incoming ACKs - * even if they advertise zero window. Hence, connection is killed only - * if we received no ACKs for normal connection timeout. It is not killed - * only because window stays zero for some time, window may be zero - * until armageddon and even later. We are in full accordance - * with RFCs, only probe timer combines both retransmission timeout - * and probe timeout in one bottle. --ANK + /* RFC 1122 4.2.2.17 requires the sender to stay open indefinitely as + * long as the receiver continues to respond probes. We support this by + * default and reset icsk_probes_out with incoming ACKs. But if the + * socket is orphaned or the user specifies TCP_USER_TIMEOUT, we + * kill the socket when the retry count and the time exceeds the + * corresponding system limit. We also implement similar policy when + * we use RTO to probe window in tcp_retransmit_timer(). */ - max_probes = sysctl_tcp_retries2; + start_ts = tcp_skb_timestamp(tcp_send_head(sk)); + if (!start_ts) + skb_mstamp_get(&tcp_send_head(sk)->skb_mstamp); + else if (icsk->icsk_user_timeout && + (s32)(tcp_time_stamp - start_ts) > icsk->icsk_user_timeout) + goto abort; + max_probes = sysctl_tcp_retries2; if (sock_flag(sk, SOCK_DEAD)) { const int alive = inet_csk_rto_backoff(icsk, TCP_RTO_MAX) < TCP_RTO_MAX; max_probes = tcp_orphan_retries(sk, alive); - - if (tcp_out_of_resources(sk, alive || icsk->icsk_probes_out <= max_probes)) + if (!alive && icsk->icsk_backoff >= max_probes) + goto abort; + if (tcp_out_of_resources(sk, true)) return; } if (icsk->icsk_probes_out > max_probes) { - tcp_write_err(sk); +abort: tcp_write_err(sk); } else { /* Only send another probe if we didn't close things up. */ tcp_send_probe0(sk); diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 19ebe6a39ddc..507310ef4b56 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -25,8 +25,11 @@ struct udp_offload_priv { struct udp_offload_priv __rcu *next; }; -struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, - netdev_features_t features) +static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, + netdev_features_t features, + struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb, + netdev_features_t features), + __be16 new_protocol) { struct sk_buff *segs = ERR_PTR(-EINVAL); u16 mac_offset = skb->mac_header; @@ -48,7 +51,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, skb_reset_mac_header(skb); skb_set_network_header(skb, skb_inner_network_offset(skb)); skb->mac_len = skb_inner_network_offset(skb); - skb->protocol = htons(ETH_P_TEB); + skb->protocol = new_protocol; need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM); if (need_csum) @@ -56,7 +59,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, /* segment inner packet. */ enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); - segs = skb_mac_gso_segment(skb, enc_features); + segs = gso_inner_segment(skb, enc_features); if (IS_ERR_OR_NULL(segs)) { skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, mac_len); @@ -101,6 +104,44 @@ out: return segs; } +struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, + netdev_features_t features, + bool is_ipv6) +{ + __be16 protocol = skb->protocol; + const struct net_offload **offloads; + const struct net_offload *ops; + struct sk_buff *segs = ERR_PTR(-EINVAL); + struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb, + netdev_features_t features); + + rcu_read_lock(); + + switch (skb->inner_protocol_type) { + case ENCAP_TYPE_ETHER: + protocol = skb->inner_protocol; + gso_inner_segment = skb_mac_gso_segment; + break; + case ENCAP_TYPE_IPPROTO: + offloads = is_ipv6 ? inet6_offloads : inet_offloads; + ops = rcu_dereference(offloads[skb->inner_ipproto]); + if (!ops || !ops->callbacks.gso_segment) + goto out_unlock; + gso_inner_segment = ops->callbacks.gso_segment; + break; + default: + goto out_unlock; + } + + segs = __skb_udp_tunnel_segment(skb, features, gso_inner_segment, + protocol); + +out_unlock: + rcu_read_unlock(); + + return segs; +} + static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, netdev_features_t features) { @@ -113,7 +154,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, if (skb->encapsulation && (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))) { - segs = skb_udp_tunnel_segment(skb, features); + segs = skb_udp_tunnel_segment(skb, features, false); goto out; } @@ -293,6 +334,7 @@ static struct sk_buff **udp4_gro_receive(struct sk_buff **head, skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check, inet_gro_compute_pseudo); skip: + NAPI_GRO_CB(skb)->is_ipv6 = 0; return udp_gro_receive(head, skb, uh); flush: diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e189480f8fd6..725c763270a0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4783,10 +4783,11 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) if (ip6_del_rt(ifp->rt)) dst_free(&ifp->rt->dst); + + rt_genid_bump_ipv6(net); break; } atomic_inc(&net->ipv6.dev_addr_genid); - rt_genid_bump_ipv6(net); } static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index e6960457f625..98cc4cd570e2 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c @@ -8,6 +8,13 @@ #include <net/addrconf.h> #include <net/ip.h> +/* if ipv6 module registers this function is used by xfrm to force all + * sockets to relookup their nodes - this is fairly expensive, be + * careful + */ +void (*__fib6_flush_trees)(struct net *); +EXPORT_SYMBOL(__fib6_flush_trees); + #define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16) static inline unsigned int ipv6_addr_scope2type(unsigned int scope) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 76b7f5ee8f4c..97b9fa8de377 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1605,6 +1605,24 @@ static void fib6_prune_clones(struct net *net, struct fib6_node *fn) fib6_clean_tree(net, fn, fib6_prune_clone, 1, NULL); } +static int fib6_update_sernum(struct rt6_info *rt, void *arg) +{ + __u32 sernum = *(__u32 *)arg; + + if (rt->rt6i_node && + rt->rt6i_node->fn_sernum != sernum) + rt->rt6i_node->fn_sernum = sernum; + + return 0; +} + +static void fib6_flush_trees(struct net *net) +{ + __u32 new_sernum = fib6_new_sernum(); + + fib6_clean_all(net, fib6_update_sernum, &new_sernum); +} + /* * Garbage collection */ @@ -1788,6 +1806,8 @@ int __init fib6_init(void) NULL); if (ret) goto out_unregister_subsys; + + __fib6_flush_trees = fib6_flush_trees; out: return ret; diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 5f19dfbc4c6a..74b677916a70 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -314,6 +314,8 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); t = ip6gre_tunnel_find(net, parms, ARPHRD_IP6GRE); + if (t && create) + return NULL; if (t || !create) return t; @@ -616,6 +618,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, int err = -1; u8 proto; struct sk_buff *new_skb; + __be16 protocol; if (dev->type == ARPHRD_ETHER) IPCB(skb)->flags = 0; @@ -732,8 +735,9 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, ipv6h->daddr = fl6->daddr; ((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags; - ((__be16 *)(ipv6h + 1))[1] = (dev->type == ARPHRD_ETHER) ? - htons(ETH_P_TEB) : skb->protocol; + protocol = (dev->type == ARPHRD_ETHER) ? + htons(ETH_P_TEB) : skb->protocol; + ((__be16 *)(ipv6h + 1))[1] = protocol; if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { __be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4); @@ -754,6 +758,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, } } + skb_set_inner_protocol(skb, protocol); + ip6tunnel_xmit(skb, dev); if (ndst) ip6_tnl_dst_store(tunnel, ndst); @@ -1724,4 +1730,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("D. Kozlov ([email protected])"); MODULE_DESCRIPTION("GRE over IPv6 tunneling device"); MODULE_ALIAS_RTNL_LINK("ip6gre"); +MODULE_ALIAS_RTNL_LINK("ip6gretap"); MODULE_ALIAS_NETDEV("ip6gre0"); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index e01bd0399297..d3e8888ad611 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -364,8 +364,12 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net, (t = rtnl_dereference(*tp)) != NULL; tp = &t->next) { if (ipv6_addr_equal(local, &t->parms.laddr) && - ipv6_addr_equal(remote, &t->parms.raddr)) + ipv6_addr_equal(remote, &t->parms.raddr)) { + if (create) + return NULL; + return t; + } } if (!create) return NULL; diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 7f52fd9fa7b0..5833a2244467 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -253,8 +253,12 @@ static struct ip6_tnl *vti6_locate(struct net *net, struct __ip6_tnl_parm *p, (t = rtnl_dereference(*tp)) != NULL; tp = &t->next) { if (ipv6_addr_equal(local, &t->parms.laddr) && - ipv6_addr_equal(remote, &t->parms.raddr)) + ipv6_addr_equal(remote, &t->parms.raddr)) { + if (create) + return NULL; + return t; + } } if (!create) return NULL; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f74b0417bd60..a318dd89b6d9 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -314,7 +314,6 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net, memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers); - rt->rt6i_genid = rt_genid_ipv6(net); INIT_LIST_HEAD(&rt->rt6i_siblings); } return rt; @@ -1096,9 +1095,6 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) * DST_OBSOLETE_FORCE_CHK which forces validation calls down * into this function always. */ - if (rt->rt6i_genid != rt_genid_ipv6(dev_net(rt->dst.dev))) - return NULL; - if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie)) return NULL; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index db75809ab843..0d4e27466f82 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -982,6 +982,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, goto tx_error; } + skb_set_inner_ipproto(skb, IPPROTO_IPV6); + err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl, df, !net_eq(tunnel->net, dev_net(dev))); @@ -1006,6 +1008,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (IS_ERR(skb)) goto out; + skb_set_inner_ipproto(skb, IPPROTO_IPIP); + ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP); return NETDEV_TX_OK; out: diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 212ebfc7973f..6b8f543f6ac6 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -58,7 +58,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, if (skb->encapsulation && skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM)) - segs = skb_udp_tunnel_segment(skb, features); + segs = skb_udp_tunnel_segment(skb, features, true); else { const struct ipv6hdr *ipv6h; struct udphdr *uh; @@ -140,6 +140,7 @@ static struct sk_buff **udp6_gro_receive(struct sk_buff **head, ip6_gro_compute_pseudo); skip: + NAPI_GRO_CB(skb)->is_ipv6 = 1; return udp_gro_receive(head, skb, uh); flush: diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 608d18986923..ae5096ab65eb 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -856,6 +856,7 @@ config NETFILTER_XT_TARGET_TPROXY tristate '"TPROXY" target transparent proxying support' depends on NETFILTER_XTABLES depends on NETFILTER_ADVANCED + depends on (IPV6 || IPV6=n) depends on IP_NF_MANGLE select NF_DEFRAG_IPV4 select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index f77d3f7f22b5..6c5a915cfa75 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -222,6 +222,51 @@ replay: } } +struct nfnl_err { + struct list_head head; + struct nlmsghdr *nlh; + int err; +}; + +static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err) +{ + struct nfnl_err *nfnl_err; + + nfnl_err = kmalloc(sizeof(struct nfnl_err), GFP_KERNEL); + if (nfnl_err == NULL) + return -ENOMEM; + + nfnl_err->nlh = nlh; + nfnl_err->err = err; + list_add_tail(&nfnl_err->head, list); + + return 0; +} + +static void nfnl_err_del(struct nfnl_err *nfnl_err) +{ + list_del(&nfnl_err->head); + kfree(nfnl_err); +} + +static void nfnl_err_reset(struct list_head *err_list) +{ + struct nfnl_err *nfnl_err, *next; + + list_for_each_entry_safe(nfnl_err, next, err_list, head) + nfnl_err_del(nfnl_err); +} + +static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb) +{ + struct nfnl_err *nfnl_err, *next; + + list_for_each_entry_safe(nfnl_err, next, err_list, head) { + netlink_ack(skb, nfnl_err->nlh, nfnl_err->err); + nfnl_err_del(nfnl_err); + } +} + static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, u_int16_t subsys_id) { @@ -230,6 +275,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, const struct nfnetlink_subsystem *ss; const struct nfnl_callback *nc; bool success = true, done = false; + static LIST_HEAD(err_list); int err; if (subsys_id >= NFNL_SUBSYS_COUNT) @@ -287,6 +333,7 @@ replay: type = nlh->nlmsg_type; if (type == NFNL_MSG_BATCH_BEGIN) { /* Malformed: Batch begin twice */ + nfnl_err_reset(&err_list); success = false; goto done; } else if (type == NFNL_MSG_BATCH_END) { @@ -333,6 +380,7 @@ replay: * original skb. */ if (err == -EAGAIN) { + nfnl_err_reset(&err_list); ss->abort(oskb); nfnl_unlock(subsys_id); kfree_skb(nskb); @@ -341,11 +389,24 @@ replay: } ack: if (nlh->nlmsg_flags & NLM_F_ACK || err) { + /* Errors are delivered once the full batch has been + * processed, this avoids that the same error is + * reported several times when replaying the batch. + */ + if (nfnl_err_add(&err_list, nlh, err) < 0) { + /* We failed to enqueue an error, reset the + * list of errors and send OOM to userspace + * pointing to the batch header. + */ + nfnl_err_reset(&err_list); + netlink_ack(skb, nlmsg_hdr(oskb), -ENOMEM); + success = false; + goto done; + } /* We don't stop processing the batch on errors, thus, * userspace gets all the errors that the batch * triggers. */ - netlink_ack(skb, nlh, err); if (err) success = false; } @@ -361,6 +422,7 @@ done: else ss->abort(oskb); + nfnl_err_deliver(&err_list, oskb); nfnl_unlock(subsys_id); kfree_skb(nskb); } diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 28fb8f38e6ba..8892b7b6184a 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c @@ -180,15 +180,17 @@ static int nft_hash_init(const struct nft_set *set, static void nft_hash_destroy(const struct nft_set *set) { const struct rhashtable *priv = nft_set_priv(set); - const struct bucket_table *tbl; + const struct bucket_table *tbl = priv->tbl; struct nft_hash_elem *he, *next; unsigned int i; - tbl = rht_dereference(priv->tbl, priv); - for (i = 0; i < tbl->size; i++) - rht_for_each_entry_safe(he, next, tbl->buckets[i], priv, node) + for (i = 0; i < tbl->size; i++) { + for (he = rht_entry(tbl->buckets[i], struct nft_hash_elem, node); + he != NULL; he = next) { + next = rht_entry(he->node.next, struct nft_hash_elem, node); nft_hash_elem_destroy(set, he); - + } + } rhashtable_destroy(priv); } diff --git a/net/netfilter/nft_rbtree.c b/net/netfilter/nft_rbtree.c index e1836ff88199..46214f245665 100644 --- a/net/netfilter/nft_rbtree.c +++ b/net/netfilter/nft_rbtree.c @@ -234,13 +234,11 @@ static void nft_rbtree_destroy(const struct nft_set *set) struct nft_rbtree_elem *rbe; struct rb_node *node; - spin_lock_bh(&nft_rbtree_lock); while ((node = priv->root.rb_node) != NULL) { rb_erase(node, &priv->root); rbe = rb_entry(node, struct nft_rbtree_elem, node); nft_rbtree_elem_destroy(set, rbe); } - spin_unlock_bh(&nft_rbtree_lock); } static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 8d0e83d6903e..30f10fb07f4a 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -254,10 +254,15 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, cp->tp = tp; if (p->perfect) { + int i; + cp->perfect = kmemdup(p->perfect, sizeof(*r) * cp->hash, GFP_KERNEL); if (!cp->perfect) goto errout; + for (i = 0; i < cp->hash; i++) + tcf_exts_init(&cp->perfect[i].exts, + TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); balloc = 1; } cp->h = p->h; @@ -353,6 +358,9 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, f = kzalloc(sizeof(*f), GFP_KERNEL); if (!f) goto errout_alloc; + f->key = handle; + tcindex_filter_result_init(&f->result); + f->next = NULL; } if (tb[TCA_TCINDEX_CLASSID]) { @@ -376,9 +384,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, struct tcindex_filter *nfp; struct tcindex_filter __rcu **fp; - f->key = handle; - f->result = new_filter_result; - f->next = NULL; + tcf_exts_change(tp, &f->result.exts, &r->exts); fp = cp->h + (handle % cp->hash); for (nfp = rtnl_dereference(*fp); diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 4be3ebf46d67..0472909bb014 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -358,7 +358,6 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n, bool free_pf) { - tcf_unbind_filter(tp, &n->res); tcf_exts_destroy(&n->exts); if (n->ht_down) n->ht_down->refcnt--; @@ -416,6 +415,7 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) if (pkp == key) { RCU_INIT_POINTER(*kp, key->next); + tcf_unbind_filter(tp, &key->res); call_rcu(&key->rcu, u32_delete_key_freepf_rcu); return 0; } @@ -425,7 +425,7 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) return 0; } -static void u32_clear_hnode(struct tc_u_hnode *ht) +static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht) { struct tc_u_knode *n; unsigned int h; @@ -434,6 +434,7 @@ static void u32_clear_hnode(struct tc_u_hnode *ht) while ((n = rtnl_dereference(ht->ht[h])) != NULL) { RCU_INIT_POINTER(ht->ht[h], rtnl_dereference(n->next)); + tcf_unbind_filter(tp, &n->res); call_rcu(&n->rcu, u32_delete_key_freepf_rcu); } } @@ -447,7 +448,7 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht) WARN_ON(ht->refcnt); - u32_clear_hnode(ht); + u32_clear_hnode(tp, ht); hn = &tp_c->hlist; for (phn = rtnl_dereference(*hn); @@ -482,7 +483,7 @@ static void u32_destroy(struct tcf_proto *tp) ht; ht = rtnl_dereference(ht->next)) { ht->refcnt--; - u32_clear_hnode(ht); + u32_clear_hnode(tp, ht); } while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) { @@ -731,6 +732,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, } u32_replace_knode(tp, tp_c, new); + tcf_unbind_filter(tp, &n->res); call_rcu(&n->rcu, u32_delete_key_rcu); return 0; } diff --git a/net/sched/ematch.c b/net/sched/ematch.c index 3a633debb6df..ad57f4444b9c 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -526,9 +526,11 @@ pop_stack: match_idx = stack[--stackp]; cur_match = tcf_em_get_match(tree, match_idx); - if (tcf_em_early_end(cur_match, res)) + if (tcf_em_early_end(cur_match, res)) { + if (tcf_em_is_inverted(cur_match)) + res = !res; goto pop_stack; - else { + } else { match_idx++; goto proceed; } diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index aa8329508dba..c79a226cc25c 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -578,8 +578,10 @@ static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, timer); + rcu_read_lock(); qdisc_unthrottled(wd->qdisc); __netif_schedule(qdisc_root(wd->qdisc)); + rcu_read_unlock(); return HRTIMER_NORESTART; } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 7c8e5d73d433..2b349a4de3c8 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -56,11 +56,34 @@ static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) return 0; } -static inline struct sk_buff *dequeue_skb(struct Qdisc *q) +static void try_bulk_dequeue_skb(struct Qdisc *q, + struct sk_buff *skb, + const struct netdev_queue *txq) +{ + int bytelimit = qdisc_avail_bulklimit(txq) - skb->len; + + while (bytelimit > 0) { + struct sk_buff *nskb = q->dequeue(q); + + if (!nskb) + break; + + bytelimit -= nskb->len; /* covers GSO len */ + skb->next = nskb; + skb = nskb; + } + skb->next = NULL; +} + +/* Note that dequeue_skb can possibly return a SKB list (via skb->next). + * A requeued skb (via q->gso_skb) can also be a SKB list. + */ +static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate) { struct sk_buff *skb = q->gso_skb; const struct netdev_queue *txq = q->dev_queue; + *validate = true; if (unlikely(skb)) { /* check the reason of requeuing without tx lock first */ txq = skb_get_tx_queue(txq->dev, skb); @@ -69,14 +92,16 @@ static inline struct sk_buff *dequeue_skb(struct Qdisc *q) q->q.qlen--; } else skb = NULL; + /* skb in gso_skb were already validated */ + *validate = false; } else { - if (!(q->flags & TCQ_F_ONETXQUEUE) || !netif_xmit_frozen_or_stopped(txq)) { + if (!(q->flags & TCQ_F_ONETXQUEUE) || + !netif_xmit_frozen_or_stopped(txq)) { skb = q->dequeue(q); - if (skb) - skb = validate_xmit_skb(skb, qdisc_dev(q)); + if (skb && qdisc_may_bulk(q)) + try_bulk_dequeue_skb(q, skb, txq); } } - return skb; } @@ -120,19 +145,24 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb, */ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, struct net_device *dev, struct netdev_queue *txq, - spinlock_t *root_lock) + spinlock_t *root_lock, bool validate) { int ret = NETDEV_TX_BUSY; /* And release qdisc */ spin_unlock(root_lock); - HARD_TX_LOCK(dev, txq, smp_processor_id()); - if (!netif_xmit_frozen_or_stopped(txq)) - skb = dev_hard_start_xmit(skb, dev, txq, &ret); + /* Note that we validate skb (GSO, checksum, ...) outside of locks */ + if (validate) + skb = validate_xmit_skb_list(skb, dev); - HARD_TX_UNLOCK(dev, txq); + if (skb) { + HARD_TX_LOCK(dev, txq, smp_processor_id()); + if (!netif_xmit_frozen_or_stopped(txq)) + skb = dev_hard_start_xmit(skb, dev, txq, &ret); + HARD_TX_UNLOCK(dev, txq); + } spin_lock(root_lock); if (dev_xmit_complete(ret)) { @@ -181,9 +211,10 @@ static inline int qdisc_restart(struct Qdisc *q) struct net_device *dev; spinlock_t *root_lock; struct sk_buff *skb; + bool validate; /* Dequeue packet */ - skb = dequeue_skb(q); + skb = dequeue_skb(q, &validate); if (unlikely(!skb)) return 0; @@ -193,7 +224,7 @@ static inline int qdisc_restart(struct Qdisc *q) dev = qdisc_dev(q); txq = skb_get_tx_queue(dev, skb); - return sch_direct_xmit(skb, q, dev, txq, root_lock); + return sch_direct_xmit(skb, q, dev, txq, root_lock, validate); } void __qdisc_run(struct Qdisc *q) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index f623dca6ce30..4c4e457e7888 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1961,10 +1961,8 @@ static int xdst_queue_output(struct sock *sk, struct sk_buff *skb) struct xfrm_dst *xdst = (struct xfrm_dst *) dst; struct xfrm_policy *pol = xdst->pols[0]; struct xfrm_policy_queue *pq = &pol->polq; - const struct sk_buff *fclone = skb + 1; - if (unlikely(skb->fclone == SKB_FCLONE_ORIG && - fclone->fclone == SKB_FCLONE_CLONE)) { + if (unlikely(skb_fclone_busy(skb))) { kfree_skb(skb); return 0; } diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c index d10992e2740e..f44ef11f65a7 100644 --- a/samples/bpf/test_verifier.c +++ b/samples/bpf/test_verifier.c @@ -461,6 +461,136 @@ static struct bpf_test tests[] = { .errstr = "R0 invalid mem access", .result = REJECT, }, + { + "jump test 1", + .insns = { + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -8), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 1), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 1), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 1), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 1), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 1), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 5), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + }, + { + "jump test 2", + .insns = { + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 2), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0), + BPF_JMP_IMM(BPF_JA, 0, 0, 14), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 2), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 0), + BPF_JMP_IMM(BPF_JA, 0, 0, 11), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 2), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 0), + BPF_JMP_IMM(BPF_JA, 0, 0, 8), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 2), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -40, 0), + BPF_JMP_IMM(BPF_JA, 0, 0, 5), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 2), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -48, 0), + BPF_JMP_IMM(BPF_JA, 0, 0, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 1), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -56, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + }, + { + "jump test 3", + .insns = { + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_JMP_IMM(BPF_JA, 0, 0, 19), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 3), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), + BPF_JMP_IMM(BPF_JA, 0, 0, 15), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 3), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -32), + BPF_JMP_IMM(BPF_JA, 0, 0, 11), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 3), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -40, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -40), + BPF_JMP_IMM(BPF_JA, 0, 0, 7), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 3), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -48, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -48), + BPF_JMP_IMM(BPF_JA, 0, 0, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 0), + BPF_ST_MEM(BPF_DW, BPF_REG_2, -56, 0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -56), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_unspec), + BPF_EXIT_INSN(), + }, + .fixup = {24}, + .result = ACCEPT, + }, + { + "jump test 4", + .insns = { + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + }, }; static int probe_filter_length(struct bpf_insn *fp) diff --git a/scripts/tags.sh b/scripts/tags.sh index cbfd269a6011..293828bfd4ac 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -197,6 +197,9 @@ exuberant() --regex-c++='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/' \ --regex-c++='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/' \ --regex-c++='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \ + --regex-c++='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/' \ + --regex-c++='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/' \ + --regex-c++='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/'\ --regex-c='/PCI_OP_READ\((\w*).*[1-4]\)/pci_bus_read_config_\1/' \ --regex-c='/PCI_OP_WRITE\((\w*).*[1-4]\)/pci_bus_write_config_\1/' \ --regex-c='/DEFINE_(MUTEX|SEMAPHORE|SPINLOCK)\((\w*)/\2/v/' \ @@ -260,6 +263,9 @@ emacs() --regex='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/' \ --regex='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/' \ --regex='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \ + --regex='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/' \ + --regex='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/' \ + --regex='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/' \ --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' \ --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \ --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\ |