]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorDavid S. Miller <davem@davemloft.net>
Mon, 8 Sep 2014 04:41:53 +0000 (21:41 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 8 Sep 2014 04:41:53 +0000 (21:41 -0700)
339 files changed:
Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/broadcom-sf2.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/m_can.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/rcar_can.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/dsa/dsa.txt
Documentation/devicetree/bindings/net/socfpga-dwmac.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/timestamping.txt
Documentation/networking/timestamping/Makefile
Documentation/networking/timestamping/txtimestamp.c [new file with mode: 0644]
Documentation/sysctl/net.txt
MAINTAINERS
arch/arm/net/bpf_jit_32.c
arch/mips/net/bpf_jit.c
arch/powerpc/net/bpf_jit_comp.c
arch/s390/net/bpf_jit_comp.c
arch/sparc/net/bpf_jit_comp.c
arch/x86/net/bpf_jit_comp.c
drivers/isdn/gigaset/bas-gigaset.c
drivers/isdn/gigaset/usb-gigaset.c
drivers/isdn/mISDN/dsp_cmx.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_netlink.c
drivers/net/bonding/bond_options.c
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/c_can/Makefile
drivers/net/can/cc770/Makefile
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/can/m_can/Kconfig [new file with mode: 0644]
drivers/net/can/m_can/Makefile [new file with mode: 0644]
drivers/net/can/m_can/m_can.c [new file with mode: 0644]
drivers/net/can/mscan/Makefile
drivers/net/can/rcar_can.c
drivers/net/can/sja1000/Makefile
drivers/net/can/softing/Makefile
drivers/net/can/spi/Makefile
drivers/net/can/spi/mcp251x.c
drivers/net/can/usb/Makefile
drivers/net/dsa/Kconfig
drivers/net/dsa/Makefile
drivers/net/dsa/bcm_sf2.c [new file with mode: 0644]
drivers/net/dsa/bcm_sf2.h [new file with mode: 0644]
drivers/net/dsa/bcm_sf2_regs.h [new file with mode: 0644]
drivers/net/ethernet/amd/xgbe/xgbe-common.h
drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
drivers/net/ethernet/amd/xgbe/xgbe-desc.c
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
drivers/net/ethernet/amd/xgbe/xgbe-main.c
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
drivers/net/ethernet/amd/xgbe/xgbe.h
drivers/net/ethernet/arc/Kconfig
drivers/net/ethernet/arc/Makefile
drivers/net/ethernet/arc/emac.h
drivers/net/ethernet/arc/emac_arc.c [new file with mode: 0644]
drivers/net/ethernet/arc/emac_main.c
drivers/net/ethernet/arc/emac_mdio.c
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/cisco/enic/enic.h
drivers/net/ethernet/cisco/enic/enic_ethtool.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/dec/tulip/dmfe.c
drivers/net/ethernet/ec_bhf.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/emulex/benet/be_hw.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/intel/e1000/e1000_ethtool.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_adminq.c
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_prototype.h
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
drivers/net/ethernet/intel/i40evf/i40e_adminq.c
drivers/net/ethernet/intel/i40evf/i40e_common.c
drivers/net/ethernet/intel/i40evf/i40e_prototype.h
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.h
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_82575.h
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbevf/vf.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
drivers/net/ethernet/sun/sungem.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/amd-xgbe-phy.c
drivers/net/phy/bcm7xxx.c
drivers/net/phy/broadcom.c
drivers/net/phy/dp83640.c
drivers/net/phy/fixed.c
drivers/net/phy/mdio-bcm-unimac.c [new file with mode: 0644]
drivers/net/phy/mdio_bus.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/sungem_phy.c
drivers/net/team/team.c
drivers/net/usb/r8152.c
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/net/wan/dlci.c
drivers/usb/gadget/function/f_ncm.c
include/linux/brcmphy.h
include/linux/cycx_x25.h [deleted file]
include/linux/etherdevice.h
include/linux/ethtool.h
include/linux/filter.h
include/linux/i82593.h [deleted file]
include/linux/igmp.h
include/linux/mlx4/device.h
include/linux/netdevice.h
include/linux/phonedev.h [deleted file]
include/linux/phy.h
include/linux/phy_fixed.h
include/linux/random.h
include/linux/rhashtable.h
include/linux/skbuff.h
include/linux/tcp.h
include/linux/udp.h
include/net/codel.h
include/net/dsa.h
include/net/flow_keys.h
include/net/ip.h
include/net/ip6_checksum.h
include/net/ip_fib.h
include/net/ipv6.h
include/net/pkt_sched.h
include/net/sock.h
include/net/tcp.h
include/net/udp.h
include/rxrpc/types.h [deleted file]
include/uapi/linux/ethtool.h
include/uapi/linux/if_ether.h
kernel/bpf/core.c
kernel/crash_dump.c
kernel/seccomp.c
lib/random32.c
lib/rhashtable.c
lib/test_bpf.c
net/atm/mpc.c
net/bridge/br_multicast.c
net/core/dev.c
net/core/dev_ioctl.c
net/core/ethtool.c
net/core/filter.c
net/core/flow_dissector.c
net/core/netpoll.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/secure_seq.c
net/core/skbuff.c
net/core/sock.c
net/core/timestamping.c
net/decnet/af_decnet.c
net/decnet/dn_dev.c
net/decnet/dn_timer.c
net/dsa/Kconfig
net/dsa/Makefile
net/dsa/dsa.c
net/dsa/dsa_priv.h
net/dsa/slave.c
net/dsa/tag_brcm.c [new file with mode: 0644]
net/dsa/tag_dsa.c
net/dsa/tag_edsa.c
net/dsa/tag_trailer.c
net/ethernet/eth.c
net/ipv4/fib_frontend.c
net/ipv4/fib_semantics.c
net/ipv4/gre_demux.c
net/ipv4/gre_offload.c
net/ipv4/igmp.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_sockglue.c
net/ipv4/ipconfig.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_bic.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_diag.c
net/ipv4/tcp_highspeed.c
net/ipv4/tcp_htcp.c
net/ipv4/tcp_hybla.c
net/ipv4/tcp_illinois.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_offload.c
net/ipv4/tcp_output.c
net/ipv4/tcp_probe.c
net/ipv4/tcp_scalable.c
net/ipv4/tcp_timer.c
net/ipv4/tcp_vegas.c
net/ipv4/tcp_veno.c
net/ipv4/tcp_westwood.c
net/ipv4/tcp_yeah.c
net/ipv4/udp.c
net/ipv4/udp_offload.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ah6.c
net/ipv6/datagram.c
net/ipv6/esp6.c
net/ipv6/exthdrs.c
net/ipv6/icmp.c
net/ipv6/inet6_connection_sock.c
net/ipv6/inet6_hashtables.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_icmp.c
net/ipv6/ip6_input.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/ipcomp6.c
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/mip6.c
net/ipv6/ndisc.c
net/ipv6/output_core.c
net/ipv6/proc.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/syncookies.c
net/ipv6/sysctl_net_ipv6.c
net/ipv6/tcp_ipv6.c
net/ipv6/tcpv6_offload.c
net/ipv6/tunnel6.c
net/ipv6/udp.c
net/ipv6/udp_offload.c
net/ipv6/xfrm6_input.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_state.c
net/ipv6/xfrm6_tunnel.c
net/l2tp/l2tp_core.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_nat_core.c
net/netfilter/xt_HMARK.c
net/netfilter/xt_cluster.c
net/netfilter/xt_hashlimit.c
net/openvswitch/flow.c
net/packet/af_packet.c
net/rose/rose_link.c
net/rxrpc/ar-error.c
net/rxrpc/ar-input.c
net/sched/act_police.c
net/sched/sch_fq.c
net/sched/sch_fq_codel.c
net/sched/sch_generic.c
net/sched/sch_htb.c
net/sched/sch_tbf.c
net/sched/sch_teql.c
net/sctp/input.c
net/tipc/Makefile
net/tipc/bcast.c
net/tipc/config.c
net/tipc/core.c
net/tipc/core.h
net/tipc/link.c
net/tipc/link.h
net/tipc/msg.c
net/tipc/msg.h
net/tipc/name_distr.c
net/tipc/name_distr.h
net/tipc/name_table.c
net/tipc/net.c
net/tipc/node.c
net/tipc/node.h
net/tipc/port.c [deleted file]
net/tipc/port.h [deleted file]
net/tipc/ref.c [deleted file]
net/tipc/ref.h [deleted file]
net/tipc/socket.c
net/tipc/socket.h
net/tipc/subscr.c
net/tipc/sysctl.c

diff --git a/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt b/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
new file mode 100644 (file)
index 0000000..ab0bb42
--- /dev/null
@@ -0,0 +1,39 @@
+* Broadcom UniMAC MDIO bus controller
+
+Required properties:
+- compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2",
+  "brcm,genet-mdio-v3", "brcm,genet-mdio-v4" or "brcm,unimac-mdio"
+- reg: address and length of the regsiter set for the device, first one is the
+  base register, and the second one is optional and for indirect accesses to
+  larger than 16-bits MDIO transactions
+- reg-names: name(s) of the register must be "mdio" and optional "mdio_indir_rw"
+- #size-cells: must be 1
+- #address-cells: must be 0
+
+Optional properties:
+- interrupts: must be one if the interrupt is shared with the Ethernet MAC or
+  Ethernet switch this MDIO block is integrated from, or must be two, if there
+  are two separate interrupts, first one must be "mdio done" and second must be
+  for "mdio error"
+- interrupt-names: must be "mdio_done_error" when there is a share interrupt fed
+  to this hardware block, or must be "mdio_done" for the first interrupt and
+  "mdio_error" for the second when there are separate interrupts
+
+Child nodes of this MDIO bus controller node are standard Ethernet PHY device
+nodes as described in Documentation/devicetree/bindings/net/phy.txt
+
+Example:
+
+mdio@403c0 {
+       compatible = "brcm,unimac-mdio";
+       reg = <0x403c0 0x8 0x40300 0x18>;
+       reg-names = "mdio", "mdio_indir_rw";
+       #size-cells = <1>;
+       #address-cells = <0>;
+
+       ...
+       phy@0 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/net/broadcom-sf2.txt b/Documentation/devicetree/bindings/net/broadcom-sf2.txt
new file mode 100644 (file)
index 0000000..30d4875
--- /dev/null
@@ -0,0 +1,78 @@
+* Broadcom Starfighter 2 integrated swich
+
+Required properties:
+
+- compatible: should be "brcm,bcm7445-switch-v4.0"
+- reg: addresses and length of the register sets for the device, must be 6
+  pairs of register addresses and lengths
+- interrupts: interrupts for the devices, must be two interrupts
+- dsa,mii-bus: phandle to the MDIO bus controller, see dsa/dsa.txt
+- dsa,ethernet: phandle to the CPU network interface controller, see dsa/dsa.txt
+- #size-cells: must be 0
+- #address-cells: must be 2, see dsa/dsa.txt
+
+Subnodes:
+
+The integrated switch subnode should be specified according to the binding
+described in dsa/dsa.txt.
+
+Optional properties:
+
+- reg-names: litteral names for the device base register addresses, when present
+  must be: "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb"
+
+- interrupt-names: litternal names for the device interrupt lines, when present
+  must be: "switch_0" and "switch_1"
+
+- brcm,num-gphy: specify the maximum number of integrated gigabit PHYs in the
+  switch
+
+- brcm,num-rgmii-ports: specify the maximum number of RGMII interfaces supported
+  by the switch
+
+- brcm,fcb-pause-override: boolean property, if present indicates that the switch
+  supports Failover Control Block pause override capability
+
+- brcm,acb-packets-inflight: boolean property, if present indicates that the switch
+  Admission Control Block supports reporting the number of packets in-flight in a
+  switch queue
+
+Example:
+
+switch_top@f0b00000 {
+       compatible = "simple-bus";
+       #size-cells = <1>;
+       #address-cells = <1>;
+       ranges = <0 0xf0b00000 0x40804>;
+
+       ethernet_switch@0 {
+               compatible = "brcm,bcm7445-switch-v4.0";
+               #size-cells = <0>;
+               #address-cells = <2>;
+               reg = <0x0 0x40000
+                       0x40000 0x110
+                       0x40340 0x30
+                       0x40380 0x30
+                       0x40400 0x34
+                       0x40600 0x208>;
+               interrupts = <0 0x18 0
+                               0 0x19 0>;
+               brcm,num-gphy = <1>;
+               brcm,num-rgmii-ports = <2>;
+               brcm,fcb-pause-override;
+               brcm,acb-packets-inflight;
+
+               ...
+               switch@0 {
+                       reg = <0 0>;
+                       #size-cells = <0>;
+                       #address-cells <1>;
+
+                       port@0 {
+                               label = "gphy";
+                               reg = <0>;
+                       };
+                       ...
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/net/can/m_can.txt b/Documentation/devicetree/bindings/net/can/m_can.txt
new file mode 100644 (file)
index 0000000..9e33177
--- /dev/null
@@ -0,0 +1,67 @@
+Bosch MCAN controller Device Tree Bindings
+-------------------------------------------------
+
+Required properties:
+- compatible           : Should be "bosch,m_can" for M_CAN controllers
+- reg                  : physical base address and size of the M_CAN
+                         registers map and Message RAM
+- reg-names            : Should be "m_can" and "message_ram"
+- interrupts           : Should be the interrupt number of M_CAN interrupt
+                         line 0 and line 1, could be same if sharing
+                         the same interrupt.
+- interrupt-names      : Should contain "int0" and "int1"
+- clocks               : Clocks used by controller, should be host clock
+                         and CAN clock.
+- clock-names          : Should contain "hclk" and "cclk"
+- pinctrl-<n>          : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt
+- pinctrl-names        : Names corresponding to the numbered pinctrl states
+- bosch,mram-cfg       : Message RAM configuration data.
+                         Multiple M_CAN instances can share the same Message
+                         RAM and each element(e.g Rx FIFO or Tx Buffer and etc)
+                         number in Message RAM is also configurable,
+                         so this property is telling driver how the shared or
+                         private Message RAM are used by this M_CAN controller.
+
+                         The format should be as follows:
+                         <offset sidf_elems xidf_elems rxf0_elems rxf1_elems
+                          rxb_elems txe_elems txb_elems>
+                         The 'offset' is an address offset of the Message RAM
+                         where the following elements start from. This is
+                         usually set to 0x0 if you're using a private Message
+                         RAM. The remain cells are used to specify how many
+                         elements are used for each FIFO/Buffer.
+
+                         M_CAN includes the following elements according to user manual:
+                         11-bit Filter 0-128 elements / 0-128 words
+                         29-bit Filter 0-64 elements / 0-128 words
+                         Rx FIFO 0     0-64 elements / 0-1152 words
+                         Rx FIFO 1     0-64 elements / 0-1152 words
+                         Rx Buffers    0-64 elements / 0-1152 words
+                         Tx Event FIFO 0-32 elements / 0-64 words
+                         Tx Buffers    0-32 elements / 0-576 words
+
+                         Please refer to 2.4.1 Message RAM Configuration in
+                         Bosch M_CAN user manual for details.
+
+Example:
+SoC dtsi:
+m_can1: can@020e8000 {
+       compatible = "bosch,m_can";
+       reg = <0x020e8000 0x4000>, <0x02298000 0x4000>;
+       reg-names = "m_can", "message_ram";
+       interrupts = <0 114 0x04>,
+                    <0 114 0x04>;
+       interrupt-names = "int0", "int1";
+       clocks = <&clks IMX6SX_CLK_CANFD>,
+                <&clks IMX6SX_CLK_CANFD>;
+       clock-names = "hclk", "cclk";
+       bosch,mram-cfg = <0x0 0 0 32 0 0 0 1>;
+       status = "disabled";
+};
+
+Board dts:
+&m_can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_m_can1>;
+       status = "enabled";
+};
diff --git a/Documentation/devicetree/bindings/net/can/rcar_can.txt b/Documentation/devicetree/bindings/net/can/rcar_can.txt
new file mode 100644 (file)
index 0000000..002d844
--- /dev/null
@@ -0,0 +1,43 @@
+Renesas R-Car CAN controller Device Tree Bindings
+-------------------------------------------------
+
+Required properties:
+- compatible: "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC.
+             "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC.
+             "renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC.
+             "renesas,can-r8a7791" if CAN controller is a part of R8A7791 SoC.
+- reg: physical base address and size of the R-Car CAN register map.
+- interrupts: interrupt specifier for the sole interrupt.
+- clocks: phandles and clock specifiers for 3 CAN clock inputs.
+- clock-names: 3 clock input name strings: "clkp1", "clkp2", "can_clk".
+- pinctrl-0: pin control group to be used for this controller.
+- pinctrl-names: must be "default".
+
+Optional properties:
+- renesas,can-clock-select: R-Car CAN Clock Source Select. Valid values are:
+                           <0x0> (default) : Peripheral clock (clkp1)
+                           <0x1> : Peripheral clock (clkp2)
+                           <0x3> : Externally input clock
+
+Example
+-------
+
+SoC common .dtsi file:
+
+       can0: can@e6e80000 {
+               compatible = "renesas,can-r8a7791";
+               reg = <0 0xe6e80000 0 0x1000>;
+               interrupts = <0 186 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp9_clks R8A7791_CLK_RCAN0>,
+                        <&cpg_clocks R8A7791_CLK_RCAN>, <&can_clk>;
+               clock-names = "clkp1", "clkp2", "can_clk";
+               status = "disabled";
+       };
+
+Board specific .dts file:
+
+&can0 {
+       pinctrl-0 = <&can0_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
index 49f4f7ae3f5145921a6def4250cc39fabb4fdafa..a62c889aafcaf070774bc3e9bc93c96ba9ea1992 100644 (file)
@@ -39,6 +39,22 @@ Optionnal property:
                          This property is only used when switches are being
                          chained/cascaded together.
 
+- phy-handle           : Phandle to a PHY on an external MDIO bus, not the
+                         switch internal one. See
+                         Documentation/devicetree/bindings/net/ethernet.txt
+                         for details.
+
+- phy-mode             : String representing the connection to the designated
+                         PHY node specified by the 'phy-handle' property. See
+                         Documentation/devicetree/bindings/net/ethernet.txt
+                         for details.
+
+Optional subnodes:
+- fixed-link           : Fixed-link subnode describing a link to a non-MDIO
+                         managed entity. See
+                         Documentation/devicetree/bindings/net/fixed-link.txt
+                         for details.
+
 Example:
 
        dsa@0 {
@@ -58,6 +74,7 @@ Example:
                        port@0 {
                                reg = <0>;
                                label = "lan1";
+                               phy-handle = <&phy0>;
                        };
 
                        port@1 {
index 2a60cd3e8d5ddb7bdf3b2caad2bc414a3d8566e0..3a9d6795160654080ec4aaa114304b62d5f0754f 100644 (file)
@@ -12,6 +12,10 @@ Required properties:
  - altr,sysmgr-syscon : Should be the phandle to the system manager node that
    encompasses the glue register, the register offset, and the register shift.
 
+Optional properties:
+altr,emac-splitter: Should be the phandle to the emac splitter soft IP node if
+               DWMAC controller is connected emac splitter.
+
 Example:
 
 gmac0: ethernet@ff700000 {
index 29a93518bf18acc7d9a0a3ac443abd03662e3792..db2383cb1df9a71d051aafe581f4e44f85bba0d9 100644 (file)
@@ -65,6 +65,12 @@ neigh/default/gc_thresh1 - INTEGER
        purge entries if there are fewer than this number.
        Default: 128
 
+neigh/default/gc_thresh2 - INTEGER
+       Threshold when garbage collector becomes more aggressive about
+       purging entries. Entries older than 5 seconds will be cleared
+       when over this number.
+       Default: 512
+
 neigh/default/gc_thresh3 - INTEGER
        Maximum number of neighbor entries allowed.  Increase this
        when using large numbers of interfaces and when communicating
@@ -838,6 +844,11 @@ igmp_max_memberships - INTEGER
 
        conf/all/*        is special, changes the settings for all interfaces
 
+igmp_qrv - INTEGER
+        Controls the IGMP query robustness variable (see RFC2236 8.1).
+        Default: 2 (as specified by RFC2236 8.1)
+        Minimum: 1 (as specified by RFC6636 4.5)
+
 log_martians - BOOLEAN
        Log packets with impossible addresses to kernel log.
        log_martians for the interface will be enabled if at least one of
@@ -1146,6 +1157,11 @@ anycast_src_echo_reply - BOOLEAN
        FALSE: disabled
        Default: FALSE
 
+mld_qrv - INTEGER
+       Controls the MLD query robustness variable (see RFC3810 9.1).
+       Default: 2 (as specified by RFC3810 9.1)
+       Minimum: 1 (as specified by RFC6636 4.5)
+
 IPv6 Fragmentation:
 
 ip6frag_high_thresh - INTEGER
index 897f942b976bd61597d5dd49ceb17cf24a0bc70d..412f45ca2d73e3cd31a487e5fe13b73fc552d9f5 100644 (file)
-The existing interfaces for getting network packages time stamped are:
+
+1. Control Interfaces
+
+The interfaces for receiving network packages timestamps are:
 
 * SO_TIMESTAMP
-  Generate time stamp for each incoming packet using the (not necessarily
-  monotonous!) system time. Result is returned via recv_msg() in a
-  control message as timeval (usec resolution).
+  Generates a timestamp for each incoming packet in (not necessarily
+  monotonic) system time. Reports the timestamp via recvmsg() in a
+  control message as struct timeval (usec resolution).
 
 * SO_TIMESTAMPNS
-  Same time stamping mechanism as SO_TIMESTAMP, but returns result as
-  timespec (nsec resolution).
+  Same timestamping mechanism as SO_TIMESTAMP, but reports the
+  timestamp as struct timespec (nsec resolution).
 
 * IP_MULTICAST_LOOP + SO_TIMESTAMP[NS]
-  Only for multicasts: approximate send time stamp by receiving the looped
-  packet and using its receive time stamp.
+  Only for multicast:approximate transmit timestamp obtained by
+  reading the looped packet receive timestamp.
 
-The following interface complements the existing ones: receive time
-stamps can be generated and returned for arbitrary packets and much
-closer to the point where the packet is really sent. Time stamps can
-be generated in software (as before) or in hardware (if the hardware
-has such a feature).
+* SO_TIMESTAMPING
+  Generates timestamps on reception, transmission or both. Supports
+  multiple timestamp sources, including hardware. Supports generating
+  timestamps for stream sockets.
 
-SO_TIMESTAMPING:
 
-Instructs the socket layer which kind of information should be collected
-and/or reported.  The parameter is an integer with some of the following
-bits set. Setting other bits is an error and doesn't change the current
-state.
+1.1 SO_TIMESTAMP:
 
-Four of the bits are requests to the stack to try to generate
-timestamps.  Any combination of them is valid.
+This socket option enables timestamping of datagrams on the reception
+path. Because the destination socket, if any, is not known early in
+the network stack, the feature has to be enabled for all packets. The
+same is true for all early receive timestamp options.
 
-SOF_TIMESTAMPING_TX_HARDWARE:  try to obtain send time stamps in hardware
-SOF_TIMESTAMPING_TX_SOFTWARE:  try to obtain send time stamps in software
-SOF_TIMESTAMPING_RX_HARDWARE:  try to obtain receive time stamps in hardware
-SOF_TIMESTAMPING_RX_SOFTWARE:  try to obtain receive time stamps in software
+For interface details, see `man 7 socket`.
+
+
+1.2 SO_TIMESTAMPNS:
+
+This option is identical to SO_TIMESTAMP except for the returned data type.
+Its struct timespec allows for higher resolution (ns) timestamps than the
+timeval of SO_TIMESTAMP (ms).
+
+
+1.3 SO_TIMESTAMPING:
+
+Supports multiple types of timestamp requests. As a result, this
+socket option takes a bitmap of flags, not a boolean. In
+
+  err = setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, (void *) val, &val);
+
+val is an integer with any of the following bits set. Setting other
+bit returns EINVAL and does not change the current state.
 
-The other three bits control which timestamps will be reported in a
-generated control message.  If none of these bits are set or if none of
-the set bits correspond to data that is available, then the control
-message will not be generated:
 
-SOF_TIMESTAMPING_SOFTWARE:     report systime if available
-SOF_TIMESTAMPING_SYS_HARDWARE: report hwtimetrans if available (deprecated)
-SOF_TIMESTAMPING_RAW_HARDWARE: report hwtimeraw if available
+1.3.1 Timestamp Generation
 
-It is worth noting that timestamps may be collected for reasons other
-than being requested by a particular socket with
-SOF_TIMESTAMPING_[TR]X_(HARD|SOFT)WARE.  For example, most drivers that
-can generate hardware receive timestamps ignore
-SOF_TIMESTAMPING_RX_HARDWARE.  It is still a good idea to set that flag
-in case future drivers pay attention.
+Some bits are requests to the stack to try to generate timestamps. Any
+combination of them is valid. Changes to these bits apply to newly
+created packets, not to packets already in the stack. As a result, it
+is possible to selectively request timestamps for a subset of packets
+(e.g., for sampling) by embedding an send() call within two setsockopt
+calls, one to enable timestamp generation and one to disable it.
+Timestamps may also be generated for reasons other than being
+requested by a particular socket, such as when receive timestamping is
+enabled system wide, as explained earlier.
 
-If timestamps are reported, they will appear in a control message with
-cmsg_level==SOL_SOCKET, cmsg_type==SO_TIMESTAMPING, and a payload like
-this:
+SOF_TIMESTAMPING_RX_HARDWARE:
+  Request rx timestamps generated by the network adapter.
+
+SOF_TIMESTAMPING_RX_SOFTWARE:
+  Request rx timestamps when data enters the kernel. These timestamps
+  are generated just after a device driver hands a packet to the
+  kernel receive stack.
+
+SOF_TIMESTAMPING_TX_HARDWARE:
+  Request tx timestamps generated by the network adapter.
+
+SOF_TIMESTAMPING_TX_SOFTWARE:
+  Request tx timestamps when data leaves the kernel. These timestamps
+  are generated in the device driver as close as possible, but always
+  prior to, passing the packet to the network interface. Hence, they
+  require driver support and may not be available for all devices.
+
+SOF_TIMESTAMPING_TX_SCHED:
+  Request tx timestamps prior to entering the packet scheduler. Kernel
+  transmit latency is, if long, often dominated by queuing delay. The
+  difference between this timestamp and one taken at
+  SOF_TIMESTAMPING_TX_SOFTWARE will expose this latency independent
+  of protocol processing. The latency incurred in protocol
+  processing, if any, can be computed by subtracting a userspace
+  timestamp taken immediately before send() from this timestamp. On
+  machines with virtual devices where a transmitted packet travels
+  through multiple devices and, hence, multiple packet schedulers,
+  a timestamp is generated at each layer. This allows for fine
+  grained measurement of queuing delay.
+
+SOF_TIMESTAMPING_TX_ACK:
+  Request tx timestamps when all data in the send buffer has been
+  acknowledged. This only makes sense for reliable protocols. It is
+  currently only implemented for TCP. For that protocol, it may
+  over-report measurement, because the timestamp is generated when all
+  data up to and including the buffer at send() was acknowledged: the
+  cumulative acknowledgment. The mechanism ignores SACK and FACK.
+
+
+1.3.2 Timestamp Reporting
+
+The other three bits control which timestamps will be reported in a
+generated control message. Changes to the bits take immediate
+effect at the timestamp reporting locations in the stack. Timestamps
+are only reported for packets that also have the relevant timestamp
+generation request set.
+
+SOF_TIMESTAMPING_SOFTWARE:
+  Report any software timestamps when available.
+
+SOF_TIMESTAMPING_SYS_HARDWARE:
+  This option is deprecated and ignored.
+
+SOF_TIMESTAMPING_RAW_HARDWARE:
+  Report hardware timestamps as generated by
+  SOF_TIMESTAMPING_TX_HARDWARE when available.
+
+
+1.3.3 Timestamp Options
+
+The interface supports one option
+
+SOF_TIMESTAMPING_OPT_ID:
+
+  Generate a unique identifier along with each packet. A process can
+  have multiple concurrent timestamping requests outstanding. Packets
+  can be reordered in the transmit path, for instance in the packet
+  scheduler. In that case timestamps will be queued onto the error
+  queue out of order from the original send() calls. This option
+  embeds a counter that is incremented at send() time, to order
+  timestamps within a flow.
+
+  This option is implemented only for transmit timestamps. There, the
+  timestamp is always looped along with a struct sock_extended_err.
+  The option modifies field ee_info to pass an id that is unique
+  among all possibly concurrently outstanding timestamp requests for
+  that socket. In practice, it is a monotonically increasing u32
+  (that wraps).
+
+  In datagram sockets, the counter increments on each send call. In
+  stream sockets, it increments with every byte.
+
+
+1.4 Bytestream Timestamps
+
+The SO_TIMESTAMPING interface supports timestamping of bytes in a
+bytestream. Each request is interpreted as a request for when the
+entire contents of the buffer has passed a timestamping point. That
+is, for streams option SOF_TIMESTAMPING_TX_SOFTWARE will record
+when all bytes have reached the device driver, regardless of how
+many packets the data has been converted into.
+
+In general, bytestreams have no natural delimiters and therefore
+correlating a timestamp with data is non-trivial. A range of bytes
+may be split across segments, any segments may be merged (possibly
+coalescing sections of previously segmented buffers associated with
+independent send() calls). Segments can be reordered and the same
+byte range can coexist in multiple segments for protocols that
+implement retransmissions.
+
+It is essential that all timestamps implement the same semantics,
+regardless of these possible transformations, as otherwise they are
+incomparable. Handling "rare" corner cases differently from the
+simple case (a 1:1 mapping from buffer to skb) is insufficient
+because performance debugging often needs to focus on such outliers.
+
+In practice, timestamps can be correlated with segments of a
+bytestream consistently, if both semantics of the timestamp and the
+timing of measurement are chosen correctly. This challenge is no
+different from deciding on a strategy for IP fragmentation. There, the
+definition is that only the first fragment is timestamped. For
+bytestreams, we chose that a timestamp is generated only when all
+bytes have passed a point. SOF_TIMESTAMPING_TX_ACK as defined is easy to
+implement and reason about. An implementation that has to take into
+account SACK would be more complex due to possible transmission holes
+and out of order arrival.
+
+On the host, TCP can also break the simple 1:1 mapping from buffer to
+skbuff as a result of Nagle, cork, autocork, segmentation and GSO. The
+implementation ensures correctness in all cases by tracking the
+individual last byte passed to send(), even if it is no longer the
+last byte after an skbuff extend or merge operation. It stores the
+relevant sequence number in skb_shinfo(skb)->tskey. Because an skbuff
+has only one such field, only one timestamp can be generated.
+
+In rare cases, a timestamp request can be missed if two requests are
+collapsed onto the same skb. A process can detect this situation by
+enabling SOF_TIMESTAMPING_OPT_ID and comparing the byte offset at
+send time with the value returned for each timestamp. It can prevent
+the situation by always flushing the TCP stack in between requests,
+for instance by enabling TCP_NODELAY and disabling TCP_CORK and
+autocork.
+
+These precautions ensure that the timestamp is generated only when all
+bytes have passed a timestamp point, assuming that the network stack
+itself does not reorder the segments. The stack indeed tries to avoid
+reordering. The one exception is under administrator control: it is
+possible to construct a packet scheduler configuration that delays
+segments from the same stream differently. Such a setup would be
+unusual.
+
+
+2 Data Interfaces
+
+Timestamps are read using the ancillary data feature of recvmsg().
+See `man 3 cmsg` for details of this interface. The socket manual
+page (`man 7 socket`) describes how timestamps generated with
+SO_TIMESTAMP and SO_TIMESTAMPNS records can be retrieved.
+
+
+2.1 SCM_TIMESTAMPING records
+
+These timestamps are returned in a control message with cmsg_level
+SOL_SOCKET, cmsg_type SCM_TIMESTAMPING, and payload of type
 
 struct scm_timestamping {
-       struct timespec systime;
-       struct timespec hwtimetrans;
-       struct timespec hwtimeraw;
+       struct timespec ts[3];
 };
 
-recvmsg() can be used to get this control message for regular incoming
-packets. For send time stamps the outgoing packet is looped back to
-the socket's error queue with the send time stamp(s) attached. It can
-be received with recvmsg(flags=MSG_ERRQUEUE). The call returns the
-original outgoing packet data including all headers preprended down to
-and including the link layer, the scm_timestamping control message and
-a sock_extended_err control message with ee_errno==ENOMSG and
-ee_origin==SO_EE_ORIGIN_TIMESTAMPING. A socket with such a pending
-bounced packet is ready for reading as far as select() is concerned.
-If the outgoing packet has to be fragmented, then only the first
-fragment is time stamped and returned to the sending socket.
-
-All three values correspond to the same event in time, but were
-generated in different ways. Each of these values may be empty (= all
-zero), in which case no such value was available. If the application
-is not interested in some of these values, they can be left blank to
-avoid the potential overhead of calculating them.
-
-systime is the value of the system time at that moment. This
-corresponds to the value also returned via SO_TIMESTAMP[NS]. If the
-time stamp was generated by hardware, then this field is
-empty. Otherwise it is filled in if SOF_TIMESTAMPING_SOFTWARE is
-set.
-
-hwtimeraw is the original hardware time stamp. Filled in if
-SOF_TIMESTAMPING_RAW_HARDWARE is set. No assumptions about its
-relation to system time should be made.
-
-hwtimetrans is always zero. This field is deprecated. It used to hold
-hw timestamps converted to system time. Instead, expose the hardware
-clock device on the NIC directly as a HW PTP clock source, to allow
-time conversion in userspace and optionally synchronize system time
-with a userspace PTP stack such as linuxptp. For the PTP clock API,
-see Documentation/ptp/ptp.txt.
-
-
-SIOCSHWTSTAMP, SIOCGHWTSTAMP:
+The structure can return up to three timestamps. This is a legacy
+feature. Only one field is non-zero at any time. Most timestamps
+are passed in ts[0]. Hardware timestamps are passed in ts[2].
+
+ts[1] used to hold hardware timestamps converted to system time.
+Instead, expose the hardware clock device on the NIC directly as
+a HW PTP clock source, to allow time conversion in userspace and
+optionally synchronize system time with a userspace PTP stack such
+as linuxptp. For the PTP clock API, see Documentation/ptp/ptp.txt.
+
+2.1.1 Transmit timestamps with MSG_ERRQUEUE
+
+For transmit timestamps the outgoing packet is looped back to the
+socket's error queue with the send timestamp(s) attached. A process
+receives the timestamps by calling recvmsg() with flag MSG_ERRQUEUE
+set and with a msg_control buffer sufficiently large to receive the
+relevant metadata structures. The recvmsg call returns the original
+outgoing data packet with two ancillary messages attached.
+
+A message of cm_level SOL_IP(V6) and cm_type IP(V6)_RECVERR
+embeds a struct sock_extended_err. This defines the error type. For
+timestamps, the ee_errno field is ENOMSG. The other ancillary message
+will have cm_level SOL_SOCKET and cm_type SCM_TIMESTAMPING. This
+embeds the struct scm_timestamping.
+
+
+2.1.1.2 Timestamp types
+
+The semantics of the three struct timespec are defined by field
+ee_info in the extended error structure. It contains a value of
+type SCM_TSTAMP_* to define the actual timestamp passed in
+scm_timestamping.
+
+The SCM_TSTAMP_* types are 1:1 matches to the SOF_TIMESTAMPING_*
+control fields discussed previously, with one exception. For legacy
+reasons, SCM_TSTAMP_SND is equal to zero and can be set for both
+SOF_TIMESTAMPING_TX_HARDWARE and SOF_TIMESTAMPING_TX_SOFTWARE. It
+is the first if ts[2] is non-zero, the second otherwise, in which
+case the timestamp is stored in ts[0].
+
+
+2.1.1.3 Fragmentation
+
+Fragmentation of outgoing datagrams is rare, but is possible, e.g., by
+explicitly disabling PMTU discovery. If an outgoing packet is fragmented,
+then only the first fragment is timestamped and returned to the sending
+socket.
+
+
+2.1.1.4 Packet Payload
+
+The calling application is often not interested in receiving the whole
+packet payload that it passed to the stack originally: the socket
+error queue mechanism is just a method to piggyback the timestamp on.
+In this case, the application can choose to read datagrams with a
+smaller buffer, possibly even of length 0. The payload is truncated
+accordingly. Until the process calls recvmsg() on the error queue,
+however, the full packet is queued, taking up budget from SO_RCVBUF.
+
+
+2.1.1.5 Blocking Read
+
+Reading from the error queue is always a non-blocking operation. To
+block waiting on a timestamp, use poll or select. poll() will return
+POLLERR in pollfd.revents if any data is ready on the error queue.
+There is no need to pass this flag in pollfd.events. This flag is
+ignored on request. See also `man 2 poll`.
+
+
+2.1.2 Receive timestamps
+
+On reception, there is no reason to read from the socket error queue.
+The SCM_TIMESTAMPING ancillary data is sent along with the packet data
+on a normal recvmsg(). Since this is not a socket error, it is not
+accompanied by a message SOL_IP(V6)/IP(V6)_RECVERROR. In this case,
+the meaning of the three fields in struct scm_timestamping is
+implicitly defined. ts[0] holds a software timestamp if set, ts[1]
+is again deprecated and ts[2] holds a hardware timestamp if set.
+
+
+3. Hardware Timestamping configuration: SIOCSHWTSTAMP and SIOCGHWTSTAMP
 
 Hardware time stamping must also be initialized for each device driver
 that is expected to do hardware time stamping. The parameter is defined in
@@ -167,8 +372,7 @@ enum {
         */
 };
 
-
-DEVICE IMPLEMENTATION
+3.1 Hardware Timestamping Implementation: Device Drivers
 
 A driver which supports hardware time stamping must support the
 SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with
index d934afc8306a495134bf24559c6ecbd94178f36f..95e239c7007646cec7e3ee8646926a02af89f0ff 100644 (file)
@@ -1,14 +1,20 @@
+# To compile, from the source root
+#
+#    make headers_install
+#    make M=documentation
+
 # kbuild trick to avoid linker error. Can be omitted if a module is built.
 obj- := dummy.o
 
 # List of programs to build
-hostprogs-y := timestamping hwtstamp_config
+hostprogs-y := timestamping txtimestamp hwtstamp_config
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
 
 HOSTCFLAGS_timestamping.o += -I$(objtree)/usr/include
+HOSTCFLAGS_txtimestamp.o += -I$(objtree)/usr/include
 HOSTCFLAGS_hwtstamp_config.o += -I$(objtree)/usr/include
 
 clean:
-       rm -f timestamping hwtstamp_config
+       rm -f timestamping txtimestamp hwtstamp_config
diff --git a/Documentation/networking/timestamping/txtimestamp.c b/Documentation/networking/timestamping/txtimestamp.c
new file mode 100644 (file)
index 0000000..b32fc2a
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2014 Google Inc.
+ * Author: willemb@google.com (Willem de Bruijn)
+ *
+ * Test software tx timestamping, including
+ *
+ * - SCHED, SND and ACK timestamps
+ * - RAW, UDP and TCP
+ * - IPv4 and IPv6
+ * - various packet sizes (to test GSO and TSO)
+ *
+ * Consult the command line arguments for help on running
+ * the various testcases.
+ *
+ * This test requires a dummy TCP server.
+ * A simple `nc6 [-u] -l -p $DESTPORT` will do
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <arpa/inet.h>
+#include <asm/types.h>
+#include <error.h>
+#include <errno.h>
+#include <linux/errqueue.h>
+#include <linux/if_ether.h>
+#include <linux/net_tstamp.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netpacket/packet.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+/* command line parameters */
+static int cfg_proto = SOCK_STREAM;
+static int cfg_ipproto = IPPROTO_TCP;
+static int cfg_num_pkts = 4;
+static int do_ipv4 = 1;
+static int do_ipv6 = 1;
+static int cfg_payload_len = 10;
+static uint16_t dest_port = 9000;
+
+static struct sockaddr_in daddr;
+static struct sockaddr_in6 daddr6;
+static struct timespec ts_prev;
+
+static void __print_timestamp(const char *name, struct timespec *cur,
+                             uint32_t key, int payload_len)
+{
+       if (!(cur->tv_sec | cur->tv_nsec))
+               return;
+
+       fprintf(stderr, "  %s: %lu s %lu us (seq=%u, len=%u)",
+                       name, cur->tv_sec, cur->tv_nsec / 1000,
+                       key, payload_len);
+
+       if ((ts_prev.tv_sec | ts_prev.tv_nsec)) {
+               int64_t cur_ms, prev_ms;
+
+               cur_ms = (long) cur->tv_sec * 1000 * 1000;
+               cur_ms += cur->tv_nsec / 1000;
+
+               prev_ms = (long) ts_prev.tv_sec * 1000 * 1000;
+               prev_ms += ts_prev.tv_nsec / 1000;
+
+               fprintf(stderr, "  (%+ld us)", cur_ms - prev_ms);
+       }
+
+       ts_prev = *cur;
+       fprintf(stderr, "\n");
+}
+
+static void print_timestamp_usr(void)
+{
+       struct timespec ts;
+       struct timeval tv;      /* avoid dependency on -lrt */
+
+       gettimeofday(&tv, NULL);
+       ts.tv_sec = tv.tv_sec;
+       ts.tv_nsec = tv.tv_usec * 1000;
+
+       __print_timestamp("  USR", &ts, 0, 0);
+}
+
+static void print_timestamp(struct scm_timestamping *tss, int tstype,
+                           int tskey, int payload_len)
+{
+       const char *tsname;
+
+       switch (tstype) {
+       case SCM_TSTAMP_SCHED:
+               tsname = "  ENQ";
+               break;
+       case SCM_TSTAMP_SND:
+               tsname = "  SND";
+               break;
+       case SCM_TSTAMP_ACK:
+               tsname = "  ACK";
+               break;
+       default:
+               error(1, 0, "unknown timestamp type: %u",
+               tstype);
+       }
+       __print_timestamp(tsname, &tss->ts[0], tskey, payload_len);
+}
+
+static void __poll(int fd)
+{
+       struct pollfd pollfd;
+       int ret;
+
+       memset(&pollfd, 0, sizeof(pollfd));
+       pollfd.fd = fd;
+       ret = poll(&pollfd, 1, 100);
+       if (ret != 1)
+               error(1, errno, "poll");
+}
+
+static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len)
+{
+       struct sock_extended_err *serr = NULL;
+       struct scm_timestamping *tss = NULL;
+       struct cmsghdr *cm;
+
+       for (cm = CMSG_FIRSTHDR(msg);
+            cm && cm->cmsg_len;
+            cm = CMSG_NXTHDR(msg, cm)) {
+               if (cm->cmsg_level == SOL_SOCKET &&
+                   cm->cmsg_type == SCM_TIMESTAMPING) {
+                       tss = (void *) CMSG_DATA(cm);
+               } else if ((cm->cmsg_level == SOL_IP &&
+                    cm->cmsg_type == IP_RECVERR) ||
+                   (cm->cmsg_level == SOL_IPV6 &&
+                    cm->cmsg_type == IPV6_RECVERR)) {
+
+                       serr = (void *) CMSG_DATA(cm);
+                       if (serr->ee_errno != ENOMSG ||
+                           serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
+                               fprintf(stderr, "unknown ip error %d %d\n",
+                                               serr->ee_errno,
+                                               serr->ee_origin);
+                               serr = NULL;
+                       }
+               } else
+                       fprintf(stderr, "unknown cmsg %d,%d\n",
+                                       cm->cmsg_level, cm->cmsg_type);
+       }
+
+       if (serr && tss)
+               print_timestamp(tss, serr->ee_info, serr->ee_data, payload_len);
+}
+
+static int recv_errmsg(int fd)
+{
+       static char ctrl[1024 /* overprovision*/];
+       static struct msghdr msg;
+       struct iovec entry;
+       static char *data;
+       int ret = 0;
+
+       data = malloc(cfg_payload_len);
+       if (!data)
+               error(1, 0, "malloc");
+
+       memset(&msg, 0, sizeof(msg));
+       memset(&entry, 0, sizeof(entry));
+       memset(ctrl, 0, sizeof(ctrl));
+
+       entry.iov_base = data;
+       entry.iov_len = cfg_payload_len;
+       msg.msg_iov = &entry;
+       msg.msg_iovlen = 1;
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+       msg.msg_control = ctrl;
+       msg.msg_controllen = sizeof(ctrl);
+
+       ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
+       if (ret == -1 && errno != EAGAIN)
+               error(1, errno, "recvmsg");
+
+       __recv_errmsg_cmsg(&msg, ret);
+
+       free(data);
+       return ret == -1;
+}
+
+static void do_test(int family, unsigned int opt)
+{
+       char *buf;
+       int fd, i, val, total_len;
+
+       if (family == IPPROTO_IPV6 && cfg_proto != SOCK_STREAM) {
+               /* due to lack of checksum generation code */
+               fprintf(stderr, "test: skipping datagram over IPv6\n");
+               return;
+       }
+
+       total_len = cfg_payload_len;
+       if (cfg_proto == SOCK_RAW) {
+               total_len += sizeof(struct udphdr);
+               if (cfg_ipproto == IPPROTO_RAW)
+                       total_len += sizeof(struct iphdr);
+       }
+
+       buf = malloc(total_len);
+       if (!buf)
+               error(1, 0, "malloc");
+
+       fd = socket(family, cfg_proto, cfg_ipproto);
+       if (fd < 0)
+               error(1, errno, "socket");
+
+       if (cfg_proto == SOCK_STREAM) {
+               val = 1;
+               if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
+                              (char*) &val, sizeof(val)))
+                       error(1, 0, "setsockopt no nagle");
+
+               if (family == PF_INET) {
+                       if (connect(fd, (void *) &daddr, sizeof(daddr)))
+                               error(1, errno, "connect ipv4");
+               } else {
+                       if (connect(fd, (void *) &daddr6, sizeof(daddr6)))
+                               error(1, errno, "connect ipv6");
+               }
+       }
+
+       opt |= SOF_TIMESTAMPING_SOFTWARE |
+              SOF_TIMESTAMPING_OPT_ID;
+       if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING,
+                      (char *) &opt, sizeof(opt)))
+               error(1, 0, "setsockopt timestamping");
+
+       for (i = 0; i < cfg_num_pkts; i++) {
+               memset(&ts_prev, 0, sizeof(ts_prev));
+               memset(buf, 'a' + i, total_len);
+               buf[total_len - 2] = '\n';
+               buf[total_len - 1] = '\0';
+
+               if (cfg_proto == SOCK_RAW) {
+                       struct udphdr *udph;
+                       int off = 0;
+
+                       if (cfg_ipproto == IPPROTO_RAW) {
+                               struct iphdr *iph = (void *) buf;
+
+                               memset(iph, 0, sizeof(*iph));
+                               iph->ihl      = 5;
+                               iph->version  = 4;
+                               iph->ttl      = 2;
+                               iph->daddr    = daddr.sin_addr.s_addr;
+                               iph->protocol = IPPROTO_UDP;
+                               /* kernel writes saddr, csum, len */
+
+                               off = sizeof(*iph);
+                       }
+
+                       udph = (void *) buf + off;
+                       udph->source = ntohs(9000);     /* random spoof */
+                       udph->dest   = ntohs(dest_port);
+                       udph->len    = ntohs(sizeof(*udph) + cfg_payload_len);
+                       udph->check  = 0;       /* not allowed for IPv6 */
+               }
+
+               print_timestamp_usr();
+               if (cfg_proto != SOCK_STREAM) {
+                       if (family == PF_INET)
+                               val = sendto(fd, buf, total_len, 0, (void *) &daddr, sizeof(daddr));
+                       else
+                               val = sendto(fd, buf, total_len, 0, (void *) &daddr6, sizeof(daddr6));
+               } else {
+                       val = send(fd, buf, cfg_payload_len, 0);
+               }
+               if (val != total_len)
+                       error(1, errno, "send");
+
+               /* wait for all errors to be queued, else ACKs arrive OOO */
+               usleep(50 * 1000);
+
+               __poll(fd);
+
+               while (!recv_errmsg(fd)) {}
+       }
+
+       if (close(fd))
+               error(1, errno, "close");
+
+       free(buf);
+       usleep(400 * 1000);
+}
+
+static void __attribute__((noreturn)) usage(const char *filepath)
+{
+       fprintf(stderr, "\nUsage: %s [options] hostname\n"
+                       "\nwhere options are:\n"
+                       "  -4:   only IPv4\n"
+                       "  -6:   only IPv6\n"
+                       "  -h:   show this message\n"
+                       "  -l N: send N bytes at a time\n"
+                       "  -r:   use raw\n"
+                       "  -R:   use raw (IP_HDRINCL)\n"
+                       "  -p N: connect to port N\n"
+                       "  -u:   use udp\n",
+                       filepath);
+       exit(1);
+}
+
+static void parse_opt(int argc, char **argv)
+{
+       int proto_count = 0;
+       char c;
+
+       while ((c = getopt(argc, argv, "46hl:p:rRu")) != -1) {
+               switch (c) {
+               case '4':
+                       do_ipv6 = 0;
+                       break;
+               case '6':
+                       do_ipv4 = 0;
+                       break;
+               case 'r':
+                       proto_count++;
+                       cfg_proto = SOCK_RAW;
+                       cfg_ipproto = IPPROTO_UDP;
+                       break;
+               case 'R':
+                       proto_count++;
+                       cfg_proto = SOCK_RAW;
+                       cfg_ipproto = IPPROTO_RAW;
+                       break;
+               case 'u':
+                       proto_count++;
+                       cfg_proto = SOCK_DGRAM;
+                       cfg_ipproto = IPPROTO_UDP;
+                       break;
+               case 'l':
+                       cfg_payload_len = strtoul(optarg, NULL, 10);
+                       break;
+               case 'p':
+                       dest_port = strtoul(optarg, NULL, 10);
+                       break;
+               case 'h':
+               default:
+                       usage(argv[0]);
+               }
+       }
+
+       if (!cfg_payload_len)
+               error(1, 0, "payload may not be nonzero");
+       if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472)
+               error(1, 0, "udp packet might exceed expected MTU");
+       if (!do_ipv4 && !do_ipv6)
+               error(1, 0, "pass -4 or -6, not both");
+       if (proto_count > 1)
+               error(1, 0, "pass -r, -R or -u, not multiple");
+
+       if (optind != argc - 1)
+               error(1, 0, "missing required hostname argument");
+}
+
+static void resolve_hostname(const char *hostname)
+{
+       struct addrinfo *addrs, *cur;
+       int have_ipv4 = 0, have_ipv6 = 0;
+
+       if (getaddrinfo(hostname, NULL, NULL, &addrs))
+               error(1, errno, "getaddrinfo");
+
+       cur = addrs;
+       while (cur && !have_ipv4 && !have_ipv6) {
+               if (!have_ipv4 && cur->ai_family == AF_INET) {
+                       memcpy(&daddr, cur->ai_addr, sizeof(daddr));
+                       daddr.sin_port = htons(dest_port);
+                       have_ipv4 = 1;
+               }
+               else if (!have_ipv6 && cur->ai_family == AF_INET6) {
+                       memcpy(&daddr6, cur->ai_addr, sizeof(daddr6));
+                       daddr6.sin6_port = htons(dest_port);
+                       have_ipv6 = 1;
+               }
+               cur = cur->ai_next;
+       }
+       if (addrs)
+               freeaddrinfo(addrs);
+
+       do_ipv4 &= have_ipv4;
+       do_ipv6 &= have_ipv6;
+}
+
+static void do_main(int family)
+{
+       fprintf(stderr, "family:       %s\n",
+                       family == PF_INET ? "INET" : "INET6");
+
+       fprintf(stderr, "test SND\n");
+       do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE);
+
+       fprintf(stderr, "test ENQ\n");
+       do_test(family, SOF_TIMESTAMPING_TX_SCHED);
+
+       fprintf(stderr, "test ENQ + SND\n");
+       do_test(family, SOF_TIMESTAMPING_TX_SCHED |
+                       SOF_TIMESTAMPING_TX_SOFTWARE);
+
+       if (cfg_proto == SOCK_STREAM) {
+               fprintf(stderr, "\ntest ACK\n");
+               do_test(family, SOF_TIMESTAMPING_TX_ACK);
+
+               fprintf(stderr, "\ntest SND + ACK\n");
+               do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE |
+                               SOF_TIMESTAMPING_TX_ACK);
+
+               fprintf(stderr, "\ntest ENQ + SND + ACK\n");
+               do_test(family, SOF_TIMESTAMPING_TX_SCHED |
+                               SOF_TIMESTAMPING_TX_SOFTWARE |
+                               SOF_TIMESTAMPING_TX_ACK);
+       }
+}
+
+const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" };
+
+int main(int argc, char **argv)
+{
+       if (argc == 1)
+               usage(argv[0]);
+
+       parse_opt(argc, argv);
+       resolve_hostname(argv[argc - 1]);
+
+       fprintf(stderr, "protocol:     %s\n", sock_names[cfg_proto]);
+       fprintf(stderr, "payload:      %u\n", cfg_payload_len);
+       fprintf(stderr, "server port:  %u\n", dest_port);
+       fprintf(stderr, "\n");
+
+       if (do_ipv4)
+               do_main(PF_INET);
+       if (do_ipv6)
+               do_main(PF_INET6);
+
+       return 0;
+}
index 9a0319a8247032c0fb6ae1a34129eacbba40c5eb..04892b821157774b81f4adecae870e06ef6f9bd4 100644 (file)
@@ -241,6 +241,9 @@ address of the router (or Connected) for internal networks.
 6. TIPC
 -------------------------------------------------------
 
+tipc_rmem
+----------
+
 The TIPC protocol now has a tunable for the receive memory, similar to the
 tcp_rmem - i.e. a vector of 3 INTEGERs: (min, default, max)
 
@@ -252,3 +255,16 @@ The max value is set to CONN_OVERLOAD_LIMIT, and the default and min values
 are scaled (shifted) versions of that same value.  Note that the min value
 is not at this point in time used in any meaningful way, but the triplet is
 preserved in order to be consistent with things like tcp_rmem.
+
+named_timeout
+--------------
+
+TIPC name table updates are distributed asynchronously in a cluster, without
+any form of transaction handling. This means that different race scenarios are
+possible. One such is that a name withdrawal sent out by one node and received
+by another node may arrive after a second, overlapping name publication already
+has been accepted from a third node, although the conflicting updates
+originally may have been issued in the correct sequential order.
+If named_timeout is nonzero, failed topology updates will be placed on a defer
+queue until another event arrives that clears the error, or until the timeout
+expires. Value is in milliseconds.
index 5e7866a486b0c3310b64ca5c9aa6cd6d9c16d354..fd86604f3a9cfb190be54195541a11fbbb527bee 100644 (file)
@@ -7378,7 +7378,7 @@ F:        drivers/net/ethernet/qlogic/qla3xxx.*
 
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
 M:     Shahed Shaikh <shahed.shaikh@qlogic.com>
-M:     Dept-HSGLinuxNICDev@qlogic.com
+M:     Dept-GELinuxNICDev@qlogic.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/qlogic/qlcnic/
index a37b989a2f91e302be654a7633082321e8f0c5bb..a76623bcf722b2a576469e755ce2c5f301532916 100644 (file)
@@ -930,5 +930,6 @@ void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
                module_free(NULL, fp->bpf_func);
-       kfree(fp);
+
+       bpf_prog_unlock_free(fp);
 }
index 05a56619ece2f72044641c6aa1fd2d99f558bb69..cfa83cf2447dc6a8831c1bdf394c1a3fd8b203be 100644 (file)
@@ -1427,5 +1427,6 @@ void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
                module_free(NULL, fp->bpf_func);
-       kfree(fp);
+
+       bpf_prog_unlock_free(fp);
 }
index 3afa6f4c195705569726ef927ddc8f392af097ac..40c53ff59124d306f111ed65ceede655ca7f6682 100644 (file)
@@ -697,5 +697,6 @@ void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
                module_free(NULL, fp->bpf_func);
-       kfree(fp);
+
+       bpf_prog_unlock_free(fp);
 }
index 61e45b7c04d7bdf122a195903face00cfb6c2ce3..f2833c5b218a798260b89f4d2216da3569b04749 100644 (file)
@@ -887,5 +887,5 @@ void bpf_jit_free(struct bpf_prog *fp)
        module_free(NULL, header);
 
 free_filter:
-       kfree(fp);
+       bpf_prog_unlock_free(fp);
 }
index 1f76c22a6a75d64a5dafd6f24da19eec6c816e96..f7a736b645e843da002c02338aa0892965a44d42 100644 (file)
@@ -812,5 +812,6 @@ void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
                module_free(NULL, fp->bpf_func);
-       kfree(fp);
+
+       bpf_prog_unlock_free(fp);
 }
index 5c8cb8043c5a2b19df3e524d9d35ee3ec1949cd5..39ccfbb4a72311e95f1f09b52a62b1fba2ab65e0 100644 (file)
@@ -515,6 +515,48 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                        EMIT3(0xC1, add_1reg(b3, dst_reg), imm32);
                        break;
 
+               case BPF_ALU | BPF_LSH | BPF_X:
+               case BPF_ALU | BPF_RSH | BPF_X:
+               case BPF_ALU | BPF_ARSH | BPF_X:
+               case BPF_ALU64 | BPF_LSH | BPF_X:
+               case BPF_ALU64 | BPF_RSH | BPF_X:
+               case BPF_ALU64 | BPF_ARSH | BPF_X:
+
+                       /* check for bad case when dst_reg == rcx */
+                       if (dst_reg == BPF_REG_4) {
+                               /* mov r11, dst_reg */
+                               EMIT_mov(AUX_REG, dst_reg);
+                               dst_reg = AUX_REG;
+                       }
+
+                       if (src_reg != BPF_REG_4) { /* common case */
+                               EMIT1(0x51); /* push rcx */
+
+                               /* mov rcx, src_reg */
+                               EMIT_mov(BPF_REG_4, src_reg);
+                       }
+
+                       /* shl %rax, %cl | shr %rax, %cl | sar %rax, %cl */
+                       if (BPF_CLASS(insn->code) == BPF_ALU64)
+                               EMIT1(add_1mod(0x48, dst_reg));
+                       else if (is_ereg(dst_reg))
+                               EMIT1(add_1mod(0x40, dst_reg));
+
+                       switch (BPF_OP(insn->code)) {
+                       case BPF_LSH: b3 = 0xE0; break;
+                       case BPF_RSH: b3 = 0xE8; break;
+                       case BPF_ARSH: b3 = 0xF8; break;
+                       }
+                       EMIT2(0xD3, add_1reg(b3, dst_reg));
+
+                       if (src_reg != BPF_REG_4)
+                               EMIT1(0x59); /* pop rcx */
+
+                       if (insn->dst_reg == BPF_REG_4)
+                               /* mov dst_reg, r11 */
+                               EMIT_mov(insn->dst_reg, AUX_REG);
+                       break;
+
                case BPF_ALU | BPF_END | BPF_FROM_BE:
                        switch (imm32) {
                        case 16:
@@ -930,23 +972,17 @@ out:
        kfree(addrs);
 }
 
-static void bpf_jit_free_deferred(struct work_struct *work)
+void bpf_jit_free(struct bpf_prog *fp)
 {
-       struct bpf_prog *fp = container_of(work, struct bpf_prog, work);
        unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
        struct bpf_binary_header *header = (void *)addr;
 
+       if (!fp->jited)
+               goto free_filter;
+
        set_memory_rw(addr, header->pages);
        module_free(NULL, header);
-       kfree(fp);
-}
 
-void bpf_jit_free(struct bpf_prog *fp)
-{
-       if (fp->jited) {
-               INIT_WORK(&fp->work, bpf_jit_free_deferred);
-               schedule_work(&fp->work);
-       } else {
-               kfree(fp);
-       }
+free_filter:
+       bpf_prog_unlock_free(fp);
 }
index b7ae0a0dd5b6814c61332d3f56b4b7626754ddea..aecec6d3246370004a0e9434a1f58303e96b7c46 100644 (file)
@@ -2365,7 +2365,7 @@ static int gigaset_probe(struct usb_interface *interface,
        endpoint = &hostif->endpoint[0].desc;
        usb_fill_int_urb(ucs->urb_int_in, udev,
                         usb_rcvintpipe(udev,
-                                       (endpoint->bEndpointAddress) & 0x0f),
+                                       usb_endpoint_num(endpoint)),
                         ucs->int_in_buf, IP_MSGSIZE, read_int_callback, cs,
                         endpoint->bInterval);
        rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL);
index d0a41cb0cf627fe8c6687324e93f9dd3cb0384b7..00d40773b07fa073840feecf89f5a3cf2428e4ee 100644 (file)
@@ -751,7 +751,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,
-                                       endpoint->bEndpointAddress & 0x0f),
+                                       usb_endpoint_num(endpoint)),
                         ucs->rcvbuf, buffer_size,
                         gigaset_read_int_callback,
                         cs, endpoint->bInterval);
index a4f05c54c32b021cc04fb9ea65ece506a1e94e2a..87f7dff20ff66b269537b166642690722fd4accc 100644 (file)
@@ -1454,66 +1454,63 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
 #ifdef CMX_CONF_DEBUG
        if (0) {
 #else
-               if (members == 2) {
+       if (members == 2) {
 #endif
-                       /* "other" becomes other party */
-                       other = (list_entry(conf->mlist.next,
-                                           struct dsp_conf_member, list))->dsp;
-                       if (other == member)
-                               other = (list_entry(conf->mlist.prev,
-                                                   struct dsp_conf_member, list))->dsp;
-                       o_q = other->rx_buff; /* received data */
-                       o_rr = (other->rx_R + len) & CMX_BUFF_MASK;
-                       /* end of rx-pointer */
-                       o_r = (o_rr - rr + r) & CMX_BUFF_MASK;
-                       /* start rx-pointer at current read position*/
-                       /* -> if echo is NOT enabled */
-                       if (!dsp->echo.software) {
-                               /*
-                                * -> copy other member's rx-data,
-                                * if tx-data is available, mix
-                                */
-                               while (o_r != o_rr && t != tt) {
-                                       *d++ = dsp_audio_mix_law[(p[t] << 8) | o_q[o_r]];
-                                       t = (t + 1) & CMX_BUFF_MASK;
-                                       o_r = (o_r + 1) & CMX_BUFF_MASK;
-                               }
-                               while (o_r != o_rr) {
-                                       *d++ = o_q[o_r];
-                                       o_r = (o_r + 1) & CMX_BUFF_MASK;
-                               }
-                               /* -> if echo is enabled */
-                       } else {
-                               /*
-                                * -> mix other member's rx-data with echo,
-                                * if tx-data is available, mix
-                                */
-                               while (r != rr && t != tt) {
-                                       sample = dsp_audio_law_to_s32[p[t]] +
-                                               dsp_audio_law_to_s32[q[r]] +
-                                               dsp_audio_law_to_s32[o_q[o_r]];
-                                       if (sample < -32768)
-                                               sample = -32768;
-                                       else if (sample > 32767)
-                                               sample = 32767;
-                                       *d++ = dsp_audio_s16_to_law[sample & 0xffff];
-                                       /* tx-data + rx_data + echo */
-                                       t = (t + 1) & CMX_BUFF_MASK;
-                                       r = (r + 1) & CMX_BUFF_MASK;
-                                       o_r = (o_r + 1) & CMX_BUFF_MASK;
-                               }
-                               while (r != rr) {
-                                       *d++ = dsp_audio_mix_law[(q[r] << 8) | o_q[o_r]];
-                                       r = (r + 1) & CMX_BUFF_MASK;
-                                       o_r = (o_r + 1) & CMX_BUFF_MASK;
-                               }
+               /* "other" becomes other party */
+               other = (list_entry(conf->mlist.next,
+                                   struct dsp_conf_member, list))->dsp;
+               if (other == member)
+                       other = (list_entry(conf->mlist.prev,
+                                   struct dsp_conf_member, list))->dsp;
+               o_q = other->rx_buff; /* received data */
+               o_rr = (other->rx_R + len) & CMX_BUFF_MASK;
+               /* end of rx-pointer */
+               o_r = (o_rr - rr + r) & CMX_BUFF_MASK;
+               /* start rx-pointer at current read position*/
+               /* -> if echo is NOT enabled */
+               if (!dsp->echo.software) {
+                       /*
+                        * -> copy other member's rx-data,
+                        * if tx-data is available, mix
+                        */
+                       while (o_r != o_rr && t != tt) {
+                               *d++ = dsp_audio_mix_law[(p[t] << 8) | o_q[o_r]];
+                               t = (t + 1) & CMX_BUFF_MASK;
+                               o_r = (o_r + 1) & CMX_BUFF_MASK;
+                       }
+                       while (o_r != o_rr) {
+                               *d++ = o_q[o_r];
+                               o_r = (o_r + 1) & CMX_BUFF_MASK;
+                       }
+                       /* -> if echo is enabled */
+               } else {
+                       /*
+                        * -> mix other member's rx-data with echo,
+                        * if tx-data is available, mix
+                        */
+                       while (r != rr && t != tt) {
+                               sample = dsp_audio_law_to_s32[p[t]] +
+                                       dsp_audio_law_to_s32[q[r]] +
+                                       dsp_audio_law_to_s32[o_q[o_r]];
+                               if (sample < -32768)
+                                       sample = -32768;
+                               else if (sample > 32767)
+                                       sample = 32767;
+                               *d++ = dsp_audio_s16_to_law[sample & 0xffff];
+                               /* tx-data + rx_data + echo */
+                               t = (t + 1) & CMX_BUFF_MASK;
+                               r = (r + 1) & CMX_BUFF_MASK;
+                               o_r = (o_r + 1) & CMX_BUFF_MASK;
+                       }
+                       while (r != rr) {
+                               *d++ = dsp_audio_mix_law[(q[r] << 8) | o_q[o_r]];
+                               r = (r + 1) & CMX_BUFF_MASK;
+                               o_r = (o_r + 1) & CMX_BUFF_MASK;
                        }
-                       dsp->tx_R = t;
-                       goto send_packet;
                }
-#ifdef DSP_NEVER_DEFINED
+               dsp->tx_R = t;
+               goto send_packet;
        }
-#endif
        /* PROCESS DATA (three or more members) */
        /* -> if echo is NOT enabled */
        if (!dsp->echo.software) {
index 95dd1f58c260d941c51ac4a369b2b97ba3f4ba34..73c21e233131f6f8af6a48e540659dd71f649f48 100644 (file)
@@ -1388,7 +1388,7 @@ static int bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond,
        }
 
        if (tx_slave && bond_slave_can_tx(tx_slave)) {
-               if (tx_slave != rcu_dereference(bond->curr_active_slave)) {
+               if (tx_slave != rcu_access_pointer(bond->curr_active_slave)) {
                        ether_addr_copy(eth_data->h_source,
                                        tx_slave->dev->dev_addr);
                }
index d163e112f04ce00956fedd17221c3c283ff8a3c6..e1489d9df2a4985563a5932f02844b087e22d202 100644 (file)
@@ -96,6 +96,10 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
        [IFLA_BOND_AD_INFO]             = { .type = NLA_NESTED },
 };
 
+static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
+       [IFLA_BOND_SLAVE_QUEUE_ID]      = { .type = NLA_U16 },
+};
+
 static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
 {
        if (tb[IFLA_ADDRESS]) {
@@ -107,6 +111,33 @@ static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
        return 0;
 }
 
+static int bond_slave_changelink(struct net_device *bond_dev,
+                                struct net_device *slave_dev,
+                                struct nlattr *tb[], struct nlattr *data[])
+{
+       struct bonding *bond = netdev_priv(bond_dev);
+       struct bond_opt_value newval;
+       int err;
+
+       if (!data)
+               return 0;
+
+       if (data[IFLA_BOND_SLAVE_QUEUE_ID]) {
+               u16 queue_id = nla_get_u16(data[IFLA_BOND_SLAVE_QUEUE_ID]);
+               char queue_id_str[IFNAMSIZ + 7];
+
+               /* queue_id option setting expects slave_name:queue_id */
+               snprintf(queue_id_str, sizeof(queue_id_str), "%s:%u\n",
+                        slave_dev->name, queue_id);
+               bond_opt_initstr(&newval, queue_id_str);
+               err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int bond_changelink(struct net_device *bond_dev,
                           struct nlattr *tb[], struct nlattr *data[])
 {
@@ -562,6 +593,9 @@ struct rtnl_link_ops bond_link_ops __read_mostly = {
        .get_num_tx_queues      = bond_get_num_tx_queues,
        .get_num_rx_queues      = bond_get_num_tx_queues, /* Use the same number
                                                             as for TX queues */
+       .slave_maxtype          = IFLA_BOND_SLAVE_MAX,
+       .slave_policy           = bond_slave_policy,
+       .slave_changelink       = bond_slave_changelink,
        .get_slave_size         = bond_get_slave_size,
        .fill_slave_info        = bond_fill_slave_info,
 };
index dc73463c2c237d99bf26c9b3ff21512c36f69504..d8dc17faa6b4cba1e5196e1ebdd8fda09eb49a5c 100644 (file)
@@ -625,6 +625,8 @@ int __bond_opt_set(struct bonding *bond,
 out:
        if (ret)
                bond_opt_error_interpret(bond, opt, ret, val);
+       else
+               call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev);
 
        return ret;
 }
index 41688229c570eb92e9e79b2bee2bd5b9d6173e39..e78d6b32431d6ce509a8e219114af5c9e5789779 100644 (file)
@@ -143,6 +143,8 @@ source "drivers/net/can/sja1000/Kconfig"
 
 source "drivers/net/can/c_can/Kconfig"
 
+source "drivers/net/can/m_can/Kconfig"
+
 source "drivers/net/can/cc770/Kconfig"
 
 source "drivers/net/can/spi/Kconfig"
index 1697f22353a943315bdb5e162d3cdce4f7d535f7..fc9304143f449c8eee3aaddcaf1d701fc90b7bb5 100644 (file)
@@ -17,6 +17,7 @@ obj-y                         += softing/
 obj-$(CONFIG_CAN_SJA1000)      += sja1000/
 obj-$(CONFIG_CAN_MSCAN)                += mscan/
 obj-$(CONFIG_CAN_C_CAN)                += c_can/
+obj-$(CONFIG_CAN_M_CAN)                += m_can/
 obj-$(CONFIG_CAN_CC770)                += cc770/
 obj-$(CONFIG_CAN_AT91)         += at91_can.o
 obj-$(CONFIG_CAN_TI_HECC)      += ti_hecc.o
@@ -28,4 +29,4 @@ obj-$(CONFIG_CAN_GRCAN)               += grcan.o
 obj-$(CONFIG_CAN_RCAR)         += rcar_can.o
 obj-$(CONFIG_CAN_XILINXCAN)    += xilinx_can.o
 
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index ad1cc842170add4076f17ec08c211bc16b7b647b..9fdc678b5b3787776a94371215a11f2a3d5194f3 100644 (file)
@@ -5,5 +5,3 @@
 obj-$(CONFIG_CAN_C_CAN) += c_can.o
 obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
 obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 9fb8321b33eb770c16090963b02d45720e26f8af..8657f879ae19084cbd9143c62e72f72dfea9fe91 100644 (file)
@@ -5,5 +5,3 @@
 obj-$(CONFIG_CAN_CC770) += cc770.o
 obj-$(CONFIG_CAN_CC770_ISA) += cc770_isa.o
 obj-$(CONFIG_CAN_CC770_PLATFORM) += cc770_platform.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 9f91fcba43f8718f4d546e39faaef1aa3bd9fabf..02492d241e4c9e8cb8d49ae319067c7c0aa1f9cf 100644 (file)
@@ -103,11 +103,11 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
                              const struct can_bittiming_const *btc)
 {
        struct can_priv *priv = netdev_priv(dev);
-       long rate, best_rate = 0;
        long best_error = 1000000000, error = 0;
        int best_tseg = 0, best_brp = 0, brp = 0;
        int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
        int spt_error = 1000, spt = 0, sampl_pt;
+       long rate;
        u64 v64;
 
        /* Use CIA recommended sample points */
@@ -152,7 +152,6 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
                }
                best_tseg = tseg / 2;
                best_brp = brp;
-               best_rate = rate;
                if (error == 0)
                        break;
        }
index 944aa5d3af6ef4602329b75a57e8f87be85d79f8..2700865efcad5d73ab7ba244abdef3fe6917c395 100644 (file)
 #define FLEXCAN_CTRL_ERR_ALL \
        (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
 
+/* FLEXCAN control register 2 (CTRL2) bits */
+#define FLEXCAN_CRL2_ECRWRE            BIT(29)
+#define FLEXCAN_CRL2_WRMFRZ            BIT(28)
+#define FLEXCAN_CRL2_RFFN(x)           (((x) & 0x0f) << 24)
+#define FLEXCAN_CRL2_TASD(x)           (((x) & 0x1f) << 19)
+#define FLEXCAN_CRL2_MRP               BIT(18)
+#define FLEXCAN_CRL2_RRS               BIT(17)
+#define FLEXCAN_CRL2_EACEN             BIT(16)
+
+/* FLEXCAN memory error control register (MECR) bits */
+#define FLEXCAN_MECR_ECRWRDIS          BIT(31)
+#define FLEXCAN_MECR_HANCEI_MSK                BIT(19)
+#define FLEXCAN_MECR_FANCEI_MSK                BIT(18)
+#define FLEXCAN_MECR_CEI_MSK           BIT(16)
+#define FLEXCAN_MECR_HAERRIE           BIT(15)
+#define FLEXCAN_MECR_FAERRIE           BIT(14)
+#define FLEXCAN_MECR_EXTERRIE          BIT(13)
+#define FLEXCAN_MECR_RERRDIS           BIT(9)
+#define FLEXCAN_MECR_ECCDIS            BIT(8)
+#define FLEXCAN_MECR_NCEFAFRZ          BIT(7)
+
 /* FLEXCAN error and status register (ESR) bits */
 #define FLEXCAN_ESR_TWRN_INT           BIT(17)
 #define FLEXCAN_ESR_RWRN_INT           BIT(16)
  * FLEXCAN hardware feature flags
  *
  * Below is some version info we got:
- *    SOC   Version   IP-Version  Glitch-  [TR]WRN_INT
- *                                Filter?   connected?
- *   MX25  FlexCAN2  03.00.00.00     no         no
- *   MX28  FlexCAN2  03.00.04.00    yes        yes
- *   MX35  FlexCAN2  03.00.00.00     no         no
- *   MX53  FlexCAN2  03.00.00.00    yes         no
- *   MX6s  FlexCAN3  10.00.12.00    yes        yes
+ *    SOC   Version   IP-Version  Glitch-  [TR]WRN_INT  Memory err
+ *                                Filter?   connected?  detection
+ *   MX25  FlexCAN2  03.00.00.00     no         no         no
+ *   MX28  FlexCAN2  03.00.04.00    yes        yes         no
+ *   MX35  FlexCAN2  03.00.00.00     no         no         no
+ *   MX53  FlexCAN2  03.00.00.00    yes         no         no
+ *   MX6s  FlexCAN3  10.00.12.00    yes        yes         no
+ *   VF610 FlexCAN3  ?               no        yes        yes
  *
  * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
  */
 #define FLEXCAN_HAS_V10_FEATURES       BIT(1) /* For core version >= 10 */
 #define FLEXCAN_HAS_BROKEN_ERR_STATE   BIT(2) /* [TR]WRN_INT not connected */
+#define FLEXCAN_HAS_MECR_FEATURES      BIT(3) /* Memory error detection */
 
 /* Structure of the message buffer */
 struct flexcan_mb {
@@ -192,8 +215,17 @@ struct flexcan_regs {
        u32 crcr;               /* 0x44 */
        u32 rxfgmask;           /* 0x48 */
        u32 rxfir;              /* 0x4c */
-       u32 _reserved3[12];
-       struct flexcan_mb cantxfg[64];
+       u32 _reserved3[12];     /* 0x50 */
+       struct flexcan_mb cantxfg[64];  /* 0x80 */
+       u32 _reserved4[408];
+       u32 mecr;               /* 0xae0 */
+       u32 erriar;             /* 0xae4 */
+       u32 erridpr;            /* 0xae8 */
+       u32 errippr;            /* 0xaec */
+       u32 rerrar;             /* 0xaf0 */
+       u32 rerrdr;             /* 0xaf4 */
+       u32 rerrsynr;           /* 0xaf8 */
+       u32 errsr;              /* 0xafc */
 };
 
 struct flexcan_devtype_data {
@@ -223,6 +255,9 @@ static struct flexcan_devtype_data fsl_imx28_devtype_data;
 static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
        .features = FLEXCAN_HAS_V10_FEATURES,
 };
+static struct flexcan_devtype_data fsl_vf610_devtype_data = {
+       .features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_MECR_FEATURES,
+};
 
 static const struct can_bittiming_const flexcan_bittiming_const = {
        .name = DRV_NAME,
@@ -378,8 +413,9 @@ static int flexcan_chip_softreset(struct flexcan_priv *priv)
        return 0;
 }
 
-static int flexcan_get_berr_counter(const struct net_device *dev,
-                                   struct can_berr_counter *bec)
+
+static int __flexcan_get_berr_counter(const struct net_device *dev,
+                                     struct can_berr_counter *bec)
 {
        const struct flexcan_priv *priv = netdev_priv(dev);
        struct flexcan_regs __iomem *regs = priv->base;
@@ -391,6 +427,29 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
        return 0;
 }
 
+static int flexcan_get_berr_counter(const struct net_device *dev,
+                                   struct can_berr_counter *bec)
+{
+       const struct flexcan_priv *priv = netdev_priv(dev);
+       int err;
+
+       err = clk_prepare_enable(priv->clk_ipg);
+       if (err)
+               return err;
+
+       err = clk_prepare_enable(priv->clk_per);
+       if (err)
+               goto out_disable_ipg;
+
+       err = __flexcan_get_berr_counter(dev, bec);
+
+       clk_disable_unprepare(priv->clk_per);
+ out_disable_ipg:
+       clk_disable_unprepare(priv->clk_ipg);
+
+       return err;
+}
+
 static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        const struct flexcan_priv *priv = netdev_priv(dev);
@@ -503,7 +562,7 @@ static void do_state(struct net_device *dev,
        struct flexcan_priv *priv = netdev_priv(dev);
        struct can_berr_counter bec;
 
-       flexcan_get_berr_counter(dev, &bec);
+       __flexcan_get_berr_counter(dev, &bec);
 
        switch (priv->can.state) {
        case CAN_STATE_ERROR_ACTIVE:
@@ -800,7 +859,7 @@ static int flexcan_chip_start(struct net_device *dev)
        struct flexcan_priv *priv = netdev_priv(dev);
        struct flexcan_regs __iomem *regs = priv->base;
        int err;
-       u32 reg_mcr, reg_ctrl;
+       u32 reg_mcr, reg_ctrl, reg_crl2, reg_mecr;
 
        /* enable module */
        err = flexcan_chip_enable(priv);
@@ -879,6 +938,31 @@ static int flexcan_chip_start(struct net_device *dev)
        if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
                flexcan_write(0x0, &regs->rxfgmask);
 
+       /*
+        * On Vybrid, disable memory error detection interrupts
+        * and freeze mode.
+        * This also works around errata e5295 which generates
+        * false positive memory errors and put the device in
+        * freeze mode.
+        */
+       if (priv->devtype_data->features & FLEXCAN_HAS_MECR_FEATURES) {
+               /*
+                * Follow the protocol as described in "Detection
+                * and Correction of Memory Errors" to write to
+                * MECR register
+                */
+               reg_crl2 = flexcan_read(&regs->crl2);
+               reg_crl2 |= FLEXCAN_CRL2_ECRWRE;
+               flexcan_write(reg_crl2, &regs->crl2);
+
+               reg_mecr = flexcan_read(&regs->mecr);
+               reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
+               flexcan_write(reg_mecr, &regs->mecr);
+               reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK |
+                               FLEXCAN_MECR_FANCEI_MSK);
+               flexcan_write(reg_mecr, &regs->mecr);
+       }
+
        err = flexcan_transceiver_enable(priv);
        if (err)
                goto out_chip_disable;
@@ -1089,6 +1173,7 @@ static const struct of_device_id flexcan_of_match[] = {
        { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
        { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
        { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
+       { .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, flexcan_of_match);
diff --git a/drivers/net/can/m_can/Kconfig b/drivers/net/can/m_can/Kconfig
new file mode 100644 (file)
index 0000000..fca5482
--- /dev/null
@@ -0,0 +1,4 @@
+config CAN_M_CAN
+       tristate "Bosch M_CAN devices"
+       ---help---
+         Say Y here if you want to support for Bosch M_CAN controller.
diff --git a/drivers/net/can/m_can/Makefile b/drivers/net/can/m_can/Makefile
new file mode 100644 (file)
index 0000000..8bbd7f2
--- /dev/null
@@ -0,0 +1,5 @@
+#
+#  Makefile for the Bosch M_CAN controller driver.
+#
+
+obj-$(CONFIG_CAN_M_CAN) += m_can.o
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
new file mode 100644 (file)
index 0000000..10d571e
--- /dev/null
@@ -0,0 +1,1202 @@
+/*
+ * CAN bus driver for Bosch M_CAN controller
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *     Dong Aisheng <b29396@freescale.com>
+ *
+ * Bosch M_CAN user manual can be obtained from:
+ * http://www.bosch-semiconductors.de/media/pdf_1/ipmodules_1/m_can/
+ * mcan_users_manual_v302.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <linux/can/dev.h>
+
+/* napi related */
+#define M_CAN_NAPI_WEIGHT      64
+
+/* message ram configuration data length */
+#define MRAM_CFG_LEN   8
+
+/* registers definition */
+enum m_can_reg {
+       M_CAN_CREL      = 0x0,
+       M_CAN_ENDN      = 0x4,
+       M_CAN_CUST      = 0x8,
+       M_CAN_FBTP      = 0xc,
+       M_CAN_TEST      = 0x10,
+       M_CAN_RWD       = 0x14,
+       M_CAN_CCCR      = 0x18,
+       M_CAN_BTP       = 0x1c,
+       M_CAN_TSCC      = 0x20,
+       M_CAN_TSCV      = 0x24,
+       M_CAN_TOCC      = 0x28,
+       M_CAN_TOCV      = 0x2c,
+       M_CAN_ECR       = 0x40,
+       M_CAN_PSR       = 0x44,
+       M_CAN_IR        = 0x50,
+       M_CAN_IE        = 0x54,
+       M_CAN_ILS       = 0x58,
+       M_CAN_ILE       = 0x5c,
+       M_CAN_GFC       = 0x80,
+       M_CAN_SIDFC     = 0x84,
+       M_CAN_XIDFC     = 0x88,
+       M_CAN_XIDAM     = 0x90,
+       M_CAN_HPMS      = 0x94,
+       M_CAN_NDAT1     = 0x98,
+       M_CAN_NDAT2     = 0x9c,
+       M_CAN_RXF0C     = 0xa0,
+       M_CAN_RXF0S     = 0xa4,
+       M_CAN_RXF0A     = 0xa8,
+       M_CAN_RXBC      = 0xac,
+       M_CAN_RXF1C     = 0xb0,
+       M_CAN_RXF1S     = 0xb4,
+       M_CAN_RXF1A     = 0xb8,
+       M_CAN_RXESC     = 0xbc,
+       M_CAN_TXBC      = 0xc0,
+       M_CAN_TXFQS     = 0xc4,
+       M_CAN_TXESC     = 0xc8,
+       M_CAN_TXBRP     = 0xcc,
+       M_CAN_TXBAR     = 0xd0,
+       M_CAN_TXBCR     = 0xd4,
+       M_CAN_TXBTO     = 0xd8,
+       M_CAN_TXBCF     = 0xdc,
+       M_CAN_TXBTIE    = 0xe0,
+       M_CAN_TXBCIE    = 0xe4,
+       M_CAN_TXEFC     = 0xf0,
+       M_CAN_TXEFS     = 0xf4,
+       M_CAN_TXEFA     = 0xf8,
+};
+
+/* m_can lec values */
+enum m_can_lec_type {
+       LEC_NO_ERROR = 0,
+       LEC_STUFF_ERROR,
+       LEC_FORM_ERROR,
+       LEC_ACK_ERROR,
+       LEC_BIT1_ERROR,
+       LEC_BIT0_ERROR,
+       LEC_CRC_ERROR,
+       LEC_UNUSED,
+};
+
+enum m_can_mram_cfg {
+       MRAM_SIDF = 0,
+       MRAM_XIDF,
+       MRAM_RXF0,
+       MRAM_RXF1,
+       MRAM_RXB,
+       MRAM_TXE,
+       MRAM_TXB,
+       MRAM_CFG_NUM,
+};
+
+/* Test Register (TEST) */
+#define TEST_LBCK      BIT(4)
+
+/* CC Control Register(CCCR) */
+#define CCCR_TEST      BIT(7)
+#define CCCR_MON       BIT(5)
+#define CCCR_CCE       BIT(1)
+#define CCCR_INIT      BIT(0)
+
+/* Bit Timing & Prescaler Register (BTP) */
+#define BTR_BRP_MASK           0x3ff
+#define BTR_BRP_SHIFT          16
+#define BTR_TSEG1_SHIFT                8
+#define BTR_TSEG1_MASK         (0x3f << BTR_TSEG1_SHIFT)
+#define BTR_TSEG2_SHIFT                4
+#define BTR_TSEG2_MASK         (0xf << BTR_TSEG2_SHIFT)
+#define BTR_SJW_SHIFT          0
+#define BTR_SJW_MASK           0xf
+
+/* Error Counter Register(ECR) */
+#define ECR_RP                 BIT(15)
+#define ECR_REC_SHIFT          8
+#define ECR_REC_MASK           (0x7f << ECR_REC_SHIFT)
+#define ECR_TEC_SHIFT          0
+#define ECR_TEC_MASK           0xff
+
+/* Protocol Status Register(PSR) */
+#define PSR_BO         BIT(7)
+#define PSR_EW         BIT(6)
+#define PSR_EP         BIT(5)
+#define PSR_LEC_MASK   0x7
+
+/* Interrupt Register(IR) */
+#define IR_ALL_INT     0xffffffff
+#define IR_STE         BIT(31)
+#define IR_FOE         BIT(30)
+#define IR_ACKE                BIT(29)
+#define IR_BE          BIT(28)
+#define IR_CRCE                BIT(27)
+#define IR_WDI         BIT(26)
+#define IR_BO          BIT(25)
+#define IR_EW          BIT(24)
+#define IR_EP          BIT(23)
+#define IR_ELO         BIT(22)
+#define IR_BEU         BIT(21)
+#define IR_BEC         BIT(20)
+#define IR_DRX         BIT(19)
+#define IR_TOO         BIT(18)
+#define IR_MRAF                BIT(17)
+#define IR_TSW         BIT(16)
+#define IR_TEFL                BIT(15)
+#define IR_TEFF                BIT(14)
+#define IR_TEFW                BIT(13)
+#define IR_TEFN                BIT(12)
+#define IR_TFE         BIT(11)
+#define IR_TCF         BIT(10)
+#define IR_TC          BIT(9)
+#define IR_HPM         BIT(8)
+#define IR_RF1L                BIT(7)
+#define IR_RF1F                BIT(6)
+#define IR_RF1W                BIT(5)
+#define IR_RF1N                BIT(4)
+#define IR_RF0L                BIT(3)
+#define IR_RF0F                BIT(2)
+#define IR_RF0W                BIT(1)
+#define IR_RF0N                BIT(0)
+#define IR_ERR_STATE   (IR_BO | IR_EW | IR_EP)
+#define IR_ERR_LEC     (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE)
+#define IR_ERR_BUS     (IR_ERR_LEC | IR_WDI | IR_ELO | IR_BEU | \
+                        IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
+                        IR_RF1L | IR_RF0L)
+#define IR_ERR_ALL     (IR_ERR_STATE | IR_ERR_BUS)
+
+/* Interrupt Line Select (ILS) */
+#define ILS_ALL_INT0   0x0
+#define ILS_ALL_INT1   0xFFFFFFFF
+
+/* Interrupt Line Enable (ILE) */
+#define ILE_EINT0      BIT(0)
+#define ILE_EINT1      BIT(1)
+
+/* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */
+#define RXFC_FWM_OFF   24
+#define RXFC_FWM_MASK  0x7f
+#define RXFC_FWM_1     (1 << RXFC_FWM_OFF)
+#define RXFC_FS_OFF    16
+#define RXFC_FS_MASK   0x7f
+
+/* Rx FIFO 0/1 Status (RXF0S/RXF1S) */
+#define RXFS_RFL       BIT(25)
+#define RXFS_FF                BIT(24)
+#define RXFS_FPI_OFF   16
+#define RXFS_FPI_MASK  0x3f0000
+#define RXFS_FGI_OFF   8
+#define RXFS_FGI_MASK  0x3f00
+#define RXFS_FFL_MASK  0x7f
+
+/* Rx Buffer / FIFO Element Size Configuration (RXESC) */
+#define M_CAN_RXESC_8BYTES     0x0
+
+/* Tx Buffer Configuration(TXBC) */
+#define TXBC_NDTB_OFF          16
+#define TXBC_NDTB_MASK         0x3f
+
+/* Tx Buffer Element Size Configuration(TXESC) */
+#define TXESC_TBDS_8BYTES      0x0
+
+/* Tx Event FIFO Con.guration (TXEFC) */
+#define TXEFC_EFS_OFF          16
+#define TXEFC_EFS_MASK         0x3f
+
+/* Message RAM Configuration (in bytes) */
+#define SIDF_ELEMENT_SIZE      4
+#define XIDF_ELEMENT_SIZE      8
+#define RXF0_ELEMENT_SIZE      16
+#define RXF1_ELEMENT_SIZE      16
+#define RXB_ELEMENT_SIZE       16
+#define TXE_ELEMENT_SIZE       8
+#define TXB_ELEMENT_SIZE       16
+
+/* Message RAM Elements */
+#define M_CAN_FIFO_ID          0x0
+#define M_CAN_FIFO_DLC         0x4
+#define M_CAN_FIFO_DATA(n)     (0x8 + ((n) << 2))
+
+/* Rx Buffer Element */
+#define RX_BUF_ESI             BIT(31)
+#define RX_BUF_XTD             BIT(30)
+#define RX_BUF_RTR             BIT(29)
+
+/* Tx Buffer Element */
+#define TX_BUF_XTD             BIT(30)
+#define TX_BUF_RTR             BIT(29)
+
+/* address offset and element number for each FIFO/Buffer in the Message RAM */
+struct mram_cfg {
+       u16 off;
+       u8  num;
+};
+
+/* m_can private data structure */
+struct m_can_priv {
+       struct can_priv can;    /* must be the first member */
+       struct napi_struct napi;
+       struct net_device *dev;
+       struct device *device;
+       struct clk *hclk;
+       struct clk *cclk;
+       void __iomem *base;
+       u32 irqstatus;
+
+       /* message ram configuration */
+       void __iomem *mram_base;
+       struct mram_cfg mcfg[MRAM_CFG_NUM];
+};
+
+static inline u32 m_can_read(const struct m_can_priv *priv, enum m_can_reg reg)
+{
+       return readl(priv->base + reg);
+}
+
+static inline void m_can_write(const struct m_can_priv *priv,
+                              enum m_can_reg reg, u32 val)
+{
+       writel(val, priv->base + reg);
+}
+
+static inline u32 m_can_fifo_read(const struct m_can_priv *priv,
+                                 u32 fgi, unsigned int offset)
+{
+       return readl(priv->mram_base + priv->mcfg[MRAM_RXF0].off +
+                    fgi * RXF0_ELEMENT_SIZE + offset);
+}
+
+static inline void m_can_fifo_write(const struct m_can_priv *priv,
+                                   u32 fpi, unsigned int offset, u32 val)
+{
+       return writel(val, priv->mram_base + priv->mcfg[MRAM_TXB].off +
+                     fpi * TXB_ELEMENT_SIZE + offset);
+}
+
+static inline void m_can_config_endisable(const struct m_can_priv *priv,
+                                         bool enable)
+{
+       u32 cccr = m_can_read(priv, M_CAN_CCCR);
+       u32 timeout = 10;
+       u32 val = 0;
+
+       if (enable) {
+               /* enable m_can configuration */
+               m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT);
+               /* CCCR.CCE can only be set/reset while CCCR.INIT = '1' */
+               m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT | CCCR_CCE);
+       } else {
+               m_can_write(priv, M_CAN_CCCR, cccr & ~(CCCR_INIT | CCCR_CCE));
+       }
+
+       /* there's a delay for module initialization */
+       if (enable)
+               val = CCCR_INIT | CCCR_CCE;
+
+       while ((m_can_read(priv, M_CAN_CCCR) & (CCCR_INIT | CCCR_CCE)) != val) {
+               if (timeout == 0) {
+                       netdev_warn(priv->dev, "Failed to init module\n");
+                       return;
+               }
+               timeout--;
+               udelay(1);
+       }
+}
+
+static inline void m_can_enable_all_interrupts(const struct m_can_priv *priv)
+{
+       m_can_write(priv, M_CAN_ILE, ILE_EINT0 | ILE_EINT1);
+}
+
+static inline void m_can_disable_all_interrupts(const struct m_can_priv *priv)
+{
+       m_can_write(priv, M_CAN_ILE, 0x0);
+}
+
+static void m_can_read_fifo(const struct net_device *dev, struct can_frame *cf,
+                           u32 rxfs)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       u32 id, fgi;
+
+       /* calculate the fifo get index for where to read data */
+       fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_OFF;
+       id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_ID);
+       if (id & RX_BUF_XTD)
+               cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
+       else
+               cf->can_id = (id >> 18) & CAN_SFF_MASK;
+
+       if (id & RX_BUF_RTR) {
+               cf->can_id |= CAN_RTR_FLAG;
+       } else {
+               id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_DLC);
+               cf->can_dlc = get_can_dlc((id >> 16) & 0x0F);
+               *(u32 *)(cf->data + 0) = m_can_fifo_read(priv, fgi,
+                                                        M_CAN_FIFO_DATA(0));
+               *(u32 *)(cf->data + 4) = m_can_fifo_read(priv, fgi,
+                                                        M_CAN_FIFO_DATA(1));
+       }
+
+       /* acknowledge rx fifo 0 */
+       m_can_write(priv, M_CAN_RXF0A, fgi);
+}
+
+static int m_can_do_rx_poll(struct net_device *dev, int quota)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
+       struct sk_buff *skb;
+       struct can_frame *frame;
+       u32 pkts = 0;
+       u32 rxfs;
+
+       rxfs = m_can_read(priv, M_CAN_RXF0S);
+       if (!(rxfs & RXFS_FFL_MASK)) {
+               netdev_dbg(dev, "no messages in fifo0\n");
+               return 0;
+       }
+
+       while ((rxfs & RXFS_FFL_MASK) && (quota > 0)) {
+               if (rxfs & RXFS_RFL)
+                       netdev_warn(dev, "Rx FIFO 0 Message Lost\n");
+
+               skb = alloc_can_skb(dev, &frame);
+               if (!skb) {
+                       stats->rx_dropped++;
+                       return pkts;
+               }
+
+               m_can_read_fifo(dev, frame, rxfs);
+
+               stats->rx_packets++;
+               stats->rx_bytes += frame->can_dlc;
+
+               netif_receive_skb(skb);
+
+               quota--;
+               pkts++;
+               rxfs = m_can_read(priv, M_CAN_RXF0S);
+       }
+
+       if (pkts)
+               can_led_event(dev, CAN_LED_EVENT_RX);
+
+       return pkts;
+}
+
+static int m_can_handle_lost_msg(struct net_device *dev)
+{
+       struct net_device_stats *stats = &dev->stats;
+       struct sk_buff *skb;
+       struct can_frame *frame;
+
+       netdev_err(dev, "msg lost in rxf0\n");
+
+       stats->rx_errors++;
+       stats->rx_over_errors++;
+
+       skb = alloc_can_err_skb(dev, &frame);
+       if (unlikely(!skb))
+               return 0;
+
+       frame->can_id |= CAN_ERR_CRTL;
+       frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+
+       netif_receive_skb(skb);
+
+       return 1;
+}
+
+static int m_can_handle_lec_err(struct net_device *dev,
+                               enum m_can_lec_type lec_type)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
+       struct can_frame *cf;
+       struct sk_buff *skb;
+
+       priv->can.can_stats.bus_error++;
+       stats->rx_errors++;
+
+       /* propagate the error condition to the CAN stack */
+       skb = alloc_can_err_skb(dev, &cf);
+       if (unlikely(!skb))
+               return 0;
+
+       /* check for 'last error code' which tells us the
+        * type of the last error to occur on the CAN bus
+        */
+       cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+
+       switch (lec_type) {
+       case LEC_STUFF_ERROR:
+               netdev_dbg(dev, "stuff error\n");
+               cf->data[2] |= CAN_ERR_PROT_STUFF;
+               break;
+       case LEC_FORM_ERROR:
+               netdev_dbg(dev, "form error\n");
+               cf->data[2] |= CAN_ERR_PROT_FORM;
+               break;
+       case LEC_ACK_ERROR:
+               netdev_dbg(dev, "ack error\n");
+               cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
+                               CAN_ERR_PROT_LOC_ACK_DEL);
+               break;
+       case LEC_BIT1_ERROR:
+               netdev_dbg(dev, "bit1 error\n");
+               cf->data[2] |= CAN_ERR_PROT_BIT1;
+               break;
+       case LEC_BIT0_ERROR:
+               netdev_dbg(dev, "bit0 error\n");
+               cf->data[2] |= CAN_ERR_PROT_BIT0;
+               break;
+       case LEC_CRC_ERROR:
+               netdev_dbg(dev, "CRC error\n");
+               cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+                               CAN_ERR_PROT_LOC_CRC_DEL);
+               break;
+       default:
+               break;
+       }
+
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
+
+       return 1;
+}
+
+static int m_can_get_berr_counter(const struct net_device *dev,
+                                 struct can_berr_counter *bec)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       unsigned int ecr;
+       int err;
+
+       err = clk_prepare_enable(priv->hclk);
+       if (err)
+               return err;
+
+       err = clk_prepare_enable(priv->cclk);
+       if (err) {
+               clk_disable_unprepare(priv->hclk);
+               return err;
+       }
+
+       ecr = m_can_read(priv, M_CAN_ECR);
+       bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
+       bec->txerr = ecr & ECR_TEC_MASK;
+
+       clk_disable_unprepare(priv->cclk);
+       clk_disable_unprepare(priv->hclk);
+
+       return 0;
+}
+
+static int m_can_handle_state_change(struct net_device *dev,
+                                    enum can_state new_state)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       struct can_berr_counter bec;
+       unsigned int ecr;
+
+       switch (new_state) {
+       case CAN_STATE_ERROR_ACTIVE:
+               /* error warning state */
+               priv->can.can_stats.error_warning++;
+               priv->can.state = CAN_STATE_ERROR_WARNING;
+               break;
+       case CAN_STATE_ERROR_PASSIVE:
+               /* error passive state */
+               priv->can.can_stats.error_passive++;
+               priv->can.state = CAN_STATE_ERROR_PASSIVE;
+               break;
+       case CAN_STATE_BUS_OFF:
+               /* bus-off state */
+               priv->can.state = CAN_STATE_BUS_OFF;
+               m_can_disable_all_interrupts(priv);
+               can_bus_off(dev);
+               break;
+       default:
+               break;
+       }
+
+       /* propagate the error condition to the CAN stack */
+       skb = alloc_can_err_skb(dev, &cf);
+       if (unlikely(!skb))
+               return 0;
+
+       m_can_get_berr_counter(dev, &bec);
+
+       switch (new_state) {
+       case CAN_STATE_ERROR_ACTIVE:
+               /* error warning state */
+               cf->can_id |= CAN_ERR_CRTL;
+               cf->data[1] = (bec.txerr > bec.rxerr) ?
+                       CAN_ERR_CRTL_TX_WARNING :
+                       CAN_ERR_CRTL_RX_WARNING;
+               cf->data[6] = bec.txerr;
+               cf->data[7] = bec.rxerr;
+               break;
+       case CAN_STATE_ERROR_PASSIVE:
+               /* error passive state */
+               cf->can_id |= CAN_ERR_CRTL;
+               ecr = m_can_read(priv, M_CAN_ECR);
+               if (ecr & ECR_RP)
+                       cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+               if (bec.txerr > 127)
+                       cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+               cf->data[6] = bec.txerr;
+               cf->data[7] = bec.rxerr;
+               break;
+       case CAN_STATE_BUS_OFF:
+               /* bus-off state */
+               cf->can_id |= CAN_ERR_BUSOFF;
+               break;
+       default:
+               break;
+       }
+
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
+
+       return 1;
+}
+
+static int m_can_handle_state_errors(struct net_device *dev, u32 psr)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       int work_done = 0;
+
+       if ((psr & PSR_EW) &&
+           (priv->can.state != CAN_STATE_ERROR_WARNING)) {
+               netdev_dbg(dev, "entered error warning state\n");
+               work_done += m_can_handle_state_change(dev,
+                                                      CAN_STATE_ERROR_WARNING);
+       }
+
+       if ((psr & PSR_EP) &&
+           (priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
+               netdev_dbg(dev, "entered error warning state\n");
+               work_done += m_can_handle_state_change(dev,
+                                                      CAN_STATE_ERROR_PASSIVE);
+       }
+
+       if ((psr & PSR_BO) &&
+           (priv->can.state != CAN_STATE_BUS_OFF)) {
+               netdev_dbg(dev, "entered error warning state\n");
+               work_done += m_can_handle_state_change(dev,
+                                                      CAN_STATE_BUS_OFF);
+       }
+
+       return work_done;
+}
+
+static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
+{
+       if (irqstatus & IR_WDI)
+               netdev_err(dev, "Message RAM Watchdog event due to missing READY\n");
+       if (irqstatus & IR_BEU)
+               netdev_err(dev, "Error Logging Overflow\n");
+       if (irqstatus & IR_BEU)
+               netdev_err(dev, "Bit Error Uncorrected\n");
+       if (irqstatus & IR_BEC)
+               netdev_err(dev, "Bit Error Corrected\n");
+       if (irqstatus & IR_TOO)
+               netdev_err(dev, "Timeout reached\n");
+       if (irqstatus & IR_MRAF)
+               netdev_err(dev, "Message RAM access failure occurred\n");
+}
+
+static inline bool is_lec_err(u32 psr)
+{
+       psr &= LEC_UNUSED;
+
+       return psr && (psr != LEC_UNUSED);
+}
+
+static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,
+                                  u32 psr)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       int work_done = 0;
+
+       if (irqstatus & IR_RF0L)
+               work_done += m_can_handle_lost_msg(dev);
+
+       /* handle lec errors on the bus */
+       if ((priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
+           is_lec_err(psr))
+               work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED);
+
+       /* other unproccessed error interrupts */
+       m_can_handle_other_err(dev, irqstatus);
+
+       return work_done;
+}
+
+static int m_can_poll(struct napi_struct *napi, int quota)
+{
+       struct net_device *dev = napi->dev;
+       struct m_can_priv *priv = netdev_priv(dev);
+       int work_done = 0;
+       u32 irqstatus, psr;
+
+       irqstatus = priv->irqstatus | m_can_read(priv, M_CAN_IR);
+       if (!irqstatus)
+               goto end;
+
+       psr = m_can_read(priv, M_CAN_PSR);
+       if (irqstatus & IR_ERR_STATE)
+               work_done += m_can_handle_state_errors(dev, psr);
+
+       if (irqstatus & IR_ERR_BUS)
+               work_done += m_can_handle_bus_errors(dev, irqstatus, psr);
+
+       if (irqstatus & IR_RF0N)
+               work_done += m_can_do_rx_poll(dev, (quota - work_done));
+
+       if (work_done < quota) {
+               napi_complete(napi);
+               m_can_enable_all_interrupts(priv);
+       }
+
+end:
+       return work_done;
+}
+
+static irqreturn_t m_can_isr(int irq, void *dev_id)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
+       u32 ir;
+
+       ir = m_can_read(priv, M_CAN_IR);
+       if (!ir)
+               return IRQ_NONE;
+
+       /* ACK all irqs */
+       if (ir & IR_ALL_INT)
+               m_can_write(priv, M_CAN_IR, ir);
+
+       /* schedule NAPI in case of
+        * - rx IRQ
+        * - state change IRQ
+        * - bus error IRQ and bus error reporting
+        */
+       if ((ir & IR_RF0N) || (ir & IR_ERR_ALL)) {
+               priv->irqstatus = ir;
+               m_can_disable_all_interrupts(priv);
+               napi_schedule(&priv->napi);
+       }
+
+       /* transmission complete interrupt */
+       if (ir & IR_TC) {
+               stats->tx_bytes += can_get_echo_skb(dev, 0);
+               stats->tx_packets++;
+               can_led_event(dev, CAN_LED_EVENT_TX);
+               netif_wake_queue(dev);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static const struct can_bittiming_const m_can_bittiming_const = {
+       .name = KBUILD_MODNAME,
+       .tseg1_min = 2,         /* Time segment 1 = prop_seg + phase_seg1 */
+       .tseg1_max = 64,
+       .tseg2_min = 1,         /* Time segment 2 = phase_seg2 */
+       .tseg2_max = 16,
+       .sjw_max = 16,
+       .brp_min = 1,
+       .brp_max = 1024,
+       .brp_inc = 1,
+};
+
+static int m_can_set_bittiming(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       const struct can_bittiming *bt = &priv->can.bittiming;
+       u16 brp, sjw, tseg1, tseg2;
+       u32 reg_btp;
+
+       brp = bt->brp - 1;
+       sjw = bt->sjw - 1;
+       tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+       tseg2 = bt->phase_seg2 - 1;
+       reg_btp = (brp << BTR_BRP_SHIFT) | (sjw << BTR_SJW_SHIFT) |
+                       (tseg1 << BTR_TSEG1_SHIFT) | (tseg2 << BTR_TSEG2_SHIFT);
+       m_can_write(priv, M_CAN_BTP, reg_btp);
+       netdev_dbg(dev, "setting BTP 0x%x\n", reg_btp);
+
+       return 0;
+}
+
+/* Configure M_CAN chip:
+ * - set rx buffer/fifo element size
+ * - configure rx fifo
+ * - accept non-matching frame into fifo 0
+ * - configure tx buffer
+ * - configure mode
+ * - setup bittiming
+ */
+static void m_can_chip_config(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       u32 cccr, test;
+
+       m_can_config_endisable(priv, true);
+
+       /* RX Buffer/FIFO Element Size 8 bytes data field */
+       m_can_write(priv, M_CAN_RXESC, M_CAN_RXESC_8BYTES);
+
+       /* Accept Non-matching Frames Into FIFO 0 */
+       m_can_write(priv, M_CAN_GFC, 0x0);
+
+       /* only support one Tx Buffer currently */
+       m_can_write(priv, M_CAN_TXBC, (1 << TXBC_NDTB_OFF) |
+                   priv->mcfg[MRAM_TXB].off);
+
+       /* only support 8 bytes firstly */
+       m_can_write(priv, M_CAN_TXESC, TXESC_TBDS_8BYTES);
+
+       m_can_write(priv, M_CAN_TXEFC, (1 << TXEFC_EFS_OFF) |
+                   priv->mcfg[MRAM_TXE].off);
+
+       /* rx fifo configuration, blocking mode, fifo size 1 */
+       m_can_write(priv, M_CAN_RXF0C,
+                   (priv->mcfg[MRAM_RXF0].num << RXFC_FS_OFF) |
+                   RXFC_FWM_1 | priv->mcfg[MRAM_RXF0].off);
+
+       m_can_write(priv, M_CAN_RXF1C,
+                   (priv->mcfg[MRAM_RXF1].num << RXFC_FS_OFF) |
+                   RXFC_FWM_1 | priv->mcfg[MRAM_RXF1].off);
+
+       cccr = m_can_read(priv, M_CAN_CCCR);
+       cccr &= ~(CCCR_TEST | CCCR_MON);
+       test = m_can_read(priv, M_CAN_TEST);
+       test &= ~TEST_LBCK;
+
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+               cccr |= CCCR_MON;
+
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+               cccr |= CCCR_TEST;
+               test |= TEST_LBCK;
+       }
+
+       m_can_write(priv, M_CAN_CCCR, cccr);
+       m_can_write(priv, M_CAN_TEST, test);
+
+       /* enable interrupts */
+       m_can_write(priv, M_CAN_IR, IR_ALL_INT);
+       if (!(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
+               m_can_write(priv, M_CAN_IE, IR_ALL_INT & ~IR_ERR_LEC);
+       else
+               m_can_write(priv, M_CAN_IE, IR_ALL_INT);
+
+       /* route all interrupts to INT0 */
+       m_can_write(priv, M_CAN_ILS, ILS_ALL_INT0);
+
+       /* set bittiming params */
+       m_can_set_bittiming(dev);
+
+       m_can_config_endisable(priv, false);
+}
+
+static void m_can_start(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+
+       /* basic m_can configuration */
+       m_can_chip_config(dev);
+
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+       m_can_enable_all_interrupts(priv);
+}
+
+static int m_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+       switch (mode) {
+       case CAN_MODE_START:
+               m_can_start(dev);
+               netif_wake_queue(dev);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static void free_m_can_dev(struct net_device *dev)
+{
+       free_candev(dev);
+}
+
+static struct net_device *alloc_m_can_dev(void)
+{
+       struct net_device *dev;
+       struct m_can_priv *priv;
+
+       dev = alloc_candev(sizeof(*priv), 1);
+       if (!dev)
+               return NULL;
+
+       priv = netdev_priv(dev);
+       netif_napi_add(dev, &priv->napi, m_can_poll, M_CAN_NAPI_WEIGHT);
+
+       priv->dev = dev;
+       priv->can.bittiming_const = &m_can_bittiming_const;
+       priv->can.do_set_mode = m_can_set_mode;
+       priv->can.do_get_berr_counter = m_can_get_berr_counter;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+                                       CAN_CTRLMODE_LISTENONLY |
+                                       CAN_CTRLMODE_BERR_REPORTING;
+
+       return dev;
+}
+
+static int m_can_open(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       int err;
+
+       err = clk_prepare_enable(priv->hclk);
+       if (err)
+               return err;
+
+       err = clk_prepare_enable(priv->cclk);
+       if (err)
+               goto exit_disable_hclk;
+
+       /* open the can device */
+       err = open_candev(dev);
+       if (err) {
+               netdev_err(dev, "failed to open can device\n");
+               goto exit_disable_cclk;
+       }
+
+       /* register interrupt handler */
+       err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name,
+                         dev);
+       if (err < 0) {
+               netdev_err(dev, "failed to request interrupt\n");
+               goto exit_irq_fail;
+       }
+
+       /* start the m_can controller */
+       m_can_start(dev);
+
+       can_led_event(dev, CAN_LED_EVENT_OPEN);
+       napi_enable(&priv->napi);
+       netif_start_queue(dev);
+
+       return 0;
+
+exit_irq_fail:
+       close_candev(dev);
+exit_disable_cclk:
+       clk_disable_unprepare(priv->cclk);
+exit_disable_hclk:
+       clk_disable_unprepare(priv->hclk);
+       return err;
+}
+
+static void m_can_stop(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+
+       /* disable all interrupts */
+       m_can_disable_all_interrupts(priv);
+
+       clk_disable_unprepare(priv->hclk);
+       clk_disable_unprepare(priv->cclk);
+
+       /* set the state as STOPPED */
+       priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int m_can_close(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+       napi_disable(&priv->napi);
+       m_can_stop(dev);
+       free_irq(dev->irq, dev);
+       close_candev(dev);
+       can_led_event(dev, CAN_LED_EVENT_STOP);
+
+       return 0;
+}
+
+static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
+                                   struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct can_frame *cf = (struct can_frame *)skb->data;
+       u32 id;
+
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
+       netif_stop_queue(dev);
+
+       if (cf->can_id & CAN_EFF_FLAG) {
+               id = cf->can_id & CAN_EFF_MASK;
+               id |= TX_BUF_XTD;
+       } else {
+               id = ((cf->can_id & CAN_SFF_MASK) << 18);
+       }
+
+       if (cf->can_id & CAN_RTR_FLAG)
+               id |= TX_BUF_RTR;
+
+       /* message ram configuration */
+       m_can_fifo_write(priv, 0, M_CAN_FIFO_ID, id);
+       m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC, cf->can_dlc << 16);
+       m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(0), *(u32 *)(cf->data + 0));
+       m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(1), *(u32 *)(cf->data + 4));
+       can_put_echo_skb(skb, dev, 0);
+
+       /* enable first TX buffer to start transfer  */
+       m_can_write(priv, M_CAN_TXBTIE, 0x1);
+       m_can_write(priv, M_CAN_TXBAR, 0x1);
+
+       return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops m_can_netdev_ops = {
+       .ndo_open = m_can_open,
+       .ndo_stop = m_can_close,
+       .ndo_start_xmit = m_can_start_xmit,
+};
+
+static int register_m_can_dev(struct net_device *dev)
+{
+       dev->flags |= IFF_ECHO; /* we support local echo */
+       dev->netdev_ops = &m_can_netdev_ops;
+
+       return register_candev(dev);
+}
+
+static int m_can_of_parse_mram(struct platform_device *pdev,
+                              struct m_can_priv *priv)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *res;
+       void __iomem *addr;
+       u32 out_val[MRAM_CFG_LEN];
+       int ret;
+
+       /* message ram could be shared */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
+       if (!res)
+               return -ENODEV;
+
+       addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!addr)
+               return -ENOMEM;
+
+       /* get message ram configuration */
+       ret = of_property_read_u32_array(np, "bosch,mram-cfg",
+                                        out_val, sizeof(out_val) / 4);
+       if (ret) {
+               dev_err(&pdev->dev, "can not get message ram configuration\n");
+               return -ENODEV;
+       }
+
+       priv->mram_base = addr;
+       priv->mcfg[MRAM_SIDF].off = out_val[0];
+       priv->mcfg[MRAM_SIDF].num = out_val[1];
+       priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off +
+                       priv->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE;
+       priv->mcfg[MRAM_XIDF].num = out_val[2];
+       priv->mcfg[MRAM_RXF0].off = priv->mcfg[MRAM_XIDF].off +
+                       priv->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
+       priv->mcfg[MRAM_RXF0].num = out_val[3] & RXFC_FS_MASK;
+       priv->mcfg[MRAM_RXF1].off = priv->mcfg[MRAM_RXF0].off +
+                       priv->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
+       priv->mcfg[MRAM_RXF1].num = out_val[4] & RXFC_FS_MASK;
+       priv->mcfg[MRAM_RXB].off = priv->mcfg[MRAM_RXF1].off +
+                       priv->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
+       priv->mcfg[MRAM_RXB].num = out_val[5];
+       priv->mcfg[MRAM_TXE].off = priv->mcfg[MRAM_RXB].off +
+                       priv->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE;
+       priv->mcfg[MRAM_TXE].num = out_val[6];
+       priv->mcfg[MRAM_TXB].off = priv->mcfg[MRAM_TXE].off +
+                       priv->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
+       priv->mcfg[MRAM_TXB].num = out_val[7] & TXBC_NDTB_MASK;
+
+       dev_dbg(&pdev->dev, "mram_base %p sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n",
+               priv->mram_base,
+               priv->mcfg[MRAM_SIDF].off, priv->mcfg[MRAM_SIDF].num,
+               priv->mcfg[MRAM_XIDF].off, priv->mcfg[MRAM_XIDF].num,
+               priv->mcfg[MRAM_RXF0].off, priv->mcfg[MRAM_RXF0].num,
+               priv->mcfg[MRAM_RXF1].off, priv->mcfg[MRAM_RXF1].num,
+               priv->mcfg[MRAM_RXB].off, priv->mcfg[MRAM_RXB].num,
+               priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
+               priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
+
+       return 0;
+}
+
+static int m_can_plat_probe(struct platform_device *pdev)
+{
+       struct net_device *dev;
+       struct m_can_priv *priv;
+       struct resource *res;
+       void __iomem *addr;
+       struct clk *hclk, *cclk;
+       int irq, ret;
+
+       hclk = devm_clk_get(&pdev->dev, "hclk");
+       cclk = devm_clk_get(&pdev->dev, "cclk");
+       if (IS_ERR(hclk) || IS_ERR(cclk)) {
+               dev_err(&pdev->dev, "no clock find\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can");
+       addr = devm_ioremap_resource(&pdev->dev, res);
+       irq = platform_get_irq_byname(pdev, "int0");
+       if (IS_ERR(addr) || irq < 0)
+               return -EINVAL;
+
+       /* allocate the m_can device */
+       dev = alloc_m_can_dev();
+       if (!dev)
+               return -ENOMEM;
+
+       priv = netdev_priv(dev);
+       dev->irq = irq;
+       priv->base = addr;
+       priv->device = &pdev->dev;
+       priv->hclk = hclk;
+       priv->cclk = cclk;
+       priv->can.clock.freq = clk_get_rate(cclk);
+
+       ret = m_can_of_parse_mram(pdev, priv);
+       if (ret)
+               goto failed_free_dev;
+
+       platform_set_drvdata(pdev, dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       ret = register_m_can_dev(dev);
+       if (ret) {
+               dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+                       KBUILD_MODNAME, ret);
+               goto failed_free_dev;
+       }
+
+       devm_can_led_init(dev);
+
+       dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
+                KBUILD_MODNAME, priv->base, dev->irq);
+
+       return 0;
+
+failed_free_dev:
+       free_m_can_dev(dev);
+       return ret;
+}
+
+static __maybe_unused int m_can_suspend(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct m_can_priv *priv = netdev_priv(ndev);
+
+       if (netif_running(ndev)) {
+               netif_stop_queue(ndev);
+               netif_device_detach(ndev);
+       }
+
+       /* TODO: enter low power */
+
+       priv->can.state = CAN_STATE_SLEEPING;
+
+       return 0;
+}
+
+static __maybe_unused int m_can_resume(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct m_can_priv *priv = netdev_priv(ndev);
+
+       /* TODO: exit low power */
+
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+       if (netif_running(ndev)) {
+               netif_device_attach(ndev);
+               netif_start_queue(ndev);
+       }
+
+       return 0;
+}
+
+static void unregister_m_can_dev(struct net_device *dev)
+{
+       unregister_candev(dev);
+}
+
+static int m_can_plat_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+
+       unregister_m_can_dev(dev);
+       platform_set_drvdata(pdev, NULL);
+
+       free_m_can_dev(dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops m_can_pmops = {
+       SET_SYSTEM_SLEEP_PM_OPS(m_can_suspend, m_can_resume)
+};
+
+static const struct of_device_id m_can_of_table[] = {
+       { .compatible = "bosch,m_can", .data = NULL },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, m_can_of_table);
+
+static struct platform_driver m_can_plat_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .of_match_table = m_can_of_table,
+               .pm     = &m_can_pmops,
+       },
+       .probe = m_can_plat_probe,
+       .remove = m_can_plat_remove,
+};
+
+module_platform_driver(m_can_plat_driver);
+
+MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller");
index c9fab17cd8b4d9b37297b1a339faea8f7d820871..58903b45f5fb91c5649eb4c458a41034ab478eef 100644 (file)
@@ -1,5 +1,3 @@
 
 obj-$(CONFIG_CAN_MPC5XXX)      += mscan-mpc5xxx.o
 mscan-mpc5xxx-objs             := mscan.o mpc5xxx_can.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 5268d216ecfae7b5a447abbd1327d7a08a632b46..1abe133d159428e0e098d611e8898bdaabb04c71 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/can/dev.h>
 #include <linux/clk.h>
 #include <linux/can/platform/rcar_can.h>
+#include <linux/of.h>
 
 #define RCAR_CAN_DRV_NAME      "rcar_can"
 
@@ -87,6 +88,7 @@ struct rcar_can_priv {
        struct napi_struct napi;
        struct rcar_can_regs __iomem *regs;
        struct clk *clk;
+       struct clk *can_clk;
        u8 tx_dlc[RCAR_CAN_FIFO_DEPTH];
        u32 tx_head;
        u32 tx_tail;
@@ -505,14 +507,20 @@ static int rcar_can_open(struct net_device *ndev)
 
        err = clk_prepare_enable(priv->clk);
        if (err) {
-               netdev_err(ndev, "clk_prepare_enable() failed, error %d\n",
+               netdev_err(ndev, "failed to enable periperal clock, error %d\n",
                           err);
                goto out;
        }
+       err = clk_prepare_enable(priv->can_clk);
+       if (err) {
+               netdev_err(ndev, "failed to enable CAN clock, error %d\n",
+                          err);
+               goto out_clock;
+       }
        err = open_candev(ndev);
        if (err) {
                netdev_err(ndev, "open_candev() failed, error %d\n", err);
-               goto out_clock;
+               goto out_can_clock;
        }
        napi_enable(&priv->napi);
        err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev);
@@ -527,6 +535,8 @@ static int rcar_can_open(struct net_device *ndev)
 out_close:
        napi_disable(&priv->napi);
        close_candev(ndev);
+out_can_clock:
+       clk_disable_unprepare(priv->can_clk);
 out_clock:
        clk_disable_unprepare(priv->clk);
 out:
@@ -565,6 +575,7 @@ static int rcar_can_close(struct net_device *ndev)
        rcar_can_stop(ndev);
        free_irq(ndev->irq, ndev);
        napi_disable(&priv->napi);
+       clk_disable_unprepare(priv->can_clk);
        clk_disable_unprepare(priv->clk);
        close_candev(ndev);
        can_led_event(ndev, CAN_LED_EVENT_STOP);
@@ -715,6 +726,12 @@ static int rcar_can_get_berr_counter(const struct net_device *dev,
        return 0;
 }
 
+static const char * const clock_names[] = {
+       [CLKR_CLKP1]    = "clkp1",
+       [CLKR_CLKP2]    = "clkp2",
+       [CLKR_CLKEXT]   = "can_clk",
+};
+
 static int rcar_can_probe(struct platform_device *pdev)
 {
        struct rcar_can_platform_data *pdata;
@@ -722,13 +739,20 @@ static int rcar_can_probe(struct platform_device *pdev)
        struct net_device *ndev;
        struct resource *mem;
        void __iomem *addr;
+       u32 clock_select = CLKR_CLKP1;
        int err = -ENODEV;
        int irq;
 
-       pdata = dev_get_platdata(&pdev->dev);
-       if (!pdata) {
-               dev_err(&pdev->dev, "No platform data provided!\n");
-               goto fail;
+       if (pdev->dev.of_node) {
+               of_property_read_u32(pdev->dev.of_node,
+                                    "renesas,can-clock-select", &clock_select);
+       } else {
+               pdata = dev_get_platdata(&pdev->dev);
+               if (!pdata) {
+                       dev_err(&pdev->dev, "No platform data provided!\n");
+                       goto fail;
+               }
+               clock_select = pdata->clock_select;
        }
 
        irq = platform_get_irq(pdev, 0);
@@ -753,10 +777,22 @@ static int rcar_can_probe(struct platform_device *pdev)
 
        priv = netdev_priv(ndev);
 
-       priv->clk = devm_clk_get(&pdev->dev, NULL);
+       priv->clk = devm_clk_get(&pdev->dev, "clkp1");
        if (IS_ERR(priv->clk)) {
                err = PTR_ERR(priv->clk);
-               dev_err(&pdev->dev, "cannot get clock: %d\n", err);
+               dev_err(&pdev->dev, "cannot get peripheral clock: %d\n", err);
+               goto fail_clk;
+       }
+
+       if (clock_select >= ARRAY_SIZE(clock_names)) {
+               err = -EINVAL;
+               dev_err(&pdev->dev, "invalid CAN clock selected\n");
+               goto fail_clk;
+       }
+       priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]);
+       if (IS_ERR(priv->can_clk)) {
+               err = PTR_ERR(priv->can_clk);
+               dev_err(&pdev->dev, "cannot get CAN clock: %d\n", err);
                goto fail_clk;
        }
 
@@ -765,8 +801,8 @@ static int rcar_can_probe(struct platform_device *pdev)
        ndev->flags |= IFF_ECHO;
        priv->ndev = ndev;
        priv->regs = addr;
-       priv->clock_select = pdata->clock_select;
-       priv->can.clock.freq = clk_get_rate(priv->clk);
+       priv->clock_select = clock_select;
+       priv->can.clock.freq = clk_get_rate(priv->can_clk);
        priv->can.bittiming_const = &rcar_can_bittiming_const;
        priv->can.do_set_mode = rcar_can_do_set_mode;
        priv->can.do_get_berr_counter = rcar_can_get_berr_counter;
@@ -858,10 +894,20 @@ static int __maybe_unused rcar_can_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume);
 
+static const struct of_device_id rcar_can_of_table[] __maybe_unused = {
+       { .compatible = "renesas,can-r8a7778" },
+       { .compatible = "renesas,can-r8a7779" },
+       { .compatible = "renesas,can-r8a7790" },
+       { .compatible = "renesas,can-r8a7791" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, rcar_can_of_table);
+
 static struct platform_driver rcar_can_driver = {
        .driver = {
                .name = RCAR_CAN_DRV_NAME,
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(rcar_can_of_table),
                .pm = &rcar_can_pm_ops,
        },
        .probe = rcar_can_probe,
index 531d5fcc97e58bded41ac3f3022a2a84a41ba6f0..be11ddd11b87447c8e2b348bdeb7b57cca1b5d25 100644 (file)
@@ -12,5 +12,3 @@ obj-$(CONFIG_CAN_PEAK_PCMCIA) += peak_pcmcia.o
 obj-$(CONFIG_CAN_PEAK_PCI) += peak_pci.o
 obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
 obj-$(CONFIG_CAN_TSCAN1) += tscan1.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index c5e5016c742ee040f5ccf8f202b4896357abe7b4..a23da492dad52b169bcdca64cc4fbb6d729d9979 100644 (file)
@@ -2,5 +2,3 @@
 softing-y := softing_main.o softing_fw.o
 obj-$(CONFIG_CAN_SOFTING) += softing.o
 obj-$(CONFIG_CAN_SOFTING_CS) += softing_cs.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 90bcacffbc65c15372c32cb04df36b6781b82024..0e86040cdd8ce9c2ca037ed27c234dd362812a5f 100644 (file)
@@ -4,5 +4,3 @@
 
 
 obj-$(CONFIG_CAN_MCP251X)      += mcp251x.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 5df239e68812635e1d209f835e9a62dbe2fdf555..c66d699640a9c1478026da5df023264a7b1ff973 100644 (file)
@@ -1107,10 +1107,10 @@ static int mcp251x_can_probe(struct spi_device *spi)
                 * Minimum coherent DMA allocation is PAGE_SIZE, so allocate
                 * that much and share it between Tx and Rx DMA buffers.
                 */
-               priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,
-                                                     PAGE_SIZE,
-                                                     &priv->spi_tx_dma,
-                                                     GFP_DMA);
+               priv->spi_tx_buf = dmam_alloc_coherent(&spi->dev,
+                                                      PAGE_SIZE,
+                                                      &priv->spi_tx_dma,
+                                                      GFP_DMA);
 
                if (priv->spi_tx_buf) {
                        priv->spi_rx_buf = (priv->spi_tx_buf + (PAGE_SIZE / 2));
@@ -1156,9 +1156,6 @@ static int mcp251x_can_probe(struct spi_device *spi)
        return 0;
 
 error_probe:
-       if (mcp251x_enable_dma)
-               dma_free_coherent(&spi->dev, PAGE_SIZE,
-                                 priv->spi_tx_buf, priv->spi_tx_dma);
        mcp251x_power_enable(priv->power, 0);
 
 out_clk:
@@ -1178,11 +1175,6 @@ static int mcp251x_can_remove(struct spi_device *spi)
 
        unregister_candev(net);
 
-       if (mcp251x_enable_dma) {
-               dma_free_coherent(&spi->dev, PAGE_SIZE,
-                                 priv->spi_tx_buf, priv->spi_tx_dma);
-       }
-
        mcp251x_power_enable(priv->power, 0);
 
        if (!IS_ERR(priv->clk))
index 7b9a393b1ac82a1caf4684a704d7121ad16dc3c9..a64cf983fb87af3111c0b8b8ed276943a20067e4 100644 (file)
@@ -8,5 +8,3 @@ obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
 obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
 obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index b8fe808b7957c735e0f4c8248ad3bcff14b46716..c6ee07c6a1b54d3197d3ff04ee40f426d097b7de 100644 (file)
@@ -36,4 +36,15 @@ config NET_DSA_MV88E6123_61_65
          This enables support for the Marvell 88E6123/6161/6165
          ethernet switch chips.
 
+config NET_DSA_BCM_SF2
+       tristate "Broadcom Starfighter 2 Ethernet switch support"
+       select NET_DSA
+       select NET_DSA_TAG_BRCM
+       select FIXED_PHY if NET_DSA_BCM_SF2=y
+       select BCM7XXX_PHY
+       select MDIO_BCM_UNIMAC
+       ---help---
+         This enables support for the Broadcom Starfighter 2 Ethernet
+         switch chips.
+
 endmenu
index f3bda05536cc55e861ae2996103d930433a74dfc..dd3cd3b8157f82ead0a78c07fdf2d7c0754418bd 100644 (file)
@@ -7,3 +7,4 @@ endif
 ifdef CONFIG_NET_DSA_MV88E6131
 mv88e6xxx_drv-y += mv88e6131.o
 endif
+obj-$(CONFIG_NET_DSA_BCM_SF2)  += bcm_sf2.o
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
new file mode 100644 (file)
index 0000000..bb7cb8e
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * Broadcom Starfighter 2 DSA switch driver
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/mii.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <net/dsa.h>
+
+#include "bcm_sf2.h"
+#include "bcm_sf2_regs.h"
+
+/* String, offset, and register size in bytes if different from 4 bytes */
+static const struct bcm_sf2_hw_stats bcm_sf2_mib[] = {
+       { "TxOctets",           0x000, 8        },
+       { "TxDropPkts",         0x020           },
+       { "TxQPKTQ0",           0x030           },
+       { "TxBroadcastPkts",    0x040           },
+       { "TxMulticastPkts",    0x050           },
+       { "TxUnicastPKts",      0x060           },
+       { "TxCollisions",       0x070           },
+       { "TxSingleCollision",  0x080           },
+       { "TxMultipleCollision", 0x090          },
+       { "TxDeferredCollision", 0x0a0          },
+       { "TxLateCollision",    0x0b0           },
+       { "TxExcessiveCollision", 0x0c0         },
+       { "TxFrameInDisc",      0x0d0           },
+       { "TxPausePkts",        0x0e0           },
+       { "TxQPKTQ1",           0x0f0           },
+       { "TxQPKTQ2",           0x100           },
+       { "TxQPKTQ3",           0x110           },
+       { "TxQPKTQ4",           0x120           },
+       { "TxQPKTQ5",           0x130           },
+       { "RxOctets",           0x140, 8        },
+       { "RxUndersizePkts",    0x160           },
+       { "RxPausePkts",        0x170           },
+       { "RxPkts64Octets",     0x180           },
+       { "RxPkts65to127Octets", 0x190          },
+       { "RxPkts128to255Octets", 0x1a0         },
+       { "RxPkts256to511Octets", 0x1b0         },
+       { "RxPkts512to1023Octets", 0x1c0        },
+       { "RxPkts1024toMaxPktsOctets", 0x1d0    },
+       { "RxOversizePkts",     0x1e0           },
+       { "RxJabbers",          0x1f0           },
+       { "RxAlignmentErrors",  0x200           },
+       { "RxFCSErrors",        0x210           },
+       { "RxGoodOctets",       0x220, 8        },
+       { "RxDropPkts",         0x240           },
+       { "RxUnicastPkts",      0x250           },
+       { "RxMulticastPkts",    0x260           },
+       { "RxBroadcastPkts",    0x270           },
+       { "RxSAChanges",        0x280           },
+       { "RxFragments",        0x290           },
+       { "RxJumboPkt",         0x2a0           },
+       { "RxSymblErr",         0x2b0           },
+       { "InRangeErrCount",    0x2c0           },
+       { "OutRangeErrCount",   0x2d0           },
+       { "EEELpiEvent",        0x2e0           },
+       { "EEELpiDuration",     0x2f0           },
+       { "RxDiscard",          0x300, 8        },
+       { "TxQPKTQ6",           0x320           },
+       { "TxQPKTQ7",           0x330           },
+       { "TxPkts64Octets",     0x340           },
+       { "TxPkts65to127Octets", 0x350          },
+       { "TxPkts128to255Octets", 0x360         },
+       { "TxPkts256to511Ocets", 0x370          },
+       { "TxPkts512to1023Ocets", 0x380         },
+       { "TxPkts1024toMaxPktOcets", 0x390      },
+};
+
+#define BCM_SF2_STATS_SIZE     ARRAY_SIZE(bcm_sf2_mib)
+
+static void bcm_sf2_sw_get_strings(struct dsa_switch *ds,
+                                  int port, uint8_t *data)
+{
+       unsigned int i;
+
+       for (i = 0; i < BCM_SF2_STATS_SIZE; i++)
+               memcpy(data + i * ETH_GSTRING_LEN,
+                      bcm_sf2_mib[i].string, ETH_GSTRING_LEN);
+}
+
+static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds,
+                                        int port, uint64_t *data)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       const struct bcm_sf2_hw_stats *s;
+       unsigned int i;
+       u64 val = 0;
+       u32 offset;
+
+       mutex_lock(&priv->stats_mutex);
+
+       /* Now fetch the per-port counters */
+       for (i = 0; i < BCM_SF2_STATS_SIZE; i++) {
+               s = &bcm_sf2_mib[i];
+
+               /* Do a latched 64-bit read if needed */
+               offset = s->reg + CORE_P_MIB_OFFSET(port);
+               if (s->sizeof_stat == 8)
+                       val = core_readq(priv, offset);
+               else
+                       val = core_readl(priv, offset);
+
+               data[i] = (u64)val;
+       }
+
+       mutex_unlock(&priv->stats_mutex);
+}
+
+static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds)
+{
+       return BCM_SF2_STATS_SIZE;
+}
+
+static char *bcm_sf2_sw_probe(struct mii_bus *bus, int sw_addr)
+{
+       return "Broadcom Starfighter 2";
+}
+
+static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       unsigned int i;
+       u32 reg, val;
+
+       /* Enable the port memories */
+       reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+       reg &= ~P_TXQ_PSM_VDD(port);
+       core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+
+       /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
+       reg = core_readl(priv, CORE_IMP_CTL);
+       reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN);
+       reg &= ~(RX_DIS | TX_DIS);
+       core_writel(priv, reg, CORE_IMP_CTL);
+
+       /* Enable forwarding */
+       core_writel(priv, SW_FWDG_EN, CORE_SWMODE);
+
+       /* Enable IMP port in dumb mode */
+       reg = core_readl(priv, CORE_SWITCH_CTRL);
+       reg |= MII_DUMB_FWDG_EN;
+       core_writel(priv, reg, CORE_SWITCH_CTRL);
+
+       /* Resolve which bit controls the Broadcom tag */
+       switch (port) {
+       case 8:
+               val = BRCM_HDR_EN_P8;
+               break;
+       case 7:
+               val = BRCM_HDR_EN_P7;
+               break;
+       case 5:
+               val = BRCM_HDR_EN_P5;
+               break;
+       default:
+               val = 0;
+               break;
+       }
+
+       /* Enable Broadcom tags for IMP port */
+       reg = core_readl(priv, CORE_BRCM_HDR_CTRL);
+       reg |= val;
+       core_writel(priv, reg, CORE_BRCM_HDR_CTRL);
+
+       /* Enable reception Broadcom tag for CPU TX (switch RX) to
+        * allow us to tag outgoing frames
+        */
+       reg = core_readl(priv, CORE_BRCM_HDR_RX_DIS);
+       reg &= ~(1 << port);
+       core_writel(priv, reg, CORE_BRCM_HDR_RX_DIS);
+
+       /* Enable transmission of Broadcom tags from the switch (CPU RX) to
+        * allow delivering frames to the per-port net_devices
+        */
+       reg = core_readl(priv, CORE_BRCM_HDR_TX_DIS);
+       reg &= ~(1 << port);
+       core_writel(priv, reg, CORE_BRCM_HDR_TX_DIS);
+
+       /* Force link status for IMP port */
+       reg = core_readl(priv, CORE_STS_OVERRIDE_IMP);
+       reg |= (MII_SW_OR | LINK_STS);
+       core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
+
+       /* Enable the IMP Port to be in the same VLAN as the other ports
+        * on a per-port basis such that we only have Port i and IMP in
+        * the same VLAN.
+        */
+       for (i = 0; i < priv->hw_params.num_ports; i++) {
+               if (!((1 << i) & ds->phys_port_mask))
+                       continue;
+
+               reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
+               reg |= (1 << port);
+               core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
+       }
+}
+
+static void bcm_sf2_port_setup(struct dsa_switch *ds, int port)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       u32 reg;
+
+       /* Clear the memory power down */
+       reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+       reg &= ~P_TXQ_PSM_VDD(port);
+       core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+
+       /* Clear the Rx and Tx disable bits and set to no spanning tree */
+       core_writel(priv, 0, CORE_G_PCTL_PORT(port));
+
+       /* Enable port 7 interrupts to get notified */
+       if (port == 7)
+               intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF));
+
+       /* Set this port, and only this one to be in the default VLAN */
+       reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
+       reg &= ~PORT_VLAN_CTRL_MASK;
+       reg |= (1 << port);
+       core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port));
+}
+
+static void bcm_sf2_port_disable(struct dsa_switch *ds, int port)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       u32 off, reg;
+
+       if (dsa_is_cpu_port(ds, port))
+               off = CORE_IMP_CTL;
+       else
+               off = CORE_G_PCTL_PORT(port);
+
+       reg = core_readl(priv, off);
+       reg |= RX_DIS | TX_DIS;
+       core_writel(priv, reg, off);
+
+       /* Power down the port memory */
+       reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+       reg |= P_TXQ_PSM_VDD(port);
+       core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+}
+
+static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
+{
+       struct bcm_sf2_priv *priv = dev_id;
+
+       priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) &
+                               ~priv->irq0_mask;
+       intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id)
+{
+       struct bcm_sf2_priv *priv = dev_id;
+
+       priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) &
+                               ~priv->irq1_mask;
+       intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
+
+       if (priv->irq1_stat & P_LINK_UP_IRQ(P7_IRQ_OFF))
+               priv->port_sts[7].link = 1;
+       if (priv->irq1_stat & P_LINK_DOWN_IRQ(P7_IRQ_OFF))
+               priv->port_sts[7].link = 0;
+
+       return IRQ_HANDLED;
+}
+
+static int bcm_sf2_sw_setup(struct dsa_switch *ds)
+{
+       const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       struct device_node *dn;
+       void __iomem **base;
+       unsigned int port;
+       unsigned int i;
+       u32 reg, rev;
+       int ret;
+
+       spin_lock_init(&priv->indir_lock);
+       mutex_init(&priv->stats_mutex);
+
+       /* All the interesting properties are at the parent device_node
+        * level
+        */
+       dn = ds->pd->of_node->parent;
+
+       priv->irq0 = irq_of_parse_and_map(dn, 0);
+       priv->irq1 = irq_of_parse_and_map(dn, 1);
+
+       base = &priv->core;
+       for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
+               *base = of_iomap(dn, i);
+               if (*base == NULL) {
+                       pr_err("unable to find register: %s\n", reg_names[i]);
+                       return -ENODEV;
+               }
+               base++;
+       }
+
+       /* Disable all interrupts and request them */
+       intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+       intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+       intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+       intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+       intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+       intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+
+       ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0,
+                         "switch_0", priv);
+       if (ret < 0) {
+               pr_err("failed to request switch_0 IRQ\n");
+               goto out_unmap;
+       }
+
+       ret = request_irq(priv->irq1, bcm_sf2_switch_1_isr, 0,
+                         "switch_1", priv);
+       if (ret < 0) {
+               pr_err("failed to request switch_1 IRQ\n");
+               goto out_free_irq0;
+       }
+
+       /* Reset the MIB counters */
+       reg = core_readl(priv, CORE_GMNCFGCFG);
+       reg |= RST_MIB_CNT;
+       core_writel(priv, reg, CORE_GMNCFGCFG);
+       reg &= ~RST_MIB_CNT;
+       core_writel(priv, reg, CORE_GMNCFGCFG);
+
+       /* Get the maximum number of ports for this switch */
+       priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1;
+       if (priv->hw_params.num_ports > DSA_MAX_PORTS)
+               priv->hw_params.num_ports = DSA_MAX_PORTS;
+
+       /* Assume a single GPHY setup if we can't read that property */
+       if (of_property_read_u32(dn, "brcm,num-gphy",
+                                &priv->hw_params.num_gphy))
+               priv->hw_params.num_gphy = 1;
+
+       /* Enable all valid ports and disable those unused */
+       for (port = 0; port < priv->hw_params.num_ports; port++) {
+               /* IMP port receives special treatment */
+               if ((1 << port) & ds->phys_port_mask)
+                       bcm_sf2_port_setup(ds, port);
+               else if (dsa_is_cpu_port(ds, port))
+                       bcm_sf2_imp_setup(ds, port);
+               else
+                       bcm_sf2_port_disable(ds, port);
+       }
+
+       /* Include the pseudo-PHY address and the broadcast PHY address to
+        * divert reads towards our workaround
+        */
+       ds->phys_mii_mask |= ((1 << 30) | (1 << 0));
+
+       rev = reg_readl(priv, REG_SWITCH_REVISION);
+       priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
+                                       SWITCH_TOP_REV_MASK;
+       priv->hw_params.core_rev = (rev & SF2_REV_MASK);
+
+       pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
+               priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
+               priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
+               priv->core, priv->irq0, priv->irq1);
+
+       return 0;
+
+out_free_irq0:
+       free_irq(priv->irq0, priv);
+out_unmap:
+       base = &priv->core;
+       for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
+               iounmap(*base);
+               base++;
+       }
+       return ret;
+}
+
+static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr)
+{
+       return 0;
+}
+
+static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr,
+                              int regnum, u16 val)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       int ret = 0;
+       u32 reg;
+
+       reg = reg_readl(priv, REG_SWITCH_CNTRL);
+       reg |= MDIO_MASTER_SEL;
+       reg_writel(priv, reg, REG_SWITCH_CNTRL);
+
+       /* Page << 8 | offset */
+       reg = 0x70;
+       reg <<= 2;
+       core_writel(priv, addr, reg);
+
+       /* Page << 8 | offset */
+       reg = 0x80 << 8 | regnum << 1;
+       reg <<= 2;
+
+       if (op)
+               ret = core_readl(priv, reg);
+       else
+               core_writel(priv, val, reg);
+
+       reg = reg_readl(priv, REG_SWITCH_CNTRL);
+       reg &= ~MDIO_MASTER_SEL;
+       reg_writel(priv, reg, REG_SWITCH_CNTRL);
+
+       return ret & 0xffff;
+}
+
+static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum)
+{
+       /* Intercept reads from the MDIO broadcast address or Broadcom
+        * pseudo-PHY address
+        */
+       switch (addr) {
+       case 0:
+       case 30:
+               return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0);
+       default:
+               return 0xffff;
+       }
+}
+
+static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum,
+                               u16 val)
+{
+       /* Intercept writes to the MDIO broadcast address or Broadcom
+        * pseudo-PHY address
+        */
+       switch (addr) {
+       case 0:
+       case 30:
+               bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val);
+               break;
+       }
+
+       return 0;
+}
+
+static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port,
+                                  struct phy_device *phydev)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       u32 id_mode_dis = 0, port_mode;
+       const char *str = NULL;
+       u32 reg;
+
+       switch (phydev->interface) {
+       case PHY_INTERFACE_MODE_RGMII:
+               str = "RGMII (no delay)";
+               id_mode_dis = 1;
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               if (!str)
+                       str = "RGMII (TX delay)";
+               port_mode = EXT_GPHY;
+               break;
+       case PHY_INTERFACE_MODE_MII:
+               str = "MII";
+               port_mode = EXT_EPHY;
+               break;
+       case PHY_INTERFACE_MODE_REVMII:
+               str = "Reverse MII";
+               port_mode = EXT_REVMII;
+               break;
+       default:
+               goto force_link;
+       }
+
+       /* Clear id_mode_dis bit, and the existing port mode, but
+        * make sure we enable the RGMII block for data to pass
+        */
+       reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+       reg &= ~ID_MODE_DIS;
+       reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
+       reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
+
+       reg |= port_mode | RGMII_MODE_EN;
+       if (id_mode_dis)
+               reg |= ID_MODE_DIS;
+
+       if (phydev->pause) {
+               if (phydev->asym_pause)
+                       reg |= TX_PAUSE_EN;
+               reg |= RX_PAUSE_EN;
+       }
+
+       reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+
+       pr_info("Port %d configured for %s\n", port, str);
+
+force_link:
+       /* Force link settings detected from the PHY */
+       reg = SW_OVERRIDE;
+       switch (phydev->speed) {
+       case SPEED_1000:
+               reg |= SPDSTS_1000 << SPEED_SHIFT;
+               break;
+       case SPEED_100:
+               reg |= SPDSTS_100 << SPEED_SHIFT;
+               break;
+       }
+
+       if (phydev->link)
+               reg |= LINK_STS;
+       if (phydev->duplex == DUPLEX_FULL)
+               reg |= DUPLX_MODE;
+
+       core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
+}
+
+static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
+                                        struct fixed_phy_status *status)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       u32 link, duplex, pause, speed;
+       u32 reg;
+
+       link = core_readl(priv, CORE_LNKSTS);
+       duplex = core_readl(priv, CORE_DUPSTS);
+       pause = core_readl(priv, CORE_PAUSESTS);
+       speed = core_readl(priv, CORE_SPDSTS);
+
+       speed >>= (port * SPDSTS_SHIFT);
+       speed &= SPDSTS_MASK;
+
+       status->link = 0;
+
+       /* Port 7 is special as we do not get link status from CORE_LNKSTS,
+        * which means that we need to force the link at the port override
+        * level to get the data to flow. We do use what the interrupt handler
+        * did determine before.
+        */
+       if (port == 7) {
+               status->link = priv->port_sts[port].link;
+               reg = core_readl(priv, CORE_STS_OVERRIDE_GMIIP_PORT(7));
+               reg |= SW_OVERRIDE;
+               if (status->link)
+                       reg |= LINK_STS;
+               else
+                       reg &= ~LINK_STS;
+               core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(7));
+               status->duplex = 1;
+       } else {
+               status->link = !!(link & (1 << port));
+               status->duplex = !!(duplex & (1 << port));
+       }
+
+       switch (speed) {
+       case SPDSTS_10:
+               status->speed = SPEED_10;
+               break;
+       case SPDSTS_100:
+               status->speed = SPEED_100;
+               break;
+       case SPDSTS_1000:
+               status->speed = SPEED_1000;
+               break;
+       }
+
+       if ((pause & (1 << port)) &&
+           (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) {
+               status->asym_pause = 1;
+               status->pause = 1;
+       }
+
+       if (pause & (1 << port))
+               status->pause = 1;
+}
+
+static struct dsa_switch_driver bcm_sf2_switch_driver = {
+       .tag_protocol           = htons(ETH_P_BRCMTAG),
+       .priv_size              = sizeof(struct bcm_sf2_priv),
+       .probe                  = bcm_sf2_sw_probe,
+       .setup                  = bcm_sf2_sw_setup,
+       .set_addr               = bcm_sf2_sw_set_addr,
+       .phy_read               = bcm_sf2_sw_phy_read,
+       .phy_write              = bcm_sf2_sw_phy_write,
+       .get_strings            = bcm_sf2_sw_get_strings,
+       .get_ethtool_stats      = bcm_sf2_sw_get_ethtool_stats,
+       .get_sset_count         = bcm_sf2_sw_get_sset_count,
+       .adjust_link            = bcm_sf2_sw_adjust_link,
+       .fixed_link_update      = bcm_sf2_sw_fixed_link_update,
+};
+
+static int __init bcm_sf2_init(void)
+{
+       register_switch_driver(&bcm_sf2_switch_driver);
+
+       return 0;
+}
+module_init(bcm_sf2_init);
+
+static void __exit bcm_sf2_exit(void)
+{
+       unregister_switch_driver(&bcm_sf2_switch_driver);
+}
+module_exit(bcm_sf2_exit);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:brcm-sf2");
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
new file mode 100644 (file)
index 0000000..260bab3
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Broadcom Starfighter2 private context
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __BCM_SF2_H
+#define __BCM_SF2_H
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/mii.h>
+
+#include <net/dsa.h>
+
+#include "bcm_sf2_regs.h"
+
+struct bcm_sf2_hw_params {
+       u16     top_rev;
+       u16     core_rev;
+       u32     num_gphy;
+       u8      num_acb_queue;
+       u8      num_rgmii;
+       u8      num_ports;
+       u8      fcb_pause_override:1;
+       u8      acb_packets_inflight:1;
+};
+
+#define BCM_SF2_REGS_NAME {\
+       "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb" \
+}
+
+#define BCM_SF2_REGS_NUM       6
+
+struct bcm_sf2_port_status {
+       unsigned int link;
+};
+
+struct bcm_sf2_priv {
+       /* Base registers, keep those in order with BCM_SF2_REGS_NAME */
+       void __iomem                    *core;
+       void __iomem                    *reg;
+       void __iomem                    *intrl2_0;
+       void __iomem                    *intrl2_1;
+       void __iomem                    *fcb;
+       void __iomem                    *acb;
+
+       /* spinlock protecting access to the indirect registers */
+       spinlock_t                      indir_lock;
+
+       int                             irq0;
+       int                             irq1;
+       u32                             irq0_stat;
+       u32                             irq0_mask;
+       u32                             irq1_stat;
+       u32                             irq1_mask;
+
+       /* Mutex protecting access to the MIB counters */
+       struct mutex                    stats_mutex;
+
+       struct bcm_sf2_hw_params        hw_params;
+
+       struct bcm_sf2_port_status      port_sts[DSA_MAX_PORTS];
+};
+
+struct bcm_sf2_hw_stats {
+       const char      *string;
+       u16             reg;
+       u8              sizeof_stat;
+};
+
+#define SF2_IO_MACRO(name) \
+static inline u32 name##_readl(struct bcm_sf2_priv *priv, u32 off)     \
+{                                                                      \
+       return __raw_readl(priv->name + off);                           \
+}                                                                      \
+static inline void name##_writel(struct bcm_sf2_priv *priv,            \
+                                 u32 val, u32 off)                     \
+{                                                                      \
+       __raw_writel(val, priv->name + off);                            \
+}                                                                      \
+
+/* Accesses to 64-bits register requires us to latch the hi/lo pairs
+ * using the REG_DIR_DATA_{READ,WRITE} ancillary registers. The 'indir_lock'
+ * spinlock is automatically grabbed and released to provide relative
+ * atomiticy with latched reads/writes.
+ */
+#define SF2_IO64_MACRO(name) \
+static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off)     \
+{                                                                      \
+       u32 indir, dir;                                                 \
+       spin_lock(&priv->indir_lock);                                   \
+       indir = reg_readl(priv, REG_DIR_DATA_READ);                     \
+       dir = __raw_readl(priv->name + off);                            \
+       spin_unlock(&priv->indir_lock);                                 \
+       return (u64)indir << 32 | dir;                                  \
+}                                                                      \
+static inline void name##_writeq(struct bcm_sf2_priv *priv, u32 off,   \
+                                                       u64 val)        \
+{                                                                      \
+       spin_lock(&priv->indir_lock);                                   \
+       reg_writel(priv, upper_32_bits(val), REG_DIR_DATA_WRITE);       \
+       __raw_writel(lower_32_bits(val), priv->name + off);             \
+       spin_unlock(&priv->indir_lock);                                 \
+}
+
+#define SWITCH_INTR_L2(which)                                          \
+static inline void intrl2_##which##_mask_clear(struct bcm_sf2_priv *priv, \
+                                               u32 mask)               \
+{                                                                      \
+       intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR);     \
+       priv->irq##which##_mask &= ~(mask);                             \
+}                                                                      \
+static inline void intrl2_##which##_mask_set(struct bcm_sf2_priv *priv, \
+                                               u32 mask)               \
+{                                                                      \
+       intrl2_## which##_writel(priv, mask, INTRL2_CPU_MASK_SET);      \
+       priv->irq##which##_mask |= (mask);                              \
+}                                                                      \
+
+SF2_IO_MACRO(core);
+SF2_IO_MACRO(reg);
+SF2_IO64_MACRO(core);
+SF2_IO_MACRO(intrl2_0);
+SF2_IO_MACRO(intrl2_1);
+SF2_IO_MACRO(fcb);
+SF2_IO_MACRO(acb);
+
+SWITCH_INTR_L2(0);
+SWITCH_INTR_L2(1);
+
+#endif /* __BCM_SF2_H */
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
new file mode 100644 (file)
index 0000000..885c231
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Broadcom Starfighter 2 switch register defines
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __BCM_SF2_REGS_H
+#define __BCM_SF2_REGS_H
+
+/* Register set relative to 'REG' */
+#define REG_SWITCH_CNTRL               0x00
+#define  MDIO_MASTER_SEL               (1 << 0)
+
+#define REG_SWITCH_STATUS              0x04
+#define REG_DIR_DATA_WRITE             0x08
+#define REG_DIR_DATA_READ              0x0C
+
+#define REG_SWITCH_REVISION            0x18
+#define  SF2_REV_MASK                  0xffff
+#define  SWITCH_TOP_REV_SHIFT          16
+#define  SWITCH_TOP_REV_MASK           0xffff
+
+#define REG_PHY_REVISION               0x1C
+
+#define REG_SPHY_CNTRL                 0x2C
+#define  IDDQ_BIAS                     (1 << 0)
+#define  EXT_PWR_DOWN                  (1 << 1)
+#define  FORCE_DLL_EN                  (1 << 2)
+#define  IDDQ_GLOBAL_PWR               (1 << 3)
+#define  CK25_DIS                      (1 << 4)
+#define  PHY_RESET                     (1 << 5)
+#define  PHY_PHYAD_SHIFT               8
+#define  PHY_PHYAD_MASK                        0x1F
+
+#define REG_RGMII_0_BASE               0x34
+#define REG_RGMII_CNTRL                        0x00
+#define REG_RGMII_IB_STATUS            0x04
+#define REG_RGMII_RX_CLOCK_DELAY_CNTRL 0x08
+#define REG_RGMII_CNTRL_SIZE           0x0C
+#define REG_RGMII_CNTRL_P(x)           (REG_RGMII_0_BASE + \
+                                       ((x) * REG_RGMII_CNTRL_SIZE))
+/* Relative to REG_RGMII_CNTRL */
+#define  RGMII_MODE_EN                 (1 << 0)
+#define  ID_MODE_DIS                   (1 << 1)
+#define  PORT_MODE_SHIFT               2
+#define  INT_EPHY                      (0 << PORT_MODE_SHIFT)
+#define  INT_GPHY                      (1 << PORT_MODE_SHIFT)
+#define  EXT_EPHY                      (2 << PORT_MODE_SHIFT)
+#define  EXT_GPHY                      (3 << PORT_MODE_SHIFT)
+#define  EXT_REVMII                    (4 << PORT_MODE_SHIFT)
+#define  PORT_MODE_MASK                        0x7
+#define  RVMII_REF_SEL                 (1 << 5)
+#define  RX_PAUSE_EN                   (1 << 6)
+#define  TX_PAUSE_EN                   (1 << 7)
+#define  TX_CLK_STOP_EN                        (1 << 8)
+#define  LPI_COUNT_SHIFT               9
+#define  LPI_COUNT_MASK                        0x3F
+
+/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
+#define INTRL2_CPU_STATUS              0x00
+#define INTRL2_CPU_SET                 0x04
+#define INTRL2_CPU_CLEAR               0x08
+#define INTRL2_CPU_MASK_STATUS         0x0c
+#define INTRL2_CPU_MASK_SET            0x10
+#define INTRL2_CPU_MASK_CLEAR          0x14
+
+/* Shared INTRL2_0 and INTRL2_ interrupt sources macros */
+#define P_LINK_UP_IRQ(x)               (1 << (0 + (x)))
+#define P_LINK_DOWN_IRQ(x)             (1 << (1 + (x)))
+#define P_ENERGY_ON_IRQ(x)             (1 << (2 + (x)))
+#define P_ENERGY_OFF_IRQ(x)            (1 << (3 + (x)))
+#define P_GPHY_IRQ(x)                  (1 << (4 + (x)))
+#define P_NUM_IRQ                      5
+#define P_IRQ_MASK(x)                  (P_LINK_UP_IRQ((x)) | \
+                                        P_LINK_DOWN_IRQ((x)) | \
+                                        P_ENERGY_ON_IRQ((x)) | \
+                                        P_ENERGY_OFF_IRQ((x)) | \
+                                        P_GPHY_IRQ((x)))
+
+/* INTRL2_0 interrupt sources */
+#define P0_IRQ_OFF                     0
+#define MEM_DOUBLE_IRQ                 (1 << 5)
+#define EEE_LPI_IRQ                    (1 << 6)
+#define P5_CPU_WAKE_IRQ                        (1 << 7)
+#define P8_CPU_WAKE_IRQ                        (1 << 8)
+#define P7_CPU_WAKE_IRQ                        (1 << 9)
+#define IEEE1588_IRQ                   (1 << 10)
+#define MDIO_ERR_IRQ                   (1 << 11)
+#define MDIO_DONE_IRQ                  (1 << 12)
+#define GISB_ERR_IRQ                   (1 << 13)
+#define UBUS_ERR_IRQ                   (1 << 14)
+#define FAILOVER_ON_IRQ                        (1 << 15)
+#define FAILOVER_OFF_IRQ               (1 << 16)
+#define TCAM_SOFT_ERR_IRQ              (1 << 17)
+
+/* INTRL2_1 interrupt sources */
+#define P7_IRQ_OFF                     0
+#define P_IRQ_OFF(x)                   ((6 - (x)) * P_NUM_IRQ)
+
+/* Register set relative to 'CORE' */
+#define CORE_G_PCTL_PORT0              0x00000
+#define CORE_G_PCTL_PORT(x)            (CORE_G_PCTL_PORT0 + (x * 0x4))
+#define CORE_IMP_CTL                   0x00020
+#define  RX_DIS                                (1 << 0)
+#define  TX_DIS                                (1 << 1)
+#define  RX_BCST_EN                    (1 << 2)
+#define  RX_MCST_EN                    (1 << 3)
+#define  RX_UCST_EN                    (1 << 4)
+#define  G_MISTP_STATE_SHIFT           5
+#define  G_MISTP_NO_STP                        (0 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_DIS_STATE             (1 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_BLOCK_STATE           (2 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_LISTEN_STATE          (3 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_LEARN_STATE           (4 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_FWD_STATE             (5 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_STATE_MASK            0x7
+
+#define CORE_SWMODE                    0x0002c
+#define  SW_FWDG_MODE                  (1 << 0)
+#define  SW_FWDG_EN                    (1 << 1)
+#define  RTRY_LMT_DIS                  (1 << 2)
+
+#define CORE_STS_OVERRIDE_IMP          0x00038
+#define  GMII_SPEED_UP_2G              (1 << 6)
+#define  MII_SW_OR                     (1 << 7)
+
+#define CORE_NEW_CTRL                  0x00084
+#define  IP_MC                         (1 << 0)
+#define  OUTRANGEERR_DISCARD           (1 << 1)
+#define  INRANGEERR_DISCARD            (1 << 2)
+#define  CABLE_DIAG_LEN                        (1 << 3)
+#define  OVERRIDE_AUTO_PD_WAR          (1 << 4)
+#define  EN_AUTO_PD_WAR                        (1 << 5)
+#define  UC_FWD_EN                     (1 << 6)
+#define  MC_FWD_EN                     (1 << 7)
+
+#define CORE_SWITCH_CTRL               0x00088
+#define  MII_DUMB_FWDG_EN              (1 << 6)
+
+#define CORE_SFT_LRN_CTRL              0x000f8
+#define  SW_LEARN_CNTL(x)              (1 << (x))
+
+#define CORE_STS_OVERRIDE_GMIIP_PORT(x)        (0x160 + (x) * 4)
+#define  LINK_STS                      (1 << 0)
+#define  DUPLX_MODE                    (1 << 1)
+#define  SPEED_SHIFT                   2
+#define  SPEED_MASK                    0x3
+#define  RXFLOW_CNTL                   (1 << 4)
+#define  TXFLOW_CNTL                   (1 << 5)
+#define  SW_OVERRIDE                   (1 << 6)
+
+#define CORE_WATCHDOG_CTRL             0x001e4
+#define  SOFTWARE_RESET                        (1 << 7)
+#define  EN_CHIP_RST                   (1 << 6)
+#define  EN_SW_RESET                   (1 << 4)
+
+#define CORE_LNKSTS                    0x00400
+#define  LNK_STS_MASK                  0x1ff
+
+#define CORE_SPDSTS                    0x00410
+#define  SPDSTS_10                     0
+#define  SPDSTS_100                    1
+#define  SPDSTS_1000                   2
+#define  SPDSTS_SHIFT                  2
+#define  SPDSTS_MASK                   0x3
+
+#define CORE_DUPSTS                    0x00420
+#define  CORE_DUPSTS_MASK              0x1ff
+
+#define CORE_PAUSESTS                  0x00428
+#define  PAUSESTS_TX_PAUSE_SHIFT       9
+
+#define CORE_GMNCFGCFG                 0x0800
+#define  RST_MIB_CNT                   (1 << 0)
+#define  RXBPDU_EN                     (1 << 1)
+
+#define CORE_IMP0_PRT_ID               0x0804
+
+#define CORE_BRCM_HDR_CTRL             0x0080c
+#define  BRCM_HDR_EN_P8                        (1 << 0)
+#define  BRCM_HDR_EN_P5                        (1 << 1)
+#define  BRCM_HDR_EN_P7                        (1 << 2)
+
+#define CORE_BRCM_HDR_CTRL2            0x0828
+
+#define CORE_HL_PRTC_CTRL              0x0940
+#define  ARP_EN                                (1 << 0)
+#define  RARP_EN                       (1 << 1)
+#define  DHCP_EN                       (1 << 2)
+#define  ICMPV4_EN                     (1 << 3)
+#define  ICMPV6_EN                     (1 << 4)
+#define  ICMPV6_FWD_MODE               (1 << 5)
+#define  IGMP_DIP_EN                   (1 << 8)
+#define  IGMP_RPTLVE_EN                        (1 << 9)
+#define  IGMP_RTPLVE_FWD_MODE          (1 << 10)
+#define  IGMP_QRY_EN                   (1 << 11)
+#define  IGMP_QRY_FWD_MODE             (1 << 12)
+#define  IGMP_UKN_EN                   (1 << 13)
+#define  IGMP_UKN_FWD_MODE             (1 << 14)
+#define  MLD_RPTDONE_EN                        (1 << 15)
+#define  MLD_RPTDONE_FWD_MODE          (1 << 16)
+#define  MLD_QRY_EN                    (1 << 17)
+#define  MLD_QRY_FWD_MODE              (1 << 18)
+
+#define CORE_RST_MIB_CNT_EN            0x0950
+
+#define CORE_BRCM_HDR_RX_DIS           0x0980
+#define CORE_BRCM_HDR_TX_DIS           0x0988
+
+#define CORE_MEM_PSM_VDD_CTRL          0x2380
+#define  P_TXQ_PSM_VDD_SHIFT           2
+#define  P_TXQ_PSM_VDD_MASK            0x3
+#define  P_TXQ_PSM_VDD(x)              (P_TXQ_PSM_VDD_MASK << \
+                                       ((x) * P_TXQ_PSM_VDD_SHIFT))
+
+#define        CORE_P0_MIB_OFFSET              0x8000
+#define P_MIB_SIZE                     0x400
+#define CORE_P_MIB_OFFSET(x)           (CORE_P0_MIB_OFFSET + (x) * P_MIB_SIZE)
+
+#define CORE_PORT_VLAN_CTL_PORT(x)     (0xc400 + ((x) * 0x8))
+#define  PORT_VLAN_CTRL_MASK           0x1ff
+
+#endif /* __BCM_SF2_REGS_H */
index cc25a3a9e7cf388d6da509c7bfb7277d0f70549a..caade30820d50b9851228589a192f17bb8c9a915 100644 (file)
 #define DMA_PBL_X8_DISABLE             0x00
 #define DMA_PBL_X8_ENABLE              0x01
 
-
 /* MAC register offsets */
 #define MAC_TCR                                0x0000
 #define MAC_RCR                                0x0004
 #define MTL_Q_DISABLED                 0x00
 #define MTL_Q_ENABLED                  0x02
 
-
 /* MTL traffic class register offsets
  *   Multiple traffic classes can be active.  The first class has registers
  *   that begin at 0x1100.  Each subsequent queue has registers that
 #define MTL_TSA_SP                     0x00
 #define MTL_TSA_ETS                    0x02
 
-
 /* PCS MMD select register offset
  *  The MMD select register is used for accessing PCS registers
  *  when the underlying APB3 interface is using indirect addressing.
  */
 #define PCS_MMD_SELECT                 0xff
 
-
 /* Descriptor/Packet entry bit positions and sizes */
 #define RX_PACKET_ERRORS_CRC_INDEX             2
 #define RX_PACKET_ERRORS_CRC_WIDTH             1
 #define MDIO_AN_COMP_STAT              0x0030
 #endif
 
-
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
  *  the variable
@@ -957,7 +952,6 @@ do {                                                                        \
                              ((0x1 << (_width)) - 1)) << (_index)));   \
 } while (0)
 
-
 /* Bit setting and getting macros based on register fields
  *  The get macro uses the bit field definitions formed using the input
  *  names to extract the current bit field value from within the
@@ -986,7 +980,6 @@ do {                                                                        \
                 _prefix##_##_field##_INDEX,                            \
                 _prefix##_##_field##_WIDTH, (_val))
 
-
 /* Macros for reading or writing registers
  *  The ioread macros will get bit fields or full values using the
  *  register definitions formed using the input names
@@ -1014,7 +1007,6 @@ do {                                                                      \
        XGMAC_IOWRITE((_pdata), _reg, reg_val);                         \
 } while (0)
 
-
 /* Macros for reading or writing MTL queue or traffic class registers
  *  Similar to the standard read and write macros except that the
  *  base register value is calculated by the queue or traffic class number
@@ -1041,7 +1033,6 @@ do {                                                                      \
        XGMAC_MTL_IOWRITE((_pdata), (_n), _reg, reg_val);               \
 } while (0)
 
-
 /* Macros for reading or writing DMA channel registers
  *  Similar to the standard read and write macros except that the
  *  base register value is obtained from the ring
@@ -1066,7 +1057,6 @@ do {                                                                      \
        XGMAC_DMA_IOWRITE((_channel), _reg, reg_val);                   \
 } while (0)
 
-
 /* Macros for building, reading or writing register values or bits
  * within the register values of XPCS registers.
  */
@@ -1076,7 +1066,6 @@ do {                                                                      \
 #define XPCS_IOREAD(_pdata, _off)                                      \
        ioread32((_pdata)->xpcs_regs + (_off))
 
-
 /* Macros for building, reading or writing register values or bits
  * using MDIO.  Different from above because of the use of standardized
  * Linux include values.  No shifting is performed with the bit
index 7d6a49b2432188665412ee2bdf44d58156cf51e9..8a50b01c2686292b06e97dae11c21c57095f6844 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static int xgbe_dcb_ieee_getets(struct net_device *netdev,
                                struct ieee_ets *ets)
 {
index a3c11355a34dd199a40252dab901ab23cb908ffb..76479d04b9037370ebb91cd161574c793eaf881b 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static ssize_t xgbe_common_read(char __user *buffer, size_t count,
                                loff_t *ppos, unsigned int value)
 {
index 1c5d62e8dab655013ea3883d983543ea7993a4b6..6fc5da01437d8ba75a3b8cf0cd16244b61e4f7d8 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static void xgbe_unmap_skb(struct xgbe_prv_data *, struct xgbe_ring_data *);
 
 static void xgbe_free_ring(struct xgbe_prv_data *pdata,
@@ -524,11 +523,8 @@ static void xgbe_realloc_skb(struct xgbe_channel *channel)
 
                /* Allocate skb & assign to each rdesc */
                skb = dev_alloc_skb(pdata->rx_buf_size);
-               if (skb == NULL) {
-                       netdev_alert(pdata->netdev,
-                                    "failed to allocate skb\n");
+               if (skb == NULL)
                        break;
-               }
                skb_dma = dma_map_single(pdata->dev, skb->data,
                                         pdata->rx_buf_size, DMA_FROM_DEVICE);
                if (dma_mapping_error(pdata->dev, skb_dma)) {
index ea273836d999c854d89d45789e33d1ff81afc92b..9da3a03e8c0777595a7f99774be62c9528e55c6a 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata,
                                      unsigned int usec)
 {
index b26d75856553bf62c975e533dc815051f7968de5..29554992215aa18301f26b7e431b1fc19dfff9cb 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static int xgbe_poll(struct napi_struct *, int);
 static void xgbe_set_rx_mode(struct net_device *);
 
index 46f613028e9c00ba9b659a4b8ccc7a8f5f47c644..49508ec98b72c1c01fdd189fc71e8c7465c77d2c 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 struct xgbe_stats {
        char stat_string[ETH_GSTRING_LEN];
        int stat_size;
@@ -173,6 +172,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = {
        XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
        XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
 };
+
 #define XGBE_STATS_COUNT       ARRAY_SIZE(xgbe_gstring_stats)
 
 static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
index bdf9cfa70e88c4dac3c7f3c439fa2b3eef29aaa6..f5a8fa03921aafdff9dd8c8274b4bd055ad05e8c 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(XGBE_DRV_VERSION);
index 6d2221e023f45a70ebdcb32f668f32b0e59b7671..363b210560f332e08837e9bfb9426dcea62707a4 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static int xgbe_mdio_read(struct mii_bus *mii, int prtad, int mmd_reg)
 {
        struct xgbe_prv_data *pdata = mii->priv;
index 37e64cfa5718e6e45dc71d580296101327b7f49a..a1bf9d1cdae1e9d5dc666cf7b37f6320d1b2adff 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static cycle_t xgbe_cc_read(const struct cyclecounter *cc)
 {
        struct xgbe_prv_data *pdata = container_of(cc,
index e9fe6e6ddcc34acd7469aef6b523855e535f5a99..789957d43a1379939e2aa9b8d15f267473a271a6 100644 (file)
 #include <linux/net_tstamp.h>
 #include <net/dcbnl.h>
 
-
 #define XGBE_DRV_NAME          "amd-xgbe"
 #define XGBE_DRV_VERSION       "1.0.0-a"
 #define XGBE_DRV_DESC          "AMD 10 Gigabit Ethernet Driver"
        ((_ring)->rdata +                                       \
         ((_idx) & ((_ring)->rdesc_count - 1)))
 
-
 /* Default coalescing parameters */
 #define XGMAC_INIT_DMA_TX_USECS                50
 #define XGMAC_INIT_DMA_TX_FRAMES       25
index 514c57fd26f1bbf6eda45da6c6e1aebdb735e37c..89e04fde5f4e7e366e6015be1c9d80ace400b78e 100644 (file)
@@ -17,10 +17,14 @@ config NET_VENDOR_ARC
 
 if NET_VENDOR_ARC
 
-config ARC_EMAC
-       tristate "ARC EMAC support"
+config ARC_EMAC_CORE
+       tristate
        select MII
        select PHYLIB
+
+config ARC_EMAC
+       tristate "ARC EMAC support"
+       select ARC_EMAC_CORE
        depends on OF_IRQ
        depends on OF_NET
        ---help---
index 00c8657637d56d8396d10d3edf3b298cd4efd298..241bb809f35105665324d206e3aa5ebe9275d9a1 100644 (file)
@@ -3,4 +3,5 @@
 #
 
 arc_emac-objs := emac_main.o emac_mdio.o
-obj-$(CONFIG_ARC_EMAC) += arc_emac.o
+obj-$(CONFIG_ARC_EMAC_CORE) += arc_emac.o
+obj-$(CONFIG_ARC_EMAC) += emac_arc.o
index 36cc9bd07c478e7e776f7be199af0787eeb04da5..eb2ba67ac711b9f5ef0d3ccfcfc15e59824e9720 100644 (file)
@@ -124,6 +124,8 @@ struct buffer_state {
  */
 struct arc_emac_priv {
        /* Devices */
+       const char *drv_name;
+       const char *drv_version;
        struct device *dev;
        struct phy_device *phy_dev;
        struct mii_bus *bus;
@@ -204,7 +206,9 @@ static inline void arc_reg_clr(struct arc_emac_priv *priv, int reg, int mask)
        arc_reg_set(priv, reg, value & ~mask);
 }
 
-int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv);
+int arc_mdio_probe(struct arc_emac_priv *priv);
 int arc_mdio_remove(struct arc_emac_priv *priv);
+int arc_emac_probe(struct net_device *ndev, int interface);
+int arc_emac_remove(struct net_device *ndev);
 
 #endif /* ARC_EMAC_H */
diff --git a/drivers/net/ethernet/arc/emac_arc.c b/drivers/net/ethernet/arc/emac_arc.c
new file mode 100644 (file)
index 0000000..f9cb99b
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+ * emac_arc.c - ARC EMAC specific glue layer
+ *
+ * Copyright (C) 2014 Romain Perier
+ *
+ * Romain Perier  <romain.perier@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/platform_device.h>
+
+#include "emac.h"
+
+#define DRV_NAME    "emac_arc"
+#define DRV_VERSION "1.0"
+
+static int emac_arc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct net_device *ndev;
+       struct arc_emac_priv *priv;
+       int interface, err;
+
+       if (!dev->of_node)
+               return -ENODEV;
+
+       ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
+       if (!ndev)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, ndev);
+       SET_NETDEV_DEV(ndev, dev);
+
+       priv = netdev_priv(ndev);
+       priv->drv_name = DRV_NAME;
+       priv->drv_version = DRV_VERSION;
+
+       interface = of_get_phy_mode(dev->of_node);
+       if (interface < 0)
+               interface = PHY_INTERFACE_MODE_MII;
+
+       priv->clk = devm_clk_get(dev, "hclk");
+       if (IS_ERR(priv->clk)) {
+               dev_err(dev, "failed to retrieve host clock from device tree\n");
+               err = -EINVAL;
+               goto out_netdev;
+       }
+
+       err = arc_emac_probe(ndev, interface);
+out_netdev:
+       if (err)
+               free_netdev(ndev);
+       return err;
+}
+
+static int emac_arc_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       int err;
+
+       err = arc_emac_remove(ndev);
+       free_netdev(ndev);
+       return err;
+}
+
+static const struct of_device_id emac_arc_dt_ids[] = {
+       { .compatible = "snps,arc-emac" },
+       { /* Sentinel */ }
+};
+
+static struct platform_driver emac_arc_driver = {
+       .probe = emac_arc_probe,
+       .remove = emac_arc_remove,
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table  = emac_arc_dt_ids,
+       },
+};
+
+module_platform_driver(emac_arc_driver);
+
+MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
+MODULE_DESCRIPTION("ARC EMAC platform driver");
+MODULE_LICENSE("GPL");
index fe5cfeace6e3e1cd5bdcbce922b5b51e0f7cc326..a7773923a7a06472bd889e9d3cfe59c048d6e8d4 100644 (file)
@@ -26,8 +26,6 @@
 
 #include "emac.h"
 
-#define DRV_NAME       "arc_emac"
-#define DRV_VERSION    "1.0"
 
 /**
  * arc_emac_adjust_link - Adjust the PHY link duplex.
@@ -120,8 +118,10 @@ static int arc_emac_set_settings(struct net_device *ndev,
 static void arc_emac_get_drvinfo(struct net_device *ndev,
                                 struct ethtool_drvinfo *info)
 {
-       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
-       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       struct arc_emac_priv *priv = netdev_priv(ndev);
+
+       strlcpy(info->driver, priv->drv_name, sizeof(info->driver));
+       strlcpy(info->version, priv->drv_version, sizeof(info->version));
 }
 
 static const struct ethtool_ops arc_emac_ethtool_ops = {
@@ -671,46 +671,38 @@ static const struct net_device_ops arc_emac_netdev_ops = {
 #endif
 };
 
-static int arc_emac_probe(struct platform_device *pdev)
+int arc_emac_probe(struct net_device *ndev, int interface)
 {
+       struct device *dev = ndev->dev.parent;
        struct resource res_regs;
        struct device_node *phy_node;
        struct arc_emac_priv *priv;
-       struct net_device *ndev;
        const char *mac_addr;
        unsigned int id, clock_frequency, irq;
        int err;
 
-       if (!pdev->dev.of_node)
-               return -ENODEV;
 
        /* Get PHY from device tree */
-       phy_node = of_parse_phandle(pdev->dev.of_node, "phy", 0);
+       phy_node = of_parse_phandle(dev->of_node, "phy", 0);
        if (!phy_node) {
-               dev_err(&pdev->dev, "failed to retrieve phy description from device tree\n");
+               dev_err(dev, "failed to retrieve phy description from device tree\n");
                return -ENODEV;
        }
 
        /* Get EMAC registers base address from device tree */
-       err = of_address_to_resource(pdev->dev.of_node, 0, &res_regs);
+       err = of_address_to_resource(dev->of_node, 0, &res_regs);
        if (err) {
-               dev_err(&pdev->dev, "failed to retrieve registers base from device tree\n");
+               dev_err(dev, "failed to retrieve registers base from device tree\n");
                return -ENODEV;
        }
 
        /* Get IRQ from device tree */
-       irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       irq = irq_of_parse_and_map(dev->of_node, 0);
        if (!irq) {
-               dev_err(&pdev->dev, "failed to retrieve <irq> value from device tree\n");
+               dev_err(dev, "failed to retrieve <irq> value from device tree\n");
                return -ENODEV;
        }
 
-       ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
-       if (!ndev)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, ndev);
-       SET_NETDEV_DEV(ndev, &pdev->dev);
 
        ndev->netdev_ops = &arc_emac_netdev_ops;
        ndev->ethtool_ops = &arc_emac_ethtool_ops;
@@ -719,60 +711,57 @@ static int arc_emac_probe(struct platform_device *pdev)
        ndev->flags &= ~IFF_MULTICAST;
 
        priv = netdev_priv(ndev);
-       priv->dev = &pdev->dev;
+       priv->dev = dev;
 
-       priv->regs = devm_ioremap_resource(&pdev->dev, &res_regs);
+       priv->regs = devm_ioremap_resource(dev, &res_regs);
        if (IS_ERR(priv->regs)) {
-               err = PTR_ERR(priv->regs);
-               goto out_netdev;
+               return PTR_ERR(priv->regs);
        }
-       dev_dbg(&pdev->dev, "Registers base address is 0x%p\n", priv->regs);
+       dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
 
-       priv->clk = of_clk_get(pdev->dev.of_node, 0);
-       if (IS_ERR(priv->clk)) {
-               /* Get CPU clock frequency from device tree */
-               if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-                                       &clock_frequency)) {
-                       dev_err(&pdev->dev, "failed to retrieve <clock-frequency> from device tree\n");
-                       err = -EINVAL;
-                       goto out_netdev;
-               }
-       } else {
+       if (priv->clk) {
                err = clk_prepare_enable(priv->clk);
                if (err) {
-                       dev_err(&pdev->dev, "failed to enable clock\n");
-                       goto out_clkget;
+                       dev_err(dev, "failed to enable clock\n");
+                       return err;
                }
 
                clock_frequency = clk_get_rate(priv->clk);
+       } else {
+               /* Get CPU clock frequency from device tree */
+               if (of_property_read_u32(dev->of_node, "clock-frequency",
+                                        &clock_frequency)) {
+                       dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
+                       return -EINVAL;
+               }
        }
 
        id = arc_reg_get(priv, R_ID);
 
        /* Check for EMAC revision 5 or 7, magic number */
        if (!(id == 0x0005fd02 || id == 0x0007fd02)) {
-               dev_err(&pdev->dev, "ARC EMAC not detected, id=0x%x\n", id);
+               dev_err(dev, "ARC EMAC not detected, id=0x%x\n", id);
                err = -ENODEV;
                goto out_clken;
        }
-       dev_info(&pdev->dev, "ARC EMAC detected with id: 0x%x\n", id);
+       dev_info(dev, "ARC EMAC detected with id: 0x%x\n", id);
 
        /* Set poll rate so that it polls every 1 ms */
        arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000);
 
        ndev->irq = irq;
-       dev_info(&pdev->dev, "IRQ is %d\n", ndev->irq);
+       dev_info(dev, "IRQ is %d\n", ndev->irq);
 
        /* Register interrupt handler for device */
-       err = devm_request_irq(&pdev->dev, ndev->irq, arc_emac_intr, 0,
+       err = devm_request_irq(dev, ndev->irq, arc_emac_intr, 0,
                               ndev->name, ndev);
        if (err) {
-               dev_err(&pdev->dev, "could not allocate IRQ\n");
+               dev_err(dev, "could not allocate IRQ\n");
                goto out_clken;
        }
 
        /* Get MAC address from device tree */
-       mac_addr = of_get_mac_address(pdev->dev.of_node);
+       mac_addr = of_get_mac_address(dev->of_node);
 
        if (mac_addr)
                memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
@@ -780,14 +769,14 @@ static int arc_emac_probe(struct platform_device *pdev)
                eth_hw_addr_random(ndev);
 
        arc_emac_set_address_internal(ndev);
-       dev_info(&pdev->dev, "MAC address is now %pM\n", ndev->dev_addr);
+       dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr);
 
        /* Do 1 allocation instead of 2 separate ones for Rx and Tx BD rings */
-       priv->rxbd = dmam_alloc_coherent(&pdev->dev, RX_RING_SZ + TX_RING_SZ,
+       priv->rxbd = dmam_alloc_coherent(dev, RX_RING_SZ + TX_RING_SZ,
                                         &priv->rxbd_dma, GFP_KERNEL);
 
        if (!priv->rxbd) {
-               dev_err(&pdev->dev, "failed to allocate data buffers\n");
+               dev_err(dev, "failed to allocate data buffers\n");
                err = -ENOMEM;
                goto out_clken;
        }
@@ -795,31 +784,31 @@ static int arc_emac_probe(struct platform_device *pdev)
        priv->txbd = priv->rxbd + RX_BD_NUM;
 
        priv->txbd_dma = priv->rxbd_dma + RX_RING_SZ;
-       dev_dbg(&pdev->dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
+       dev_dbg(dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
                (unsigned int)priv->rxbd_dma, (unsigned int)priv->txbd_dma);
 
-       err = arc_mdio_probe(pdev, priv);
+       err = arc_mdio_probe(priv);
        if (err) {
-               dev_err(&pdev->dev, "failed to probe MII bus\n");
+               dev_err(dev, "failed to probe MII bus\n");
                goto out_clken;
        }
 
        priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
-                                      PHY_INTERFACE_MODE_MII);
+                                      interface);
        if (!priv->phy_dev) {
-               dev_err(&pdev->dev, "of_phy_connect() failed\n");
+               dev_err(dev, "of_phy_connect() failed\n");
                err = -ENODEV;
                goto out_mdio;
        }
 
-       dev_info(&pdev->dev, "connected to %s phy with id 0x%x\n",
+       dev_info(dev, "connected to %s phy with id 0x%x\n",
                 priv->phy_dev->drv->name, priv->phy_dev->phy_id);
 
        netif_napi_add(ndev, &priv->napi, arc_emac_poll, ARC_EMAC_NAPI_WEIGHT);
 
        err = register_netdev(ndev);
        if (err) {
-               dev_err(&pdev->dev, "failed to register network device\n");
+               dev_err(dev, "failed to register network device\n");
                goto out_netif_api;
        }
 
@@ -832,19 +821,14 @@ out_netif_api:
 out_mdio:
        arc_mdio_remove(priv);
 out_clken:
-       if (!IS_ERR(priv->clk))
+       if (priv->clk)
                clk_disable_unprepare(priv->clk);
-out_clkget:
-       if (!IS_ERR(priv->clk))
-               clk_put(priv->clk);
-out_netdev:
-       free_netdev(ndev);
        return err;
 }
+EXPORT_SYMBOL_GPL(arc_emac_probe);
 
-static int arc_emac_remove(struct platform_device *pdev)
+int arc_emac_remove(struct net_device *ndev)
 {
-       struct net_device *ndev = platform_get_drvdata(pdev);
        struct arc_emac_priv *priv = netdev_priv(ndev);
 
        phy_disconnect(priv->phy_dev);
@@ -855,31 +839,12 @@ static int arc_emac_remove(struct platform_device *pdev)
 
        if (!IS_ERR(priv->clk)) {
                clk_disable_unprepare(priv->clk);
-               clk_put(priv->clk);
        }
 
-       free_netdev(ndev);
 
        return 0;
 }
-
-static const struct of_device_id arc_emac_dt_ids[] = {
-       { .compatible = "snps,arc-emac" },
-       { /* Sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, arc_emac_dt_ids);
-
-static struct platform_driver arc_emac_driver = {
-       .probe = arc_emac_probe,
-       .remove = arc_emac_remove,
-       .driver = {
-               .name = DRV_NAME,
-               .owner = THIS_MODULE,
-               .of_match_table  = arc_emac_dt_ids,
-               },
-};
-
-module_platform_driver(arc_emac_driver);
+EXPORT_SYMBOL_GPL(arc_emac_remove);
 
 MODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>");
 MODULE_DESCRIPTION("ARC EMAC driver");
index 26ba2423f33a9a383b79c6a58d37e07b3d456cd3..d5ee986936dadd6764a0fe08ecc3b963c2e97d88 100644 (file)
@@ -100,7 +100,6 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr,
 
 /**
  * arc_mdio_probe - MDIO probe function.
- * @pdev:      Pointer to platform device.
  * @priv:      Pointer to ARC EMAC private data structure.
  *
  * returns:    0 on success, -ENOMEM when mdiobus_alloc
@@ -108,7 +107,7 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr,
  *
  * Sets up and registers the MDIO interface.
  */
-int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv)
+int arc_mdio_probe(struct arc_emac_priv *priv)
 {
        struct mii_bus *bus;
        int error;
@@ -124,9 +123,9 @@ int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv)
        bus->read = &arc_mdio_read;
        bus->write = &arc_mdio_write;
 
-       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", bus->name);
 
-       error = of_mdiobus_register(bus, pdev->dev.of_node);
+       error = of_mdiobus_register(bus, priv->dev->of_node);
        if (error) {
                dev_err(priv->dev, "cannot register MDIO bus %s\n", bus->name);
                mdiobus_free(bus);
index d8d07a818b89bc694a77b2bdc3172f5bbb6d7010..c3e260c21734c37ca1641ffbf9441c867d18deb6 100644 (file)
@@ -122,6 +122,7 @@ config TIGON3
 config BNX2X
        tristate "Broadcom NetXtremeII 10Gb support"
        depends on PCI
+       select PTP_1588_CLOCK
        select FW_LOADER
        select ZLIB_INFLATE
        select LIBCRC32C
index 6f4e18644bd4e5089c7485acd7417a0adff76bff..662cf222287350aea861f794668e41311d301388 100644 (file)
@@ -139,6 +139,15 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev,
        else
                reg &= ~RXCHK_SKIP_FCS;
 
+       /* If Broadcom tags are enabled (e.g: using a switch), make
+        * sure we tell the RXCHK hardware to expect a 4-bytes Broadcom
+        * tag after the Ethernet MAC Source Address.
+        */
+       if (netdev_uses_dsa(dev))
+               reg |= RXCHK_BRCM_TAG_EN;
+       else
+               reg &= ~RXCHK_BRCM_TAG_EN;
+
        rxchk_writel(priv, reg, RXCHK_CONTROL);
 
        return 0;
@@ -1062,16 +1071,19 @@ static void bcm_sysport_adj_link(struct net_device *dev)
        if (!phydev->pause)
                cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
 
-       if (changed) {
+       if (!changed)
+               return;
+
+       if (phydev->link) {
                reg = umac_readl(priv, UMAC_CMD);
                reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) |
                        CMD_HD_EN | CMD_RX_PAUSE_IGNORE |
                        CMD_TX_PAUSE_IGNORE);
                reg |= cmd_bits;
                umac_writel(priv, reg, UMAC_CMD);
-
-               phy_print_status(priv->phydev);
        }
+
+       phy_print_status(priv->phydev);
 }
 
 static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
index d777fae869883fedd4ecba03987f8b56e3db56cb..86e94517a536fcdf75d38673cd4f7c17895836e5 100644 (file)
 #include <linux/types.h>
 #include <linux/pci_regs.h>
 
+#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
+#include <linux/clocksource.h>
+
 /* compilation time flags */
 
 /* define this to make the driver freeze on error to allow getting debug info
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.78.19-0"
+#define DRV_MODULE_VERSION      "1.710.51-0"
 #define DRV_MODULE_RELDATE      "2014/02/10"
 #define BNX2X_BC_VER            0x040200
 
@@ -70,6 +74,7 @@ enum bnx2x_int_mode {
 #define BNX2X_MSG_SP                   0x0100000 /* was: NETIF_MSG_INTR */
 #define BNX2X_MSG_FP                   0x0200000 /* was: NETIF_MSG_INTR */
 #define BNX2X_MSG_IOV                  0x0800000
+#define BNX2X_MSG_PTP                  0x1000000
 #define BNX2X_MSG_IDLE                 0x2000000 /* used for idle check*/
 #define BNX2X_MSG_ETHTOOL              0x4000000
 #define BNX2X_MSG_DCB                  0x8000000
@@ -1587,10 +1592,11 @@ struct bnx2x {
 #define USING_SINGLE_MSIX_FLAG         (1 << 20)
 #define BC_SUPPORTS_DCBX_MSG_NON_PMF   (1 << 21)
 #define IS_VF_FLAG                     (1 << 22)
-#define INTERRUPTS_ENABLED_FLAG                (1 << 23)
-#define BC_SUPPORTS_RMMOD_CMD          (1 << 24)
-#define HAS_PHYS_PORT_ID               (1 << 25)
-#define AER_ENABLED                    (1 << 26)
+#define BC_SUPPORTS_RMMOD_CMD          (1 << 23)
+#define HAS_PHYS_PORT_ID               (1 << 24)
+#define AER_ENABLED                    (1 << 25)
+#define PTP_SUPPORTED                  (1 << 26)
+#define TX_TIMESTAMPING_EN             (1 << 27)
 
 #define BP_NOMCP(bp)                   ((bp)->flags & NO_MCP_FLAG)
 
@@ -1684,13 +1690,9 @@ struct bnx2x {
 #define BNX2X_STATE_ERROR              0xf000
 
 #define BNX2X_MAX_PRIORITY             8
-#define BNX2X_MAX_ENTRIES_PER_PRI      16
-#define BNX2X_MAX_COS                  3
-#define BNX2X_MAX_TX_COS               2
        int                     num_queues;
        uint                    num_ethernet_queues;
        uint                    num_cnic_queues;
-       int                     num_napi_queues;
        int                     disable_tpa;
 
        u32                     rx_mode;
@@ -1933,6 +1935,19 @@ struct bnx2x {
 
        u8                                      phys_port_id[ETH_ALEN];
 
+       /* PTP related context */
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info ptp_clock_info;
+       struct work_struct ptp_task;
+       struct cyclecounter cyclecounter;
+       struct timecounter timecounter;
+       bool timecounter_init_done;
+       struct sk_buff *ptp_tx_skb;
+       unsigned long ptp_tx_start;
+       bool hwtstamp_ioctl_called;
+       u16 tx_type;
+       u16 rx_filter;
+
        struct bnx2x_link_report_data           vf_link_vars;
 };
 
@@ -2559,4 +2574,11 @@ void bnx2x_update_mng_version(struct bnx2x *bp);
 
 #define E1H_MAX_MF_SB_COUNT (HC_SB_MAX_SB_E1X/(E1HVN_MAX * PORT_MAX))
 
+void bnx2x_init_ptp(struct bnx2x *bp);
+int bnx2x_configure_ptp_filters(struct bnx2x *bp);
+void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb);
+
+#define BNX2X_MAX_PHC_DRIFT 31000000
+#define BNX2X_PTP_TX_TIMEOUT
+
 #endif /* bnx2x.h */
index 4ccc806b11501bb08b96614a0e79b020867648fe..6dc32aee96bfd40634742da87233bdf60f862476 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/if_vlan.h>
 #include <linux/interrupt.h>
 #include <linux/ip.h>
+#include <linux/crash_dump.h>
 #include <net/tcp.h>
 #include <net/ipv6.h>
 #include <net/ip6_checksum.h>
@@ -64,7 +65,7 @@ static int bnx2x_calc_num_queues(struct bnx2x *bp)
        int nq = bnx2x_num_queues ? : netif_get_num_default_rss_queues();
 
        /* Reduce memory usage in kdump environment by using only one queue */
-       if (reset_devices)
+       if (is_kdump_kernel())
                nq = 1;
 
        nq = clamp(nq, 1, BNX2X_MAX_QUEUES(bp));
@@ -1063,6 +1064,11 @@ reuse_rx:
 
                skb_record_rx_queue(skb, fp->rx_queue);
 
+               /* Check if this packet was timestamped */
+               if (unlikely(cqe->fast_path_cqe.type_error_flags &
+                            (1 << ETH_FAST_PATH_RX_CQE_PTP_PKT_SHIFT)))
+                       bnx2x_set_rx_ts(bp, skb);
+
                if (le16_to_cpu(cqe_fp->pars_flags.flags) &
                    PARSING_FLAGS_VLAN)
                        __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
@@ -2078,6 +2084,10 @@ int bnx2x_rss(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
                        __set_bit(BNX2X_RSS_IPV4_UDP, &params.rss_flags);
                if (rss_obj->udp_rss_v6)
                        __set_bit(BNX2X_RSS_IPV6_UDP, &params.rss_flags);
+
+               if (!CHIP_IS_E1x(bp))
+                       /* valid only for TUNN_MODE_GRE tunnel mode */
+                       __set_bit(BNX2X_RSS_GRE_INNER_HDRS, &params.rss_flags);
        } else {
                __set_bit(BNX2X_RSS_MODE_DISABLED, &params.rss_flags);
        }
@@ -2800,7 +2810,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        /* Initialize Rx filter. */
        bnx2x_set_rx_mode_inner(bp);
 
-       /* Start the Tx */
+       if (bp->flags & PTP_SUPPORTED) {
+               bnx2x_init_ptp(bp);
+               bnx2x_configure_ptp_filters(bp);
+       }
+       /* Start Tx */
        switch (load_mode) {
        case LOAD_NORMAL:
                /* Tx queue should be only re-enabled */
@@ -3437,26 +3451,6 @@ exit_lbl:
 }
 #endif
 
-static void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
-                                u32 xmit_type)
-{
-       struct ipv6hdr *ipv6;
-
-       *parsing_data |= (skb_shinfo(skb)->gso_size <<
-                             ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
-                             ETH_TX_PARSE_BD_E2_LSO_MSS;
-
-       if (xmit_type & XMIT_GSO_ENC_V6)
-               ipv6 = inner_ipv6_hdr(skb);
-       else if (xmit_type & XMIT_GSO_V6)
-               ipv6 = ipv6_hdr(skb);
-       else
-               ipv6 = NULL;
-
-       if (ipv6 && ipv6->nexthdr == NEXTHDR_IPV6)
-               *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
-}
-
 /**
  * bnx2x_set_pbd_gso - update PBD in GSO case.
  *
@@ -3466,7 +3460,6 @@ static void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
  */
 static void bnx2x_set_pbd_gso(struct sk_buff *skb,
                              struct eth_tx_parse_bd_e1x *pbd,
-                             struct eth_tx_start_bd *tx_start_bd,
                              u32 xmit_type)
 {
        pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
@@ -3479,9 +3472,6 @@ static void bnx2x_set_pbd_gso(struct sk_buff *skb,
                        bswab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
                                                   ip_hdr(skb)->daddr,
                                                   0, IPPROTO_TCP, 0));
-
-               /* GSO on 57710/57711 needs FW to calculate IP checksum */
-               tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM;
        } else {
                pbd->tcp_pseudo_csum =
                        bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
@@ -3653,18 +3643,23 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
                           (__force u32)iph->tot_len -
                           (__force u32)iph->frag_off;
 
+               outerip_len = iph->ihl << 1;
+
                pbd2->fw_ip_csum_wo_len_flags_frag =
                        bswab16(csum_fold((__force __wsum)csum));
        } else {
                pbd2->fw_ip_hdr_to_payload_w =
                        hlen_w - ((sizeof(struct ipv6hdr)) >> 1);
+               pbd_e2->data.tunnel_data.flags |=
+                       ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER;
        }
 
        pbd2->tcp_send_seq = bswab32(inner_tcp_hdr(skb)->seq);
 
        pbd2->tcp_flags = pbd_tcp_flags(inner_tcp_hdr(skb));
 
-       if (xmit_type & XMIT_GSO_V4) {
+       /* inner IP header info */
+       if (xmit_type & XMIT_CSUM_ENC_V4) {
                pbd2->hw_ip_id = bswab16(inner_ip_hdr(skb)->id);
 
                pbd_e2->data.tunnel_data.pseudo_csum =
@@ -3672,8 +3667,6 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
                                        inner_ip_hdr(skb)->saddr,
                                        inner_ip_hdr(skb)->daddr,
                                        0, IPPROTO_TCP, 0));
-
-               outerip_len = ip_hdr(skb)->ihl << 1;
        } else {
                pbd_e2->data.tunnel_data.pseudo_csum =
                        bswab16(~csum_ipv6_magic(
@@ -3686,8 +3679,6 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
 
        *global_data |=
                outerip_off |
-               (!!(xmit_type & XMIT_CSUM_V6) <<
-                       ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER_SHIFT) |
                (outerip_len <<
                        ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W_SHIFT) |
                ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
@@ -3699,6 +3690,23 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
        }
 }
 
+static inline void bnx2x_set_ipv6_ext_e2(struct sk_buff *skb, u32 *parsing_data,
+                                        u32 xmit_type)
+{
+       struct ipv6hdr *ipv6;
+
+       if (!(xmit_type & (XMIT_GSO_ENC_V6 | XMIT_GSO_V6)))
+               return;
+
+       if (xmit_type & XMIT_GSO_ENC_V6)
+               ipv6 = inner_ipv6_hdr(skb);
+       else /* XMIT_GSO_V6 */
+               ipv6 = ipv6_hdr(skb);
+
+       if (ipv6->nexthdr == NEXTHDR_IPV6)
+               *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
+}
+
 /* called with netif_tx_lock
  * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
  * netif_wake_queue()
@@ -3831,6 +3839,20 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
 
+       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+               if (!(bp->flags & TX_TIMESTAMPING_EN)) {
+                       BNX2X_ERR("Tx timestamping was not enabled, this packet will not be timestamped\n");
+               } else if (bp->ptp_tx_skb) {
+                       BNX2X_ERR("The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
+               } else {
+                       skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+                       /* schedule check for Tx timestamp */
+                       bp->ptp_tx_skb = skb_get(skb);
+                       bp->ptp_tx_start = jiffies;
+                       schedule_work(&bp->ptp_task);
+               }
+       }
+
        /* header nbd: indirectly zero other flags! */
        tx_start_bd->general_data = 1 << ETH_TX_START_BD_HDR_NBDS_SHIFT;
 
@@ -3852,12 +3874,16 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                /* when transmitting in a vf, start bd must hold the ethertype
                 * for fw to enforce it
                 */
+#ifndef BNX2X_STOP_ON_ERROR
                if (IS_VF(bp))
+#endif
                        tx_start_bd->vlan_or_ethertype =
                                cpu_to_le16(ntohs(eth->h_proto));
+#ifndef BNX2X_STOP_ON_ERROR
                else
                        /* used by FW for packet accounting */
                        tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+#endif
        }
 
        nbd = 2; /* start_bd + pbd + frags (updated when pages are mapped) */
@@ -3915,6 +3941,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                                     xmit_type);
                }
 
+               bnx2x_set_ipv6_ext_e2(skb, &pbd_e2_parsing_data, xmit_type);
                /* Add the macs to the parsing BD if this is a vf or if
                 * Tx Switching is enabled.
                 */
@@ -3929,11 +3956,22 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                              &pbd_e2->data.mac_addr.dst_mid,
                                              &pbd_e2->data.mac_addr.dst_lo,
                                              eth->h_dest);
-               } else if (bp->flags & TX_SWITCHING) {
-                       bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
-                                             &pbd_e2->data.mac_addr.dst_mid,
-                                             &pbd_e2->data.mac_addr.dst_lo,
-                                             eth->h_dest);
+               } else {
+                       if (bp->flags & TX_SWITCHING)
+                               bnx2x_set_fw_mac_addr(
+                                               &pbd_e2->data.mac_addr.dst_hi,
+                                               &pbd_e2->data.mac_addr.dst_mid,
+                                               &pbd_e2->data.mac_addr.dst_lo,
+                                               eth->h_dest);
+#ifdef BNX2X_STOP_ON_ERROR
+                       /* Enforce security is always set in Stop on Error -
+                        * source mac should be present in the parsing BD
+                        */
+                       bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
+                                             &pbd_e2->data.mac_addr.src_mid,
+                                             &pbd_e2->data.mac_addr.src_lo,
+                                             eth->h_source);
+#endif
                }
 
                SET_FLAG(pbd_e2_parsing_data,
@@ -3980,10 +4018,12 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                                 bd_prod);
                }
                if (!CHIP_IS_E1x(bp))
-                       bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
-                                            xmit_type);
+                       pbd_e2_parsing_data |=
+                               (skb_shinfo(skb)->gso_size <<
+                                ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
+                                ETH_TX_PARSE_BD_E2_LSO_MSS;
                else
-                       bnx2x_set_pbd_gso(skb, pbd_e1x, first_bd, xmit_type);
+                       bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
        }
 
        /* Set the PBD's parsing_data field if not zero
@@ -4771,11 +4811,15 @@ netdev_features_t bnx2x_fix_features(struct net_device *dev,
        struct bnx2x *bp = netdev_priv(dev);
 
        /* TPA requires Rx CSUM offloading */
-       if (!(features & NETIF_F_RXCSUM) || bp->disable_tpa) {
+       if (!(features & NETIF_F_RXCSUM)) {
                features &= ~NETIF_F_LRO;
                features &= ~NETIF_F_GRO;
        }
 
+       /* Note: do not disable SW GRO in kernel when HW GRO is off */
+       if (bp->disable_tpa)
+               features &= ~NETIF_F_LRO;
+
        return features;
 }
 
@@ -4814,6 +4858,10 @@ int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
        if ((changes & GRO_ENABLE_FLAG) && (flags & TPA_ENABLE_FLAG))
                changes &= ~GRO_ENABLE_FLAG;
 
+       /* if GRO is changed while HW TPA is off, don't force a reload */
+       if ((changes & GRO_ENABLE_FLAG) && bp->disable_tpa)
+               changes &= ~GRO_ENABLE_FLAG;
+
        if (changes)
                bnx2x_reload = true;
 
index 571427c7226b11f4c22669ce8d8f14c81950a10d..ac63e16829efc3552ed2cc0ca7df5685e339476c 100644 (file)
@@ -932,8 +932,9 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
        else /* CHIP_IS_E1X */
                start_params->network_cos_mode = FW_WRR;
 
-       start_params->gre_tunnel_mode = L2GRE_TUNNEL;
-       start_params->gre_tunnel_rss = GRE_INNER_HEADERS_RSS;
+       start_params->tunnel_mode       = TUNN_MODE_GRE;
+       start_params->gre_tunnel_type   = IPGRE_TUNNEL;
+       start_params->inner_gre_rss_en  = 1;
 
        return bnx2x_func_state_change(bp, &func_params);
 }
index fb26bc4c42a1fd03d42ef885dc562bcf4d460ade..6e4294ed1fc997e5545fcc48a24c92124129867c 100644 (file)
@@ -2092,7 +2092,6 @@ static void bnx2x_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio,
 static u8 bnx2x_dcbnl_set_all(struct net_device *netdev)
 {
        struct bnx2x *bp = netdev_priv(netdev);
-       int rc = 0;
 
        DP(BNX2X_MSG_DCB, "SET-ALL\n");
 
@@ -2110,9 +2109,7 @@ static u8 bnx2x_dcbnl_set_all(struct net_device *netdev)
                                       1);
                bnx2x_dcbx_init(bp, true);
        }
-       DP(BNX2X_MSG_DCB, "set_dcbx_params done (%d)\n", rc);
-       if (rc)
-               return 1;
+       DP(BNX2X_MSG_DCB, "set_dcbx_params done\n");
 
        return 0;
 }
index 12eb4baee9f642e444bbb162d038911776b4d852..741aa130c19f4efb4df2e2b64b166f24bd4b6b3e 100644 (file)
@@ -40,7 +40,7 @@ struct        dump_header {
        u32 dump_meta_data; /* OR of CHIP and PATH. */
 };
 
-#define BNX2X_DUMP_VERSION 0x50acff01
+#define  BNX2X_DUMP_VERSION 0x61111111
 struct reg_addr {
        u32 addr;
        u32 size;
@@ -1464,7 +1464,6 @@ static const struct reg_addr reg_addrs[] = {
        { 0x180398, 1, 0x1c, 0x924},
        { 0x1803a0, 5, 0x1c, 0x924},
        { 0x1803b4, 2, 0x18, 0x924},
-       { 0x180400, 256, 0x3, 0xfff},
        { 0x181000, 4, 0x1f, 0x93c},
        { 0x181010, 1020, 0x1f, 0x38},
        { 0x182000, 4, 0x18, 0x924},
@@ -1576,7 +1575,6 @@ static const struct reg_addr reg_addrs[] = {
        { 0x200398, 1, 0x1c, 0x924},
        { 0x2003a0, 1, 0x1c, 0x924},
        { 0x2003a8, 2, 0x1c, 0x924},
-       { 0x200400, 256, 0x3, 0xfff},
        { 0x202000, 4, 0x1f, 0x1927},
        { 0x202010, 2044, 0x1f, 0x1007},
        { 0x204000, 4, 0x18, 0x924},
@@ -1688,7 +1686,6 @@ static const struct reg_addr reg_addrs[] = {
        { 0x280398, 1, 0x1c, 0x924},
        { 0x2803a0, 1, 0x1c, 0x924},
        { 0x2803a8, 2, 0x1c, 0x924},
-       { 0x280400, 256, 0x3, 0xfff},
        { 0x282000, 4, 0x1f, 0x9e4},
        { 0x282010, 2044, 0x1f, 0x1c0},
        { 0x284000, 4, 0x18, 0x924},
@@ -1800,7 +1797,6 @@ static const struct reg_addr reg_addrs[] = {
        { 0x300398, 1, 0x1c, 0x924},
        { 0x3003a0, 1, 0x1c, 0x924},
        { 0x3003a8, 2, 0x1c, 0x924},
-       { 0x300400, 256, 0x3, 0xfff},
        { 0x302000, 4, 0x1f, 0xf24},
        { 0x302010, 2044, 0x1f, 0xe00},
        { 0x304000, 4, 0x18, 0x924},
@@ -2206,10 +2202,10 @@ static const struct wreg_addr wreg_addr_e3b0 = {
        0x1b0c00, 128, 2, read_reg_e3b0, 0x1f, 0x1fff};
 
 static const unsigned int dump_num_registers[NUM_CHIPS][NUM_PRESETS] = {
-       {20782, 18567, 27975, 19729, 18311, 27719, 20836, 32391, 41799, 20812,
-        26247, 35655, 19074},
-       {32774, 19297, 33277, 31721, 19041, 33021, 32828, 33121, 47101, 32804,
-        26977, 40957, 35895},
+       {19758, 17543, 26951, 18705, 17287, 26695, 19812, 31367, 40775, 19788,
+        25223, 34631, 19074},
+       {31750, 18273, 32253, 30697, 18017, 31997, 31804, 32097, 46077, 31780,
+        25953, 39933, 35895},
        {36527, 17928, 33697, 35474, 18700, 34466, 36581, 31752, 47521, 36557,
         25608, 41377, 43903},
        {45239, 17936, 34387, 44186, 18708, 35156, 45293, 31760, 48211, 45269,
index 92fee842f954f8787b245c007deb5291ca8c8771..0b173ed20ae9db65fa8a3d65d4ea80be58d076bd 100644 (file)
@@ -3481,6 +3481,46 @@ static int bnx2x_set_channels(struct net_device *dev,
        return bnx2x_nic_load(bp, LOAD_NORMAL);
 }
 
+static int bnx2x_get_ts_info(struct net_device *dev,
+                            struct ethtool_ts_info *info)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+
+       if (bp->flags & PTP_SUPPORTED) {
+               info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+                                       SOF_TIMESTAMPING_RX_SOFTWARE |
+                                       SOF_TIMESTAMPING_SOFTWARE |
+                                       SOF_TIMESTAMPING_TX_HARDWARE |
+                                       SOF_TIMESTAMPING_RX_HARDWARE |
+                                       SOF_TIMESTAMPING_RAW_HARDWARE;
+
+               if (bp->ptp_clock)
+                       info->phc_index = ptp_clock_index(bp->ptp_clock);
+               else
+                       info->phc_index = -1;
+
+               info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ);
+
+               info->tx_types = (1 << HWTSTAMP_TX_OFF)|(1 << HWTSTAMP_TX_ON);
+
+               return 0;
+       }
+
+       return ethtool_op_get_ts_info(dev, info);
+}
+
 static const struct ethtool_ops bnx2x_ethtool_ops = {
        .get_settings           = bnx2x_get_settings,
        .set_settings           = bnx2x_set_settings,
@@ -3522,7 +3562,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
        .get_module_eeprom      = bnx2x_get_module_eeprom,
        .get_eee                = bnx2x_get_eee,
        .set_eee                = bnx2x_set_eee,
-       .get_ts_info            = ethtool_op_get_ts_info,
+       .get_ts_info            = bnx2x_get_ts_info,
 };
 
 static const struct ethtool_ops bnx2x_vf_ethtool_ops = {
index 95dc365435483ed9298389b88f965130d48eb7d0..7636e3c18771dced3a1d4bd3db0018cee4b4d7f3 100644 (file)
 #ifndef BNX2X_FW_DEFS_H
 #define BNX2X_FW_DEFS_H
 
-#define CSTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[148].base)
+#define CSTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[152].base)
 #define CSTORM_ASSERT_LIST_OFFSET(assertListEntry) \
-       (IRO[147].base + ((assertListEntry) * IRO[147].m1))
+       (IRO[151].base + ((assertListEntry) * IRO[151].m1))
 #define CSTORM_EVENT_RING_DATA_OFFSET(pfId) \
-       (IRO[153].base + (((pfId)>>1) * IRO[153].m1) + (((pfId)&1) * \
-       IRO[153].m2))
+       (IRO[157].base + (((pfId)>>1) * IRO[157].m1) + (((pfId)&1) * \
+       IRO[157].m2))
 #define CSTORM_EVENT_RING_PROD_OFFSET(pfId) \
-       (IRO[154].base + (((pfId)>>1) * IRO[154].m1) + (((pfId)&1) * \
-       IRO[154].m2))
+       (IRO[158].base + (((pfId)>>1) * IRO[158].m1) + (((pfId)&1) * \
+       IRO[158].m2))
 #define CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(funcId) \
-       (IRO[159].base + ((funcId) * IRO[159].m1))
+       (IRO[163].base + ((funcId) * IRO[163].m1))
 #define CSTORM_FUNC_EN_OFFSET(funcId) \
-       (IRO[149].base + ((funcId) * IRO[149].m1))
+       (IRO[153].base + ((funcId) * IRO[153].m1))
 #define CSTORM_HC_SYNC_LINE_INDEX_E1X_OFFSET(hcIndex, sbId) \
-       (IRO[139].base + ((hcIndex) * IRO[139].m1) + ((sbId) * IRO[139].m2))
+       (IRO[143].base + ((hcIndex) * IRO[143].m1) + ((sbId) * IRO[143].m2))
 #define CSTORM_HC_SYNC_LINE_INDEX_E2_OFFSET(hcIndex, sbId) \
-       (IRO[138].base + (((hcIndex)>>2) * IRO[138].m1) + (((hcIndex)&3) \
-       * IRO[138].m2) + ((sbId) * IRO[138].m3))
-#define CSTORM_IGU_MODE_OFFSET (IRO[157].base)
+       (IRO[142].base + (((hcIndex)>>2) * IRO[142].m1) + (((hcIndex)&3) \
+       * IRO[142].m2) + ((sbId) * IRO[142].m3))
+#define CSTORM_IGU_MODE_OFFSET (IRO[161].base)
 #define CSTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
-       (IRO[317].base + ((pfId) * IRO[317].m1))
+       (IRO[323].base + ((pfId) * IRO[323].m1))
 #define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
-       (IRO[318].base + ((pfId) * IRO[318].m1))
+       (IRO[324].base + ((pfId) * IRO[324].m1))
 #define CSTORM_ISCSI_EQ_CONS_OFFSET(pfId, iscsiEqId) \
-       (IRO[310].base + ((pfId) * IRO[310].m1) + ((iscsiEqId) * IRO[310].m2))
+       (IRO[316].base + ((pfId) * IRO[316].m1) + ((iscsiEqId) * IRO[316].m2))
 #define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfId, iscsiEqId) \
-       (IRO[312].base + ((pfId) * IRO[312].m1) + ((iscsiEqId) * IRO[312].m2))
+       (IRO[318].base + ((pfId) * IRO[318].m1) + ((iscsiEqId) * IRO[318].m2))
 #define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfId, iscsiEqId) \
-       (IRO[311].base + ((pfId) * IRO[311].m1) + ((iscsiEqId) * IRO[311].m2))
+       (IRO[317].base + ((pfId) * IRO[317].m1) + ((iscsiEqId) * IRO[317].m2))
 #define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfId, iscsiEqId) \
-       (IRO[313].base + ((pfId) * IRO[313].m1) + ((iscsiEqId) * IRO[313].m2))
+       (IRO[319].base + ((pfId) * IRO[319].m1) + ((iscsiEqId) * IRO[319].m2))
 #define CSTORM_ISCSI_EQ_PROD_OFFSET(pfId, iscsiEqId) \
-       (IRO[309].base + ((pfId) * IRO[309].m1) + ((iscsiEqId) * IRO[309].m2))
-#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \
        (IRO[315].base + ((pfId) * IRO[315].m1) + ((iscsiEqId) * IRO[315].m2))
+#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \
+       (IRO[321].base + ((pfId) * IRO[321].m1) + ((iscsiEqId) * IRO[321].m2))
 #define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfId, iscsiEqId) \
-       (IRO[314].base + ((pfId) * IRO[314].m1) + ((iscsiEqId) * IRO[314].m2))
+       (IRO[320].base + ((pfId) * IRO[320].m1) + ((iscsiEqId) * IRO[320].m2))
 #define CSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
-       (IRO[316].base + ((pfId) * IRO[316].m1))
+       (IRO[322].base + ((pfId) * IRO[322].m1))
 #define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-       (IRO[308].base + ((pfId) * IRO[308].m1))
+       (IRO[314].base + ((pfId) * IRO[314].m1))
 #define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-       (IRO[307].base + ((pfId) * IRO[307].m1))
+       (IRO[313].base + ((pfId) * IRO[313].m1))
 #define CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-       (IRO[306].base + ((pfId) * IRO[306].m1))
+       (IRO[312].base + ((pfId) * IRO[312].m1))
 #define CSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
-       (IRO[151].base + ((funcId) * IRO[151].m1))
+       (IRO[155].base + ((funcId) * IRO[155].m1))
 #define CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(pfId) \
-       (IRO[142].base + ((pfId) * IRO[142].m1))
+       (IRO[146].base + ((pfId) * IRO[146].m1))
 #define CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(pfId) \
-       (IRO[143].base + ((pfId) * IRO[143].m1))
+       (IRO[147].base + ((pfId) * IRO[147].m1))
 #define CSTORM_SP_STATUS_BLOCK_OFFSET(pfId) \
-       (IRO[141].base + ((pfId) * IRO[141].m1))
-#define CSTORM_SP_STATUS_BLOCK_SIZE (IRO[141].size)
+       (IRO[145].base + ((pfId) * IRO[145].m1))
+#define CSTORM_SP_STATUS_BLOCK_SIZE (IRO[145].size)
 #define CSTORM_SP_SYNC_BLOCK_OFFSET(pfId) \
-       (IRO[144].base + ((pfId) * IRO[144].m1))
-#define CSTORM_SP_SYNC_BLOCK_SIZE (IRO[144].size)
+       (IRO[148].base + ((pfId) * IRO[148].m1))
+#define CSTORM_SP_SYNC_BLOCK_SIZE (IRO[148].size)
 #define CSTORM_STATUS_BLOCK_DATA_FLAGS_OFFSET(sbId, hcIndex) \
-       (IRO[136].base + ((sbId) * IRO[136].m1) + ((hcIndex) * IRO[136].m2))
+       (IRO[140].base + ((sbId) * IRO[140].m1) + ((hcIndex) * IRO[140].m2))
 #define CSTORM_STATUS_BLOCK_DATA_OFFSET(sbId) \
-       (IRO[133].base + ((sbId) * IRO[133].m1))
+       (IRO[137].base + ((sbId) * IRO[137].m1))
 #define CSTORM_STATUS_BLOCK_DATA_STATE_OFFSET(sbId) \
-       (IRO[134].base + ((sbId) * IRO[134].m1))
+       (IRO[138].base + ((sbId) * IRO[138].m1))
 #define CSTORM_STATUS_BLOCK_DATA_TIMEOUT_OFFSET(sbId, hcIndex) \
-       (IRO[135].base + ((sbId) * IRO[135].m1) + ((hcIndex) * IRO[135].m2))
+       (IRO[139].base + ((sbId) * IRO[139].m1) + ((hcIndex) * IRO[139].m2))
 #define CSTORM_STATUS_BLOCK_OFFSET(sbId) \
-       (IRO[132].base + ((sbId) * IRO[132].m1))
-#define CSTORM_STATUS_BLOCK_SIZE (IRO[132].size)
+       (IRO[136].base + ((sbId) * IRO[136].m1))
+#define CSTORM_STATUS_BLOCK_SIZE (IRO[136].size)
 #define CSTORM_SYNC_BLOCK_OFFSET(sbId) \
-       (IRO[137].base + ((sbId) * IRO[137].m1))
-#define CSTORM_SYNC_BLOCK_SIZE (IRO[137].size)
+       (IRO[141].base + ((sbId) * IRO[141].m1))
+#define CSTORM_SYNC_BLOCK_SIZE (IRO[141].size)
 #define CSTORM_VF_PF_CHANNEL_STATE_OFFSET(vfId) \
-       (IRO[155].base + ((vfId) * IRO[155].m1))
+       (IRO[159].base + ((vfId) * IRO[159].m1))
 #define CSTORM_VF_PF_CHANNEL_VALID_OFFSET(vfId) \
-       (IRO[156].base + ((vfId) * IRO[156].m1))
+       (IRO[160].base + ((vfId) * IRO[160].m1))
 #define CSTORM_VF_TO_PF_OFFSET(funcId) \
-       (IRO[150].base + ((funcId) * IRO[150].m1))
+       (IRO[154].base + ((funcId) * IRO[154].m1))
 #define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(pfId) \
-       (IRO[203].base + ((pfId) * IRO[203].m1))
+       (IRO[207].base + ((pfId) * IRO[207].m1))
 #define TSTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[102].base)
 #define TSTORM_ASSERT_LIST_OFFSET(assertListEntry) \
        (IRO[101].base + ((assertListEntry) * IRO[101].m1))
 #define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(pfId) \
-       (IRO[201].base + ((pfId) * IRO[201].m1))
+       (IRO[205].base + ((pfId) * IRO[205].m1))
 #define TSTORM_FUNC_EN_OFFSET(funcId) \
-       (IRO[103].base + ((funcId) * IRO[103].m1))
+       (IRO[107].base + ((funcId) * IRO[107].m1))
 #define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
-       (IRO[272].base + ((pfId) * IRO[272].m1))
+       (IRO[278].base + ((pfId) * IRO[278].m1))
 #define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \
-       (IRO[273].base + ((pfId) * IRO[273].m1))
+       (IRO[279].base + ((pfId) * IRO[279].m1))
 #define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \
-       (IRO[274].base + ((pfId) * IRO[274].m1))
+       (IRO[280].base + ((pfId) * IRO[280].m1))
 #define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \
-       (IRO[275].base + ((pfId) * IRO[275].m1))
+       (IRO[281].base + ((pfId) * IRO[281].m1))
 #define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-       (IRO[271].base + ((pfId) * IRO[271].m1))
+       (IRO[277].base + ((pfId) * IRO[277].m1))
 #define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-       (IRO[270].base + ((pfId) * IRO[270].m1))
+       (IRO[276].base + ((pfId) * IRO[276].m1))
 #define TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-       (IRO[269].base + ((pfId) * IRO[269].m1))
+       (IRO[275].base + ((pfId) * IRO[275].m1))
 #define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
-       (IRO[268].base + ((pfId) * IRO[268].m1))
+       (IRO[274].base + ((pfId) * IRO[274].m1))
 #define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \
-       (IRO[278].base + ((pfId) * IRO[278].m1))
+       (IRO[284].base + ((pfId) * IRO[284].m1))
 #define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
-       (IRO[264].base + ((pfId) * IRO[264].m1))
+       (IRO[270].base + ((pfId) * IRO[270].m1))
 #define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
-       (IRO[265].base + ((pfId) * IRO[265].m1))
+       (IRO[271].base + ((pfId) * IRO[271].m1))
 #define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \
-       (IRO[266].base + ((pfId) * IRO[266].m1))
+       (IRO[272].base + ((pfId) * IRO[272].m1))
 #define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
-       (IRO[267].base + ((pfId) * IRO[267].m1))
+       (IRO[273].base + ((pfId) * IRO[273].m1))
 #define TSTORM_MAC_FILTER_CONFIG_OFFSET(pfId) \
-       (IRO[202].base + ((pfId) * IRO[202].m1))
+       (IRO[206].base + ((pfId) * IRO[206].m1))
 #define TSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
-       (IRO[105].base + ((funcId) * IRO[105].m1))
+       (IRO[109].base + ((funcId) * IRO[109].m1))
 #define TSTORM_TCP_MAX_CWND_OFFSET(pfId) \
-       (IRO[217].base + ((pfId) * IRO[217].m1))
+       (IRO[223].base + ((pfId) * IRO[223].m1))
 #define TSTORM_VF_TO_PF_OFFSET(funcId) \
-       (IRO[104].base + ((funcId) * IRO[104].m1))
-#define USTORM_AGG_DATA_OFFSET (IRO[206].base)
-#define USTORM_AGG_DATA_SIZE (IRO[206].size)
-#define USTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[177].base)
+       (IRO[108].base + ((funcId) * IRO[108].m1))
+#define USTORM_AGG_DATA_OFFSET (IRO[212].base)
+#define USTORM_AGG_DATA_SIZE (IRO[212].size)
+#define USTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[181].base)
 #define USTORM_ASSERT_LIST_OFFSET(assertListEntry) \
-       (IRO[176].base + ((assertListEntry) * IRO[176].m1))
+       (IRO[180].base + ((assertListEntry) * IRO[180].m1))
 #define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \
-       (IRO[183].base + ((portId) * IRO[183].m1))
+       (IRO[187].base + ((portId) * IRO[187].m1))
 #define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \
-       (IRO[319].base + ((pfId) * IRO[319].m1))
+       (IRO[325].base + ((pfId) * IRO[325].m1))
 #define USTORM_FUNC_EN_OFFSET(funcId) \
-       (IRO[178].base + ((funcId) * IRO[178].m1))
+       (IRO[182].base + ((funcId) * IRO[182].m1))
 #define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
-       (IRO[283].base + ((pfId) * IRO[283].m1))
+       (IRO[289].base + ((pfId) * IRO[289].m1))
 #define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
-       (IRO[284].base + ((pfId) * IRO[284].m1))
+       (IRO[290].base + ((pfId) * IRO[290].m1))
 #define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
-       (IRO[288].base + ((pfId) * IRO[288].m1))
+       (IRO[294].base + ((pfId) * IRO[294].m1))
 #define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \
-       (IRO[285].base + ((pfId) * IRO[285].m1))
+       (IRO[291].base + ((pfId) * IRO[291].m1))
 #define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-       (IRO[281].base + ((pfId) * IRO[281].m1))
+       (IRO[287].base + ((pfId) * IRO[287].m1))
 #define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-       (IRO[280].base + ((pfId) * IRO[280].m1))
+       (IRO[286].base + ((pfId) * IRO[286].m1))
 #define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-       (IRO[279].base + ((pfId) * IRO[279].m1))
+       (IRO[285].base + ((pfId) * IRO[285].m1))
 #define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
-       (IRO[282].base + ((pfId) * IRO[282].m1))
+       (IRO[288].base + ((pfId) * IRO[288].m1))
 #define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \
-       (IRO[286].base + ((pfId) * IRO[286].m1))
+       (IRO[292].base + ((pfId) * IRO[292].m1))
 #define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
-       (IRO[287].base + ((pfId) * IRO[287].m1))
+       (IRO[293].base + ((pfId) * IRO[293].m1))
 #define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(pfId) \
-       (IRO[182].base + ((pfId) * IRO[182].m1))
+       (IRO[186].base + ((pfId) * IRO[186].m1))
 #define USTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
-       (IRO[180].base + ((funcId) * IRO[180].m1))
+       (IRO[184].base + ((funcId) * IRO[184].m1))
 #define USTORM_RX_PRODS_E1X_OFFSET(portId, clientId) \
-       (IRO[209].base + ((portId) * IRO[209].m1) + ((clientId) * \
-       IRO[209].m2))
+       (IRO[215].base + ((portId) * IRO[215].m1) + ((clientId) * \
+       IRO[215].m2))
 #define USTORM_RX_PRODS_E2_OFFSET(qzoneId) \
-       (IRO[210].base + ((qzoneId) * IRO[210].m1))
-#define USTORM_TPA_BTR_OFFSET (IRO[207].base)
-#define USTORM_TPA_BTR_SIZE (IRO[207].size)
+       (IRO[216].base + ((qzoneId) * IRO[216].m1))
+#define USTORM_TPA_BTR_OFFSET (IRO[213].base)
+#define USTORM_TPA_BTR_SIZE (IRO[213].size)
 #define USTORM_VF_TO_PF_OFFSET(funcId) \
-       (IRO[179].base + ((funcId) * IRO[179].m1))
+       (IRO[183].base + ((funcId) * IRO[183].m1))
 #define XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE (IRO[67].base)
 #define XSTORM_AGG_INT_FINAL_CLEANUP_INDEX (IRO[66].base)
 #define XSTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[51].base)
 #define XSTORM_FUNC_EN_OFFSET(funcId) \
        (IRO[47].base + ((funcId) * IRO[47].m1))
 #define XSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
-       (IRO[296].base + ((pfId) * IRO[296].m1))
+       (IRO[302].base + ((pfId) * IRO[302].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \
-       (IRO[299].base + ((pfId) * IRO[299].m1))
+       (IRO[305].base + ((pfId) * IRO[305].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \
-       (IRO[300].base + ((pfId) * IRO[300].m1))
+       (IRO[306].base + ((pfId) * IRO[306].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \
-       (IRO[301].base + ((pfId) * IRO[301].m1))
+       (IRO[307].base + ((pfId) * IRO[307].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \
-       (IRO[302].base + ((pfId) * IRO[302].m1))
+       (IRO[308].base + ((pfId) * IRO[308].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \
-       (IRO[303].base + ((pfId) * IRO[303].m1))
+       (IRO[309].base + ((pfId) * IRO[309].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \
-       (IRO[304].base + ((pfId) * IRO[304].m1))
+       (IRO[310].base + ((pfId) * IRO[310].m1))
 #define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \
-       (IRO[305].base + ((pfId) * IRO[305].m1))
+       (IRO[311].base + ((pfId) * IRO[311].m1))
 #define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-       (IRO[295].base + ((pfId) * IRO[295].m1))
+       (IRO[301].base + ((pfId) * IRO[301].m1))
 #define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-       (IRO[294].base + ((pfId) * IRO[294].m1))
+       (IRO[300].base + ((pfId) * IRO[300].m1))
 #define XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-       (IRO[293].base + ((pfId) * IRO[293].m1))
+       (IRO[299].base + ((pfId) * IRO[299].m1))
 #define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
-       (IRO[298].base + ((pfId) * IRO[298].m1))
+       (IRO[304].base + ((pfId) * IRO[304].m1))
 #define XSTORM_ISCSI_SQ_SIZE_OFFSET(pfId) \
-       (IRO[297].base + ((pfId) * IRO[297].m1))
+       (IRO[303].base + ((pfId) * IRO[303].m1))
 #define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfId) \
-       (IRO[292].base + ((pfId) * IRO[292].m1))
+       (IRO[298].base + ((pfId) * IRO[298].m1))
 #define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
-       (IRO[291].base + ((pfId) * IRO[291].m1))
+       (IRO[297].base + ((pfId) * IRO[297].m1))
 #define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfId) \
-       (IRO[290].base + ((pfId) * IRO[290].m1))
+       (IRO[296].base + ((pfId) * IRO[296].m1))
 #define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfId) \
-       (IRO[289].base + ((pfId) * IRO[289].m1))
+       (IRO[295].base + ((pfId) * IRO[295].m1))
 #define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(pfId) \
        (IRO[44].base + ((pfId) * IRO[44].m1))
 #define XSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
 #define XSTORM_SPQ_PROD_OFFSET(funcId) \
        (IRO[31].base + ((funcId) * IRO[31].m1))
 #define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(portId) \
-       (IRO[211].base + ((portId) * IRO[211].m1))
+       (IRO[217].base + ((portId) * IRO[217].m1))
 #define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(portId) \
-       (IRO[212].base + ((portId) * IRO[212].m1))
+       (IRO[218].base + ((portId) * IRO[218].m1))
 #define XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(pfId) \
-       (IRO[214].base + (((pfId)>>1) * IRO[214].m1) + (((pfId)&1) * \
-       IRO[214].m2))
+       (IRO[220].base + (((pfId)>>1) * IRO[220].m1) + (((pfId)&1) * \
+       IRO[220].m2))
 #define XSTORM_VF_TO_PF_OFFSET(funcId) \
        (IRO[48].base + ((funcId) * IRO[48].m1))
 #define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0
 
+/* eth hsi version */
+#define ETH_FP_HSI_VERSION (ETH_FP_HSI_VER_2)
+
 /* Ethernet Ring parameters */
 #define X_ETH_LOCAL_RING_SIZE 13
 #define FIRST_BD_IN_PKT        0
 #define XSEMI_CLK1_RESUL_CHIP (1e-3)
 
 #define SDM_TIMER_TICK_RESUL_CHIP (4 * (1e-6))
+#define TSDM_TIMER_TICK_RESUL_CHIP (1 * (1e-6))
 
 /**** END DEFINES FOR TIMERS/CLOCKS RESOLUTIONS ****/
 
index c4daa068f1db5e37bdea6f160dde26b7c13d1659..3e0621acdf05570db85127f0da200ac80160876e 100644 (file)
@@ -2881,8 +2881,8 @@ struct afex_stats {
 };
 
 #define BCM_5710_FW_MAJOR_VERSION                      7
-#define BCM_5710_FW_MINOR_VERSION                      8
-#define BCM_5710_FW_REVISION_VERSION           19
+#define BCM_5710_FW_MINOR_VERSION                      10
+#define BCM_5710_FW_REVISION_VERSION           51
 #define BCM_5710_FW_ENGINEERING_VERSION                0
 #define BCM_5710_FW_COMPILE_FLAGS                      1
 
@@ -3451,6 +3451,7 @@ enum classify_rule {
        CLASSIFY_RULE_OPCODE_MAC,
        CLASSIFY_RULE_OPCODE_VLAN,
        CLASSIFY_RULE_OPCODE_PAIR,
+       CLASSIFY_RULE_OPCODE_VXLAN,
        MAX_CLASSIFY_RULE
 };
 
@@ -3480,7 +3481,8 @@ struct client_init_general_data {
        u8 func_id;
        u8 cos;
        u8 traffic_type;
-       u32 reserved0;
+       u8 fp_hsi_ver;
+       u8 reserved0[3];
 };
 
 
@@ -3550,7 +3552,9 @@ struct client_init_rx_data {
        __le16 rx_cos_mask;
        __le16 silent_vlan_value;
        __le16 silent_vlan_mask;
-       __le32 reserved6[2];
+       u8 handle_ptp_pkts_flg;
+       u8 reserved6[3];
+       __le32 reserved7;
 };
 
 /*
@@ -3581,7 +3585,7 @@ struct client_init_tx_data {
        u8 tunnel_lso_inc_ip_id;
        u8 refuse_outband_vlan_flg;
        u8 tunnel_non_lso_pcsum_location;
-       u8 reserved1;
+       u8 tunnel_non_lso_outer_ip_csum_location;
 };
 
 /*
@@ -3619,7 +3623,9 @@ struct client_update_ramrod_data {
        u8 refuse_outband_vlan_change_flg;
        u8 tx_switching_flg;
        u8 tx_switching_change_flg;
-       __le32 reserved1;
+       u8 handle_ptp_pkts_flg;
+       u8 handle_ptp_pkts_change_flg;
+       __le16 reserved1;
        __le32 echo;
 };
 
@@ -3639,6 +3645,11 @@ struct double_regpair {
        u32 regpair1_hi;
 };
 
+/* 2nd parse bd type used in ethernet tx BDs */
+enum eth_2nd_parse_bd_type {
+       ETH_2ND_PARSE_BD_TYPE_LSO_TUNNEL,
+       MAX_ETH_2ND_PARSE_BD_TYPE
+};
 
 /*
  * Ethernet address typesm used in ethernet tx BDs
@@ -3723,6 +3734,18 @@ struct eth_classify_vlan_cmd {
        __le16 vlan;
 };
 
+/*
+ * Command for adding/removing a VXLAN classification rule
+ */
+struct eth_classify_vxlan_cmd {
+       struct eth_classify_cmd_header header;
+       __le32 vni;
+       __le16 inner_mac_lsb;
+       __le16 inner_mac_mid;
+       __le16 inner_mac_msb;
+       __le16 reserved1;
+};
+
 /*
  * union for eth classification rule
  */
@@ -3730,6 +3753,7 @@ union eth_classify_rule_cmd {
        struct eth_classify_mac_cmd mac;
        struct eth_classify_vlan_cmd vlan;
        struct eth_classify_pair_cmd pair;
+       struct eth_classify_vxlan_cmd vxlan;
 };
 
 /*
@@ -3835,8 +3859,10 @@ struct eth_fast_path_rx_cqe {
 #define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 4
 #define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<5)
 #define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 5
-#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x3<<6)
-#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 6
+#define ETH_FAST_PATH_RX_CQE_PTP_PKT (0x1<<6)
+#define ETH_FAST_PATH_RX_CQE_PTP_PKT_SHIFT 6
+#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x1<<7)
+#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 7
        u8 status_flags;
 #define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0)
 #define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0
@@ -3907,6 +3933,13 @@ struct eth_filter_rules_ramrod_data {
        struct eth_filter_rules_cmd rules[FILTER_RULES_COUNT];
 };
 
+/* Hsi version */
+enum eth_fp_hsi_ver {
+       ETH_FP_HSI_VER_0,
+       ETH_FP_HSI_VER_1,
+       ETH_FP_HSI_VER_2,
+       MAX_ETH_FP_HSI_VER
+};
 
 /*
  * parameters for eth classification configuration ramrod
@@ -3955,29 +3988,17 @@ struct eth_mac_addresses {
 
 /* tunneling related data */
 struct eth_tunnel_data {
-#if defined(__BIG_ENDIAN)
-       __le16 dst_mid;
-       __le16 dst_lo;
-#elif defined(__LITTLE_ENDIAN)
        __le16 dst_lo;
        __le16 dst_mid;
-#endif
-#if defined(__BIG_ENDIAN)
-       __le16 reserved0;
-       __le16 dst_hi;
-#elif defined(__LITTLE_ENDIAN)
        __le16 dst_hi;
-       __le16 reserved0;
-#endif
-#if defined(__BIG_ENDIAN)
-       u8 reserved1;
-       u8 ip_hdr_start_inner_w;
-       __le16 pseudo_csum;
-#elif defined(__LITTLE_ENDIAN)
+       __le16 fw_ip_hdr_csum;
        __le16 pseudo_csum;
        u8 ip_hdr_start_inner_w;
-       u8 reserved1;
-#endif
+       u8 flags;
+#define ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER (0x1<<0)
+#define ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER_SHIFT 0
+#define ETH_TUNNEL_DATA_RESERVED (0x7F<<1)
+#define ETH_TUNNEL_DATA_RESERVED_SHIFT 1
 };
 
 /* union for mac addresses and for tunneling data.
@@ -4064,31 +4085,41 @@ enum eth_rss_mode {
  */
 struct eth_rss_update_ramrod_data {
        u8 rss_engine_id;
-       u8 capabilities;
+       u8 rss_mode;
+       __le16 capabilities;
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY (0x1<<0)
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY_SHIFT 0
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY (0x1<<1)
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY_SHIFT 1
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY (0x1<<2)
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY_SHIFT 2
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY (0x1<<3)
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY_SHIFT 3
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY (0x1<<4)
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY_SHIFT 4
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY (0x1<<5)
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY_SHIFT 5
-#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY (0x1<<6)
-#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY_SHIFT 6
-#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<7)
-#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 7
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_VXLAN_CAPABILITY (0x1<<3)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_VXLAN_CAPABILITY_SHIFT 3
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY (0x1<<4)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY_SHIFT 4
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY (0x1<<5)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY_SHIFT 5
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY (0x1<<6)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY_SHIFT 6
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY (0x1<<7)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY_SHIFT 7
+#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY (0x1<<8)
+#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY_SHIFT 8
+#define ETH_RSS_UPDATE_RAMROD_DATA_NVGRE_KEY_ENTROPY_CAPABILITY (0x1<<9)
+#define ETH_RSS_UPDATE_RAMROD_DATA_NVGRE_KEY_ENTROPY_CAPABILITY_SHIFT 9
+#define ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY (0x1<<10)
+#define ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY_SHIFT 10
+#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<11)
+#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 11
+#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED (0xF<<12)
+#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED_SHIFT 12
        u8 rss_result_mask;
-       u8 rss_mode;
-       __le16 udp_4tuple_dst_port_mask;
-       __le16 udp_4tuple_dst_port_value;
+       u8 reserved3;
+       __le16 reserved4;
        u8 indirection_table[T_ETH_INDIRECTION_TABLE_SIZE];
        __le32 rss_key[T_ETH_RSS_KEY];
        __le32 echo;
-       __le32 reserved3;
+       __le32 reserved5;
 };
 
 
@@ -4260,10 +4291,10 @@ enum eth_tunnel_lso_inc_ip_id {
 /* In case tunnel exist and L4 checksum offload,
  * the pseudo checksum location, on packet or on BD.
  */
-enum eth_tunnel_non_lso_pcsum_location {
-       PCSUM_ON_PKT,
-       PCSUM_ON_BD,
-       MAX_ETH_TUNNEL_NON_LSO_PCSUM_LOCATION
+enum eth_tunnel_non_lso_csum_location {
+       CSUM_ON_PKT,
+       CSUM_ON_BD,
+       MAX_ETH_TUNNEL_NON_LSO_CSUM_LOCATION
 };
 
 /*
@@ -4310,8 +4341,10 @@ struct eth_tx_start_bd {
        __le16 vlan_or_ethertype;
        struct eth_tx_bd_flags bd_flags;
        u8 general_data;
-#define ETH_TX_START_BD_HDR_NBDS (0xF<<0)
+#define ETH_TX_START_BD_HDR_NBDS (0x7<<0)
 #define ETH_TX_START_BD_HDR_NBDS_SHIFT 0
+#define ETH_TX_START_BD_NO_ADDED_TAGS (0x1<<3)
+#define ETH_TX_START_BD_NO_ADDED_TAGS_SHIFT 3
 #define ETH_TX_START_BD_FORCE_VLAN_MODE (0x1<<4)
 #define ETH_TX_START_BD_FORCE_VLAN_MODE_SHIFT 4
 #define ETH_TX_START_BD_PARSE_NBDS (0x3<<5)
@@ -4387,8 +4420,8 @@ struct eth_tx_parse_2nd_bd {
        __le16 global_data;
 #define ETH_TX_PARSE_2ND_BD_IP_HDR_START_OUTER_W (0xF<<0)
 #define ETH_TX_PARSE_2ND_BD_IP_HDR_START_OUTER_W_SHIFT 0
-#define ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER (0x1<<4)
-#define ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER_SHIFT 4
+#define ETH_TX_PARSE_2ND_BD_RESERVED0 (0x1<<4)
+#define ETH_TX_PARSE_2ND_BD_RESERVED0_SHIFT 4
 #define ETH_TX_PARSE_2ND_BD_LLC_SNAP_EN (0x1<<5)
 #define ETH_TX_PARSE_2ND_BD_LLC_SNAP_EN_SHIFT 5
 #define ETH_TX_PARSE_2ND_BD_NS_FLG (0x1<<6)
@@ -4397,9 +4430,14 @@ struct eth_tx_parse_2nd_bd {
 #define ETH_TX_PARSE_2ND_BD_TUNNEL_UDP_EXIST_SHIFT 7
 #define ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W (0x1F<<8)
 #define ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W_SHIFT 8
-#define ETH_TX_PARSE_2ND_BD_RESERVED0 (0x7<<13)
-#define ETH_TX_PARSE_2ND_BD_RESERVED0_SHIFT 13
-       __le16 reserved1;
+#define ETH_TX_PARSE_2ND_BD_RESERVED1 (0x7<<13)
+#define ETH_TX_PARSE_2ND_BD_RESERVED1_SHIFT 13
+       u8 bd_type;
+#define ETH_TX_PARSE_2ND_BD_TYPE (0xF<<0)
+#define ETH_TX_PARSE_2ND_BD_TYPE_SHIFT 0
+#define ETH_TX_PARSE_2ND_BD_RESERVED2 (0xF<<4)
+#define ETH_TX_PARSE_2ND_BD_RESERVED2_SHIFT 4
+       u8 reserved3;
        u8 tcp_flags;
 #define ETH_TX_PARSE_2ND_BD_FIN_FLG (0x1<<0)
 #define ETH_TX_PARSE_2ND_BD_FIN_FLG_SHIFT 0
@@ -4417,7 +4455,7 @@ struct eth_tx_parse_2nd_bd {
 #define ETH_TX_PARSE_2ND_BD_ECE_FLG_SHIFT 6
 #define ETH_TX_PARSE_2ND_BD_CWR_FLG (0x1<<7)
 #define ETH_TX_PARSE_2ND_BD_CWR_FLG_SHIFT 7
-       u8 reserved2;
+       u8 reserved4;
        u8 tunnel_udp_hdr_start_w;
        u8 fw_ip_hdr_to_payload_w;
        __le16 fw_ip_csum_wo_len_flags_frag;
@@ -5205,10 +5243,18 @@ struct function_start_data {
        u8 path_id;
        u8 network_cos_mode;
        u8 dmae_cmd_id;
-       u8 gre_tunnel_mode;
-       u8 gre_tunnel_rss;
-       u8 nvgre_clss_en;
-       __le16 reserved1[2];
+       u8 tunnel_mode;
+       u8 gre_tunnel_type;
+       u8 tunn_clss_en;
+       u8 inner_gre_rss_en;
+       u8 sd_accept_mf_clss_fail;
+       __le16 vxlan_dst_port;
+       __le16 sd_accept_mf_clss_fail_ethtype;
+       __le16 sd_vlan_eth_type;
+       u8 sd_vlan_force_pri_flg;
+       u8 sd_vlan_force_pri_val;
+       u8 sd_accept_mf_clss_fail_match_ethtype;
+       u8 no_added_tags;
 };
 
 struct function_update_data {
@@ -5225,12 +5271,20 @@ struct function_update_data {
        u8 tx_switch_suspend_change_flg;
        u8 tx_switch_suspend;
        u8 echo;
+       u8 update_tunn_cfg_flg;
+       u8 tunnel_mode;
+       u8 gre_tunnel_type;
+       u8 tunn_clss_en;
+       u8 inner_gre_rss_en;
+       __le16 vxlan_dst_port;
+       u8 sd_vlan_force_pri_change_flg;
+       u8 sd_vlan_force_pri_flg;
+       u8 sd_vlan_force_pri_val;
+       u8 sd_vlan_tag_change_flg;
+       u8 sd_vlan_eth_type_change_flg;
        u8 reserved1;
-       u8 update_gre_cfg_flg;
-       u8 gre_tunnel_mode;
-       u8 gre_tunnel_rss;
-       u8 nvgre_clss_en;
-       u32 reserved3;
+       __le16 sd_vlan_tag;
+       __le16 sd_vlan_eth_type;
 };
 
 /*
@@ -5259,17 +5313,9 @@ struct fw_version {
 #define __FW_VERSION_RESERVED_SHIFT 4
 };
 
-/* GRE RSS Mode */
-enum gre_rss_mode {
-       GRE_OUTER_HEADERS_RSS,
-       GRE_INNER_HEADERS_RSS,
-       NVGRE_KEY_ENTROPY_RSS,
-       MAX_GRE_RSS_MODE
-};
 
 /* GRE Tunnel Mode */
 enum gre_tunnel_type {
-       NO_GRE_TUNNEL,
        NVGRE_TUNNEL,
        L2GRE_TUNNEL,
        IPGRE_TUNNEL,
@@ -5442,6 +5488,7 @@ enum ip_ver {
  * Malicious VF error ID
  */
 enum malicious_vf_error_id {
+       MALICIOUS_VF_NO_ERROR,
        VF_PF_CHANNEL_NOT_READY,
        ETH_ILLEGAL_BD_LENGTHS,
        ETH_PACKET_TOO_SHORT,
@@ -5602,6 +5649,16 @@ struct protocol_common_spe {
        union protocol_common_specific_data data;
 };
 
+/* The data for the Set Timesync Ramrod */
+struct set_timesync_ramrod_data {
+       u8 drift_adjust_cmd;
+       u8 offset_cmd;
+       u8 add_sub_drift_adjust_value;
+       u8 drift_adjust_value;
+       u32 drift_adjust_period;
+       struct regpair offset_delta;
+};
+
 /*
  * The send queue element
  */
@@ -5724,10 +5781,38 @@ struct tstorm_vf_zone_data {
        struct regpair reserved;
 };
 
+/* Add or Subtract Value for Set Timesync Ramrod */
+enum ts_add_sub_value {
+       TS_SUB_VALUE,
+       TS_ADD_VALUE,
+       MAX_TS_ADD_SUB_VALUE
+};
 
-/*
- * zone A per-queue data
- */
+/* Drift-Adjust Commands for Set Timesync Ramrod */
+enum ts_drift_adjust_cmd {
+       TS_DRIFT_ADJUST_KEEP,
+       TS_DRIFT_ADJUST_SET,
+       TS_DRIFT_ADJUST_RESET,
+       MAX_TS_DRIFT_ADJUST_CMD
+};
+
+/* Offset Commands for Set Timesync Ramrod */
+enum ts_offset_cmd {
+       TS_OFFSET_KEEP,
+       TS_OFFSET_INC,
+       TS_OFFSET_DEC,
+       MAX_TS_OFFSET_CMD
+};
+
+/* Tunnel Mode */
+enum tunnel_mode {
+       TUNN_MODE_NONE,
+       TUNN_MODE_VXLAN,
+       TUNN_MODE_GRE,
+       MAX_TUNNEL_MODE
+};
+
+ /* zone A per-queue data */
 struct ustorm_queue_zone_data {
        struct ustorm_eth_rx_producers eth_rx_producers;
        struct regpair reserved[3];
index d1c093dcb054aebb71b1ee701cf175e8ab804515..32e2444ab5e1c0621e2616fdb258d0d88ebe0e26 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/if_vlan.h>
+#include <linux/crash_dump.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/tcp.h>
@@ -63,7 +64,6 @@
 #include "bnx2x_vfpf.h"
 #include "bnx2x_dcb.h"
 #include "bnx2x_sp.h"
-
 #include <linux/firmware.h>
 #include "bnx2x_fw_file_hdr.h"
 /* FW files */
@@ -290,6 +290,8 @@ static int bnx2x_set_storm_rx_mode(struct bnx2x *bp);
 * General service functions
 ****************************************************************************/
 
+static int bnx2x_hwtstamp_ioctl(struct bnx2x *bp, struct ifreq *ifr);
+
 static void __storm_memset_dma_mapping(struct bnx2x *bp,
                                       u32 addr, dma_addr_t mapping)
 {
@@ -523,6 +525,7 @@ int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
         * as long as this code is called both from syscall context and
         * from ndo_set_rx_mode() flow that may be called from BH.
         */
+
        spin_lock_bh(&bp->dmae_lock);
 
        /* reset completion */
@@ -551,7 +554,9 @@ int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
        }
 
 unlock:
+
        spin_unlock_bh(&bp->dmae_lock);
+
        return rc;
 }
 
@@ -646,119 +651,98 @@ static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
        bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
 }
 
+enum storms {
+          XSTORM,
+          TSTORM,
+          CSTORM,
+          USTORM,
+          MAX_STORMS
+};
+
+#define STORMS_NUM 4
+#define REGS_IN_ENTRY 4
+
+static inline int bnx2x_get_assert_list_entry(struct bnx2x *bp,
+                                             enum storms storm,
+                                             int entry)
+{
+       switch (storm) {
+       case XSTORM:
+               return XSTORM_ASSERT_LIST_OFFSET(entry);
+       case TSTORM:
+               return TSTORM_ASSERT_LIST_OFFSET(entry);
+       case CSTORM:
+               return CSTORM_ASSERT_LIST_OFFSET(entry);
+       case USTORM:
+               return USTORM_ASSERT_LIST_OFFSET(entry);
+       case MAX_STORMS:
+       default:
+               BNX2X_ERR("unknown storm\n");
+       }
+       return -EINVAL;
+}
+
 static int bnx2x_mc_assert(struct bnx2x *bp)
 {
        char last_idx;
-       int i, rc = 0;
-       u32 row0, row1, row2, row3;
-
-       /* XSTORM */
-       last_idx = REG_RD8(bp, BAR_XSTRORM_INTMEM +
-                          XSTORM_ASSERT_LIST_INDEX_OFFSET);
-       if (last_idx)
-               BNX2X_ERR("XSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-       /* print the asserts */
-       for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-               row0 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-                             XSTORM_ASSERT_LIST_OFFSET(i));
-               row1 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-                             XSTORM_ASSERT_LIST_OFFSET(i) + 4);
-               row2 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-                             XSTORM_ASSERT_LIST_OFFSET(i) + 8);
-               row3 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-                             XSTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-               if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-                       BNX2X_ERR("XSTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                 i, row3, row2, row1, row0);
-                       rc++;
-               } else {
-                       break;
-               }
-       }
-
-       /* TSTORM */
-       last_idx = REG_RD8(bp, BAR_TSTRORM_INTMEM +
-                          TSTORM_ASSERT_LIST_INDEX_OFFSET);
-       if (last_idx)
-               BNX2X_ERR("TSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-       /* print the asserts */
-       for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-               row0 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-                             TSTORM_ASSERT_LIST_OFFSET(i));
-               row1 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-                             TSTORM_ASSERT_LIST_OFFSET(i) + 4);
-               row2 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-                             TSTORM_ASSERT_LIST_OFFSET(i) + 8);
-               row3 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-                             TSTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-               if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-                       BNX2X_ERR("TSTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                 i, row3, row2, row1, row0);
-                       rc++;
-               } else {
-                       break;
-               }
-       }
+       int i, j, rc = 0;
+       enum storms storm;
+       u32 regs[REGS_IN_ENTRY];
+       u32 bar_storm_intmem[STORMS_NUM] = {
+               BAR_XSTRORM_INTMEM,
+               BAR_TSTRORM_INTMEM,
+               BAR_CSTRORM_INTMEM,
+               BAR_USTRORM_INTMEM
+       };
+       u32 storm_assert_list_index[STORMS_NUM] = {
+               XSTORM_ASSERT_LIST_INDEX_OFFSET,
+               TSTORM_ASSERT_LIST_INDEX_OFFSET,
+               CSTORM_ASSERT_LIST_INDEX_OFFSET,
+               USTORM_ASSERT_LIST_INDEX_OFFSET
+       };
+       char *storms_string[STORMS_NUM] = {
+               "XSTORM",
+               "TSTORM",
+               "CSTORM",
+               "USTORM"
+       };
 
-       /* CSTORM */
-       last_idx = REG_RD8(bp, BAR_CSTRORM_INTMEM +
-                          CSTORM_ASSERT_LIST_INDEX_OFFSET);
-       if (last_idx)
-               BNX2X_ERR("CSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-       /* print the asserts */
-       for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-               row0 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-                             CSTORM_ASSERT_LIST_OFFSET(i));
-               row1 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-                             CSTORM_ASSERT_LIST_OFFSET(i) + 4);
-               row2 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-                             CSTORM_ASSERT_LIST_OFFSET(i) + 8);
-               row3 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-                             CSTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-               if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-                       BNX2X_ERR("CSTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                 i, row3, row2, row1, row0);
-                       rc++;
-               } else {
-                       break;
+       for (storm = XSTORM; storm < MAX_STORMS; storm++) {
+               last_idx = REG_RD8(bp, bar_storm_intmem[storm] +
+                                  storm_assert_list_index[storm]);
+               if (last_idx)
+                       BNX2X_ERR("%s_ASSERT_LIST_INDEX 0x%x\n",
+                                 storms_string[storm], last_idx);
+
+               /* print the asserts */
+               for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
+                       /* read a single assert entry */
+                       for (j = 0; j < REGS_IN_ENTRY; j++)
+                               regs[j] = REG_RD(bp, bar_storm_intmem[storm] +
+                                         bnx2x_get_assert_list_entry(bp,
+                                                                     storm,
+                                                                     i) +
+                                         sizeof(u32) * j);
+
+                       /* log entry if it contains a valid assert */
+                       if (regs[0] != COMMON_ASM_INVALID_ASSERT_OPCODE) {
+                               BNX2X_ERR("%s_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                                         storms_string[storm], i, regs[3],
+                                         regs[2], regs[1], regs[0]);
+                               rc++;
+                       } else {
+                               break;
+                       }
                }
        }
 
-       /* USTORM */
-       last_idx = REG_RD8(bp, BAR_USTRORM_INTMEM +
-                          USTORM_ASSERT_LIST_INDEX_OFFSET);
-       if (last_idx)
-               BNX2X_ERR("USTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-       /* print the asserts */
-       for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-               row0 = REG_RD(bp, BAR_USTRORM_INTMEM +
-                             USTORM_ASSERT_LIST_OFFSET(i));
-               row1 = REG_RD(bp, BAR_USTRORM_INTMEM +
-                             USTORM_ASSERT_LIST_OFFSET(i) + 4);
-               row2 = REG_RD(bp, BAR_USTRORM_INTMEM +
-                             USTORM_ASSERT_LIST_OFFSET(i) + 8);
-               row3 = REG_RD(bp, BAR_USTRORM_INTMEM +
-                             USTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-               if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-                       BNX2X_ERR("USTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                 i, row3, row2, row1, row0);
-                       rc++;
-               } else {
-                       break;
-               }
-       }
+       BNX2X_ERR("Chip Revision: %s, FW Version: %d_%d_%d\n",
+                 CHIP_IS_E1(bp) ? "everest1" :
+                 CHIP_IS_E1H(bp) ? "everest1h" :
+                 CHIP_IS_E2(bp) ? "everest2" : "everest3",
+                 BCM_5710_FW_MAJOR_VERSION,
+                 BCM_5710_FW_MINOR_VERSION,
+                 BCM_5710_FW_REVISION_VERSION);
 
        return rc;
 }
@@ -983,6 +967,12 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
                u32 *sb_data_p;
                struct bnx2x_fp_txdata txdata;
 
+               if (!bp->fp)
+                       break;
+
+               if (!fp->rx_cons_sb)
+                       continue;
+
                /* Rx */
                BNX2X_ERR("fp%d: rx_bd_prod(0x%x)  rx_bd_cons(0x%x)  rx_comp_prod(0x%x)  rx_comp_cons(0x%x)  *rx_cons_sb(0x%x)\n",
                          i, fp->rx_bd_prod, fp->rx_bd_cons,
@@ -995,7 +985,14 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
                /* Tx */
                for_each_cos_in_tx_queue(fp, cos)
                {
+                       if (!fp->txdata_ptr[cos])
+                               break;
+
                        txdata = *fp->txdata_ptr[cos];
+
+                       if (!txdata.tx_cons_sb)
+                               continue;
+
                        BNX2X_ERR("fp%d: tx_pkt_prod(0x%x)  tx_pkt_cons(0x%x)  tx_bd_prod(0x%x)  tx_bd_cons(0x%x)  *tx_cons_sb(0x%x)\n",
                                  i, txdata.tx_pkt_prod,
                                  txdata.tx_pkt_cons, txdata.tx_bd_prod,
@@ -1097,6 +1094,12 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
        for_each_valid_rx_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
+               if (!bp->fp)
+                       break;
+
+               if (!fp->rx_cons_sb)
+                       continue;
+
                start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
                end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
                for (j = start; j != end; j = RX_BD(j + 1)) {
@@ -1130,9 +1133,19 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
        /* Tx */
        for_each_valid_tx_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
+
+               if (!bp->fp)
+                       break;
+
                for_each_cos_in_tx_queue(fp, cos) {
                        struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
 
+                       if (!fp->txdata_ptr[cos])
+                               break;
+
+                       if (!txdata->tx_cons_sb)
+                               continue;
+
                        start = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) - 10);
                        end = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) + 245);
                        for (j = start; j != end; j = TX_BD(j + 1)) {
@@ -2071,8 +2084,6 @@ int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port)
        else
                value = 0;
 
-       DP(NETIF_MSG_LINK, "pin %d  value 0x%x\n", gpio_num, value);
-
        return value;
 }
 
@@ -4678,7 +4689,7 @@ static bool bnx2x_check_blocks_with_parity2(struct bnx2x *bp, u32 sig,
        for (i = 0; sig; i++) {
                cur_bit = (0x1UL << i);
                if (sig & cur_bit) {
-                       res |= true; /* Each bit is real error! */
+                       res = true; /* Each bit is real error! */
                        if (print) {
                                switch (cur_bit) {
                                case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
@@ -4757,21 +4768,21 @@ static bool bnx2x_check_blocks_with_parity3(struct bnx2x *bp, u32 sig,
                                        _print_next_block((*par_num)++,
                                                          "MCP ROM");
                                *global = true;
-                               res |= true;
+                               res = true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY:
                                if (print)
                                        _print_next_block((*par_num)++,
                                                          "MCP UMP RX");
                                *global = true;
-                               res |= true;
+                               res = true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY:
                                if (print)
                                        _print_next_block((*par_num)++,
                                                          "MCP UMP TX");
                                *global = true;
-                               res |= true;
+                               res = true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY:
                                if (print)
@@ -4803,7 +4814,7 @@ static bool bnx2x_check_blocks_with_parity4(struct bnx2x *bp, u32 sig,
        for (i = 0; sig; i++) {
                cur_bit = (0x1UL << i);
                if (sig & cur_bit) {
-                       res |= true; /* Each bit is real error! */
+                       res = true; /* Each bit is real error! */
                        if (print) {
                                switch (cur_bit) {
                                case AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR:
@@ -5452,6 +5463,14 @@ static void bnx2x_eq_int(struct bnx2x *bp)
                                break;
 
                        goto next_spqe;
+
+               case EVENT_RING_OPCODE_SET_TIMESYNC:
+                       DP(BNX2X_MSG_SP | BNX2X_MSG_PTP,
+                          "got set_timesync ramrod completion\n");
+                       if (f_obj->complete_cmd(bp, f_obj,
+                                               BNX2X_F_CMD_SET_TIMESYNC))
+                               break;
+                       goto next_spqe;
                }
 
                switch (opcode | bp->state) {
@@ -6102,7 +6121,7 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
        }
 
        /* Set ACCEPT_ANY_VLAN as we do not enable filtering by VLAN */
-       if (bp->rx_mode != BNX2X_RX_MODE_NONE) {
+       if (rx_mode != BNX2X_RX_MODE_NONE) {
                __set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags);
                __set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags);
        }
@@ -7662,7 +7681,11 @@ static inline int bnx2x_func_switch_update(struct bnx2x *bp, int suspend)
        func_params.cmd = BNX2X_F_CMD_SWITCH_UPDATE;
 
        /* Function parameters */
-       switch_update_params->suspend = suspend;
+       __set_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND_CHNG,
+                 &switch_update_params->changes);
+       if (suspend)
+               __set_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND,
+                         &switch_update_params->changes);
 
        rc = bnx2x_func_state_change(bp, &func_params);
 
@@ -9025,7 +9048,7 @@ static int bnx2x_func_wait_started(struct bnx2x *bp)
                struct bnx2x_func_state_params func_params = {NULL};
 
                DP(NETIF_MSG_IFDOWN,
-                  "Hmmm... Unexpected function state! Forcing STARTED-->TX_ST0PPED-->STARTED\n");
+                  "Hmmm... Unexpected function state! Forcing STARTED-->TX_STOPPED-->STARTED\n");
 
                func_params.f_obj = &bp->func_obj;
                __set_bit(RAMROD_DRV_CLR_ONLY,
@@ -9044,6 +9067,48 @@ static int bnx2x_func_wait_started(struct bnx2x *bp)
        return 0;
 }
 
+static void bnx2x_disable_ptp(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+
+       /* Disable sending PTP packets to host */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_TO_HOST :
+              NIG_REG_P0_LLH_PTP_TO_HOST, 0x0);
+
+       /* Reset PTP event detection rules */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+              NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x7FF);
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+              NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3FFF);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_PARAM_MASK :
+              NIG_REG_P0_TLLH_PTP_PARAM_MASK, 0x7FF);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_RULE_MASK :
+              NIG_REG_P0_TLLH_PTP_RULE_MASK, 0x3FFF);
+
+       /* Disable the PTP feature */
+       REG_WR(bp, port ? NIG_REG_P1_PTP_EN :
+              NIG_REG_P0_PTP_EN, 0x0);
+}
+
+/* Called during unload, to stop PTP-related stuff */
+void bnx2x_stop_ptp(struct bnx2x *bp)
+{
+       /* Cancel PTP work queue. Should be done after the Tx queues are
+        * drained to prevent additional scheduling.
+        */
+       cancel_work_sync(&bp->ptp_task);
+
+       if (bp->ptp_tx_skb) {
+               dev_kfree_skb_any(bp->ptp_tx_skb);
+               bp->ptp_tx_skb = NULL;
+       }
+
+       /* Disable PTP in HW */
+       bnx2x_disable_ptp(bp);
+
+       DP(BNX2X_MSG_PTP, "PTP stop ended successfully\n");
+}
+
 void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
 {
        int port = BP_PORT(bp);
@@ -9162,6 +9227,13 @@ unload_error:
 #endif
        }
 
+       /* stop_ptp should be after the Tx queues are drained to prevent
+        * scheduling to the cancelled PTP work queue. It should also be after
+        * function stop ramrod is sent, since as part of this ramrod FW access
+        * PTP registers.
+        */
+       bnx2x_stop_ptp(bp);
+
        /* Disable HW interrupts, NAPI */
        bnx2x_netif_stop(bp, 1);
        /* Delete all NAPI objects */
@@ -11900,7 +11972,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        bp->disable_tpa = disable_tpa;
        bp->disable_tpa |= IS_MF_STORAGE_SD(bp) || IS_MF_FCOE_AFEX(bp);
        /* Reduce memory usage in kdump environment by disabling TPA */
-       bp->disable_tpa |= reset_devices;
+       bp->disable_tpa |= is_kdump_kernel();
 
        /* Set TPA flags */
        if (bp->disable_tpa) {
@@ -11976,6 +12048,9 @@ static int bnx2x_init_bp(struct bnx2x *bp)
 
        bp->dump_preset_idx = 1;
 
+       if (CHIP_IS_E3B0(bp))
+               bp->flags |= PTP_SUPPORTED;
+
        return rc;
 }
 
@@ -12308,13 +12383,17 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        struct bnx2x *bp = netdev_priv(dev);
        struct mii_ioctl_data *mdio = if_mii(ifr);
 
-       DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
-          mdio->phy_id, mdio->reg_num, mdio->val_in);
-
        if (!netif_running(dev))
                return -EAGAIN;
 
-       return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
+       switch (cmd) {
+       case SIOCSHWTSTAMP:
+               return bnx2x_hwtstamp_ioctl(bp, ifr);
+       default:
+               DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
+                  mdio->phy_id, mdio->reg_num, mdio->val_in);
+               return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
+       }
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -12958,6 +13037,191 @@ static int set_is_vf(int chip_id)
        }
 }
 
+/* nig_tsgen registers relative address */
+#define tsgen_ctrl 0x0
+#define tsgen_freecount 0x10
+#define tsgen_synctime_t0 0x20
+#define tsgen_offset_t0 0x28
+#define tsgen_drift_t0 0x30
+#define tsgen_synctime_t1 0x58
+#define tsgen_offset_t1 0x60
+#define tsgen_drift_t1 0x68
+
+/* FW workaround for setting drift */
+static int bnx2x_send_update_drift_ramrod(struct bnx2x *bp, int drift_dir,
+                                         int best_val, int best_period)
+{
+       struct bnx2x_func_state_params func_params = {NULL};
+       struct bnx2x_func_set_timesync_params *set_timesync_params =
+               &func_params.params.set_timesync;
+
+       /* Prepare parameters for function state transitions */
+       __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
+       __set_bit(RAMROD_RETRY, &func_params.ramrod_flags);
+
+       func_params.f_obj = &bp->func_obj;
+       func_params.cmd = BNX2X_F_CMD_SET_TIMESYNC;
+
+       /* Function parameters */
+       set_timesync_params->drift_adjust_cmd = TS_DRIFT_ADJUST_SET;
+       set_timesync_params->offset_cmd = TS_OFFSET_KEEP;
+       set_timesync_params->add_sub_drift_adjust_value =
+               drift_dir ? TS_ADD_VALUE : TS_SUB_VALUE;
+       set_timesync_params->drift_adjust_value = best_val;
+       set_timesync_params->drift_adjust_period = best_period;
+
+       return bnx2x_func_state_change(bp, &func_params);
+}
+
+static int bnx2x_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+       int rc;
+       int drift_dir = 1;
+       int val, period, period1, period2, dif, dif1, dif2;
+       int best_dif = BNX2X_MAX_PHC_DRIFT, best_period = 0, best_val = 0;
+
+       DP(BNX2X_MSG_PTP, "PTP adjfreq called, ppb = %d\n", ppb);
+
+       if (!netif_running(bp->dev)) {
+               DP(BNX2X_MSG_PTP,
+                  "PTP adjfreq called while the interface is down\n");
+               return -EFAULT;
+       }
+
+       if (ppb < 0) {
+               ppb = -ppb;
+               drift_dir = 0;
+       }
+
+       if (ppb == 0) {
+               best_val = 1;
+               best_period = 0x1FFFFFF;
+       } else if (ppb >= BNX2X_MAX_PHC_DRIFT) {
+               best_val = 31;
+               best_period = 1;
+       } else {
+               /* Changed not to allow val = 8, 16, 24 as these values
+                * are not supported in workaround.
+                */
+               for (val = 0; val <= 31; val++) {
+                       if ((val & 0x7) == 0)
+                               continue;
+                       period1 = val * 1000000 / ppb;
+                       period2 = period1 + 1;
+                       if (period1 != 0)
+                               dif1 = ppb - (val * 1000000 / period1);
+                       else
+                               dif1 = BNX2X_MAX_PHC_DRIFT;
+                       if (dif1 < 0)
+                               dif1 = -dif1;
+                       dif2 = ppb - (val * 1000000 / period2);
+                       if (dif2 < 0)
+                               dif2 = -dif2;
+                       dif = (dif1 < dif2) ? dif1 : dif2;
+                       period = (dif1 < dif2) ? period1 : period2;
+                       if (dif < best_dif) {
+                               best_dif = dif;
+                               best_val = val;
+                               best_period = period;
+                       }
+               }
+       }
+
+       rc = bnx2x_send_update_drift_ramrod(bp, drift_dir, best_val,
+                                           best_period);
+       if (rc) {
+               BNX2X_ERR("Failed to set drift\n");
+               return -EFAULT;
+       }
+
+       DP(BNX2X_MSG_PTP, "Configrued val = %d, period = %d\n", best_val,
+          best_period);
+
+       return 0;
+}
+
+static int bnx2x_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+       u64 now;
+
+       DP(BNX2X_MSG_PTP, "PTP adjtime called, delta = %llx\n", delta);
+
+       now = timecounter_read(&bp->timecounter);
+       now += delta;
+       /* Re-init the timecounter */
+       timecounter_init(&bp->timecounter, &bp->cyclecounter, now);
+
+       return 0;
+}
+
+static int bnx2x_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+       u64 ns;
+       u32 remainder;
+
+       ns = timecounter_read(&bp->timecounter);
+
+       DP(BNX2X_MSG_PTP, "PTP gettime called, ns = %llu\n", ns);
+
+       ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
+       ts->tv_nsec = remainder;
+
+       return 0;
+}
+
+static int bnx2x_ptp_settime(struct ptp_clock_info *ptp,
+                            const struct timespec *ts)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+       u64 ns;
+
+       ns = ts->tv_sec * 1000000000ULL;
+       ns += ts->tv_nsec;
+
+       DP(BNX2X_MSG_PTP, "PTP settime called, ns = %llu\n", ns);
+
+       /* Re-init the timecounter */
+       timecounter_init(&bp->timecounter, &bp->cyclecounter, ns);
+
+       return 0;
+}
+
+/* Enable (or disable) ancillary features of the phc subsystem */
+static int bnx2x_ptp_enable(struct ptp_clock_info *ptp,
+                           struct ptp_clock_request *rq, int on)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+
+       BNX2X_ERR("PHC ancillary features are not supported\n");
+       return -ENOTSUPP;
+}
+
+void bnx2x_register_phc(struct bnx2x *bp)
+{
+       /* Fill the ptp_clock_info struct and register PTP clock*/
+       bp->ptp_clock_info.owner = THIS_MODULE;
+       snprintf(bp->ptp_clock_info.name, 16, "%s", bp->dev->name);
+       bp->ptp_clock_info.max_adj = BNX2X_MAX_PHC_DRIFT; /* In PPB */
+       bp->ptp_clock_info.n_alarm = 0;
+       bp->ptp_clock_info.n_ext_ts = 0;
+       bp->ptp_clock_info.n_per_out = 0;
+       bp->ptp_clock_info.pps = 0;
+       bp->ptp_clock_info.adjfreq = bnx2x_ptp_adjfreq;
+       bp->ptp_clock_info.adjtime = bnx2x_ptp_adjtime;
+       bp->ptp_clock_info.gettime = bnx2x_ptp_gettime;
+       bp->ptp_clock_info.settime = bnx2x_ptp_settime;
+       bp->ptp_clock_info.enable = bnx2x_ptp_enable;
+
+       bp->ptp_clock = ptp_clock_register(&bp->ptp_clock_info, &bp->pdev->dev);
+       if (IS_ERR(bp->ptp_clock)) {
+               bp->ptp_clock = NULL;
+               BNX2X_ERR("PTP clock registeration failed\n");
+       }
+}
+
 static int bnx2x_init_one(struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
@@ -13129,6 +13393,8 @@ static int bnx2x_init_one(struct pci_dev *pdev,
                       "Unknown",
                       dev->base_addr, bp->pdev->irq, dev->dev_addr);
 
+       bnx2x_register_phc(bp);
+
        return 0;
 
 init_one_exit:
@@ -13155,6 +13421,11 @@ static void __bnx2x_remove(struct pci_dev *pdev,
                           struct bnx2x *bp,
                           bool remove_netdev)
 {
+       if (bp->ptp_clock) {
+               ptp_clock_unregister(bp->ptp_clock);
+               bp->ptp_clock = NULL;
+       }
+
        /* Delete storage MAC address */
        if (!NO_FCOE(bp)) {
                rtnl_lock();
@@ -14136,3 +14407,332 @@ int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val)
        REG_RD(bp, pretend_reg);
        return 0;
 }
+
+static void bnx2x_ptp_task(struct work_struct *work)
+{
+       struct bnx2x *bp = container_of(work, struct bnx2x, ptp_task);
+       int port = BP_PORT(bp);
+       u32 val_seq;
+       u64 timestamp, ns;
+       struct skb_shared_hwtstamps shhwtstamps;
+
+       /* Read Tx timestamp registers */
+       val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+                        NIG_REG_P0_TLLH_PTP_BUF_SEQID);
+       if (val_seq & 0x10000) {
+               /* There is a valid timestamp value */
+               timestamp = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_TS_MSB :
+                                  NIG_REG_P0_TLLH_PTP_BUF_TS_MSB);
+               timestamp <<= 32;
+               timestamp |= REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_TS_LSB :
+                                   NIG_REG_P0_TLLH_PTP_BUF_TS_LSB);
+               /* Reset timestamp register to allow new timestamp */
+               REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+                      NIG_REG_P0_TLLH_PTP_BUF_SEQID, 0x10000);
+               ns = timecounter_cyc2time(&bp->timecounter, timestamp);
+
+               memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+               shhwtstamps.hwtstamp = ns_to_ktime(ns);
+               skb_tstamp_tx(bp->ptp_tx_skb, &shhwtstamps);
+               dev_kfree_skb_any(bp->ptp_tx_skb);
+               bp->ptp_tx_skb = NULL;
+
+               DP(BNX2X_MSG_PTP, "Tx timestamp, timestamp cycles = %llu, ns = %llu\n",
+                  timestamp, ns);
+       } else {
+               DP(BNX2X_MSG_PTP, "There is no valid Tx timestamp yet\n");
+               /* Reschedule to keep checking for a valid timestamp value */
+               schedule_work(&bp->ptp_task);
+       }
+}
+
+void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb)
+{
+       int port = BP_PORT(bp);
+       u64 timestamp, ns;
+
+       timestamp = REG_RD(bp, port ? NIG_REG_P1_LLH_PTP_HOST_BUF_TS_MSB :
+                           NIG_REG_P0_LLH_PTP_HOST_BUF_TS_MSB);
+       timestamp <<= 32;
+       timestamp |= REG_RD(bp, port ? NIG_REG_P1_LLH_PTP_HOST_BUF_TS_LSB :
+                           NIG_REG_P0_LLH_PTP_HOST_BUF_TS_LSB);
+
+       /* Reset timestamp register to allow new timestamp */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_HOST_BUF_SEQID :
+              NIG_REG_P0_LLH_PTP_HOST_BUF_SEQID, 0x10000);
+
+       ns = timecounter_cyc2time(&bp->timecounter, timestamp);
+
+       skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns);
+
+       DP(BNX2X_MSG_PTP, "Rx timestamp, timestamp cycles = %llu, ns = %llu\n",
+          timestamp, ns);
+}
+
+/* Read the PHC */
+static cycle_t bnx2x_cyclecounter_read(const struct cyclecounter *cc)
+{
+       struct bnx2x *bp = container_of(cc, struct bnx2x, cyclecounter);
+       int port = BP_PORT(bp);
+       u32 wb_data[2];
+       u64 phc_cycles;
+
+       REG_RD_DMAE(bp, port ? NIG_REG_TIMESYNC_GEN_REG + tsgen_synctime_t1 :
+                   NIG_REG_TIMESYNC_GEN_REG + tsgen_synctime_t0, wb_data, 2);
+       phc_cycles = wb_data[1];
+       phc_cycles = (phc_cycles << 32) + wb_data[0];
+
+       DP(BNX2X_MSG_PTP, "PHC read cycles = %llu\n", phc_cycles);
+
+       return phc_cycles;
+}
+
+static void bnx2x_init_cyclecounter(struct bnx2x *bp)
+{
+       memset(&bp->cyclecounter, 0, sizeof(bp->cyclecounter));
+       bp->cyclecounter.read = bnx2x_cyclecounter_read;
+       bp->cyclecounter.mask = CLOCKSOURCE_MASK(64);
+       bp->cyclecounter.shift = 1;
+       bp->cyclecounter.mult = 1;
+}
+
+static int bnx2x_send_reset_timesync_ramrod(struct bnx2x *bp)
+{
+       struct bnx2x_func_state_params func_params = {NULL};
+       struct bnx2x_func_set_timesync_params *set_timesync_params =
+               &func_params.params.set_timesync;
+
+       /* Prepare parameters for function state transitions */
+       __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
+       __set_bit(RAMROD_RETRY, &func_params.ramrod_flags);
+
+       func_params.f_obj = &bp->func_obj;
+       func_params.cmd = BNX2X_F_CMD_SET_TIMESYNC;
+
+       /* Function parameters */
+       set_timesync_params->drift_adjust_cmd = TS_DRIFT_ADJUST_RESET;
+       set_timesync_params->offset_cmd = TS_OFFSET_KEEP;
+
+       return bnx2x_func_state_change(bp, &func_params);
+}
+
+int bnx2x_enable_ptp_packets(struct bnx2x *bp)
+{
+       struct bnx2x_queue_state_params q_params;
+       int rc, i;
+
+       /* send queue update ramrod to enable PTP packets */
+       memset(&q_params, 0, sizeof(q_params));
+       __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
+       q_params.cmd = BNX2X_Q_CMD_UPDATE;
+       __set_bit(BNX2X_Q_UPDATE_PTP_PKTS_CHNG,
+                 &q_params.params.update.update_flags);
+       __set_bit(BNX2X_Q_UPDATE_PTP_PKTS,
+                 &q_params.params.update.update_flags);
+
+       /* send the ramrod on all the queues of the PF */
+       for_each_eth_queue(bp, i) {
+               struct bnx2x_fastpath *fp = &bp->fp[i];
+
+               /* Set the appropriate Queue object */
+               q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
+
+               /* Update the Queue state */
+               rc = bnx2x_queue_state_change(bp, &q_params);
+               if (rc) {
+                       BNX2X_ERR("Failed to enable PTP packets\n");
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+
+int bnx2x_configure_ptp_filters(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+       int rc;
+
+       if (!bp->hwtstamp_ioctl_called)
+               return 0;
+
+       switch (bp->tx_type) {
+       case HWTSTAMP_TX_ON:
+               bp->flags |= TX_TIMESTAMPING_EN;
+               REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_TLLH_PTP_PARAM_MASK, 0x6AA);
+               REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_RULE_MASK :
+                      NIG_REG_P0_TLLH_PTP_RULE_MASK, 0x3EEE);
+               break;
+       case HWTSTAMP_TX_ONESTEP_SYNC:
+               BNX2X_ERR("One-step timestamping is not supported\n");
+               return -ERANGE;
+       }
+
+       switch (bp->rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               break;
+       case HWTSTAMP_FILTER_ALL:
+       case HWTSTAMP_FILTER_SOME:
+               bp->rx_filter = HWTSTAMP_FILTER_NONE;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+               bp->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+               /* Initialize PTP detection for UDP/IPv4 events */
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x7EE);
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+                      NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3FFE);
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+               bp->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+               /* Initialize PTP detection for UDP/IPv4 or UDP/IPv6 events */
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x7EA);
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+                      NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3FEE);
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+               bp->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+               /* Initialize PTP detection L2 events */
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x6BF);
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+                      NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3EFF);
+
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               bp->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+               /* Initialize PTP detection L2, UDP/IPv4 or UDP/IPv6 events */
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x6AA);
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+                      NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3EEE);
+               break;
+       }
+
+       /* Indicate to FW that this PF expects recorded PTP packets */
+       rc = bnx2x_enable_ptp_packets(bp);
+       if (rc)
+               return rc;
+
+       /* Enable sending PTP packets to host */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_TO_HOST :
+              NIG_REG_P0_LLH_PTP_TO_HOST, 0x1);
+
+       return 0;
+}
+
+static int bnx2x_hwtstamp_ioctl(struct bnx2x *bp, struct ifreq *ifr)
+{
+       struct hwtstamp_config config;
+       int rc;
+
+       DP(BNX2X_MSG_PTP, "HWTSTAMP IOCTL called\n");
+
+       if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+               return -EFAULT;
+
+       DP(BNX2X_MSG_PTP, "Requested tx_type: %d, requested rx_filters = %d\n",
+          config.tx_type, config.rx_filter);
+
+       if (config.flags) {
+               BNX2X_ERR("config.flags is reserved for future use\n");
+               return -EINVAL;
+       }
+
+       bp->hwtstamp_ioctl_called = 1;
+       bp->tx_type = config.tx_type;
+       bp->rx_filter = config.rx_filter;
+
+       rc = bnx2x_configure_ptp_filters(bp);
+       if (rc)
+               return rc;
+
+       config.rx_filter = bp->rx_filter;
+
+       return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+               -EFAULT : 0;
+}
+
+/* Configrues HW for PTP */
+static int bnx2x_configure_ptp(struct bnx2x *bp)
+{
+       int rc, port = BP_PORT(bp);
+       u32 wb_data[2];
+
+       /* Reset PTP event detection rules - will be configured in the IOCTL */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+              NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x7FF);
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+              NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3FFF);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_PARAM_MASK :
+              NIG_REG_P0_TLLH_PTP_PARAM_MASK, 0x7FF);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_RULE_MASK :
+              NIG_REG_P0_TLLH_PTP_RULE_MASK, 0x3FFF);
+
+       /* Disable PTP packets to host - will be configured in the IOCTL*/
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_TO_HOST :
+              NIG_REG_P0_LLH_PTP_TO_HOST, 0x0);
+
+       /* Enable the PTP feature */
+       REG_WR(bp, port ? NIG_REG_P1_PTP_EN :
+              NIG_REG_P0_PTP_EN, 0x3F);
+
+       /* Enable the free-running counter */
+       wb_data[0] = 0;
+       wb_data[1] = 0;
+       REG_WR_DMAE(bp, NIG_REG_TIMESYNC_GEN_REG + tsgen_ctrl, wb_data, 2);
+
+       /* Reset drift register (offset register is not reset) */
+       rc = bnx2x_send_reset_timesync_ramrod(bp);
+       if (rc) {
+               BNX2X_ERR("Failed to reset PHC drift register\n");
+               return -EFAULT;
+       }
+
+       /* Reset possibly old timestamps */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_HOST_BUF_SEQID :
+              NIG_REG_P0_LLH_PTP_HOST_BUF_SEQID, 0x10000);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+              NIG_REG_P0_TLLH_PTP_BUF_SEQID, 0x10000);
+
+       return 0;
+}
+
+/* Called during load, to initialize PTP-related stuff */
+void bnx2x_init_ptp(struct bnx2x *bp)
+{
+       int rc;
+
+       /* Configure PTP in HW */
+       rc = bnx2x_configure_ptp(bp);
+       if (rc) {
+               BNX2X_ERR("Stopping PTP initialization\n");
+               return;
+       }
+
+       /* Init work queue for Tx timestamping */
+       INIT_WORK(&bp->ptp_task, bnx2x_ptp_task);
+
+       /* Init cyclecounter and timecounter. This is done only in the first
+        * load. If done in every load, PTP application will fail when doing
+        * unload / load (e.g. MTU change) while it is running.
+        */
+       if (!bp->timecounter_init_done) {
+               bnx2x_init_cyclecounter(bp);
+               timecounter_init(&bp->timecounter, &bp->cyclecounter,
+                                ktime_to_ns(ktime_get_real()));
+               bp->timecounter_init_done = 1;
+       }
+
+       DP(BNX2X_MSG_PTP, "PTP initialization ended successfully\n");
+}
index 2beb5430b876cb8d77cec26661c51140ab2712ed..b0779d773343cbc82aa825eed3024205581ad33f 100644 (file)
 #define NIG_REG_P0_HWPFC_ENABLE                                 0x18078
 #define NIG_REG_P0_LLH_FUNC_MEM2                                0x18480
 #define NIG_REG_P0_LLH_FUNC_MEM2_ENABLE                         0x18440
+/* [RW 17] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. Bits [15:0] return the sequence ID of the packet. Bit 16
+ * indicates the validity of the data in the buffer. Writing a 1 to bit 16
+ * will clear the buffer.
+ */
+#define NIG_REG_P0_LLH_PTP_HOST_BUF_SEQID                       0x1875c
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. This location returns the lower 32 bits of timestamp value.
+ */
+#define NIG_REG_P0_LLH_PTP_HOST_BUF_TS_LSB                      0x18754
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. This location returns the upper 32 bits of timestamp value.
+ */
+#define NIG_REG_P0_LLH_PTP_HOST_BUF_TS_MSB                      0x18758
+/* [RW 11] Mask register for the various parameters used in determining PTP
+ * packet presence. Set each bit to 1 to mask out the particular parameter.
+ * 0-IPv4 DA 0 of 224.0.1.129. 1-IPv4 DA 1 of 224.0.0.107. 2-IPv6 DA 0 of
+ * 0xFF0*:0:0:0:0:0:0:181. 3-IPv6 DA 1 of 0xFF02:0:0:0:0:0:0:6B. 4-UDP
+ * destination port 0 of 319. 5-UDP destination port 1 of 320. 6-MAC
+ * Ethertype 0 of 0x88F7. 7-configurable MAC Ethertype 1. 8-MAC DA 0 of
+ * 0x01-1B-19-00-00-00. 9-MAC DA 1 of 0x01-80-C2-00-00-0E. 10-configurable
+ * MAC DA 2. The reset default is set to mask out all parameters.
+ */
+#define NIG_REG_P0_LLH_PTP_PARAM_MASK                           0x187a0
+/* [RW 14] Mask regiser for the rules used in detecting PTP packets. Set
+ * each bit to 1 to mask out that particular rule. 0-{IPv4 DA 0; UDP DP 0} .
+ * 1-{IPv4 DA 0; UDP DP 1} . 2-{IPv4 DA 1; UDP DP 0} . 3-{IPv4 DA 1; UDP DP
+ * 1} . 4-{IPv6 DA 0; UDP DP 0} . 5-{IPv6 DA 0; UDP DP 1} . 6-{IPv6 DA 1;
+ * UDP DP 0} . 7-{IPv6 DA 1; UDP DP 1} . 8-{MAC DA 0; Ethertype 0} . 9-{MAC
+ * DA 1; Ethertype 0} . 10-{MAC DA 0; Ethertype 1} . 11-{MAC DA 1; Ethertype
+ * 1} . 12-{MAC DA 2; Ethertype 0} . 13-{MAC DA 2; Ethertype 1} . The reset
+ * default is to mask out all of the rules. Note that rules 0-3 are for IPv4
+ * packets only and require that the packet is IPv4 for the rules to match.
+ * Note that rules 4-7 are for IPv6 packets only and require that the packet
+ * is IPv6 for the rules to match.
+ */
+#define NIG_REG_P0_LLH_PTP_RULE_MASK                            0x187a4
+/* [RW 1] Set to 1 to enable PTP packets to be forwarded to the host. */
+#define NIG_REG_P0_LLH_PTP_TO_HOST                              0x187ac
 /* [RW 1] Input enable for RX MAC interface. */
 #define NIG_REG_P0_MAC_IN_EN                                    0x185ac
 /* [RW 1] Output enable for TX MAC interface */
  * priority field is extracted from the outer-most VLAN in receive packet.
  * Only COS 0 and COS 1 are supported in E2. */
 #define NIG_REG_P0_PKT_PRIORITY_TO_COS                          0x18054
+/* [RW 6] Enable for TimeSync feature. Bits [2:0] are for RX side. Bits
+ * [5:3] are for TX side. Bit 0 enables TimeSync on RX side. Bit 1 enables
+ * V1 frame format in timesync event detection on RX side. Bit 2 enables V2
+ * frame format in timesync event detection on RX side. Bit 3 enables
+ * TimeSync on TX side. Bit 4 enables V1 frame format in timesync event
+ * detection on TX side. Bit 5 enables V2 frame format in timesync event
+ * detection on TX side. Note that for HW to detect PTP packet and extract
+ * data from the packet, at least one of the version bits of that traffic
+ * direction has to be enabled.
+ */
+#define NIG_REG_P0_PTP_EN                                       0x18788
 /* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 0. A
  * priority is mapped to COS 0 when the corresponding mask bit is 1. More
  * than one bit may be set; allowing multiple priorities to be mapped to one
  * Ethernet header. */
 #define NIG_REG_P1_HDRS_AFTER_BASIC                             0x1818c
 #define NIG_REG_P1_LLH_FUNC_MEM2                                0x184c0
-#define NIG_REG_P1_LLH_FUNC_MEM2_ENABLE                         0x18460
+#define NIG_REG_P1_LLH_FUNC_MEM2_ENABLE                         0x18460a
+/* [RW 17] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. Bits [15:0] return the sequence ID of the packet. Bit 16
+ * indicates the validity of the data in the buffer. Writing a 1 to bit 16
+ * will clear the buffer.
+ */
+#define NIG_REG_P1_LLH_PTP_HOST_BUF_SEQID                       0x18774
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. This location returns the lower 32 bits of timestamp value.
+ */
+#define NIG_REG_P1_LLH_PTP_HOST_BUF_TS_LSB                      0x1876c
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. This location returns the upper 32 bits of timestamp value.
+ */
+#define NIG_REG_P1_LLH_PTP_HOST_BUF_TS_MSB                      0x18770
+/* [RW 11] Mask register for the various parameters used in determining PTP
+ * packet presence. Set each bit to 1 to mask out the particular parameter.
+ * 0-IPv4 DA 0 of 224.0.1.129. 1-IPv4 DA 1 of 224.0.0.107. 2-IPv6 DA 0 of
+ * 0xFF0*:0:0:0:0:0:0:181. 3-IPv6 DA 1 of 0xFF02:0:0:0:0:0:0:6B. 4-UDP
+ * destination port 0 of 319. 5-UDP destination port 1 of 320. 6-MAC
+ * Ethertype 0 of 0x88F7. 7-configurable MAC Ethertype 1. 8-MAC DA 0 of
+ * 0x01-1B-19-00-00-00. 9-MAC DA 1 of 0x01-80-C2-00-00-0E. 10-configurable
+ * MAC DA 2. The reset default is set to mask out all parameters.
+ */
+#define NIG_REG_P1_LLH_PTP_PARAM_MASK                           0x187c8
+/* [RW 14] Mask regiser for the rules used in detecting PTP packets. Set
+ * each bit to 1 to mask out that particular rule. 0-{IPv4 DA 0; UDP DP 0} .
+ * 1-{IPv4 DA 0; UDP DP 1} . 2-{IPv4 DA 1; UDP DP 0} . 3-{IPv4 DA 1; UDP DP
+ * 1} . 4-{IPv6 DA 0; UDP DP 0} . 5-{IPv6 DA 0; UDP DP 1} . 6-{IPv6 DA 1;
+ * UDP DP 0} . 7-{IPv6 DA 1; UDP DP 1} . 8-{MAC DA 0; Ethertype 0} . 9-{MAC
+ * DA 1; Ethertype 0} . 10-{MAC DA 0; Ethertype 1} . 11-{MAC DA 1; Ethertype
+ * 1} . 12-{MAC DA 2; Ethertype 0} . 13-{MAC DA 2; Ethertype 1} . The reset
+ * default is to mask out all of the rules. Note that rules 0-3 are for IPv4
+ * packets only and require that the packet is IPv4 for the rules to match.
+ * Note that rules 4-7 are for IPv6 packets only and require that the packet
+ * is IPv6 for the rules to match.
+ */
+#define NIG_REG_P1_LLH_PTP_RULE_MASK                            0x187cc
+/* [RW 1] Set to 1 to enable PTP packets to be forwarded to the host. */
+#define NIG_REG_P1_LLH_PTP_TO_HOST                              0x187d4
 /* [RW 32] Specify the client number to be assigned to each priority of the
  * strict priority arbiter. This register specifies bits 31:0 of the 36-bit
  * value. Priority 0 is the highest priority. Bits [3:0] are for priority 0
  * priority field is extracted from the outer-most VLAN in receive packet.
  * Only COS 0 and COS 1 are supported in E2. */
 #define NIG_REG_P1_PKT_PRIORITY_TO_COS                          0x181a8
+/* [RW 6] Enable for TimeSync feature. Bits [2:0] are for RX side. Bits
+ * [5:3] are for TX side. Bit 0 enables TimeSync on RX side. Bit 1 enables
+ * V1 frame format in timesync event detection on RX side. Bit 2 enables V2
+ * frame format in timesync event detection on RX side. Bit 3 enables
+ * TimeSync on TX side. Bit 4 enables V1 frame format in timesync event
+ * detection on TX side. Bit 5 enables V2 frame format in timesync event
+ * detection on TX side. Note that for HW to detect PTP packet and extract
+ * data from the packet, at least one of the version bits of that traffic
+ * direction has to be enabled.
+ */
+#define NIG_REG_P1_PTP_EN                                       0x187b0
 /* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 0. A
  * priority is mapped to COS 0 when the corresponding mask bit is 1. More
  * than one bit may be set; allowing multiple priorities to be mapped to one
 #define NIG_REG_P1_RX_MACFIFO_EMPTY                             0x1858c
 /* [R 1] TLLH FIFO is empty. */
 #define NIG_REG_P1_TLLH_FIFO_EMPTY                              0x18338
+/* [RW 19] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * TX side. Bits [15:0] reflect the sequence ID of the packet. Bit 16
+ * indicates the validity of the data in the buffer. Bit 17 indicates that
+ * the sequence ID is valid and it is waiting for the TX timestamp value.
+ * Bit 18 indicates whether the timestamp is from a SW request (value of 1)
+ * or HW request (value of 0). Writing a 1 to bit 16 will clear the buffer.
+ */
+#define NIG_REG_P0_TLLH_PTP_BUF_SEQID                           0x187e0
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * MCP. This location returns the lower 32 bits of timestamp value.
+ */
+#define NIG_REG_P0_TLLH_PTP_BUF_TS_LSB                          0x187d8
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * MCP. This location returns the upper 32 bits of timestamp value.
+ */
+#define NIG_REG_P0_TLLH_PTP_BUF_TS_MSB                          0x187dc
+/* [RW 11] Mask register for the various parameters used in determining PTP
+ * packet presence. Set each bit to 1 to mask out the particular parameter.
+ * 0-IPv4 DA 0 of 224.0.1.129. 1-IPv4 DA 1 of 224.0.0.107. 2-IPv6 DA 0 of
+ * 0xFF0*:0:0:0:0:0:0:181. 3-IPv6 DA 1 of 0xFF02:0:0:0:0:0:0:6B. 4-UDP
+ * destination port 0 of 319. 5-UDP destination port 1 of 320. 6-MAC
+ * Ethertype 0 of 0x88F7. 7-configurable MAC Ethertype 1. 8-MAC DA 0 of
+ * 0x01-1B-19-00-00-00. 9-MAC DA 1 of 0x01-80-C2-00-00-0E. 10-configurable
+ * MAC DA 2. The reset default is set to mask out all parameters.
+ */
+#define NIG_REG_P0_TLLH_PTP_PARAM_MASK                          0x187f0
+/* [RW 14] Mask regiser for the rules used in detecting PTP packets. Set
+ * each bit to 1 to mask out that particular rule. 0-{IPv4 DA 0; UDP DP 0} .
+ * 1-{IPv4 DA 0; UDP DP 1} . 2-{IPv4 DA 1; UDP DP 0} . 3-{IPv4 DA 1; UDP DP
+ * 1} . 4-{IPv6 DA 0; UDP DP 0} . 5-{IPv6 DA 0; UDP DP 1} . 6-{IPv6 DA 1;
+ * UDP DP 0} . 7-{IPv6 DA 1; UDP DP 1} . 8-{MAC DA 0; Ethertype 0} . 9-{MAC
+ * DA 1; Ethertype 0} . 10-{MAC DA 0; Ethertype 1} . 11-{MAC DA 1; Ethertype
+ * 1} . 12-{MAC DA 2; Ethertype 0} . 13-{MAC DA 2; Ethertype 1} . The reset
+ * default is to mask out all of the rules.
+ */
+#define NIG_REG_P0_TLLH_PTP_RULE_MASK                           0x187f4
+/* [RW 19] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * TX side. Bits [15:0] reflect the sequence ID of the packet. Bit 16
+ * indicates the validity of the data in the buffer. Bit 17 indicates that
+ * the sequence ID is valid and it is waiting for the TX timestamp value.
+ * Bit 18 indicates whether the timestamp is from a SW request (value of 1)
+ * or HW request (value of 0). Writing a 1 to bit 16 will clear the buffer.
+ */
+#define NIG_REG_P1_TLLH_PTP_BUF_SEQID                           0x187ec
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * MCP. This location returns the lower 32 bits of timestamp value.
+ */
+#define NIG_REG_P1_TLLH_PTP_BUF_TS_LSB                          0x187e4
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * MCP. This location returns the upper 32 bits of timestamp value.
+ */
+#define NIG_REG_P1_TLLH_PTP_BUF_TS_MSB                          0x187e8
+/* [RW 11] Mask register for the various parameters used in determining PTP
+ * packet presence. Set each bit to 1 to mask out the particular parameter.
+ * 0-IPv4 DA 0 of 224.0.1.129. 1-IPv4 DA 1 of 224.0.0.107. 2-IPv6 DA 0 of
+ * 0xFF0*:0:0:0:0:0:0:181. 3-IPv6 DA 1 of 0xFF02:0:0:0:0:0:0:6B. 4-UDP
+ * destination port 0 of 319. 5-UDP destination port 1 of 320. 6-MAC
+ * Ethertype 0 of 0x88F7. 7-configurable MAC Ethertype 1. 8-MAC DA 0 of
+ * 0x01-1B-19-00-00-00. 9-MAC DA 1 of 0x01-80-C2-00-00-0E. 10-configurable
+ * MAC DA 2. The reset default is set to mask out all parameters.
+ */
+#define NIG_REG_P1_TLLH_PTP_PARAM_MASK                          0x187f8
+/* [RW 14] Mask regiser for the rules used in detecting PTP packets. Set
+ * each bit to 1 to mask out that particular rule. 0-{IPv4 DA 0; UDP DP 0} .
+ * 1-{IPv4 DA 0; UDP DP 1} . 2-{IPv4 DA 1; UDP DP 0} . 3-{IPv4 DA 1; UDP DP
+ * 1} . 4-{IPv6 DA 0; UDP DP 0} . 5-{IPv6 DA 0; UDP DP 1} . 6-{IPv6 DA 1;
+ * UDP DP 0} . 7-{IPv6 DA 1; UDP DP 1} . 8-{MAC DA 0; Ethertype 0} . 9-{MAC
+ * DA 1; Ethertype 0} . 10-{MAC DA 0; Ethertype 1} . 11-{MAC DA 1; Ethertype
+ * 1} . 12-{MAC DA 2; Ethertype 0} . 13-{MAC DA 2; Ethertype 1} . The reset
+ * default is to mask out all of the rules.
+ */
+#define NIG_REG_P1_TLLH_PTP_RULE_MASK                           0x187fc
 /* [RW 32] Specify which of the credit registers the client is to be mapped
  * to. This register specifies bits 31:0 of the 36-bit value. Bits[3:0] are
  * for client 0; bits [35:32] are for client 8. For clients that are not
    swap is equal to SPIO pin that inputs from ifmux_serdes_swap. If 1 then
    ort swap is equal to ~nig_registers_port_swap.port_swap */
 #define NIG_REG_STRAP_OVERRIDE                                  0x10398
+/* [WB 64] Addresses for TimeSync related registers in the timesync
+ * generator sub-module.
+ */
+#define NIG_REG_TIMESYNC_GEN_REG                                0x18800
 /* [RW 1] output enable for RX_XCM0 IF */
 #define NIG_REG_XCM0_OUT_EN                                     0x100f0
 /* [RW 1] output enable for RX_XCM1 IF */
index b1936044767aca73bc494609095ae2cc4fef55f0..19d0c1152434e4d8e75a71510dadae8e16c25ae1 100644 (file)
@@ -4019,6 +4019,7 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
        struct bnx2x_raw_obj *r = &o->raw;
        struct eth_rss_update_ramrod_data *data =
                (struct eth_rss_update_ramrod_data *)(r->rdata);
+       u16 caps = 0;
        u8 rss_mode = 0;
        int rc;
 
@@ -4042,28 +4043,34 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
 
        /* RSS capabilities */
        if (test_bit(BNX2X_RSS_IPV4, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV4_TCP, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV4_UDP, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV6, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV6_TCP, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV6_UDP, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY;
+
+       if (test_bit(BNX2X_RSS_GRE_INNER_HDRS, &p->rss_flags))
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY;
+
+       /* RSS keys */
+       if (test_bit(BNX2X_RSS_SET_SRCH, &p->rss_flags)) {
+               memcpy(&data->rss_key[0], &p->rss_key[0],
+                      sizeof(data->rss_key));
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY;
+       }
+
+       data->capabilities = cpu_to_le16(caps);
 
        /* Hashing mask */
        data->rss_result_mask = p->rss_result_mask;
@@ -4084,13 +4091,6 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
        if (netif_msg_ifup(bp))
                bnx2x_debug_print_ind_table(bp, p);
 
-       /* RSS keys */
-       if (test_bit(BNX2X_RSS_SET_SRCH, &p->rss_flags)) {
-               memcpy(&data->rss_key[0], &p->rss_key[0],
-                      sizeof(data->rss_key));
-               data->capabilities |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY;
-       }
-
        /* No need for an explicit memory barrier here as long as we
         * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
@@ -4336,6 +4336,8 @@ static void bnx2x_q_fill_init_general_data(struct bnx2x *bp,
                test_bit(BNX2X_Q_FLG_FCOE, flags) ?
                LLFC_TRAFFIC_TYPE_FCOE : LLFC_TRAFFIC_TYPE_NW;
 
+       gen_data->fp_hsi_ver = ETH_FP_HSI_VERSION;
+
        DP(BNX2X_MSG_SP, "flags: active %d, cos %d, stats en %d\n",
           gen_data->activate_flg, gen_data->cos, gen_data->statistics_en_flg);
 }
@@ -4357,12 +4359,13 @@ static void bnx2x_q_fill_init_tx_data(struct bnx2x_queue_sp_obj *o,
                test_bit(BNX2X_Q_FLG_ANTI_SPOOF, flags);
        tx_data->force_default_pri_flg =
                test_bit(BNX2X_Q_FLG_FORCE_DEFAULT_PRI, flags);
-
+       tx_data->refuse_outband_vlan_flg =
+               test_bit(BNX2X_Q_FLG_REFUSE_OUTBAND_VLAN, flags);
        tx_data->tunnel_lso_inc_ip_id =
                test_bit(BNX2X_Q_FLG_TUN_INC_INNER_IP_ID, flags);
        tx_data->tunnel_non_lso_pcsum_location =
-               test_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, flags) ? PCSUM_ON_PKT :
-                                                                 PCSUM_ON_BD;
+               test_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, flags) ? CSUM_ON_PKT :
+                                                           CSUM_ON_BD;
 
        tx_data->tx_status_block_id = params->fw_sb_id;
        tx_data->tx_sb_index_number = params->sb_cq_index;
@@ -4722,6 +4725,12 @@ static void bnx2x_q_fill_update_data(struct bnx2x *bp,
        data->tx_switching_change_flg =
                test_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
                         &params->update_flags);
+
+       /* PTP */
+       data->handle_ptp_pkts_flg =
+               test_bit(BNX2X_Q_UPDATE_PTP_PKTS, &params->update_flags);
+       data->handle_ptp_pkts_change_flg =
+               test_bit(BNX2X_Q_UPDATE_PTP_PKTS_CHNG, &params->update_flags);
 }
 
 static inline int bnx2x_q_send_update(struct bnx2x *bp,
@@ -5376,6 +5385,10 @@ static int bnx2x_func_chk_transition(struct bnx2x *bp,
                         (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
                        next_state = BNX2X_F_STATE_STARTED;
 
+               else if ((cmd == BNX2X_F_CMD_SET_TIMESYNC) &&
+                        (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
+                       next_state = BNX2X_F_STATE_STARTED;
+
                else if (cmd == BNX2X_F_CMD_TX_STOP)
                        next_state = BNX2X_F_STATE_TX_STOPPED;
 
@@ -5385,6 +5398,10 @@ static int bnx2x_func_chk_transition(struct bnx2x *bp,
                    (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
                        next_state = BNX2X_F_STATE_TX_STOPPED;
 
+               else if ((cmd == BNX2X_F_CMD_SET_TIMESYNC) &&
+                        (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
+                       next_state = BNX2X_F_STATE_TX_STOPPED;
+
                else if (cmd == BNX2X_F_CMD_TX_START)
                        next_state = BNX2X_F_STATE_STARTED;
 
@@ -5652,8 +5669,11 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp,
        rdata->sd_vlan_tag      = cpu_to_le16(start_params->sd_vlan_tag);
        rdata->path_id          = BP_PATH(bp);
        rdata->network_cos_mode = start_params->network_cos_mode;
-       rdata->gre_tunnel_mode  = start_params->gre_tunnel_mode;
-       rdata->gre_tunnel_rss   = start_params->gre_tunnel_rss;
+       rdata->tunnel_mode      = start_params->tunnel_mode;
+       rdata->gre_tunnel_type  = start_params->gre_tunnel_type;
+       rdata->inner_gre_rss_en = start_params->inner_gre_rss_en;
+       rdata->vxlan_dst_port   = cpu_to_le16(4789);
+       rdata->sd_vlan_eth_type = cpu_to_le16(0x8100);
 
        /* No need for an explicit memory barrier here as long we would
         * need to ensure the ordering of writing to the SPQ element
@@ -5680,8 +5700,28 @@ static inline int bnx2x_func_send_switch_update(struct bnx2x *bp,
        memset(rdata, 0, sizeof(*rdata));
 
        /* Fill the ramrod data with provided parameters */
-       rdata->tx_switch_suspend_change_flg = 1;
-       rdata->tx_switch_suspend = switch_update_params->suspend;
+       if (test_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND_CHNG,
+                    &switch_update_params->changes)) {
+               rdata->tx_switch_suspend_change_flg = 1;
+               rdata->tx_switch_suspend =
+                       test_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND,
+                                &switch_update_params->changes);
+       }
+
+       if (test_bit(BNX2X_F_UPDATE_TUNNEL_CFG_CHNG,
+                    &switch_update_params->changes)) {
+               rdata->update_tunn_cfg_flg = 1;
+               if (test_bit(BNX2X_F_UPDATE_TUNNEL_CLSS_EN,
+                            &switch_update_params->changes))
+                       rdata->tunn_clss_en = 1;
+               if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_GRE_RSS_EN,
+                            &switch_update_params->changes))
+                       rdata->inner_gre_rss_en = 1;
+               rdata->tunnel_mode = switch_update_params->tunnel_mode;
+               rdata->gre_tunnel_type = switch_update_params->gre_tunnel_type;
+               rdata->vxlan_dst_port = cpu_to_le16(4789);
+       }
+
        rdata->echo = SWITCH_UPDATE;
 
        /* No need for an explicit memory barrier here as long as we
@@ -5817,6 +5857,42 @@ static inline int bnx2x_func_send_tx_start(struct bnx2x *bp,
                             U64_LO(data_mapping), NONE_CONNECTION_TYPE);
 }
 
+static inline
+int bnx2x_func_send_set_timesync(struct bnx2x *bp,
+                                struct bnx2x_func_state_params *params)
+{
+       struct bnx2x_func_sp_obj *o = params->f_obj;
+       struct set_timesync_ramrod_data *rdata =
+               (struct set_timesync_ramrod_data *)o->rdata;
+       dma_addr_t data_mapping = o->rdata_mapping;
+       struct bnx2x_func_set_timesync_params *set_timesync_params =
+               &params->params.set_timesync;
+
+       memset(rdata, 0, sizeof(*rdata));
+
+       /* Fill the ramrod data with provided parameters */
+       rdata->drift_adjust_cmd = set_timesync_params->drift_adjust_cmd;
+       rdata->offset_cmd = set_timesync_params->offset_cmd;
+       rdata->add_sub_drift_adjust_value =
+               set_timesync_params->add_sub_drift_adjust_value;
+       rdata->drift_adjust_value = set_timesync_params->drift_adjust_value;
+       rdata->drift_adjust_period = set_timesync_params->drift_adjust_period;
+       rdata->offset_delta.lo =
+               cpu_to_le32(U64_LO(set_timesync_params->offset_delta));
+       rdata->offset_delta.hi =
+               cpu_to_le32(U64_HI(set_timesync_params->offset_delta));
+
+       DP(BNX2X_MSG_SP, "Set timesync command params: drift_cmd = %d, offset_cmd = %d, add_sub_drift = %d, drift_val = %d, drift_period = %d, offset_lo = %d, offset_hi = %d\n",
+          rdata->drift_adjust_cmd, rdata->offset_cmd,
+          rdata->add_sub_drift_adjust_value, rdata->drift_adjust_value,
+          rdata->drift_adjust_period, rdata->offset_delta.lo,
+          rdata->offset_delta.hi);
+
+       return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_TIMESYNC, 0,
+                            U64_HI(data_mapping),
+                            U64_LO(data_mapping), NONE_CONNECTION_TYPE);
+}
+
 static int bnx2x_func_send_cmd(struct bnx2x *bp,
                               struct bnx2x_func_state_params *params)
 {
@@ -5839,6 +5915,8 @@ static int bnx2x_func_send_cmd(struct bnx2x *bp,
                return bnx2x_func_send_tx_start(bp, params);
        case BNX2X_F_CMD_SWITCH_UPDATE:
                return bnx2x_func_send_switch_update(bp, params);
+       case BNX2X_F_CMD_SET_TIMESYNC:
+               return bnx2x_func_send_set_timesync(bp, params);
        default:
                BNX2X_ERR("Unknown command: %d\n", params->cmd);
                return -EINVAL;
index 718ecd2946616195cc92d53bd2f6498d525f14fe..21c8f6fb89e557b6ac98748c6c3a14943e584f70 100644 (file)
@@ -711,6 +711,7 @@ enum {
        BNX2X_RSS_IPV6,
        BNX2X_RSS_IPV6_TCP,
        BNX2X_RSS_IPV6_UDP,
+       BNX2X_RSS_GRE_INNER_HDRS,
 };
 
 struct bnx2x_config_rss_params {
@@ -769,7 +770,9 @@ enum {
        BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG,
        BNX2X_Q_UPDATE_SILENT_VLAN_REM,
        BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
-       BNX2X_Q_UPDATE_TX_SWITCHING
+       BNX2X_Q_UPDATE_TX_SWITCHING,
+       BNX2X_Q_UPDATE_PTP_PKTS_CHNG,
+       BNX2X_Q_UPDATE_PTP_PKTS,
 };
 
 /* Allowed Queue states */
@@ -831,6 +834,7 @@ enum {
        BNX2X_Q_FLG_ANTI_SPOOF,
        BNX2X_Q_FLG_SILENT_VLAN_REM,
        BNX2X_Q_FLG_FORCE_DEFAULT_PRI,
+       BNX2X_Q_FLG_REFUSE_OUTBAND_VLAN,
        BNX2X_Q_FLG_PCSUM_ON_PKT,
        BNX2X_Q_FLG_TUN_INC_INNER_IP_ID
 };
@@ -851,6 +855,10 @@ enum bnx2x_q_type {
 #define BNX2X_MULTI_TX_COS                     3 /* Maximum possible */
 
 #define MAC_PAD (ALIGN(ETH_ALEN, sizeof(u32)) - ETH_ALEN)
+/* DMAE channel to be used by FW for timesync workaroun. A driver that sends
+ * timesync-related ramrods must not use this DMAE command ID.
+ */
+#define FW_DMAE_CMD_ID 6
 
 struct bnx2x_queue_init_params {
        struct {
@@ -1085,6 +1093,16 @@ struct bnx2x_queue_sp_obj {
 };
 
 /********************** Function state update *********************************/
+
+/* UPDATE command options */
+enum {
+       BNX2X_F_UPDATE_TX_SWITCH_SUSPEND_CHNG,
+       BNX2X_F_UPDATE_TX_SWITCH_SUSPEND,
+       BNX2X_F_UPDATE_TUNNEL_CFG_CHNG,
+       BNX2X_F_UPDATE_TUNNEL_CLSS_EN,
+       BNX2X_F_UPDATE_TUNNEL_INNER_GRE_RSS_EN,
+};
+
 /* Allowed Function states */
 enum bnx2x_func_state {
        BNX2X_F_STATE_RESET,
@@ -1105,6 +1123,7 @@ enum bnx2x_func_cmd {
        BNX2X_F_CMD_TX_STOP,
        BNX2X_F_CMD_TX_START,
        BNX2X_F_CMD_SWITCH_UPDATE,
+       BNX2X_F_CMD_SET_TIMESYNC,
        BNX2X_F_CMD_MAX,
 };
 
@@ -1146,18 +1165,25 @@ struct bnx2x_func_start_params {
        /* Function cos mode */
        u8 network_cos_mode;
 
-       /* NVGRE classification enablement */
-       u8 nvgre_clss_en;
+       /* TUNN_MODE_NONE/TUNN_MODE_VXLAN/TUNN_MODE_GRE */
+       u8 tunnel_mode;
 
-       /* NO_GRE_TUNNEL/NVGRE_TUNNEL/L2GRE_TUNNEL/IPGRE_TUNNEL */
-       u8 gre_tunnel_mode;
+       /* tunneling classification enablement */
+       u8 tunn_clss_en;
 
-       /* GRE_OUTER_HEADERS_RSS/GRE_INNER_HEADERS_RSS/NVGRE_KEY_ENTROPY_RSS */
-       u8 gre_tunnel_rss;
+       /* NVGRE_TUNNEL/L2GRE_TUNNEL/IPGRE_TUNNEL */
+       u8 gre_tunnel_type;
+
+       /* Enables Inner GRE RSS on the function, depends on the client RSS
+        * capailities
+        */
+       u8 inner_gre_rss_en;
 };
 
 struct bnx2x_func_switch_update_params {
-       u8 suspend;
+       unsigned long changes; /* BNX2X_F_UPDATE_XX bits */
+       u8 tunnel_mode;
+       u8 gre_tunnel_type;
 };
 
 struct bnx2x_func_afex_update_params {
@@ -1172,6 +1198,7 @@ struct bnx2x_func_afex_viflists_params {
        u8 afex_vif_list_command;
        u8 func_to_clear;
 };
+
 struct bnx2x_func_tx_start_params {
        struct priority_cos traffic_type_to_priority_cos[MAX_TRAFFIC_TYPES];
        u8 dcb_enabled;
@@ -1179,6 +1206,24 @@ struct bnx2x_func_tx_start_params {
        u8 dont_add_pri_0_en;
 };
 
+struct bnx2x_func_set_timesync_params {
+       /* Reset, set or keep the current drift value */
+       u8 drift_adjust_cmd;
+
+       /* Dec, inc or keep the current offset */
+       u8 offset_cmd;
+
+       /* Drift value direction */
+       u8 add_sub_drift_adjust_value;
+
+       /* Drift, period and offset values to be used according to the commands
+        * above.
+        */
+       u8 drift_adjust_value;
+       u32 drift_adjust_period;
+       u64 offset_delta;
+};
+
 struct bnx2x_func_state_params {
        struct bnx2x_func_sp_obj *f_obj;
 
@@ -1197,6 +1242,7 @@ struct bnx2x_func_state_params {
                struct bnx2x_func_afex_update_params afex_update;
                struct bnx2x_func_afex_viflists_params afex_viflists;
                struct bnx2x_func_tx_start_params tx_start;
+               struct bnx2x_func_set_timesync_params set_timesync;
        } params;
 };
 
index 662310c5f4e98c4f7d7cdda3d0062969f13ddd5b..c88b20af87dff2e6613215520eeff5920b438b0f 100644 (file)
@@ -1125,7 +1125,7 @@ static int bnx2x_ari_enabled(struct pci_dev *dev)
        return dev->bus->self && dev->bus->self->ari_enabled;
 }
 
-static void
+static int
 bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
 {
        int sb_id;
@@ -1150,6 +1150,7 @@ bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
                   GET_FIELD((val), IGU_REG_MAPPING_MEMORY_VECTOR));
        }
        DP(BNX2X_MSG_IOV, "vf_sbs_pool is %d\n", BP_VFDB(bp)->vf_sbs_pool);
+       return BP_VFDB(bp)->vf_sbs_pool;
 }
 
 static void __bnx2x_iov_free_vfdb(struct bnx2x *bp)
@@ -1314,15 +1315,17 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
        }
 
        /* re-read the IGU CAM for VFs - index and abs_vfid must be set */
-       bnx2x_get_vf_igu_cam_info(bp);
+       if (!bnx2x_get_vf_igu_cam_info(bp)) {
+               BNX2X_ERR("No entries in IGU CAM for vfs\n");
+               err = -EINVAL;
+               goto failed;
+       }
 
        /* allocate the queue arrays for all VFs */
        bp->vfdb->vfqs = kzalloc(
                BNX2X_MAX_NUM_VF_QUEUES * sizeof(struct bnx2x_vf_queue),
                GFP_KERNEL);
 
-       DP(BNX2X_MSG_IOV, "bp->vfdb->vfqs was %p\n", bp->vfdb->vfqs);
-
        if (!bp->vfdb->vfqs) {
                BNX2X_ERR("failed to allocate vf queue array\n");
                err = -ENOMEM;
@@ -1349,9 +1352,7 @@ void bnx2x_iov_remove_one(struct bnx2x *bp)
        if (!IS_SRIOV(bp))
                return;
 
-       DP(BNX2X_MSG_IOV, "about to call disable sriov\n");
-       pci_disable_sriov(bp->pdev);
-       DP(BNX2X_MSG_IOV, "sriov disabled\n");
+       bnx2x_disable_sriov(bp);
 
        /* disable access to all VFs */
        for (vf_idx = 0; vf_idx < bp->vfdb->sriov.total; vf_idx++) {
@@ -1985,21 +1986,6 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
        bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
 }
 
-static inline
-struct bnx2x_virtf *__vf_from_stat_id(struct bnx2x *bp, u8 stat_id)
-{
-       int i;
-       struct bnx2x_virtf *vf = NULL;
-
-       for_each_vf(bp, i) {
-               vf = BP_VF(bp, i);
-               if (stat_id >= vf->igu_base_id &&
-                   stat_id < vf->igu_base_id + vf_sb_count(vf))
-                       break;
-       }
-       return vf;
-}
-
 /* VF API helpers */
 static void bnx2x_vf_qtbl_set_q(struct bnx2x *bp, u8 abs_vfid, u8 qid,
                                u8 enable)
@@ -2362,12 +2348,6 @@ int bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
        return rc;
 }
 
-static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp,
-                             struct bnx2x_virtf *vf, u32 *sbdf)
-{
-       *sbdf = vf->devfn | (vf->bus << 8);
-}
-
 void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
                              enum channel_tlvs tlv)
 {
@@ -2416,7 +2396,7 @@ void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
 
        /* log the unlock */
        DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel unlocked by %d\n",
-          vf->abs_vfid, vf->op_current);
+          vf->abs_vfid, current_tlv);
 }
 
 static int bnx2x_set_pf_tx_switching(struct bnx2x *bp, bool enable)
@@ -2501,7 +2481,7 @@ int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param)
        bp->requested_nr_virtfn = num_vfs_param;
        if (num_vfs_param == 0) {
                bnx2x_set_pf_tx_switching(bp, false);
-               pci_disable_sriov(dev);
+               bnx2x_disable_sriov(bp);
                return 0;
        } else {
                return bnx2x_enable_sriov(bp);
@@ -2614,6 +2594,12 @@ void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp)
 
 void bnx2x_disable_sriov(struct bnx2x *bp)
 {
+       if (pci_vfs_assigned(bp->pdev)) {
+               DP(BNX2X_MSG_IOV,
+                  "Unloading driver while VFs are assigned - VFs will not be deallocated\n");
+               return;
+       }
+
        pci_disable_sriov(bp->pdev);
 }
 
@@ -2628,7 +2614,7 @@ static int bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx,
        }
 
        if (!IS_SRIOV(bp)) {
-               BNX2X_ERR("sriov is disabled - can't utilize iov-realted functionality\n");
+               BNX2X_ERR("sriov is disabled - can't utilize iov-related functionality\n");
                return -EINVAL;
        }
 
index ca1055f3d8afda852f10412d2f551cc05b257848..01bafa4ac04589364ef092e2bd5a31231e42a5f7 100644 (file)
@@ -299,7 +299,8 @@ struct bnx2x_vfdb {
 #define BP_VFDB(bp)            ((bp)->vfdb)
        /* vf array */
        struct bnx2x_virtf      *vfs;
-#define BP_VF(bp, idx)         (&((bp)->vfdb->vfs[idx]))
+#define BP_VF(bp, idx)         ((BP_VFDB(bp) && (bp)->vfdb->vfs) ? \
+                                       &((bp)->vfdb->vfs[idx]) : NULL)
 #define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[idx].var)
 
        /* queue array - for all vfs */
index ca47665f94bf76fd6c9b2c1eb920b5aba7743124..d1608297c773746237a8faf3697277afcbe45918 100644 (file)
@@ -137,7 +137,7 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
                        cpu_to_le16(bp->stats_counter++);
 
                DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
-                       bp->fw_stats_req->hdr.drv_stats_counter);
+                  le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter));
 
                /* adjust the ramrod to include VF queues statistics */
                bnx2x_iov_adjust_stats_req(bp);
@@ -200,7 +200,7 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp)
        }
 }
 
-static int bnx2x_stats_comp(struct bnx2x *bp)
+static void bnx2x_stats_comp(struct bnx2x *bp)
 {
        u32 *stats_comp = bnx2x_sp(bp, stats_comp);
        int cnt = 10;
@@ -214,7 +214,6 @@ static int bnx2x_stats_comp(struct bnx2x *bp)
                cnt--;
                usleep_range(1000, 2000);
        }
-       return 1;
 }
 
 /*
@@ -1630,6 +1629,11 @@ void bnx2x_stats_init(struct bnx2x *bp)
        int /*abs*/port = BP_PORT(bp);
        int mb_idx = BP_FW_MB_IDX(bp);
 
+       if (IS_VF(bp)) {
+               bnx2x_memset_stats(bp);
+               return;
+       }
+
        bp->stats_pending = 0;
        bp->executer_idx = 0;
        bp->stats_counter = 0;
index 54e0427a9ee601b2a5e499a01c1e05218ffde368..b1d9c44aa56c919732721207d88163cda8080a53 100644 (file)
@@ -583,7 +583,6 @@ int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        flags |= VFPF_QUEUE_FLG_STATS;
        flags |= VFPF_QUEUE_FLG_CACHE_ALIGN;
        flags |= VFPF_QUEUE_FLG_VLAN;
-       DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
 
        /* Common */
        req->vf_qid = fp_idx;
@@ -952,14 +951,6 @@ static void storm_memset_vf_mbx_valid(struct bnx2x *bp, u16 abs_fid)
        REG_WR8(bp, addr, 1);
 }
 
-static inline void bnx2x_set_vf_mbxs_valid(struct bnx2x *bp)
-{
-       int i;
-
-       for_each_vf(bp, i)
-               storm_memset_vf_mbx_valid(bp, bnx2x_vf(bp, i, abs_vfid));
-}
-
 /* enable vf_pf mailbox (aka vf-pf-channel) */
 void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid)
 {
index a6a9f284c8dd762579e062a9d9d62f03e1ce6f96..23f23c97c2ad7b9fa52b8d589b1627a560635f92 100644 (file)
@@ -383,7 +383,7 @@ static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type,
                        break;
 
                rcu_read_lock();
-               if (!rcu_dereference(cp->ulp_ops[CNIC_ULP_L4])) {
+               if (!rcu_access_pointer(cp->ulp_ops[CNIC_ULP_L4])) {
                        rc = -ENODEV;
                        rcu_read_unlock();
                        break;
@@ -527,7 +527,7 @@ int cnic_unregister_driver(int ulp_type)
        list_for_each_entry(dev, &cnic_dev_list, list) {
                struct cnic_local *cp = dev->cnic_priv;
 
-               if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+               if (rcu_access_pointer(cp->ulp_ops[ulp_type])) {
                        pr_err("%s: Type %d still has devices registered\n",
                               __func__, ulp_type);
                        read_unlock(&cnic_dev_lock);
@@ -575,7 +575,7 @@ static int cnic_register_device(struct cnic_dev *dev, int ulp_type,
                mutex_unlock(&cnic_lock);
                return -EAGAIN;
        }
-       if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+       if (rcu_access_pointer(cp->ulp_ops[ulp_type])) {
                pr_err("%s: Type %d has already been registered to this device\n",
                       __func__, ulp_type);
                mutex_unlock(&cnic_lock);
index 962510f391dfcb3b8e041dd5ad89391b093c7bb4..5ba5ad071bb619dee3c5842fc23b7ff3c3e19216 100644 (file)
@@ -186,6 +186,7 @@ struct enic {
        ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX];
        unsigned int cq_count;
        struct enic_rfs_flw_tbl rfs_h;
+       u32 rx_copybreak;
 };
 
 static inline struct device *enic_get_dev(struct enic *enic)
index 523c9ceb04c020265b8ceabf3fbf209d9db34af6..85173d6207584aadc2546f880c22446fee0f09ff 100644 (file)
@@ -379,6 +379,43 @@ static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
        return ret;
 }
 
+static int enic_get_tunable(struct net_device *dev,
+                           const struct ethtool_tunable *tuna, void *data)
+{
+       struct enic *enic = netdev_priv(dev);
+       int ret = 0;
+
+       switch (tuna->id) {
+       case ETHTOOL_RX_COPYBREAK:
+               *(u32 *)data = enic->rx_copybreak;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int enic_set_tunable(struct net_device *dev,
+                           const struct ethtool_tunable *tuna,
+                           const void *data)
+{
+       struct enic *enic = netdev_priv(dev);
+       int ret = 0;
+
+       switch (tuna->id) {
+       case ETHTOOL_RX_COPYBREAK:
+               enic->rx_copybreak = *(u32 *)data;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static const struct ethtool_ops enic_ethtool_ops = {
        .get_settings = enic_get_settings,
        .get_drvinfo = enic_get_drvinfo,
@@ -391,6 +428,8 @@ static const struct ethtool_ops enic_ethtool_ops = {
        .get_coalesce = enic_get_coalesce,
        .set_coalesce = enic_set_coalesce,
        .get_rxnfc = enic_get_rxnfc,
+       .get_tunable = enic_get_tunable,
+       .set_tunable = enic_set_tunable,
 };
 
 void enic_set_ethtool_ops(struct net_device *netdev)
index c8832bc1c5f776a9199acbca27b693941c83d1fe..929bfe70080ac040bd879ede472d72744aaa300c 100644 (file)
@@ -66,6 +66,8 @@
 #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN     0x0044  /* enet dynamic vnic */
 #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF      0x0071  /* enet SRIOV VF */
 
+#define RX_COPYBREAK_DEFAULT           256
+
 /* Supported devices */
 static const struct pci_device_id enic_id_table[] = {
        { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) },
@@ -924,6 +926,7 @@ static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
        pci_unmap_single(enic->pdev, buf->dma_addr,
                buf->len, PCI_DMA_FROMDEVICE);
        dev_kfree_skb_any(buf->os_buf);
+       buf->os_buf = NULL;
 }
 
 static int enic_rq_alloc_buf(struct vnic_rq *rq)
@@ -934,7 +937,24 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
        unsigned int len = netdev->mtu + VLAN_ETH_HLEN;
        unsigned int os_buf_index = 0;
        dma_addr_t dma_addr;
+       struct vnic_rq_buf *buf = rq->to_use;
+
+       if (buf->os_buf) {
+               buf = buf->next;
+               rq->to_use = buf;
+               rq->ring.desc_avail--;
+               if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) {
+                       /* Adding write memory barrier prevents compiler and/or
+                        * CPU reordering, thus avoiding descriptor posting
+                        * before descriptor is initialized. Otherwise, hardware
+                        * can read stale descriptor fields.
+                        */
+                       wmb();
+                       iowrite32(buf->index, &rq->ctrl->posted_index);
+               }
 
+               return 0;
+       }
        skb = netdev_alloc_skb_ip_align(netdev, len);
        if (!skb)
                return -ENOMEM;
@@ -957,6 +977,25 @@ static void enic_intr_update_pkt_size(struct vnic_rx_bytes_counter *pkt_size,
                pkt_size->small_pkt_bytes_cnt += pkt_len;
 }
 
+static bool enic_rxcopybreak(struct net_device *netdev, struct sk_buff **skb,
+                            struct vnic_rq_buf *buf, u16 len)
+{
+       struct enic *enic = netdev_priv(netdev);
+       struct sk_buff *new_skb;
+
+       if (len > enic->rx_copybreak)
+               return false;
+       new_skb = netdev_alloc_skb_ip_align(netdev, len);
+       if (!new_skb)
+               return false;
+       pci_dma_sync_single_for_cpu(enic->pdev, buf->dma_addr, len,
+                                   DMA_FROM_DEVICE);
+       memcpy(new_skb->data, (*skb)->data, len);
+       *skb = new_skb;
+
+       return true;
+}
+
 static void enic_rq_indicate_buf(struct vnic_rq *rq,
        struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
        int skipped, void *opaque)
@@ -978,9 +1017,6 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
                return;
 
        skb = buf->os_buf;
-       prefetch(skb->data - NET_IP_ALIGN);
-       pci_unmap_single(enic->pdev, buf->dma_addr,
-               buf->len, PCI_DMA_FROMDEVICE);
 
        cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc,
                &type, &color, &q_number, &completed_index,
@@ -1011,6 +1047,13 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
                /* Good receive
                 */
 
+               if (!enic_rxcopybreak(netdev, &skb, buf, bytes_written)) {
+                       buf->os_buf = NULL;
+                       pci_unmap_single(enic->pdev, buf->dma_addr, buf->len,
+                                        PCI_DMA_FROMDEVICE);
+               }
+               prefetch(skb->data - NET_IP_ALIGN);
+
                skb_put(skb, bytes_written);
                skb->protocol = eth_type_trans(skb, netdev);
                skb_record_rx_queue(skb, q_number);
@@ -2531,6 +2574,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_err(dev, "Cannot register net device, aborting\n");
                goto err_out_dev_deinit;
        }
+       enic->rx_copybreak = RX_COPYBREAK_DEFAULT;
 
        return 0;
 
index 322213d901d5ec663ef3831f81786b199cdd41bd..c8205606c7757ff3345acef81d57a5c0118497e3 100644 (file)
@@ -328,10 +328,10 @@ static void allocate_rx_buffer(struct net_device *);
 static void update_cr6(u32, void __iomem *);
 static void send_filter_frame(struct DEVICE *);
 static void dm9132_id_table(struct DEVICE *);
-static u16 phy_read(void __iomem *, u8, u8, u32);
-static void phy_write(void __iomem *, u8, u8, u16, u32);
-static void phy_write_1bit(void __iomem *, u32);
-static u16 phy_read_1bit(void __iomem *);
+static u16 dmfe_phy_read(void __iomem *, u8, u8, u32);
+static void dmfe_phy_write(void __iomem *, u8, u8, u16, u32);
+static void dmfe_phy_write_1bit(void __iomem *, u32);
+static u16 dmfe_phy_read_1bit(void __iomem *);
 static u8 dmfe_sense_speed(struct dmfe_board_info *);
 static void dmfe_process_mode(struct dmfe_board_info *);
 static void dmfe_timer(unsigned long);
@@ -770,7 +770,7 @@ static int dmfe_stop(struct DEVICE *dev)
        /* Reset & stop DM910X board */
        dw32(DCR0, DM910X_RESET);
        udelay(100);
-       phy_write(ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
+       dmfe_phy_write(ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
 
        /* free interrupt */
        free_irq(db->pdev->irq, dev);
@@ -1154,7 +1154,7 @@ static void dmfe_timer(unsigned long data)
                if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) {
                        db->cr6_data &= ~0x40000;
                        update_cr6(db->cr6_data, ioaddr);
-                       phy_write(ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+                       dmfe_phy_write(ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
                        db->cr6_data |= 0x40000;
                        update_cr6(db->cr6_data, ioaddr);
                        db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
@@ -1230,9 +1230,9 @@ static void dmfe_timer(unsigned long data)
        */
 
        /* need a dummy read because of PHY's register latch*/
-       phy_read (db->ioaddr, db->phy_addr, 1, db->chip_id);
-       link_ok_phy = (phy_read (db->ioaddr,
-                      db->phy_addr, 1, db->chip_id) & 0x4) ? 1 : 0;
+       dmfe_phy_read (db->ioaddr, db->phy_addr, 1, db->chip_id);
+       link_ok_phy = (dmfe_phy_read (db->ioaddr,
+                                     db->phy_addr, 1, db->chip_id) & 0x4) ? 1 : 0;
 
        if (link_ok_phy != link_ok) {
                DMFE_DBUG (0, "PHY and chip report different link status", 0);
@@ -1247,8 +1247,8 @@ static void dmfe_timer(unsigned long data)
                /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
                /* AUTO or force 1M Homerun/Longrun don't need */
                if ( !(db->media_mode & 0x38) )
-                       phy_write(db->ioaddr, db->phy_addr,
-                                 0, 0x1000, db->chip_id);
+                       dmfe_phy_write(db->ioaddr, db->phy_addr,
+                                      0, 0x1000, db->chip_id);
 
                /* AUTO mode, if INT phyxcer link failed, select EXT device */
                if (db->media_mode & DMFE_AUTO) {
@@ -1649,16 +1649,16 @@ static u8 dmfe_sense_speed(struct dmfe_board_info *db)
        /* CR6 bit18=0, select 10/100M */
        update_cr6(db->cr6_data & ~0x40000, ioaddr);
 
-       phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
-       phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+       phy_mode = dmfe_phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+       phy_mode = dmfe_phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
 
        if ( (phy_mode & 0x24) == 0x24 ) {
                if (db->chip_id == PCI_DM9132_ID)       /* DM9132 */
-                       phy_mode = phy_read(db->ioaddr,
-                                   db->phy_addr, 7, db->chip_id) & 0xf000;
+                       phy_mode = dmfe_phy_read(db->ioaddr,
+                                                db->phy_addr, 7, db->chip_id) & 0xf000;
                else                            /* DM9102/DM9102A */
-                       phy_mode = phy_read(db->ioaddr,
-                                   db->phy_addr, 17, db->chip_id) & 0xf000;
+                       phy_mode = dmfe_phy_read(db->ioaddr,
+                                                db->phy_addr, 17, db->chip_id) & 0xf000;
                switch (phy_mode) {
                case 0x1000: db->op_mode = DMFE_10MHF; break;
                case 0x2000: db->op_mode = DMFE_10MFD; break;
@@ -1695,15 +1695,15 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *db)
 
        /* DM9009 Chip: Phyxcer reg18 bit12=0 */
        if (db->chip_id == PCI_DM9009_ID) {
-               phy_reg = phy_read(db->ioaddr,
-                                  db->phy_addr, 18, db->chip_id) & ~0x1000;
+               phy_reg = dmfe_phy_read(db->ioaddr,
+                                       db->phy_addr, 18, db->chip_id) & ~0x1000;
 
-               phy_write(db->ioaddr,
-                         db->phy_addr, 18, phy_reg, db->chip_id);
+               dmfe_phy_write(db->ioaddr,
+                              db->phy_addr, 18, phy_reg, db->chip_id);
        }
 
        /* Phyxcer capability setting */
-       phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
+       phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
 
        if (db->media_mode & DMFE_AUTO) {
                /* AUTO Mode */
@@ -1724,13 +1724,13 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *db)
                phy_reg|=db->PHY_reg4;
                db->media_mode|=DMFE_AUTO;
        }
-       phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
 
        /* Restart Auto-Negotiation */
        if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
-               phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
+               dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
        if ( !db->chip_type )
-               phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
+               dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
 }
 
 
@@ -1762,7 +1762,7 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
        /* 10/100M phyxcer force mode need */
        if ( !(db->media_mode & 0x18)) {
                /* Forece Mode */
-               phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
+               phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
                if ( !(phy_reg & 0x1) ) {
                        /* parter without N-Way capability */
                        phy_reg = 0x0;
@@ -1772,12 +1772,12 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
                        case DMFE_100MHF: phy_reg = 0x2000; break;
                        case DMFE_100MFD: phy_reg = 0x2100; break;
                        }
-                       phy_write(db->ioaddr,
-                                 db->phy_addr, 0, phy_reg, db->chip_id);
+                       dmfe_phy_write(db->ioaddr,
+                                      db->phy_addr, 0, phy_reg, db->chip_id);
                                if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
                                mdelay(20);
-                       phy_write(db->ioaddr,
-                                 db->phy_addr, 0, phy_reg, db->chip_id);
+                       dmfe_phy_write(db->ioaddr,
+                                      db->phy_addr, 0, phy_reg, db->chip_id);
                }
        }
 }
@@ -1787,8 +1787,8 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
  *     Write a word to Phy register
  */
 
-static void phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
-                     u16 phy_data, u32 chip_id)
+static void dmfe_phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
+                          u16 phy_data, u32 chip_id)
 {
        u16 i;
 
@@ -1799,34 +1799,34 @@ static void phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
 
                /* Send 33 synchronization clock to Phy controller */
                for (i = 0; i < 35; i++)
-                       phy_write_1bit(ioaddr, PHY_DATA_1);
+                       dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send start command(01) to Phy */
-               phy_write_1bit(ioaddr, PHY_DATA_0);
-               phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send write command(01) to Phy */
-               phy_write_1bit(ioaddr, PHY_DATA_0);
-               phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send Phy address */
                for (i = 0x10; i > 0; i = i >> 1)
-                       phy_write_1bit(ioaddr,
-                                      phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
 
                /* Send register address */
                for (i = 0x10; i > 0; i = i >> 1)
-                       phy_write_1bit(ioaddr,
-                                      offset & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           offset & i ? PHY_DATA_1 : PHY_DATA_0);
 
                /* written trasnition */
-               phy_write_1bit(ioaddr, PHY_DATA_1);
-               phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
 
                /* Write a word data to PHY controller */
                for ( i = 0x8000; i > 0; i >>= 1)
-                       phy_write_1bit(ioaddr,
-                                      phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
        }
 }
 
@@ -1835,7 +1835,7 @@ static void phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
  *     Read a word data from phy register
  */
 
-static u16 phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
+static u16 dmfe_phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
 {
        int i;
        u16 phy_data;
@@ -1848,33 +1848,33 @@ static u16 phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
 
                /* Send 33 synchronization clock to Phy controller */
                for (i = 0; i < 35; i++)
-                       phy_write_1bit(ioaddr, PHY_DATA_1);
+                       dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send start command(01) to Phy */
-               phy_write_1bit(ioaddr, PHY_DATA_0);
-               phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send read command(10) to Phy */
-               phy_write_1bit(ioaddr, PHY_DATA_1);
-               phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
 
                /* Send Phy address */
                for (i = 0x10; i > 0; i = i >> 1)
-                       phy_write_1bit(ioaddr,
-                                      phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
 
                /* Send register address */
                for (i = 0x10; i > 0; i = i >> 1)
-                       phy_write_1bit(ioaddr,
-                                      offset & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           offset & i ? PHY_DATA_1 : PHY_DATA_0);
 
                /* Skip transition state */
-               phy_read_1bit(ioaddr);
+               dmfe_phy_read_1bit(ioaddr);
 
                /* read 16bit data */
                for (phy_data = 0, i = 0; i < 16; i++) {
                        phy_data <<= 1;
-                       phy_data |= phy_read_1bit(ioaddr);
+                       phy_data |= dmfe_phy_read_1bit(ioaddr);
                }
        }
 
@@ -1886,7 +1886,7 @@ static u16 phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
  *     Write one bit data to Phy Controller
  */
 
-static void phy_write_1bit(void __iomem *ioaddr, u32 phy_data)
+static void dmfe_phy_write_1bit(void __iomem *ioaddr, u32 phy_data)
 {
        dw32(DCR9, phy_data);           /* MII Clock Low */
        udelay(1);
@@ -1901,7 +1901,7 @@ static void phy_write_1bit(void __iomem *ioaddr, u32 phy_data)
  *     Read one bit phy data from PHY controller
  */
 
-static u16 phy_read_1bit(void __iomem *ioaddr)
+static u16 dmfe_phy_read_1bit(void __iomem *ioaddr)
 {
        u16 phy_data;
 
@@ -1995,11 +1995,11 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
        /* Check DM9801 or DM9802 present or not */
        db->HPNA_present = 0;
        update_cr6(db->cr6_data | 0x40000, db->ioaddr);
-       tmp_reg = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
+       tmp_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
        if ( ( tmp_reg & 0xfff0 ) == 0xb900 ) {
                /* DM9801 or DM9802 present */
                db->HPNA_timer = 8;
-               if ( phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
+               if ( dmfe_phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
                        /* DM9801 HomeRun */
                        db->HPNA_present = 1;
                        dmfe_program_DM9801(db, tmp_reg);
@@ -2025,29 +2025,29 @@ static void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev)
        switch(HPNA_rev) {
        case 0xb900: /* DM9801 E3 */
                db->HPNA_command |= 0x1000;
-               reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
+               reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
                reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
-               reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+               reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
                break;
        case 0xb901: /* DM9801 E4 */
-               reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+               reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
                reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
-               reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+               reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
                reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
                break;
        case 0xb902: /* DM9801 E5 */
        case 0xb903: /* DM9801 E6 */
        default:
                db->HPNA_command |= 0x1000;
-               reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+               reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
                reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
-               reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+               reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
                reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
                break;
        }
-       phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
-       phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
-       phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
 }
 
 
@@ -2060,10 +2060,10 @@ static void dmfe_program_DM9802(struct dmfe_board_info * db)
        uint phy_reg;
 
        if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9802_NOISE_FLOOR;
-       phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
-       phy_reg = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+       phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
        phy_reg = ( phy_reg & 0xff00) + HPNA_NoiseFloor;
-       phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
 }
 
 
@@ -2077,7 +2077,7 @@ static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
        uint phy_reg;
 
        /* Got remote device status */
-       phy_reg = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
+       phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
        switch(phy_reg) {
        case 0x00: phy_reg = 0x0a00;break; /* LP/LS */
        case 0x20: phy_reg = 0x0900;break; /* LP/HS */
@@ -2087,8 +2087,8 @@ static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
 
        /* Check remote device status match our setting ot not */
        if ( phy_reg != (db->HPNA_command & 0x0f00) ) {
-               phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command,
-                         db->chip_id);
+               dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command,
+                              db->chip_id);
                db->HPNA_timer=8;
        } else
                db->HPNA_timer=600;     /* Match, every 10 minutes, check */
index 056b44b934773cb0084d5126dd7946d08bb24c46..d1017509b08ac1e171a12a89770373a5057c5d64 100644 (file)
@@ -1,5 +1,5 @@
  /*
- * drivers/net/ethernet/beckhoff/ec_bhf.c
+ * drivers/net/ethernet/ec_bhf.c
  *
  * Copyright (C) 2014 Darek Marcinkiewicz <reksio@newterm.pl>
  *
@@ -18,9 +18,6 @@
  * Those can be found on Bechhoff CX50xx industrial PCs.
  */
 
-#if 0
-#define DEBUG
-#endif
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -74,6 +71,8 @@
 
 #define DMA_WINDOW_SIZE_MASK   0xfffffffc
 
+#define ETHERCAT_MASTER_ID     0x14
+
 static struct pci_device_id ids[] = {
        { PCI_DEVICE(0x15ec, 0x5000), },
        { 0, }
@@ -131,7 +130,6 @@ struct bhf_dma {
 
 struct ec_bhf_priv {
        struct net_device *net_dev;
-
        struct pci_dev *dev;
 
        void __iomem *io;
@@ -162,32 +160,6 @@ struct ec_bhf_priv {
 
 #define PRIV_TO_DEV(priv) (&(priv)->dev->dev)
 
-#define ETHERCAT_MASTER_ID     0x14
-
-static void ec_bhf_print_status(struct ec_bhf_priv *priv)
-{
-       struct device *dev = PRIV_TO_DEV(priv);
-
-       dev_dbg(dev, "Frame error counter: %d\n",
-               ioread8(priv->mac_io + MAC_FRAME_ERR_CNT));
-       dev_dbg(dev, "RX error counter: %d\n",
-               ioread8(priv->mac_io + MAC_RX_ERR_CNT));
-       dev_dbg(dev, "CRC error counter: %d\n",
-               ioread8(priv->mac_io + MAC_CRC_ERR_CNT));
-       dev_dbg(dev, "TX frame counter: %d\n",
-               ioread32(priv->mac_io + MAC_TX_FRAME_CNT));
-       dev_dbg(dev, "RX frame counter: %d\n",
-               ioread32(priv->mac_io + MAC_RX_FRAME_CNT));
-       dev_dbg(dev, "TX fifo level: %d\n",
-               ioread8(priv->mac_io + MAC_TX_FIFO_LVL));
-       dev_dbg(dev, "Dropped frames: %d\n",
-               ioread8(priv->mac_io + MAC_DROPPED_FRMS));
-       dev_dbg(dev, "Connected with CCAT slot: %d\n",
-               ioread8(priv->mac_io + MAC_CONNECTED_CCAT_FLAG));
-       dev_dbg(dev, "Link status: %d\n",
-               ioread8(priv->mii_io + MII_LINK_STATUS));
-}
-
 static void ec_bhf_reset(struct ec_bhf_priv *priv)
 {
        iowrite8(0, priv->mac_io + MAC_FRAME_ERR_CNT);
@@ -210,8 +182,6 @@ static void ec_bhf_send_packet(struct ec_bhf_priv *priv, struct tx_desc *desc)
        u32 addr = (u8 *)desc - priv->tx_buf.buf;
 
        iowrite32((ALIGN(len, 8) << 24) | addr, priv->fifo_io + FIFO_TX_REG);
-
-       dev_dbg(PRIV_TO_DEV(priv), "Done sending packet\n");
 }
 
 static int ec_bhf_desc_sent(struct tx_desc *desc)
@@ -244,7 +214,6 @@ static void ec_bhf_add_rx_desc(struct ec_bhf_priv *priv, struct rx_desc *desc)
 static void ec_bhf_process_rx(struct ec_bhf_priv *priv)
 {
        struct rx_desc *desc = &priv->rx_descs[priv->rx_dnext];
-       struct device *dev = PRIV_TO_DEV(priv);
 
        while (ec_bhf_pkt_received(desc)) {
                int pkt_size = (le16_to_cpu(desc->header.len) &
@@ -253,20 +222,16 @@ static void ec_bhf_process_rx(struct ec_bhf_priv *priv)
                struct sk_buff *skb;
 
                skb = netdev_alloc_skb_ip_align(priv->net_dev, pkt_size);
-               dev_dbg(dev, "Received packet, size: %d\n", pkt_size);
-
                if (skb) {
                        memcpy(skb_put(skb, pkt_size), data, pkt_size);
                        skb->protocol = eth_type_trans(skb, priv->net_dev);
-                       dev_dbg(dev, "Protocol type: %x\n", skb->protocol);
-
                        priv->stat_rx_bytes += pkt_size;
 
                        netif_rx(skb);
                } else {
-                       dev_err_ratelimited(dev,
-                               "Couldn't allocate a skb_buff for a packet of size %u\n",
-                               pkt_size);
+                       dev_err_ratelimited(PRIV_TO_DEV(priv),
+                                           "Couldn't allocate a skb_buff for a packet of size %u\n",
+                                           pkt_size);
                }
 
                desc->header.recv = 0;
@@ -276,7 +241,6 @@ static void ec_bhf_process_rx(struct ec_bhf_priv *priv)
                priv->rx_dnext = (priv->rx_dnext + 1) % priv->rx_dcount;
                desc = &priv->rx_descs[priv->rx_dnext];
        }
-
 }
 
 static enum hrtimer_restart ec_bhf_timer_fun(struct hrtimer *timer)
@@ -299,14 +263,7 @@ static int ec_bhf_setup_offsets(struct ec_bhf_priv *priv)
        unsigned block_count, i;
        void __iomem *ec_info;
 
-       dev_dbg(dev, "Info block:\n");
-       dev_dbg(dev, "Type of function: %x\n", (unsigned)ioread16(priv->io));
-       dev_dbg(dev, "Revision of function: %x\n",
-               (unsigned)ioread16(priv->io + INFO_BLOCK_REV));
-
        block_count = ioread8(priv->io + INFO_BLOCK_BLK_CNT);
-       dev_dbg(dev, "Number of function blocks: %x\n", block_count);
-
        for (i = 0; i < block_count; i++) {
                u16 type = ioread16(priv->io + i * INFO_BLOCK_SIZE +
                                    INFO_BLOCK_TYPE);
@@ -317,29 +274,17 @@ static int ec_bhf_setup_offsets(struct ec_bhf_priv *priv)
                dev_err(dev, "EtherCAT master with DMA block not found\n");
                return -ENODEV;
        }
-       dev_dbg(dev, "EtherCAT master with DMA block found at pos: %d\n", i);
 
        ec_info = priv->io + i * INFO_BLOCK_SIZE;
-       dev_dbg(dev, "EtherCAT master revision: %d\n",
-               ioread16(ec_info + INFO_BLOCK_REV));
 
        priv->tx_dma_chan = ioread8(ec_info + INFO_BLOCK_TX_CHAN);
-       dev_dbg(dev, "EtherCAT master tx dma channel: %d\n",
-               priv->tx_dma_chan);
-
        priv->rx_dma_chan = ioread8(ec_info + INFO_BLOCK_RX_CHAN);
-       dev_dbg(dev, "EtherCAT master rx dma channel: %d\n",
-                priv->rx_dma_chan);
 
        priv->ec_io = priv->io + ioread32(ec_info + INFO_BLOCK_OFFSET);
        priv->mii_io = priv->ec_io + ioread32(priv->ec_io + EC_MII_OFFSET);
        priv->fifo_io = priv->ec_io + ioread32(priv->ec_io + EC_FIFO_OFFSET);
        priv->mac_io = priv->ec_io + ioread32(priv->ec_io + EC_MAC_OFFSET);
 
-       dev_dbg(dev,
-               "EtherCAT block addres: %p, fifo address: %p, mii address: %p, mac address: %p\n",
-               priv->ec_io, priv->fifo_io, priv->mii_io, priv->mac_io);
-
        return 0;
 }
 
@@ -350,8 +295,6 @@ static netdev_tx_t ec_bhf_start_xmit(struct sk_buff *skb,
        struct tx_desc *desc;
        unsigned len;
 
-       dev_dbg(PRIV_TO_DEV(priv), "Starting xmit\n");
-
        desc = &priv->tx_descs[priv->tx_dnext];
 
        skb_copy_and_csum_dev(skb, desc->data);
@@ -366,15 +309,12 @@ static netdev_tx_t ec_bhf_start_xmit(struct sk_buff *skb,
        priv->tx_dnext = (priv->tx_dnext + 1) % priv->tx_dcount;
 
        if (!ec_bhf_desc_sent(&priv->tx_descs[priv->tx_dnext])) {
-               /* Make sure that update updates to tx_dnext are perceived
+               /* Make sure that updates to tx_dnext are perceived
                 * by timer routine.
                 */
                smp_wmb();
 
                netif_stop_queue(net_dev);
-
-               dev_dbg(PRIV_TO_DEV(priv), "Stopping netif queue\n");
-               ec_bhf_print_status(priv);
        }
 
        priv->stat_tx_bytes += len;
@@ -397,7 +337,6 @@ static int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
 
        mask = ioread32(priv->dma_io + offset);
        mask &= DMA_WINDOW_SIZE_MASK;
-       dev_dbg(dev, "Read mask %x for channel %d\n", mask, channel);
 
        /* We want to allocate a chunk of memory that is:
         * - aligned to the mask we just read
@@ -408,12 +347,10 @@ static int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
        buf->len = min_t(int, ~mask + 1, size);
        buf->alloc_len = 2 * buf->len;
 
-       dev_dbg(dev, "Allocating %d bytes for channel %d",
-               (int)buf->alloc_len, channel);
        buf->alloc = dma_alloc_coherent(dev, buf->alloc_len, &buf->alloc_phys,
                                        GFP_KERNEL);
        if (buf->alloc == NULL) {
-               dev_info(dev, "Failed to allocate buffer\n");
+               dev_err(dev, "Failed to allocate buffer\n");
                return -ENOMEM;
        }
 
@@ -422,8 +359,6 @@ static int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
 
        iowrite32(0, priv->dma_io + offset + 4);
        iowrite32(buf->buf_phys, priv->dma_io + offset);
-       dev_dbg(dev, "Buffer: %x and read from dev: %x",
-               (unsigned)buf->buf_phys, ioread32(priv->dma_io + offset));
 
        return 0;
 }
@@ -433,7 +368,7 @@ static void ec_bhf_setup_tx_descs(struct ec_bhf_priv *priv)
        int i = 0;
 
        priv->tx_dcount = priv->tx_buf.len / sizeof(struct tx_desc);
-       priv->tx_descs = (struct tx_desc *) priv->tx_buf.buf;
+       priv->tx_descs = (struct tx_desc *)priv->tx_buf.buf;
        priv->tx_dnext = 0;
 
        for (i = 0; i < priv->tx_dcount; i++)
@@ -445,7 +380,7 @@ static void ec_bhf_setup_rx_descs(struct ec_bhf_priv *priv)
        int i;
 
        priv->rx_dcount = priv->rx_buf.len / sizeof(struct rx_desc);
-       priv->rx_descs = (struct rx_desc *) priv->rx_buf.buf;
+       priv->rx_descs = (struct rx_desc *)priv->rx_buf.buf;
        priv->rx_dnext = 0;
 
        for (i = 0; i < priv->rx_dcount; i++) {
@@ -469,8 +404,6 @@ static int ec_bhf_open(struct net_device *net_dev)
        struct device *dev = PRIV_TO_DEV(priv);
        int err = 0;
 
-       dev_info(dev, "Opening device\n");
-
        ec_bhf_reset(priv);
 
        err = ec_bhf_alloc_dma_mem(priv, &priv->rx_buf, priv->rx_dma_chan,
@@ -481,20 +414,13 @@ static int ec_bhf_open(struct net_device *net_dev)
        }
        ec_bhf_setup_rx_descs(priv);
 
-       dev_info(dev, "RX buffer allocated, address: %x\n",
-                (unsigned)priv->rx_buf.buf_phys);
-
        err = ec_bhf_alloc_dma_mem(priv, &priv->tx_buf, priv->tx_dma_chan,
                                   FIFO_SIZE * sizeof(struct tx_desc));
        if (err) {
                dev_err(dev, "Failed to allocate tx buffer\n");
                goto error_rx_free;
        }
-       dev_dbg(dev, "TX buffer allocated, addres: %x\n",
-               (unsigned)priv->tx_buf.buf_phys);
-
        iowrite8(0, priv->mii_io + MII_MAC_FILT_FLAG);
-
        ec_bhf_setup_tx_descs(priv);
 
        netif_start_queue(net_dev);
@@ -504,10 +430,6 @@ static int ec_bhf_open(struct net_device *net_dev)
        hrtimer_start(&priv->hrtimer, ktime_set(0, polling_frequency),
                      HRTIMER_MODE_REL);
 
-       dev_info(PRIV_TO_DEV(priv), "Device open\n");
-
-       ec_bhf_print_status(priv);
-
        return 0;
 
 error_rx_free:
@@ -640,9 +562,6 @@ static int ec_bhf_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
        memcpy_fromio(net_dev->dev_addr, priv->mii_io + MII_MAC_ADDR, 6);
 
-       dev_dbg(&dev->dev, "CX5020 Ethercat master address: %pM\n",
-               net_dev->dev_addr);
-
        err = register_netdev(net_dev);
        if (err < 0)
                goto err_free_net_dev;
index 43e08d0bc3d316ff407555bf1ec170c44c3c2be2..a9f239adc3e3a7db481026e31367281ce6d1e6f5 100644 (file)
@@ -86,6 +86,8 @@ static inline char *nic_name(struct pci_dev *pdev)
 
 #define BE_MAX_JUMBO_FRAME_SIZE        9018
 #define BE_MIN_MTU             256
+#define BE_MAX_MTU              (BE_MAX_JUMBO_FRAME_SIZE -     \
+                                (ETH_HLEN + ETH_FCS_LEN))
 
 #define BE_NUM_VLANS_SUPPORTED 64
 #define BE_MAX_EQD             128u
@@ -112,7 +114,6 @@ static inline char *nic_name(struct pci_dev *pdev)
 #define MAX_ROCE_EQS           5
 #define MAX_MSIX_VECTORS       32
 #define MIN_MSIX_VECTORS       1
-#define BE_TX_BUDGET           256
 #define BE_NAPI_WEIGHT         64
 #define MAX_RX_POST            BE_NAPI_WEIGHT /* Frags posted at a time */
 #define RX_FRAGS_REFILL_WM     (RX_Q_LEN - MAX_RX_POST)
@@ -198,7 +199,6 @@ struct be_eq_obj {
 
        u8 idx;                 /* array index */
        u8 msix_idx;
-       u16 tx_budget;
        u16 spurious_intr;
        struct napi_struct napi;
        struct be_adapter *adapter;
@@ -248,6 +248,13 @@ struct be_tx_stats {
        ulong tx_jiffies;
        u32 tx_stops;
        u32 tx_drv_drops;       /* pkts dropped by driver */
+       /* the error counters are described in be_ethtool.c */
+       u32 tx_hdr_parse_err;
+       u32 tx_dma_err;
+       u32 tx_tso_err;
+       u32 tx_spoof_check_err;
+       u32 tx_qinq_err;
+       u32 tx_internal_parity_err;
        struct u64_stats_sync sync;
        struct u64_stats_sync sync_compl;
 };
@@ -316,6 +323,7 @@ struct be_rx_obj {
 struct be_drv_stats {
        u32 be_on_die_temperature;
        u32 eth_red_drops;
+       u32 dma_map_errors;
        u32 rx_drops_no_pbuf;
        u32 rx_drops_no_txpb;
        u32 rx_drops_no_erx_descr;
@@ -613,6 +621,10 @@ extern const struct ethtool_ops be_ethtool_ops;
        for (i = eqo->idx, rxo = &adapter->rx_obj[i]; i < adapter->num_rx_qs;\
                 i += adapter->num_evt_qs, rxo += adapter->num_evt_qs)
 
+#define for_all_tx_queues_on_eq(adapter, eqo, txo, i)                  \
+       for (i = eqo->idx, txo = &adapter->tx_obj[i]; i < adapter->num_tx_qs;\
+               i += adapter->num_evt_qs, txo += adapter->num_evt_qs)
+
 #define is_mcc_eqo(eqo)                        (eqo->idx == 0)
 #define mcc_eqo(adapter)               (&adapter->eq_obj[0])
 
@@ -661,6 +673,18 @@ static inline u32 amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset)
                        amap_mask(sizeof(((_struct *)0)->field)),       \
                        AMAP_BIT_OFFSET(_struct, field))
 
+#define GET_RX_COMPL_V0_BITS(field, ptr)                               \
+               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, field, ptr)
+
+#define GET_RX_COMPL_V1_BITS(field, ptr)                               \
+               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, field, ptr)
+
+#define GET_TX_COMPL_BITS(field, ptr)                                  \
+               AMAP_GET_BITS(struct amap_eth_tx_compl, field, ptr)
+
+#define SET_TX_WRB_HDR_BITS(field, ptr, val)                           \
+               AMAP_SET_BITS(struct amap_eth_hdr_wrb, field, ptr, val)
+
 #define be_dws_cpu_to_le(wrb, len)     swap_dws(wrb, len)
 #define be_dws_le_to_cpu(wrb, len)     swap_dws(wrb, len)
 static inline void swap_dws(void *wrb, int len)
index 4370ec1952accd2b3ce8ea3beda71ca35ba03331..5be100d1bc0ae4e935d302817a90dde5a91fe64d 100644 (file)
@@ -1681,17 +1681,17 @@ err:
        return status;
 }
 
-void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
+int be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
 {
        struct be_dma_mem get_fat_cmd;
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_get_fat *req;
        u32 offset = 0, total_size, buf_size,
                                log_offset = sizeof(u32), payload_len;
-       int status;
+       int status = 0;
 
        if (buf_len == 0)
-               return;
+               return -EIO;
 
        total_size = buf_len;
 
@@ -1700,10 +1700,9 @@ void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
                                              get_fat_cmd.size,
                                              &get_fat_cmd.dma);
        if (!get_fat_cmd.va) {
-               status = -ENOMEM;
                dev_err(&adapter->pdev->dev,
                "Memory allocation failure while retrieving FAT data\n");
-               return;
+               return -ENOMEM;
        }
 
        spin_lock_bh(&adapter->mcc_lock);
@@ -1746,6 +1745,7 @@ err:
        pci_free_consistent(adapter->pdev, get_fat_cmd.size,
                            get_fat_cmd.va, get_fat_cmd.dma);
        spin_unlock_bh(&adapter->mcc_lock);
+       return status;
 }
 
 /* Uses synchronous mcc */
@@ -1771,6 +1771,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter)
        status = be_mcc_notify_wait(adapter);
        if (!status) {
                struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb);
+
                strcpy(adapter->fw_ver, resp->firmware_version_string);
                strcpy(adapter->fw_on_flash, resp->fw_on_flash_version_string);
        }
@@ -2018,6 +2019,9 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter)
                adapter->function_mode = le32_to_cpu(resp->function_mode);
                adapter->function_caps = le32_to_cpu(resp->function_caps);
                adapter->asic_rev = le32_to_cpu(resp->asic_revision) & 0xFF;
+               dev_info(&adapter->pdev->dev,
+                        "FW config: function_mode=0x%x, function_caps=0x%x\n",
+                        adapter->function_mode, adapter->function_caps);
        }
 
        mutex_unlock(&adapter->mbox_lock);
index 5284b825bba28521b072c8b0891a3b36c3b464a6..0e1186856aa61ba9cef38e16fa14589fec8c11a0 100644 (file)
@@ -2101,7 +2101,7 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter);
 int be_cmd_get_cntl_attributes(struct be_adapter *adapter);
 int be_cmd_req_native_mode(struct be_adapter *adapter);
 int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size);
-void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf);
+int be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf);
 int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege,
                             u32 domain);
 int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges,
index 0cd3311409a82a1aef601c66f46c3c72fc244070..2fd38261bedb17c7ff8118a7ea7b9f6af090791c 100644 (file)
@@ -78,6 +78,11 @@ static const struct be_ethtool_stat et_stats[] = {
         * fifo must never overflow.
         */
        {DRVSTAT_INFO(rxpp_fifo_overflow_drop)},
+       /* Received packets dropped when the RX block runs out of space in
+        * one of its input FIFOs. This could happen due a long burst of
+        * minimum-sized (64b) frames in the receive path.
+        * This counter may also be erroneously incremented rarely.
+        */
        {DRVSTAT_INFO(rx_input_fifo_overflow_drop)},
        {DRVSTAT_INFO(rx_ip_checksum_errs)},
        {DRVSTAT_INFO(rx_tcp_checksum_errs)},
@@ -114,6 +119,8 @@ static const struct be_ethtool_stat et_stats[] = {
         * is more than 9018 bytes
         */
        {DRVSTAT_INFO(rx_drops_mtu)},
+       /* Number of dma mapping errors */
+       {DRVSTAT_INFO(dma_map_errors)},
        /* Number of packets dropped due to random early drop function */
        {DRVSTAT_INFO(eth_red_drops)},
        {DRVSTAT_INFO(be_on_die_temperature)},
@@ -152,6 +159,34 @@ static const struct be_ethtool_stat et_rx_stats[] = {
  */
 static const struct be_ethtool_stat et_tx_stats[] = {
        {DRVSTAT_TX_INFO(tx_compl)}, /* If moving this member see above note */
+       /* This counter is incremented when the HW encounters an error while
+        * parsing the packet header of an outgoing TX request. This counter is
+        * applicable only for BE2, BE3 and Skyhawk based adapters.
+        */
+       {DRVSTAT_TX_INFO(tx_hdr_parse_err)},
+       /* This counter is incremented when an error occurs in the DMA
+        * operation associated with the TX request from the host to the device.
+        */
+       {DRVSTAT_TX_INFO(tx_dma_err)},
+       /* This counter is incremented when MAC or VLAN spoof checking is
+        * enabled on the interface and the TX request fails the spoof check
+        * in HW.
+        */
+       {DRVSTAT_TX_INFO(tx_spoof_check_err)},
+       /* This counter is incremented when the HW encounters an error while
+        * performing TSO offload. This counter is applicable only for Lancer
+        * adapters.
+        */
+       {DRVSTAT_TX_INFO(tx_tso_err)},
+       /* This counter is incremented when the HW detects Q-in-Q style VLAN
+        * tagging in a packet and such tagging is not expected on the outgoing
+        * interface. This counter is applicable only for Lancer adapters.
+        */
+       {DRVSTAT_TX_INFO(tx_qinq_err)},
+       /* This counter is incremented when the HW detects parity errors in the
+        * packet data. This counter is applicable only for Lancer adapters.
+        */
+       {DRVSTAT_TX_INFO(tx_internal_parity_err)},
        {DRVSTAT_TX_INFO(tx_bytes)},
        {DRVSTAT_TX_INFO(tx_pkts)},
        /* Number of skbs queued for trasmission by the driver */
index 8840c64aaeca7daca310d0a5a38dfdbed790fb12..295ee0835ba0bb32979d9923fd2db75f030e55a6 100644 (file)
@@ -315,6 +315,18 @@ struct be_eth_hdr_wrb {
        u32 dw[4];
 };
 
+/********* Tx Compl Status Encoding *********/
+#define BE_TX_COMP_HDR_PARSE_ERR       0x2
+#define BE_TX_COMP_NDMA_ERR            0x3
+#define BE_TX_COMP_ACL_ERR             0x5
+
+#define LANCER_TX_COMP_LSO_ERR                 0x1
+#define LANCER_TX_COMP_HSW_DROP_MAC_ERR                0x3
+#define LANCER_TX_COMP_HSW_DROP_VLAN_ERR       0x5
+#define LANCER_TX_COMP_QINQ_ERR                        0x7
+#define LANCER_TX_COMP_PARITY_ERR              0xb
+#define LANCER_TX_COMP_DMA_ERR                 0xd
+
 /* TX Compl Queue Descriptor */
 
 /* Pseudo amap definition for eth_tx_compl in which each bit of the
index 93ff8ef3935227c348d5bc8b20a6f0c4248ca570..5b26c4c9ab2b4fb2b98bb868a611bf5aeffb41a3 100644 (file)
@@ -738,38 +738,37 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
 
        memset(hdr, 0, sizeof(*hdr));
 
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
+       SET_TX_WRB_HDR_BITS(crc, hdr, 1);
 
        if (skb_is_gso(skb)) {
-               AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1);
-               AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss,
-                       hdr, skb_shinfo(skb)->gso_size);
+               SET_TX_WRB_HDR_BITS(lso, hdr, 1);
+               SET_TX_WRB_HDR_BITS(lso_mss, hdr, skb_shinfo(skb)->gso_size);
                if (skb_is_gso_v6(skb) && !lancer_chip(adapter))
-                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
+                       SET_TX_WRB_HDR_BITS(lso6, hdr, 1);
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                if (skb->encapsulation) {
-                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, ipcs, hdr, 1);
+                       SET_TX_WRB_HDR_BITS(ipcs, hdr, 1);
                        proto = skb_inner_ip_proto(skb);
                } else {
                        proto = skb_ip_proto(skb);
                }
                if (proto == IPPROTO_TCP)
-                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
+                       SET_TX_WRB_HDR_BITS(tcpcs, hdr, 1);
                else if (proto == IPPROTO_UDP)
-                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1);
+                       SET_TX_WRB_HDR_BITS(udpcs, hdr, 1);
        }
 
        if (vlan_tx_tag_present(skb)) {
-               AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
+               SET_TX_WRB_HDR_BITS(vlan, hdr, 1);
                vlan_tag = be_get_tx_vlan_tag(adapter, skb);
-               AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
+               SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag);
        }
 
        /* To skip HW VLAN tagging: evt = 1, compl = 0 */
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, !skip_hw_vlan);
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1);
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, num_wrb, hdr, wrb_cnt);
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len);
+       SET_TX_WRB_HDR_BITS(complete, hdr, !skip_hw_vlan);
+       SET_TX_WRB_HDR_BITS(event, hdr, 1);
+       SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt);
+       SET_TX_WRB_HDR_BITS(len, hdr, len);
 }
 
 static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
@@ -850,6 +849,7 @@ dma_err:
                unmap_tx_frag(dev, wrb, map_single);
                map_single = false;
                copied -= wrb->frag_len;
+               adapter->drv_stats.dma_map_errors++;
                queue_head_inc(txq);
        }
        return 0;
@@ -1073,15 +1073,15 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
 static int be_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       if (new_mtu < BE_MIN_MTU ||
-           new_mtu > (BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN))) {
-               dev_info(&adapter->pdev->dev,
-                        "MTU must be between %d and %d bytes\n",
-                        BE_MIN_MTU,
-                        (BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN)));
+       struct device *dev = &adapter->pdev->dev;
+
+       if (new_mtu < BE_MIN_MTU || new_mtu > BE_MAX_MTU) {
+               dev_info(dev, "MTU must be between %d and %d bytes\n",
+                        BE_MIN_MTU, BE_MAX_MTU);
                return -EINVAL;
        }
-       dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n",
+
+       dev_info(dev, "MTU changed from %d to %d bytes\n",
                 netdev->mtu, new_mtu);
        netdev->mtu = new_mtu;
        return 0;
@@ -1683,7 +1683,7 @@ static void be_rx_compl_process(struct be_rx_obj *rxo, struct napi_struct *napi,
        if (netdev->features & NETIF_F_RXHASH)
                skb_set_hash(skb, rxcp->rss_hash, PKT_HASH_TYPE_L3);
 
-       skb->encapsulation = rxcp->tunneled;
+       skb->csum_level = rxcp->tunneled;
        skb_mark_napi_id(skb, napi);
 
        if (rxcp->vlanf)
@@ -1741,7 +1741,7 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo,
        if (adapter->netdev->features & NETIF_F_RXHASH)
                skb_set_hash(skb, rxcp->rss_hash, PKT_HASH_TYPE_L3);
 
-       skb->encapsulation = rxcp->tunneled;
+       skb->csum_level = rxcp->tunneled;
        skb_mark_napi_id(skb, napi);
 
        if (rxcp->vlanf)
@@ -1753,65 +1753,46 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo,
 static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl,
                                 struct be_rx_compl_info *rxcp)
 {
-       rxcp->pkt_size =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, pktsize, compl);
-       rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtp, compl);
-       rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, err, compl);
-       rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, tcpf, compl);
-       rxcp->udpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, udpf, compl);
-       rxcp->ip_csum =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ipcksm, compl);
-       rxcp->l4_csum =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, l4_cksm, compl);
-       rxcp->ipv6 =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ip_version, compl);
-       rxcp->num_rcvd =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl);
-       rxcp->pkt_type =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
-       rxcp->rss_hash =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, compl);
+       rxcp->pkt_size = GET_RX_COMPL_V1_BITS(pktsize, compl);
+       rxcp->vlanf = GET_RX_COMPL_V1_BITS(vtp, compl);
+       rxcp->err = GET_RX_COMPL_V1_BITS(err, compl);
+       rxcp->tcpf = GET_RX_COMPL_V1_BITS(tcpf, compl);
+       rxcp->udpf = GET_RX_COMPL_V1_BITS(udpf, compl);
+       rxcp->ip_csum = GET_RX_COMPL_V1_BITS(ipcksm, compl);
+       rxcp->l4_csum = GET_RX_COMPL_V1_BITS(l4_cksm, compl);
+       rxcp->ipv6 = GET_RX_COMPL_V1_BITS(ip_version, compl);
+       rxcp->num_rcvd = GET_RX_COMPL_V1_BITS(numfrags, compl);
+       rxcp->pkt_type = GET_RX_COMPL_V1_BITS(cast_enc, compl);
+       rxcp->rss_hash = GET_RX_COMPL_V1_BITS(rsshash, compl);
        if (rxcp->vlanf) {
-               rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, qnq,
-                                         compl);
-               rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1,
-                                              vlan_tag, compl);
+               rxcp->qnq = GET_RX_COMPL_V1_BITS(qnq, compl);
+               rxcp->vlan_tag = GET_RX_COMPL_V1_BITS(vlan_tag, compl);
        }
-       rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, port, compl);
+       rxcp->port = GET_RX_COMPL_V1_BITS(port, compl);
        rxcp->tunneled =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, tunneled, compl);
+               GET_RX_COMPL_V1_BITS(tunneled, compl);
 }
 
 static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
                                 struct be_rx_compl_info *rxcp)
 {
-       rxcp->pkt_size =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, pktsize, compl);
-       rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtp, compl);
-       rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, err, compl);
-       rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, tcpf, compl);
-       rxcp->udpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, udpf, compl);
-       rxcp->ip_csum =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ipcksm, compl);
-       rxcp->l4_csum =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, l4_cksm, compl);
-       rxcp->ipv6 =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ip_version, compl);
-       rxcp->num_rcvd =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl);
-       rxcp->pkt_type =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
-       rxcp->rss_hash =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, compl);
+       rxcp->pkt_size = GET_RX_COMPL_V0_BITS(pktsize, compl);
+       rxcp->vlanf = GET_RX_COMPL_V0_BITS(vtp, compl);
+       rxcp->err = GET_RX_COMPL_V0_BITS(err, compl);
+       rxcp->tcpf = GET_RX_COMPL_V0_BITS(tcpf, compl);
+       rxcp->udpf = GET_RX_COMPL_V0_BITS(udpf, compl);
+       rxcp->ip_csum = GET_RX_COMPL_V0_BITS(ipcksm, compl);
+       rxcp->l4_csum = GET_RX_COMPL_V0_BITS(l4_cksm, compl);
+       rxcp->ipv6 = GET_RX_COMPL_V0_BITS(ip_version, compl);
+       rxcp->num_rcvd = GET_RX_COMPL_V0_BITS(numfrags, compl);
+       rxcp->pkt_type = GET_RX_COMPL_V0_BITS(cast_enc, compl);
+       rxcp->rss_hash = GET_RX_COMPL_V0_BITS(rsshash, compl);
        if (rxcp->vlanf) {
-               rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, qnq,
-                                         compl);
-               rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0,
-                                              vlan_tag, compl);
+               rxcp->qnq = GET_RX_COMPL_V0_BITS(qnq, compl);
+               rxcp->vlan_tag = GET_RX_COMPL_V0_BITS(vlan_tag, compl);
        }
-       rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, port, compl);
-       rxcp->ip_frag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0,
-                                     ip_frag, compl);
+       rxcp->port = GET_RX_COMPL_V0_BITS(port, compl);
+       rxcp->ip_frag = GET_RX_COMPL_V0_BITS(ip_frag, compl);
 }
 
 static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
@@ -1897,7 +1878,7 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
                        if (dma_mapping_error(dev, page_dmaaddr)) {
                                put_page(pagep);
                                pagep = NULL;
-                               rx_stats(rxo)->rx_post_fail++;
+                               adapter->drv_stats.dma_map_errors++;
                                break;
                        }
                        page_offset = 0;
@@ -1991,7 +1972,7 @@ static u16 be_tx_compl_process(struct be_adapter *adapter,
                queue_tail_inc(txq);
        } while (cur_index != last_index);
 
-       dev_kfree_skb_any(sent_skb);
+       dev_consume_skb_any(sent_skb);
        return num_wrbs;
 }
 
@@ -2091,9 +2072,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
                        num_wrbs = 0;
                        txq = &txo->q;
                        while ((txcp = be_tx_compl_get(&txo->cq))) {
-                               end_idx =
-                                       AMAP_GET_BITS(struct amap_eth_tx_compl,
-                                                     wrb_index, txcp);
+                               end_idx = GET_TX_COMPL_BITS(wrb_index, txcp);
                                num_wrbs += be_tx_compl_process(adapter, txo,
                                                                end_idx);
                                cmpl++;
@@ -2164,7 +2143,6 @@ static int be_evt_queues_create(struct be_adapter *adapter)
                napi_hash_add(&eqo->napi);
                aic = &adapter->aic_obj[i];
                eqo->adapter = adapter;
-               eqo->tx_budget = BE_TX_BUDGET;
                eqo->idx = i;
                aic->max_eqd = BE_MAX_EQD;
                aic->enable = true;
@@ -2443,20 +2421,63 @@ loop_continue:
        return work_done;
 }
 
-static bool be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
-                         int budget, int idx)
+static inline void be_update_tx_err(struct be_tx_obj *txo, u32 status)
+{
+       switch (status) {
+       case BE_TX_COMP_HDR_PARSE_ERR:
+               tx_stats(txo)->tx_hdr_parse_err++;
+               break;
+       case BE_TX_COMP_NDMA_ERR:
+               tx_stats(txo)->tx_dma_err++;
+               break;
+       case BE_TX_COMP_ACL_ERR:
+               tx_stats(txo)->tx_spoof_check_err++;
+               break;
+       }
+}
+
+static inline void lancer_update_tx_err(struct be_tx_obj *txo, u32 status)
+{
+       switch (status) {
+       case LANCER_TX_COMP_LSO_ERR:
+               tx_stats(txo)->tx_tso_err++;
+               break;
+       case LANCER_TX_COMP_HSW_DROP_MAC_ERR:
+       case LANCER_TX_COMP_HSW_DROP_VLAN_ERR:
+               tx_stats(txo)->tx_spoof_check_err++;
+               break;
+       case LANCER_TX_COMP_QINQ_ERR:
+               tx_stats(txo)->tx_qinq_err++;
+               break;
+       case LANCER_TX_COMP_PARITY_ERR:
+               tx_stats(txo)->tx_internal_parity_err++;
+               break;
+       case LANCER_TX_COMP_DMA_ERR:
+               tx_stats(txo)->tx_dma_err++;
+               break;
+       }
+}
+
+static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
+                         int idx)
 {
        struct be_eth_tx_compl *txcp;
-       int num_wrbs = 0, work_done;
+       int num_wrbs = 0, work_done = 0;
+       u32 compl_status;
+       u16 last_idx;
 
-       for (work_done = 0; work_done < budget; work_done++) {
-               txcp = be_tx_compl_get(&txo->cq);
-               if (!txcp)
-                       break;
-               num_wrbs += be_tx_compl_process(adapter, txo,
-                                               AMAP_GET_BITS(struct
-                                                             amap_eth_tx_compl,
-                                                             wrb_index, txcp));
+       while ((txcp = be_tx_compl_get(&txo->cq))) {
+               last_idx = GET_TX_COMPL_BITS(wrb_index, txcp);
+               num_wrbs += be_tx_compl_process(adapter, txo, last_idx);
+               work_done++;
+
+               compl_status = GET_TX_COMPL_BITS(status, txcp);
+               if (compl_status) {
+                       if (lancer_chip(adapter))
+                               lancer_update_tx_err(txo, compl_status);
+                       else
+                               be_update_tx_err(txo, compl_status);
+               }
        }
 
        if (work_done) {
@@ -2474,7 +2495,6 @@ static bool be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
                tx_stats(txo)->tx_compl += work_done;
                u64_stats_update_end(&tx_stats(txo)->sync_compl);
        }
-       return (work_done < budget); /* Done */
 }
 
 int be_poll(struct napi_struct *napi, int budget)
@@ -2483,17 +2503,12 @@ int be_poll(struct napi_struct *napi, int budget)
        struct be_adapter *adapter = eqo->adapter;
        int max_work = 0, work, i, num_evts;
        struct be_rx_obj *rxo;
-       bool tx_done;
+       struct be_tx_obj *txo;
 
        num_evts = events_get(eqo);
 
-       /* Process all TXQs serviced by this EQ */
-       for (i = eqo->idx; i < adapter->num_tx_qs; i += adapter->num_evt_qs) {
-               tx_done = be_process_tx(adapter, &adapter->tx_obj[i],
-                                       eqo->tx_budget, i);
-               if (!tx_done)
-                       max_work = budget;
-       }
+       for_all_tx_queues_on_eq(adapter, eqo, txo, i)
+               be_process_tx(adapter, txo, i);
 
        if (be_lock_napi(eqo)) {
                /* This loop will iterate twice for EQ0 in which
@@ -3309,10 +3324,20 @@ static void BEx_get_resources(struct be_adapter *adapter,
         */
        if (BE2_chip(adapter) || use_sriov ||  (adapter->port_num > 1) ||
            !be_physfn(adapter) || (be_is_mc(adapter) &&
-           !(adapter->function_caps & BE_FUNCTION_CAPS_RSS)))
+           !(adapter->function_caps & BE_FUNCTION_CAPS_RSS))) {
                res->max_tx_qs = 1;
-       else
+       } else if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
+               struct be_resources super_nic_res = {0};
+
+               /* On a SuperNIC profile, the driver needs to use the
+                * GET_PROFILE_CONFIG cmd to query the per-function TXQ limits
+                */
+               be_cmd_get_profile_config(adapter, &super_nic_res, 0);
+               /* Some old versions of BE3 FW don't report max_tx_qs value */
+               res->max_tx_qs = super_nic_res.max_tx_qs ? : BE3_MAX_TX_QS;
+       } else {
                res->max_tx_qs = BE3_MAX_TX_QS;
+       }
 
        if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
            !use_sriov && be_physfn(adapter))
@@ -3413,16 +3438,16 @@ static int be_get_resources(struct be_adapter *adapter)
                if (be_roce_supported(adapter))
                        res.max_evt_qs /= 2;
                adapter->res = res;
-
-               dev_info(dev, "Max: txqs %d, rxqs %d, rss %d, eqs %d, vfs %d\n",
-                        be_max_txqs(adapter), be_max_rxqs(adapter),
-                        be_max_rss(adapter), be_max_eqs(adapter),
-                        be_max_vfs(adapter));
-               dev_info(dev, "Max: uc-macs %d, mc-macs %d, vlans %d\n",
-                        be_max_uc(adapter), be_max_mc(adapter),
-                        be_max_vlans(adapter));
        }
 
+       dev_info(dev, "Max: txqs %d, rxqs %d, rss %d, eqs %d, vfs %d\n",
+                be_max_txqs(adapter), be_max_rxqs(adapter),
+                be_max_rss(adapter), be_max_eqs(adapter),
+                be_max_vfs(adapter));
+       dev_info(dev, "Max: uc-macs %d, mc-macs %d, vlans %d\n",
+                be_max_uc(adapter), be_max_mc(adapter),
+                be_max_vlans(adapter));
+
        return 0;
 }
 
@@ -3633,6 +3658,7 @@ static int be_setup(struct be_adapter *adapter)
                goto err;
 
        be_cmd_get_fw_ver(adapter);
+       dev_info(dev, "FW version is %s\n", adapter->fw_ver);
 
        if (BE2_chip(adapter) && fw_major_num(adapter->fw_ver) < 4) {
                dev_err(dev, "Firmware on card is old(%s), IRQs may not work.",
@@ -4052,6 +4078,7 @@ static int lancer_fw_download(struct be_adapter *adapter,
 {
 #define LANCER_FW_DOWNLOAD_CHUNK      (32 * 1024)
 #define LANCER_FW_DOWNLOAD_LOCATION   "/prg"
+       struct device *dev = &adapter->pdev->dev;
        struct be_dma_mem flash_cmd;
        const u8 *data_ptr = NULL;
        u8 *dest_image_ptr = NULL;
@@ -4064,21 +4091,16 @@ static int lancer_fw_download(struct be_adapter *adapter,
        u8 change_status;
 
        if (!IS_ALIGNED(fw->size, sizeof(u32))) {
-               dev_err(&adapter->pdev->dev,
-                       "FW Image not properly aligned. "
-                       "Length must be 4 byte aligned.\n");
-               status = -EINVAL;
-               goto lancer_fw_exit;
+               dev_err(dev, "FW image size should be multiple of 4\n");
+               return -EINVAL;
        }
 
        flash_cmd.size = sizeof(struct lancer_cmd_req_write_object)
                                + LANCER_FW_DOWNLOAD_CHUNK;
-       flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
+       flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size,
                                          &flash_cmd.dma, GFP_KERNEL);
-       if (!flash_cmd.va) {
-               status = -ENOMEM;
-               goto lancer_fw_exit;
-       }
+       if (!flash_cmd.va)
+               return -ENOMEM;
 
        dest_image_ptr = flash_cmd.va +
                                sizeof(struct lancer_cmd_req_write_object);
@@ -4113,35 +4135,27 @@ static int lancer_fw_download(struct be_adapter *adapter,
                                                 &add_status);
        }
 
-       dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va,
-                         flash_cmd.dma);
+       dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma);
        if (status) {
-               dev_err(&adapter->pdev->dev,
-                       "Firmware load error. "
-                       "Status code: 0x%x Additional Status: 0x%x\n",
-                       status, add_status);
-               goto lancer_fw_exit;
+               dev_err(dev, "Firmware load error\n");
+               return be_cmd_status(status);
        }
 
+       dev_info(dev, "Firmware flashed successfully\n");
+
        if (change_status == LANCER_FW_RESET_NEEDED) {
-               dev_info(&adapter->pdev->dev,
-                        "Resetting adapter to activate new FW\n");
+               dev_info(dev, "Resetting adapter to activate new FW\n");
                status = lancer_physdev_ctrl(adapter,
                                             PHYSDEV_CONTROL_FW_RESET_MASK);
                if (status) {
-                       dev_err(&adapter->pdev->dev,
-                               "Adapter busy for FW reset.\n"
-                               "New FW will not be active.\n");
-                       goto lancer_fw_exit;
+                       dev_err(dev, "Adapter busy, could not reset FW\n");
+                       dev_err(dev, "Reboot server to activate new FW\n");
                }
        } else if (change_status != LANCER_NO_RESET_NEEDED) {
-               dev_err(&adapter->pdev->dev,
-                       "System reboot required for new FW to be active\n");
+               dev_info(dev, "Reboot server to activate new FW\n");
        }
 
-       dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
-lancer_fw_exit:
-       return status;
+       return 0;
 }
 
 #define UFI_TYPE2              2
@@ -4506,6 +4520,7 @@ static int be_map_pci_bars(struct be_adapter *adapter)
        return 0;
 
 pci_map_err:
+       dev_err(&adapter->pdev->dev, "Error in mapping PCI BARs\n");
        be_unmap_pci_bars(adapter);
        return -ENOMEM;
 }
@@ -4822,6 +4837,8 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
        struct net_device *netdev;
        char port_name;
 
+       dev_info(&pdev->dev, "%s version is %s\n", DRV_NAME, DRV_VER);
+
        status = pci_enable_device(pdev);
        if (status)
                goto do_none;
index cca5bca44e737dd6fdd23e758bcffb8e2ce119e7..9b50272824a1e2c859feeaf00312aace09ec380c 100644 (file)
@@ -1,35 +1,30 @@
 /*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2006 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+ * Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2006 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
 
 /* ethtool support for e1000 */
 
 #include "e1000.h"
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 enum {NETDEV_STATS, E1000_STATS};
 
@@ -42,7 +37,7 @@ struct e1000_stats {
 
 #define E1000_STAT(m)          E1000_STATS, \
                                sizeof(((struct e1000_adapter *)0)->m), \
-                               offsetof(struct e1000_adapter, m)
+                               offsetof(struct e1000_adapter, m)
 #define E1000_NETDEV_STAT(m)   NETDEV_STATS, \
                                sizeof(((struct net_device *)0)->m), \
                                offsetof(struct net_device, m)
@@ -104,6 +99,7 @@ static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
        "Interrupt test (offline)", "Loopback test  (offline)",
        "Link test   (on/offline)"
 };
+
 #define E1000_TEST_LEN ARRAY_SIZE(e1000_gstrings_test)
 
 static int e1000_get_settings(struct net_device *netdev,
@@ -113,7 +109,6 @@ static int e1000_get_settings(struct net_device *netdev,
        struct e1000_hw *hw = &adapter->hw;
 
        if (hw->media_type == e1000_media_type_copper) {
-
                ecmd->supported = (SUPPORTED_10baseT_Half |
                                   SUPPORTED_10baseT_Full |
                                   SUPPORTED_100baseT_Half |
@@ -155,9 +150,8 @@ static int e1000_get_settings(struct net_device *netdev,
        }
 
        if (er32(STATUS) & E1000_STATUS_LU) {
-
                e1000_get_speed_and_duplex(hw, &adapter->link_speed,
-                                                  &adapter->link_duplex);
+                                          &adapter->link_duplex);
                ethtool_cmd_speed_set(ecmd, adapter->link_speed);
 
                /* unfortunately FULL_DUPLEX != DUPLEX_FULL
@@ -247,9 +241,9 @@ static int e1000_set_settings(struct net_device *netdev,
        if (netif_running(adapter->netdev)) {
                e1000_down(adapter);
                e1000_up(adapter);
-       } else
+       } else {
                e1000_reset(adapter);
-
+       }
        clear_bit(__E1000_RESETTING, &adapter->flags);
        return 0;
 }
@@ -279,11 +273,11 @@ static void e1000_get_pauseparam(struct net_device *netdev,
        pause->autoneg =
                (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
 
-       if (hw->fc == E1000_FC_RX_PAUSE)
+       if (hw->fc == E1000_FC_RX_PAUSE) {
                pause->rx_pause = 1;
-       else if (hw->fc == E1000_FC_TX_PAUSE)
+       } else if (hw->fc == E1000_FC_TX_PAUSE) {
                pause->tx_pause = 1;
-       else if (hw->fc == E1000_FC_FULL) {
+       else if (hw->fc == E1000_FC_FULL) {
                pause->rx_pause = 1;
                pause->tx_pause = 1;
        }
@@ -316,8 +310,9 @@ static int e1000_set_pauseparam(struct net_device *netdev,
                if (netif_running(adapter->netdev)) {
                        e1000_down(adapter);
                        e1000_up(adapter);
-               } else
+               } else {
                        e1000_reset(adapter);
+               }
        } else
                retval = ((hw->media_type == e1000_media_type_fiber) ?
                          e1000_setup_link(hw) : e1000_force_mac_fc(hw));
@@ -329,12 +324,14 @@ static int e1000_set_pauseparam(struct net_device *netdev,
 static u32 e1000_get_msglevel(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
+
        return adapter->msg_enable;
 }
 
 static void e1000_set_msglevel(struct net_device *netdev, u32 data)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
+
        adapter->msg_enable = data;
 }
 
@@ -526,7 +523,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
                 * only the first byte of the word is being modified
                 */
                ret_val = e1000_read_eeprom(hw, last_word, 1,
-                                 &eeprom_buff[last_word - first_word]);
+                                           &eeprom_buff[last_word - first_word]);
        }
 
        /* Device's eeprom is always little-endian, word addressable */
@@ -618,13 +615,12 @@ static int e1000_set_ringparam(struct net_device *netdev,
        adapter->tx_ring = txdr;
        adapter->rx_ring = rxdr;
 
-       rxdr->count = max(ring->rx_pending,(u32)E1000_MIN_RXD);
-       rxdr->count = min(rxdr->count,(u32)(mac_type < e1000_82544 ?
+       rxdr->count = max(ring->rx_pending, (u32)E1000_MIN_RXD);
+       rxdr->count = min(rxdr->count, (u32)(mac_type < e1000_82544 ?
                          E1000_MAX_RXD : E1000_MAX_82544_RXD));
        rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
-
-       txdr->count = max(ring->tx_pending,(u32)E1000_MIN_TXD);
-       txdr->count = min(txdr->count,(u32)(mac_type < e1000_82544 ?
+       txdr->count = max(ring->tx_pending, (u32)E1000_MIN_TXD);
+       txdr->count = min(txdr->count, (u32)(mac_type < e1000_82544 ?
                          E1000_MAX_TXD : E1000_MAX_82544_TXD));
        txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
 
@@ -680,8 +676,9 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data, int reg,
                             u32 mask, u32 write)
 {
        struct e1000_hw *hw = &adapter->hw;
-       static const u32 test[] =
-               {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+       static const u32 test[] = {
+               0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
+       };
        u8 __iomem *address = hw->hw_addr + reg;
        u32 read;
        int i;
@@ -793,8 +790,8 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
                REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF);
                value = E1000_RAR_ENTRIES;
                for (i = 0; i < value; i++) {
-                       REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
-                                        0xFFFFFFFF);
+                       REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2),
+                                        0x8003FFFF, 0xFFFFFFFF);
                }
        } else {
                REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF);
@@ -877,7 +874,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
 
        /* Test each interrupt */
        for (; i < 10; i++) {
-
                /* Interrupt to test */
                mask = 1 << i;
 
@@ -1149,8 +1145,7 @@ static void e1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter)
         */
        e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
        phy_reg |= M88E1000_EPSCR_TX_CLK_25;
-       e1000_write_phy_reg(hw,
-               M88E1000_EXT_PHY_SPEC_CTRL, phy_reg);
+       e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_reg);
 
        /* In addition, because of the s/w reset above, we need to enable
         * CRS on TX.  This must be set for both full and half duplex
@@ -1158,8 +1153,7 @@ static void e1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter)
         */
        e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_reg);
        phy_reg |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-       e1000_write_phy_reg(hw,
-               M88E1000_PHY_SPEC_CTRL, phy_reg);
+       e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_reg);
 }
 
 static int e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter)
@@ -1216,7 +1210,7 @@ static int e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter)
        /* Check Phy Configuration */
        e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg);
        if (phy_reg != 0x4100)
-                return 9;
+               return 9;
 
        e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
        if (phy_reg != 0x0070)
@@ -1261,7 +1255,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
                        E1000_CTRL_FD); /* Force Duplex to FULL */
 
        if (hw->media_type == e1000_media_type_copper &&
-          hw->phy_type == e1000_phy_m88)
+           hw->phy_type == e1000_phy_m88)
                ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
        else {
                /* Set the ILOS bit on the fiber Nic is half
@@ -1299,7 +1293,7 @@ static int e1000_set_phy_loopback(struct e1000_adapter *adapter)
                         * attempt this 10 times.
                         */
                        while (e1000_nonintegrated_phy_loopback(adapter) &&
-                             count++ < 10);
+                              count++ < 10);
                        if (count < 11)
                                return 0;
                }
@@ -1348,8 +1342,9 @@ static int e1000_setup_loopback_test(struct e1000_adapter *adapter)
                        ew32(RCTL, rctl);
                        return 0;
                }
-       } else if (hw->media_type == e1000_media_type_copper)
+       } else if (hw->media_type == e1000_media_type_copper) {
                return e1000_set_phy_loopback(adapter);
+       }
 
        return 7;
 }
@@ -1395,9 +1390,9 @@ static int e1000_check_lbtest_frame(struct sk_buff *skb,
                                    unsigned int frame_size)
 {
        frame_size &= ~1;
-       if (*(skb->data + 3) == 0xFF) {
-               if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
-                  (*(skb->data + frame_size / 2 + 12) == 0xAF)) {
+       if (skb->data[3] == 0xFF) {
+               if (skb->data[frame_size / 2 + 10] == 0xBE &&
+                   skb->data[frame_size / 2 + 12] == 0xAF) {
                        return 0;
                }
        }
@@ -1410,7 +1405,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
        struct e1000_tx_ring *txdr = &adapter->test_tx_ring;
        struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
        struct pci_dev *pdev = adapter->pdev;
-       int i, j, k, l, lc, good_cnt, ret_val=0;
+       int i, j, k, l, lc, good_cnt, ret_val = 0;
        unsigned long time;
 
        ew32(RDT, rxdr->count - 1);
@@ -1429,12 +1424,13 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
        for (j = 0; j <= lc; j++) { /* loop count loop */
                for (i = 0; i < 64; i++) { /* send the packets */
                        e1000_create_lbtest_frame(txdr->buffer_info[i].skb,
-                                       1024);
+                                                 1024);
                        dma_sync_single_for_device(&pdev->dev,
                                                   txdr->buffer_info[k].dma,
                                                   txdr->buffer_info[k].length,
                                                   DMA_TO_DEVICE);
-                       if (unlikely(++k == txdr->count)) k = 0;
+                       if (unlikely(++k == txdr->count))
+                               k = 0;
                }
                ew32(TDT, k);
                E1000_WRITE_FLUSH();
@@ -1452,7 +1448,8 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
                                        1024);
                        if (!ret_val)
                                good_cnt++;
-                       if (unlikely(++l == rxdr->count)) l = 0;
+                       if (unlikely(++l == rxdr->count))
+                               l = 0;
                        /* time + 20 msecs (200 msecs on 2.4) is more than
                         * enough time to complete the receives, if it's
                         * exceeded, break and error off
@@ -1494,6 +1491,7 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
        *data = 0;
        if (hw->media_type == e1000_media_type_internal_serdes) {
                int i = 0;
+
                hw->serdes_has_link = false;
 
                /* On some blade server designs, link establishment
@@ -1512,9 +1510,8 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
                if (hw->autoneg)  /* if auto_neg is set wait for it */
                        msleep(4000);
 
-               if (!(er32(STATUS) & E1000_STATUS_LU)) {
+               if (!(er32(STATUS) & E1000_STATUS_LU))
                        *data = 1;
-               }
        }
        return *data;
 }
@@ -1665,8 +1662,7 @@ static void e1000_get_wol(struct net_device *netdev,
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
-       wol->supported = WAKE_UCAST | WAKE_MCAST |
-                        WAKE_BCAST | WAKE_MAGIC;
+       wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
        wol->wolopts = 0;
 
        /* this function will set ->supported = 0 and return 1 if wol is not
@@ -1819,6 +1815,7 @@ static int e1000_set_coalesce(struct net_device *netdev,
 static int e1000_nway_reset(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
+
        if (netif_running(netdev))
                e1000_reinit_locked(adapter);
        return 0;
@@ -1830,22 +1827,29 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
        struct e1000_adapter *adapter = netdev_priv(netdev);
        int i;
        char *p = NULL;
+       const struct e1000_stats *stat = e1000_gstrings_stats;
 
        e1000_update_stats(adapter);
        for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
-               switch (e1000_gstrings_stats[i].type) {
+               switch (stat->type) {
                case NETDEV_STATS:
-                       p = (char *) netdev +
-                                       e1000_gstrings_stats[i].stat_offset;
+                       p = (char *)netdev + stat->stat_offset;
                        break;
                case E1000_STATS:
-                       p = (char *) adapter +
-                                       e1000_gstrings_stats[i].stat_offset;
+                       p = (char *)adapter + stat->stat_offset;
+                       break;
+               default:
+                       WARN_ONCE(1, "Invalid E1000 stat type: %u index %d\n",
+                                 stat->type, i);
                        break;
                }
 
-               data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
-                       sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+               if (stat->sizeof_stat == sizeof(u64))
+                       data[i] = *(u64 *)p;
+               else
+                       data[i] = *(u32 *)p;
+
+               stat++;
        }
 /* BUG_ON(i != E1000_STATS_LEN); */
 }
@@ -1858,8 +1862,7 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,
 
        switch (stringset) {
        case ETH_SS_TEST:
-               memcpy(data, *e1000_gstrings_test,
-                       sizeof(e1000_gstrings_test));
+               memcpy(data, e1000_gstrings_test, sizeof(e1000_gstrings_test));
                break;
        case ETH_SS_STATS:
                for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
index 801da392a20e23dc84e176579720f0a106695776..f1e33f896439b1d6ccbc5f2428d9aef05fcbcee3 100644 (file)
@@ -144,6 +144,8 @@ enum i40e_state_t {
        __I40E_PTP_TX_IN_PROGRESS,
        __I40E_BAD_EEPROM,
        __I40E_DOWN_REQUESTED,
+       __I40E_FD_FLUSH_REQUESTED,
+       __I40E_RESET_FAILED,
 };
 
 enum i40e_interrupt_policy {
@@ -250,6 +252,11 @@ struct i40e_pf {
        u16 fdir_pf_active_filters;
        u16 fd_sb_cnt_idx;
        u16 fd_atr_cnt_idx;
+       unsigned long fd_flush_timestamp;
+       u32 fd_flush_cnt;
+       u32 fd_add_err;
+       u32 fd_atr_cnt;
+       u32 fd_tcp_rule;
 
 #ifdef CONFIG_I40E_VXLAN
        __be16  vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
@@ -310,6 +317,7 @@ struct i40e_pf {
        u32 tx_timeout_count;
        u32 tx_timeout_recovery_level;
        unsigned long tx_timeout_last_recovery;
+       u32 tx_sluggish_count;
        u32 hw_csum_rx_error;
        u32 led_status;
        u16 corer_count; /* Core reset count */
@@ -608,6 +616,7 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi,
 void i40e_fdir_check_and_reenable(struct i40e_pf *pf);
 int i40e_get_current_fd_count(struct i40e_pf *pf);
 int i40e_get_cur_guaranteed_fd_count(struct i40e_pf *pf);
+int i40e_get_current_atr_cnt(struct i40e_pf *pf);
 bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features);
 void i40e_set_ethtool_ops(struct net_device *netdev);
 struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
index b29c157b1f57b7d587f00ff208a0124991d06bdb..72f5d25a222f0769ea514d5789407a543e66c3c2 100644 (file)
@@ -840,7 +840,8 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
 
        /* bump the tail */
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
-       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff);
+       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring,
+                     buff, buff_size);
        (hw->aq.asq.next_to_use)++;
        if (hw->aq.asq.next_to_use == hw->aq.asq.count)
                hw->aq.asq.next_to_use = 0;
@@ -891,7 +892,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
 
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: desc and buffer writeback:\n");
-       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff);
+       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size);
 
        /* update the error if time out occurred */
        if ((!cmd_completed) &&
@@ -987,7 +988,8 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
                       e->msg_size);
 
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
-       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf);
+       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf,
+                     hw->aq.arq_buf_size);
 
        /* Restore the original datalen and buffer address in the desc,
         * FW updates datalen to indicate the event message
index df43e7c6777c238423af02e9171bf418ad08e339..30056b25d94e6c331d9456c7171e3b51b5b7e754 100644 (file)
@@ -75,13 +75,15 @@ static i40e_status i40e_set_mac_type(struct i40e_hw *hw)
  * @mask: debug mask
  * @desc: pointer to admin queue descriptor
  * @buffer: pointer to command buffer
+ * @buf_len: max length of buffer
  *
  * Dumps debug log about adminq command with descriptor contents.
  **/
 void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
-                  void *buffer)
+                  void *buffer, u16 buf_len)
 {
        struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
+       u16 len = le16_to_cpu(aq_desc->datalen);
        u8 *aq_buffer = (u8 *)buffer;
        u32 data[4];
        u32 i = 0;
@@ -105,7 +107,9 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
        if ((buffer != NULL) && (aq_desc->datalen != 0)) {
                memset(data, 0, sizeof(data));
                i40e_debug(hw, mask, "AQ CMD Buffer:\n");
-               for (i = 0; i < le16_to_cpu(aq_desc->datalen); i++) {
+               if (buf_len < len)
+                       len = buf_len;
+               for (i = 0; i < len; i++) {
                        data[((i % 16) / 4)] |=
                                ((u32)aq_buffer[i]) << (8 * (i % 4));
                        if ((i % 16) == 15) {
@@ -748,6 +752,8 @@ static enum i40e_media_type i40e_get_media_type(struct i40e_hw *hw)
        switch (hw->phy.link_info.phy_type) {
        case I40E_PHY_TYPE_10GBASE_SR:
        case I40E_PHY_TYPE_10GBASE_LR:
+       case I40E_PHY_TYPE_1000BASE_SX:
+       case I40E_PHY_TYPE_1000BASE_LX:
        case I40E_PHY_TYPE_40GBASE_SR4:
        case I40E_PHY_TYPE_40GBASE_LR4:
                media = I40E_MEDIA_TYPE_FIBER;
index 5a0cabeb35ed7f21e37a523a1418981fb23d0836..7067f4b9159c99e9720484ca2ea5d7fe574fed5f 100644 (file)
@@ -1356,6 +1356,9 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                                 "emp reset count: %d\n", pf->empr_count);
                        dev_info(&pf->pdev->dev,
                                 "pf reset count: %d\n", pf->pfr_count);
+                       dev_info(&pf->pdev->dev,
+                                "pf tx sluggish count: %d\n",
+                                pf->tx_sluggish_count);
                } else if (strncmp(&cmd_buf[5], "port", 4) == 0) {
                        struct i40e_aqc_query_port_ets_config_resp *bw_data;
                        struct i40e_dcbx_config *cfg =
index e8ba7470700af1abaaf33826c7bffc8409666b9e..1dda467ae1ac62bdc5428e4c6086c322fdac597d 100644 (file)
@@ -145,6 +145,7 @@ static struct i40e_stats i40e_gstrings_stats[] = {
        I40E_PF_STAT("rx_jabber", stats.rx_jabber),
        I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
        I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
+       I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt),
        I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match),
        I40E_PF_STAT("fdir_sb_match", stats.fd_sb_match),
 
@@ -312,7 +313,10 @@ static int i40e_get_settings(struct net_device *netdev,
                break;
        case I40E_PHY_TYPE_10GBASE_SR:
        case I40E_PHY_TYPE_10GBASE_LR:
+       case I40E_PHY_TYPE_1000BASE_SX:
+       case I40E_PHY_TYPE_1000BASE_LX:
                ecmd->supported = SUPPORTED_10000baseT_Full;
+               ecmd->supported |= SUPPORTED_1000baseT_Full;
                break;
        case I40E_PHY_TYPE_10GBASE_CR1_CU:
        case I40E_PHY_TYPE_10GBASE_CR1:
@@ -351,7 +355,8 @@ static int i40e_get_settings(struct net_device *netdev,
                break;
        default:
                /* if we got here and link is up something bad is afoot */
-               WARN_ON(link_up);
+               netdev_info(netdev, "WARNING: Link is up but PHY type 0x%x is not recognized.\n",
+                           hw_link_info->phy_type);
        }
 
 no_valid_phy_type:
@@ -461,7 +466,8 @@ static int i40e_set_settings(struct net_device *netdev,
 
        if (hw->phy.media_type != I40E_MEDIA_TYPE_BASET &&
            hw->phy.media_type != I40E_MEDIA_TYPE_FIBER &&
-           hw->phy.media_type != I40E_MEDIA_TYPE_BACKPLANE)
+           hw->phy.media_type != I40E_MEDIA_TYPE_BACKPLANE &&
+           hw->phy.link_info.link_info & I40E_AQ_LINK_UP)
                return -EOPNOTSUPP;
 
        /* get our own copy of the bits to check against */
@@ -492,11 +498,10 @@ static int i40e_set_settings(struct net_device *netdev,
        if (status)
                return -EAGAIN;
 
-       /* Copy link_speed and abilities to config in case they are not
+       /* Copy abilities to config in case autoneg is not
         * set below
         */
        memset(&config, 0, sizeof(struct i40e_aq_set_phy_config));
-       config.link_speed = abilities.link_speed;
        config.abilities = abilities.abilities;
 
        /* Check autoneg */
@@ -533,42 +538,38 @@ static int i40e_set_settings(struct net_device *netdev,
                return -EINVAL;
 
        if (advertise & ADVERTISED_100baseT_Full)
-               if (!(abilities.link_speed & I40E_LINK_SPEED_100MB)) {
-                       config.link_speed |= I40E_LINK_SPEED_100MB;
-                       change = true;
-               }
+               config.link_speed |= I40E_LINK_SPEED_100MB;
        if (advertise & ADVERTISED_1000baseT_Full ||
            advertise & ADVERTISED_1000baseKX_Full)
-               if (!(abilities.link_speed & I40E_LINK_SPEED_1GB)) {
-                       config.link_speed |= I40E_LINK_SPEED_1GB;
-                       change = true;
-               }
+               config.link_speed |= I40E_LINK_SPEED_1GB;
        if (advertise & ADVERTISED_10000baseT_Full ||
            advertise & ADVERTISED_10000baseKX4_Full ||
            advertise & ADVERTISED_10000baseKR_Full)
-               if (!(abilities.link_speed & I40E_LINK_SPEED_10GB)) {
-                       config.link_speed |= I40E_LINK_SPEED_10GB;
-                       change = true;
-               }
+               config.link_speed |= I40E_LINK_SPEED_10GB;
        if (advertise & ADVERTISED_40000baseKR4_Full ||
            advertise & ADVERTISED_40000baseCR4_Full ||
            advertise & ADVERTISED_40000baseSR4_Full ||
            advertise & ADVERTISED_40000baseLR4_Full)
-               if (!(abilities.link_speed & I40E_LINK_SPEED_40GB)) {
-                       config.link_speed |= I40E_LINK_SPEED_40GB;
-                       change = true;
-               }
+               config.link_speed |= I40E_LINK_SPEED_40GB;
 
-       if (change) {
+       if (change || (abilities.link_speed != config.link_speed)) {
                /* copy over the rest of the abilities */
                config.phy_type = abilities.phy_type;
                config.eee_capability = abilities.eee_capability;
                config.eeer = abilities.eeer_val;
                config.low_power_ctrl = abilities.d3_lpan;
 
-               /* If link is up set link and an so changes take effect */
-               if (hw->phy.link_info.link_info & I40E_AQ_LINK_UP)
-                       config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+               /* set link and auto negotiation so changes take effect */
+               config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+               /* If link is up put link down */
+               if (hw->phy.link_info.link_info & I40E_AQ_LINK_UP) {
+                       /* Tell the OS link is going down, the link will go
+                        * back up when fw says it is ready asynchronously
+                        */
+                       netdev_info(netdev, "PHY settings change requested, NIC Link is going down.\n");
+                       netif_carrier_off(netdev);
+                       netif_tx_stop_all_queues(netdev);
+               }
 
                /* make the aq call */
                status = i40e_aq_set_phy_config(hw, &config, NULL);
@@ -685,6 +686,13 @@ static int i40e_set_pauseparam(struct net_device *netdev,
        else
                 return -EINVAL;
 
+       /* Tell the OS link is going down, the link will go back up when fw
+        * says it is ready asynchronously
+        */
+       netdev_info(netdev, "Flow control settings change requested, NIC Link is going down.\n");
+       netif_carrier_off(netdev);
+       netif_tx_stop_all_queues(netdev);
+
        /* Set the fc mode and only restart an if link is up*/
        status = i40e_set_fc(hw, &aq_failures, link_up);
 
@@ -1977,6 +1985,13 @@ static int i40e_del_fdir_entry(struct i40e_vsi *vsi,
        struct i40e_pf *pf = vsi->back;
        int ret = 0;
 
+       if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
+           test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
+               return -EBUSY;
+
+       if (test_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state))
+               return -EBUSY;
+
        ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd);
 
        i40e_fdir_check_and_reenable(pf);
@@ -2010,6 +2025,13 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
        if (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)
                return -ENOSPC;
 
+       if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
+           test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
+               return -EBUSY;
+
+       if (test_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state))
+               return -EBUSY;
+
        fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
 
        if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort +
index eddec6ba095b7105118962438c9914d40acd97b4..ed5f1c15fb0f4cd5fe7ce797920fd3b6cd21f7df 100644 (file)
@@ -37,9 +37,9 @@ static const char i40e_driver_string[] =
 
 #define DRV_KERN "-k"
 
-#define DRV_VERSION_MAJOR 0
-#define DRV_VERSION_MINOR 4
-#define DRV_VERSION_BUILD 21
+#define DRV_VERSION_MAJOR 1
+#define DRV_VERSION_MINOR 0
+#define DRV_VERSION_BUILD 11
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -1239,8 +1239,11 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr,
  * i40e_rm_default_mac_filter - Remove the default MAC filter set by NVM
  * @vsi: the PF Main VSI - inappropriate for any other VSI
  * @macaddr: the MAC address
+ *
+ * Some older firmware configurations set up a default promiscuous VLAN
+ * filter that needs to be removed.
  **/
-static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
+static int i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
 {
        struct i40e_aqc_remove_macvlan_element_data element;
        struct i40e_pf *pf = vsi->back;
@@ -1248,15 +1251,18 @@ static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
 
        /* Only appropriate for the PF main VSI */
        if (vsi->type != I40E_VSI_MAIN)
-               return;
+               return -EINVAL;
 
+       memset(&element, 0, sizeof(element));
        ether_addr_copy(element.mac_addr, macaddr);
        element.vlan_tag = 0;
        element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
                        I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
        aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
        if (aq_ret)
-               dev_err(&pf->pdev->dev, "Could not remove default MAC-VLAN\n");
+               return -ENOENT;
+
+       return 0;
 }
 
 /**
@@ -1385,18 +1391,30 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
        struct sockaddr *addr = p;
        struct i40e_mac_filter *f;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       netdev_info(netdev, "set mac address=%pM\n", addr->sa_data);
+       if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) {
+               netdev_info(netdev, "already using mac address %pM\n",
+                           addr->sa_data);
+               return 0;
+       }
 
        if (test_bit(__I40E_DOWN, &vsi->back->state) ||
            test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
                return -EADDRNOTAVAIL;
 
+       if (ether_addr_equal(hw->mac.addr, addr->sa_data))
+               netdev_info(netdev, "returning to hw mac address %pM\n",
+                           hw->mac.addr);
+       else
+               netdev_info(netdev, "set new mac address %pM\n", addr->sa_data);
+
        if (vsi->type == I40E_VSI_MAIN) {
                i40e_status ret;
                ret = i40e_aq_mac_address_write(&vsi->back->hw,
@@ -1410,25 +1428,34 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
                }
        }
 
-       f = i40e_find_mac(vsi, addr->sa_data, false, true);
-       if (!f) {
-               /* In order to be sure to not drop any packets, add the
-                * new address first then delete the old one.
-                */
-               f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY,
-                                   false, false);
-               if (!f)
-                       return -ENOMEM;
+       if (ether_addr_equal(netdev->dev_addr, hw->mac.addr)) {
+               struct i40e_aqc_remove_macvlan_element_data element;
 
-               i40e_sync_vsi_filters(vsi);
+               memset(&element, 0, sizeof(element));
+               ether_addr_copy(element.mac_addr, netdev->dev_addr);
+               element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
+               i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
+       } else {
                i40e_del_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY,
                                false, false);
-               i40e_sync_vsi_filters(vsi);
        }
 
-       f->is_laa = true;
-       if (!ether_addr_equal(netdev->dev_addr, addr->sa_data))
-               ether_addr_copy(netdev->dev_addr, addr->sa_data);
+       if (ether_addr_equal(addr->sa_data, hw->mac.addr)) {
+               struct i40e_aqc_add_macvlan_element_data element;
+
+               memset(&element, 0, sizeof(element));
+               ether_addr_copy(element.mac_addr, hw->mac.addr);
+               element.flags = cpu_to_le16(I40E_AQC_MACVLAN_ADD_PERFECT_MATCH);
+               i40e_aq_add_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
+       } else {
+               f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY,
+                                   false, false);
+               if (f)
+                       f->is_laa = true;
+       }
+
+       i40e_sync_vsi_filters(vsi);
+       ether_addr_copy(netdev->dev_addr, addr->sa_data);
 
        return 0;
 }
@@ -1796,9 +1823,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                kfree(add_list);
                add_list = NULL;
 
-               if (add_happened && (!aq_ret)) {
-                       /* do nothing */;
-               } else if (add_happened && (aq_ret)) {
+               if (add_happened && aq_ret &&
+                   pf->hw.aq.asq_last_status != I40E_AQ_RC_EINVAL) {
                        dev_info(&pf->pdev->dev,
                                 "add filter failed, err %d, aq_err %d\n",
                                 aq_ret, pf->hw.aq.asq_last_status);
@@ -4480,11 +4506,26 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
                netif_carrier_on(vsi->netdev);
        } else if (vsi->netdev) {
                i40e_print_link_message(vsi, false);
+               /* need to check for qualified module here*/
+               if ((pf->hw.phy.link_info.link_info &
+                       I40E_AQ_MEDIA_AVAILABLE) &&
+                   (!(pf->hw.phy.link_info.an_info &
+                       I40E_AQ_QUALIFIED_MODULE)))
+                       netdev_err(vsi->netdev,
+                                  "the driver failed to link because an unqualified module was detected.");
        }
 
        /* replay FDIR SB filters */
-       if (vsi->type == I40E_VSI_FDIR)
+       if (vsi->type == I40E_VSI_FDIR) {
+               /* reset fd counters */
+               pf->fd_add_err = pf->fd_atr_cnt = 0;
+               if (pf->fd_tcp_rule > 0) {
+                       pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                       dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 exist\n");
+                       pf->fd_tcp_rule = 0;
+               }
                i40e_fdir_filter_restore(vsi);
+       }
        i40e_service_event_schedule(pf);
 
        return 0;
@@ -5125,6 +5166,7 @@ int i40e_get_current_fd_count(struct i40e_pf *pf)
                      I40E_PFQF_FDSTAT_BEST_CNT_SHIFT);
        return fcnt_prog;
 }
+
 /**
  * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled
  * @pf: board private structure
@@ -5133,15 +5175,17 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
 {
        u32 fcnt_prog, fcnt_avail;
 
+       if (test_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state))
+               return;
+
        /* Check if, FD SB or ATR was auto disabled and if there is enough room
         * to re-enable
         */
-       if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
-           (pf->flags & I40E_FLAG_FD_SB_ENABLED))
-               return;
        fcnt_prog = i40e_get_cur_guaranteed_fd_count(pf);
        fcnt_avail = pf->fdir_pf_filter_count;
-       if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) {
+       if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) ||
+           (pf->fd_add_err == 0) ||
+           (i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt)) {
                if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
                    (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) {
                        pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
@@ -5158,23 +5202,84 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
        }
 }
 
+#define I40E_MIN_FD_FLUSH_INTERVAL 10
+/**
+ * i40e_fdir_flush_and_replay - Function to flush all FD filters and replay SB
+ * @pf: board private structure
+ **/
+static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
+{
+       int flush_wait_retry = 50;
+       int reg;
+
+       if (time_after(jiffies, pf->fd_flush_timestamp +
+                               (I40E_MIN_FD_FLUSH_INTERVAL * HZ))) {
+               set_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
+               pf->fd_flush_timestamp = jiffies;
+               pf->auto_disable_flags |= I40E_FLAG_FD_SB_ENABLED;
+               pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+               /* flush all filters */
+               wr32(&pf->hw, I40E_PFQF_CTL_1,
+                    I40E_PFQF_CTL_1_CLEARFDTABLE_MASK);
+               i40e_flush(&pf->hw);
+               pf->fd_flush_cnt++;
+               pf->fd_add_err = 0;
+               do {
+                       /* Check FD flush status every 5-6msec */
+                       usleep_range(5000, 6000);
+                       reg = rd32(&pf->hw, I40E_PFQF_CTL_1);
+                       if (!(reg & I40E_PFQF_CTL_1_CLEARFDTABLE_MASK))
+                               break;
+               } while (flush_wait_retry--);
+               if (reg & I40E_PFQF_CTL_1_CLEARFDTABLE_MASK) {
+                       dev_warn(&pf->pdev->dev, "FD table did not flush, needs more time\n");
+               } else {
+                       /* replay sideband filters */
+                       i40e_fdir_filter_restore(pf->vsi[pf->lan_vsi]);
+
+                       pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+                       pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                       pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
+                       clear_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
+                       dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n");
+               }
+       }
+}
+
+/**
+ * i40e_get_current_atr_count - Get the count of total FD ATR filters programmed
+ * @pf: board private structure
+ **/
+int i40e_get_current_atr_cnt(struct i40e_pf *pf)
+{
+       return i40e_get_current_fd_count(pf) - pf->fdir_pf_active_filters;
+}
+
+/* We can see up to 256 filter programming desc in transit if the filters are
+ * being applied really fast; before we see the first
+ * filter miss error on Rx queue 0. Accumulating enough error messages before
+ * reacting will make sure we don't cause flush too often.
+ */
+#define I40E_MAX_FD_PROGRAM_ERROR 256
+
 /**
  * i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table
  * @pf: board private structure
  **/
 static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
 {
-       if (!(pf->flags & I40E_FLAG_FDIR_REQUIRES_REINIT))
-               return;
 
        /* if interface is down do nothing */
        if (test_bit(__I40E_DOWN, &pf->state))
                return;
+
+       if ((pf->fd_add_err >= I40E_MAX_FD_PROGRAM_ERROR) &&
+           (i40e_get_current_atr_cnt(pf) >= pf->fd_atr_cnt) &&
+           (i40e_get_current_atr_cnt(pf) > pf->fdir_pf_filter_count))
+               i40e_fdir_flush_and_replay(pf);
+
        i40e_fdir_check_and_reenable(pf);
 
-       if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
-           (pf->flags & I40E_FLAG_FD_SB_ENABLED))
-               pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
 }
 
 /**
@@ -5184,7 +5289,7 @@ static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
  **/
 static void i40e_vsi_link_event(struct i40e_vsi *vsi, bool link_up)
 {
-       if (!vsi)
+       if (!vsi || test_bit(__I40E_DOWN, &vsi->state))
                return;
 
        switch (vsi->type) {
@@ -5420,6 +5525,13 @@ static void i40e_handle_link_event(struct i40e_pf *pf,
        memcpy(&pf->hw.phy.link_info_old, hw_link_info,
               sizeof(pf->hw.phy.link_info_old));
 
+       /* check for unqualified module, if link is down */
+       if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
+           (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
+           (!(status->link_info & I40E_AQ_LINK_UP)))
+               dev_err(&pf->pdev->dev,
+                       "The driver failed to link because an unqualified module was detected.\n");
+
        /* update link status */
        hw_link_info->phy_type = (enum i40e_aq_phy_type)status->phy_type;
        hw_link_info->link_speed = (enum i40e_aq_link_speed)status->link_speed;
@@ -5456,6 +5568,10 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
        u32 oldval;
        u32 val;
 
+       /* Do not run clean AQ when PF reset fails */
+       if (test_bit(__I40E_RESET_FAILED, &pf->state))
+               return;
+
        /* check for error indications */
        val = rd32(&pf->hw, pf->hw.aq.arq.len);
        oldval = val;
@@ -5861,19 +5977,20 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        ret = i40e_pf_reset(hw);
        if (ret) {
                dev_info(&pf->pdev->dev, "PF reset failed, %d\n", ret);
-               goto end_core_reset;
+               set_bit(__I40E_RESET_FAILED, &pf->state);
+               goto clear_recovery;
        }
        pf->pfr_count++;
 
        if (test_bit(__I40E_DOWN, &pf->state))
-               goto end_core_reset;
+               goto clear_recovery;
        dev_dbg(&pf->pdev->dev, "Rebuilding internal switch\n");
 
        /* rebuild the basics for the AdminQ, HMC, and initial HW switch */
        ret = i40e_init_adminq(&pf->hw);
        if (ret) {
                dev_info(&pf->pdev->dev, "Rebuild AdminQ failed, %d\n", ret);
-               goto end_core_reset;
+               goto clear_recovery;
        }
 
        /* re-verify the eeprom if we just had an EMP reset */
@@ -5991,6 +6108,8 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        i40e_send_version(pf);
 
 end_core_reset:
+       clear_bit(__I40E_RESET_FAILED, &pf->state);
+clear_recovery:
        clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state);
 }
 
@@ -6036,9 +6155,9 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                                I40E_GL_MDET_TX_EVENT_SHIFT;
                u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
                                I40E_GL_MDET_TX_QUEUE_SHIFT;
-               dev_info(&pf->pdev->dev,
-                        "Malicious Driver Detection event 0x%02x on TX queue %d pf number 0x%02x vf number 0x%02x\n",
-                        event, queue, pf_num, vf_num);
+               if (netif_msg_tx_err(pf))
+                       dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on TX queue %d pf number 0x%02x vf number 0x%02x\n",
+                                event, queue, pf_num, vf_num);
                wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
                mdd_detected = true;
        }
@@ -6050,9 +6169,9 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                                I40E_GL_MDET_RX_EVENT_SHIFT;
                u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
                                I40E_GL_MDET_RX_QUEUE_SHIFT;
-               dev_info(&pf->pdev->dev,
-                        "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n",
-                        event, queue, func);
+               if (netif_msg_rx_err(pf))
+                       dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n",
+                                event, queue, func);
                wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
                mdd_detected = true;
        }
@@ -6061,17 +6180,13 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                reg = rd32(hw, I40E_PF_MDET_TX);
                if (reg & I40E_PF_MDET_TX_VALID_MASK) {
                        wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
-                       dev_info(&pf->pdev->dev,
-                                "MDD TX event is for this function 0x%08x, requesting PF reset.\n",
-                                reg);
+                       dev_info(&pf->pdev->dev, "TX driver issue detected, PF reset issued\n");
                        pf_mdd_detected = true;
                }
                reg = rd32(hw, I40E_PF_MDET_RX);
                if (reg & I40E_PF_MDET_RX_VALID_MASK) {
                        wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
-                       dev_info(&pf->pdev->dev,
-                                "MDD RX event is for this function 0x%08x, requesting PF reset.\n",
-                                reg);
+                       dev_info(&pf->pdev->dev, "RX driver issue detected, PF reset issued\n");
                        pf_mdd_detected = true;
                }
                /* Queue belongs to the PF, initiate a reset */
@@ -6088,14 +6203,16 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                if (reg & I40E_VP_MDET_TX_VALID_MASK) {
                        wr32(hw, I40E_VP_MDET_TX(i), 0xFFFF);
                        vf->num_mdd_events++;
-                       dev_info(&pf->pdev->dev, "MDD TX event on VF %d\n", i);
+                       dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
+                                i);
                }
 
                reg = rd32(hw, I40E_VP_MDET_RX(i));
                if (reg & I40E_VP_MDET_RX_VALID_MASK) {
                        wr32(hw, I40E_VP_MDET_RX(i), 0xFFFF);
                        vf->num_mdd_events++;
-                       dev_info(&pf->pdev->dev, "MDD RX event on VF %d\n", i);
+                       dev_info(&pf->pdev->dev, "RX driver issue detected on VF %d\n",
+                                i);
                }
 
                if (vf->num_mdd_events > I40E_DEFAULT_NUM_MDD_EVENTS_ALLOWED) {
@@ -7086,6 +7203,11 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
                }
                pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
                pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
+               /* reset fd counters */
+               pf->fd_add_err = pf->fd_atr_cnt = pf->fd_tcp_rule = 0;
+               pf->fdir_pf_active_filters = 0;
+               pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+               dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
                /* if ATR was auto disabled it can be re-enabled. */
                if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
                    (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
@@ -7352,7 +7474,7 @@ static const struct net_device_ops i40e_netdev_ops = {
        .ndo_set_vf_rate        = i40e_ndo_set_vf_bw,
        .ndo_get_vf_config      = i40e_ndo_get_vf_config,
        .ndo_set_vf_link_state  = i40e_ndo_set_vf_link_state,
-       .ndo_set_vf_spoofchk    = i40e_ndo_set_vf_spoofck,
+       .ndo_set_vf_spoofchk    = i40e_ndo_set_vf_spoofchk,
 #ifdef CONFIG_I40E_VXLAN
        .ndo_add_vxlan_port     = i40e_add_vxlan_port,
        .ndo_del_vxlan_port     = i40e_del_vxlan_port,
@@ -7421,14 +7543,14 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
        if (vsi->type == I40E_VSI_MAIN) {
                SET_NETDEV_DEV(netdev, &pf->pdev->dev);
                ether_addr_copy(mac_addr, hw->mac.perm_addr);
-               /* The following two steps are necessary to prevent reception
-                * of tagged packets - by default the NVM loads a MAC-VLAN
-                * filter that will accept any tagged packet.  This is to
-                * prevent that during normal operations until a specific
-                * VLAN tag filter has been set.
+               /* The following steps are necessary to prevent reception
+                * of tagged packets - some older NVM configurations load a
+                * default a MAC-VLAN filter that accepts any tagged packet
+                * which must be replaced by a normal filter.
                 */
-               i40e_rm_default_mac_filter(vsi, mac_addr);
-               i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, true);
+               if (!i40e_rm_default_mac_filter(vsi, mac_addr))
+                       i40e_add_filter(vsi, mac_addr,
+                                       I40E_VLAN_ANY, false, true);
        } else {
                /* relate the VSI_VMDQ name to the VSI_MAIN name */
                snprintf(netdev->name, IFNAMSIZ, "%sv%%d",
@@ -7644,7 +7766,22 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
                f_count++;
 
                if (f->is_laa && vsi->type == I40E_VSI_MAIN) {
-                       i40e_aq_mac_address_write(&vsi->back->hw,
+                       struct i40e_aqc_remove_macvlan_element_data element;
+
+                       memset(&element, 0, sizeof(element));
+                       ether_addr_copy(element.mac_addr, f->macaddr);
+                       element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
+                       ret = i40e_aq_remove_macvlan(hw, vsi->seid,
+                                                    &element, 1, NULL);
+                       if (ret) {
+                               /* some older FW has a different default */
+                               element.flags |=
+                                              I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
+                               i40e_aq_remove_macvlan(hw, vsi->seid,
+                                                      &element, 1, NULL);
+                       }
+
+                       i40e_aq_mac_address_write(hw,
                                                  I40E_AQC_WRITE_TYPE_LAA_WOL,
                                                  f->macaddr, NULL);
                }
index 949a9a01778b9c17aad87a78af9a933ac191856a..0988b5c1fe87d080e950f146c4c0c0b8ae231189 100644 (file)
@@ -52,10 +52,8 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
                                struct i40e_asq_cmd_details *cmd_details);
 
 /* debug function for adminq */
-void i40e_debug_aq(struct i40e_hw *hw,
-                  enum i40e_debug_mask mask,
-                  void *desc,
-                  void *buffer);
+void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask,
+                  void *desc, void *buffer, u16 buf_len);
 
 void i40e_idle_aq(struct i40e_hw *hw);
 bool i40e_check_asq_alive(struct i40e_hw *hw);
index 369848e107f8ed37952b4849ed632655f598b6ba..be039dd6114d5378b5896e6e58d1d10eb0578ca4 100644 (file)
@@ -224,15 +224,19 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
        ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
        if (ret) {
                dev_info(&pf->pdev->dev,
-                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
+                        "PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n",
+                        fd_data->pctype, fd_data->fd_id, ret);
                err = true;
        } else {
-               dev_info(&pf->pdev->dev,
-                        "Filter OK for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
+               if (add)
+                       dev_info(&pf->pdev->dev,
+                                "Filter OK for PCTYPE %d loc = %d\n",
+                                fd_data->pctype, fd_data->fd_id);
+               else
+                       dev_info(&pf->pdev->dev,
+                                "Filter deleted for PCTYPE %d loc = %d\n",
+                                fd_data->pctype, fd_data->fd_id);
        }
-
        return err ? -EOPNOTSUPP : 0;
 }
 
@@ -276,10 +280,18 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
        tcp->source = fd_data->src_port;
 
        if (add) {
+               pf->fd_tcp_rule++;
                if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) {
                        dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
                        pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
                }
+       } else {
+               pf->fd_tcp_rule = (pf->fd_tcp_rule > 0) ?
+                                 (pf->fd_tcp_rule - 1) : 0;
+               if (pf->fd_tcp_rule == 0) {
+                       pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+                       dev_info(&pf->pdev->dev, "ATR re-enabled due to no sideband TCP/IPv4 rules\n");
+               }
        }
 
        fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
@@ -287,12 +299,17 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
 
        if (ret) {
                dev_info(&pf->pdev->dev,
-                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
+                        "PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n",
+                        fd_data->pctype, fd_data->fd_id, ret);
                err = true;
        } else {
-               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
+               if (add)
+                       dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d loc = %d)\n",
+                                fd_data->pctype, fd_data->fd_id);
+               else
+                       dev_info(&pf->pdev->dev,
+                                "Filter deleted for PCTYPE %d loc = %d\n",
+                                fd_data->pctype, fd_data->fd_id);
        }
 
        return err ? -EOPNOTSUPP : 0;
@@ -355,13 +372,18 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
 
                if (ret) {
                        dev_info(&pf->pdev->dev,
-                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
+                                "PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n",
+                                fd_data->pctype, fd_data->fd_id, ret);
                        err = true;
                } else {
-                       dev_info(&pf->pdev->dev,
-                                "Filter OK for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
+                       if (add)
+                               dev_info(&pf->pdev->dev,
+                                        "Filter OK for PCTYPE %d loc = %d\n",
+                                        fd_data->pctype, fd_data->fd_id);
+                       else
+                               dev_info(&pf->pdev->dev,
+                                        "Filter deleted for PCTYPE %d loc = %d\n",
+                                        fd_data->pctype, fd_data->fd_id);
                }
        }
 
@@ -443,8 +465,14 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
                I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT;
 
        if (error == (0x1 << I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) {
-               dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n",
-                        rx_desc->wb.qword0.hi_dword.fd_id);
+               if ((rx_desc->wb.qword0.hi_dword.fd_id != 0) ||
+                   (I40E_DEBUG_FD & pf->hw.debug_mask))
+                       dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n",
+                                rx_desc->wb.qword0.hi_dword.fd_id);
+
+               pf->fd_add_err++;
+               /* store the current atr filter count */
+               pf->fd_atr_cnt = i40e_get_current_atr_cnt(pf);
 
                /* filter programming failed most likely due to table full */
                fcnt_prog = i40e_get_cur_guaranteed_fd_count(pf);
@@ -454,29 +482,21 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
                 * FD ATR/SB and then re-enable it when there is room.
                 */
                if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) {
-                       /* Turn off ATR first */
-                       if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+                       if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
                            !(pf->auto_disable_flags &
-                             I40E_FLAG_FD_ATR_ENABLED)) {
-                               dev_warn(&pdev->dev, "FD filter space full, ATR for further flows will be turned off\n");
-                               pf->auto_disable_flags |=
-                                                      I40E_FLAG_FD_ATR_ENABLED;
-                               pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
-                       } else if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
-                                  !(pf->auto_disable_flags &
                                     I40E_FLAG_FD_SB_ENABLED)) {
                                dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
                                pf->auto_disable_flags |=
                                                        I40E_FLAG_FD_SB_ENABLED;
-                               pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
                        }
                } else {
-                       dev_info(&pdev->dev, "FD filter programming error\n");
+                       dev_info(&pdev->dev,
+                               "FD filter programming failed due to incorrect filter parameters\n");
                }
        } else if (error ==
                          (0x1 << I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) {
                if (I40E_DEBUG_FD & pf->hw.debug_mask)
-                       dev_info(&pdev->dev, "ntuple filter loc = %d, could not be removed\n",
+                       dev_info(&pdev->dev, "ntuple filter fd_id = %d, could not be removed\n",
                                 rx_desc->wb.qword0.hi_dword.fd_id);
        }
 }
@@ -587,6 +607,7 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
 static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
 {
        u32 tx_pending = i40e_get_tx_pending(tx_ring);
+       struct i40e_pf *pf = tx_ring->vsi->back;
        bool ret = false;
 
        clear_check_for_tx_hang(tx_ring);
@@ -603,10 +624,17 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * pending but without time to complete it yet.
         */
        if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           tx_pending) {
+           (tx_pending >= I40E_MIN_DESC_PENDING)) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
+       } else if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
+                  (tx_pending < I40E_MIN_DESC_PENDING) &&
+                  (tx_pending > 0)) {
+               if (I40E_DEBUG_FLOW & pf->hw.debug_mask)
+                       dev_info(tx_ring->dev, "HW needs some more descs to do a cacheline flush. tx_pending %d, queue %d",
+                                tx_pending, tx_ring->queue_index);
+               pf->tx_sluggish_count++;
        } else {
                /* update completed stats and disarm the hang check */
                tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
@@ -1213,7 +1241,6 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        ipv6_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
                      (rx_ptype < I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
 
-       skb->encapsulation = ipv4_tunnel || ipv6_tunnel;
        skb->ip_summed = CHECKSUM_NONE;
 
        /* Rx csum enabled and ip headers found? */
@@ -1287,6 +1314,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        }
 
        skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->csum_level = ipv4_tunnel || ipv6_tunnel;
 
        return;
 
index 73f4fa4256974ed68479e5f6bebd44ee5d50d6bc..d7a625a6a14f54fa1b79456df9de7d14f9ff1809 100644 (file)
@@ -121,6 +121,7 @@ enum i40e_dyn_idx_t {
 /* Tx Descriptors needed, worst case */
 #define TXD_USE_COUNT(S) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD)
 #define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+#define I40E_MIN_DESC_PENDING  4
 
 #define I40E_TX_FLAGS_CSUM             (u32)(1)
 #define I40E_TX_FLAGS_HW_VLAN          (u32)(1 << 1)
index 3ac6a0d2f1433d8bff3323a28f77af063a2ddb89..4eeed267e4b71ce9d242d3a71fccd5ad38600c8f 100644 (file)
@@ -73,7 +73,7 @@ static inline bool i40e_vc_isvalid_queue_id(struct i40e_vf *vf, u8 vsi_id,
 {
        struct i40e_pf *pf = vf->pf;
 
-       return qid < pf->vsi[vsi_id]->num_queue_pairs;
+       return qid < pf->vsi[vsi_id]->alloc_queue_pairs;
 }
 
 /**
@@ -350,6 +350,7 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_idx,
        rx_ctx.lrxqthresh = 2;
        rx_ctx.crcstrip = 1;
        rx_ctx.prefena = 1;
+       rx_ctx.l2tsel = 1;
 
        /* clear the context in the HMC */
        ret = i40e_clear_lan_rx_queue_context(hw, pf_queue_id);
@@ -468,7 +469,7 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)
        wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), reg);
 
        /* map PF queues to VF queues */
-       for (j = 0; j < pf->vsi[vf->lan_vsi_index]->num_queue_pairs; j++) {
+       for (j = 0; j < pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs; j++) {
                u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index, j);
                reg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK);
                wr32(hw, I40E_VPLAN_QTABLE(total_queue_pairs, vf->vf_id), reg);
@@ -477,7 +478,7 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)
 
        /* map PF queues to VSI */
        for (j = 0; j < 7; j++) {
-               if (j * 2 >= pf->vsi[vf->lan_vsi_index]->num_queue_pairs) {
+               if (j * 2 >= pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs) {
                        reg = 0x07FF07FF;       /* unused */
                } else {
                        u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index,
@@ -584,7 +585,7 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)
        ret = i40e_alloc_vsi_res(vf, I40E_VSI_SRIOV);
        if (ret)
                goto error_alloc;
-       total_queue_pairs += pf->vsi[vf->lan_vsi_index]->num_queue_pairs;
+       total_queue_pairs += pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs;
        set_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
 
        /* store the total qps number for the runtime
@@ -706,35 +707,6 @@ complete_reset:
        wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE);
        i40e_flush(hw);
 }
-
-/**
- * i40e_vfs_are_assigned
- * @pf: pointer to the pf structure
- *
- * Determine if any VFs are assigned to VMs
- **/
-static bool i40e_vfs_are_assigned(struct i40e_pf *pf)
-{
-       struct pci_dev *pdev = pf->pdev;
-       struct pci_dev *vfdev;
-
-       /* loop through all the VFs to see if we own any that are assigned */
-       vfdev = pci_get_device(PCI_VENDOR_ID_INTEL, I40E_DEV_ID_VF , NULL);
-       while (vfdev) {
-               /* if we don't own it we don't care */
-               if (vfdev->is_virtfn && pci_physfn(vfdev) == pdev) {
-                       /* if it is assigned we cannot release it */
-                       if (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
-                               return true;
-               }
-
-               vfdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                      I40E_DEV_ID_VF,
-                                      vfdev);
-       }
-
-       return false;
-}
 #ifdef CONFIG_PCI_IOV
 
 /**
@@ -842,7 +814,7 @@ void i40e_free_vfs(struct i40e_pf *pf)
         * assigned. Setting the number of VFs to 0 through sysfs is caught
         * before this function ever gets called.
         */
-       if (!i40e_vfs_are_assigned(pf)) {
+       if (!pci_vfs_assigned(pf->pdev)) {
                pci_disable_sriov(pf->pdev);
                /* Acknowledge VFLR for all VFS. Without this, VFs will fail to
                 * work correctly when SR-IOV gets re-enabled.
@@ -979,7 +951,7 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
        if (num_vfs)
                return i40e_pci_sriov_enable(pdev, num_vfs);
 
-       if (!i40e_vfs_are_assigned(pf)) {
+       if (!pci_vfs_assigned(pf->pdev)) {
                i40e_free_vfs(pf);
        } else {
                dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n");
@@ -1123,7 +1095,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf)
                vfres->vsi_res[i].vsi_id = vf->lan_vsi_index;
                vfres->vsi_res[i].vsi_type = I40E_VSI_SRIOV;
                vfres->vsi_res[i].num_queue_pairs =
-                   pf->vsi[vf->lan_vsi_index]->num_queue_pairs;
+                   pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs;
                memcpy(vfres->vsi_res[i].default_mac_addr,
                       vf->default_lan_addr.addr, ETH_ALEN);
                i++;
@@ -1209,6 +1181,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
        struct i40e_virtchnl_vsi_queue_config_info *qci =
            (struct i40e_virtchnl_vsi_queue_config_info *)msg;
        struct i40e_virtchnl_queue_pair_info *qpi;
+       struct i40e_pf *pf = vf->pf;
        u16 vsi_id, vsi_queue_id;
        i40e_status aq_ret = 0;
        int i;
@@ -1242,6 +1215,8 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
                        goto error_param;
                }
        }
+       /* set vsi num_queue_pairs in use to num configured by vf */
+       pf->vsi[vf->lan_vsi_index]->num_queue_pairs = qci->num_queue_pairs;
 
 error_param:
        /* send the response to the vf */
@@ -2094,7 +2069,6 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
        /* Force the VF driver stop so it has to reload with new MAC address */
        i40e_vc_disable_vf(pf, vf);
        dev_info(&pf->pdev->dev, "Reload the VF driver to make this change effective.\n");
-       ret = 0;
 
 error_param:
        return ret;
@@ -2419,7 +2393,7 @@ error_out:
  *
  * Enable or disable VF spoof checking
  **/
-int i40e_ndo_set_vf_spoofck(struct net_device *netdev, int vf_id, bool enable)
+int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
index 63e7e0d81ad22754622695dabc1a0475885477ee..0adc61e1052db9dabdcbea3d8930ec709e1868ef 100644 (file)
@@ -122,7 +122,7 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
 int i40e_ndo_get_vf_config(struct net_device *netdev,
                           int vf_id, struct ifla_vf_info *ivi);
 int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link);
-int i40e_ndo_set_vf_spoofck(struct net_device *netdev, int vf_id, bool enable);
+int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable);
 
 void i40e_vc_notify_link_state(struct i40e_pf *pf);
 void i40e_vc_notify_reset(struct i40e_pf *pf);
index 00300603361464b4e9f3b20da7774a1069bdf071..f206be9178422afc01a955f481f8e523cbb3093c 100644 (file)
@@ -788,7 +788,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
 
        /* bump the tail */
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
-       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff);
+       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring,
+                       buff, buff_size);
        (hw->aq.asq.next_to_use)++;
        if (hw->aq.asq.next_to_use == hw->aq.asq.count)
                hw->aq.asq.next_to_use = 0;
@@ -842,7 +843,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
 
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: desc and buffer writeback:\n");
-       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff);
+       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff,
+                       buff_size);
 
        /* update the error if time out occurred */
        if ((!cmd_completed) &&
@@ -938,7 +940,8 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
                hw->aq.nvm_busy = false;
 
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
-       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf);
+       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf,
+                       hw->aq.arq_buf_size);
 
        /* Restore the original datalen and buffer address in the desc,
         * FW updates datalen to indicate the event message
index 4ea90bf239bb204ed5603b66680413191f46bf66..9525605519645eb241f5473bcdd345a0afe21a09 100644 (file)
@@ -75,13 +75,15 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw)
  * @mask: debug mask
  * @desc: pointer to admin queue descriptor
  * @buffer: pointer to command buffer
+ * @buf_len: max length of buffer
  *
  * Dumps debug log about adminq command with descriptor contents.
  **/
 void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
-                  void *buffer)
+                  void *buffer, u16 buf_len)
 {
        struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
+       u16 len = le16_to_cpu(aq_desc->datalen);
        u8 *aq_buffer = (u8 *)buffer;
        u32 data[4];
        u32 i = 0;
@@ -105,7 +107,9 @@ void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
        if ((buffer != NULL) && (aq_desc->datalen != 0)) {
                memset(data, 0, sizeof(data));
                i40e_debug(hw, mask, "AQ CMD Buffer:\n");
-               for (i = 0; i < le16_to_cpu(aq_desc->datalen); i++) {
+               if (buf_len < len)
+                       len = buf_len;
+               for (i = 0; i < len; i++) {
                        data[((i % 16) / 4)] |=
                                ((u32)aq_buffer[i]) << (8 * (i % 4));
                        if ((i % 16) == 15) {
index 849edcc2e398f7bfdaaea5eaf078ba714977ca5f..9173834825ac4cc1bbe5c3ecbc85e77db693c76f 100644 (file)
@@ -53,10 +53,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
 bool i40evf_asq_done(struct i40e_hw *hw);
 
 /* debug function for adminq */
-void i40evf_debug_aq(struct i40e_hw *hw,
-                  enum i40e_debug_mask mask,
-                  void *desc,
-                  void *buffer);
+void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask,
+                    void *desc, void *buffer, u16 buf_len);
 
 void i40e_idle_aq(struct i40e_hw *hw);
 void i40evf_resume_aq(struct i40e_hw *hw);
index 95a3ec236b4951ab7166637159393df569da97fb..04c7c1557a0c770ab0f256d3012cd3b9be70240e 100644 (file)
@@ -163,11 +163,13 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * pending but without time to complete it yet.
         */
        if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           tx_pending) {
+           (tx_pending >= I40E_MIN_DESC_PENDING)) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
-       } else {
+       } else if (!(tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) ||
+                  !(tx_pending < I40E_MIN_DESC_PENDING) ||
+                  !(tx_pending > 0)) {
                /* update completed stats and disarm the hang check */
                tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
                clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
@@ -744,7 +746,6 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        ipv6_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
                      (rx_ptype < I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
 
-       skb->encapsulation = ipv4_tunnel || ipv6_tunnel;
        skb->ip_summed = CHECKSUM_NONE;
 
        /* Rx csum enabled and ip headers found? */
@@ -818,6 +819,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        }
 
        skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->csum_level = ipv4_tunnel || ipv6_tunnel;
 
        return;
 
index 8bc6858163b0f1b668e56d3c0d682574cc4582d5..f6dcf9dd9290d95554c7505f4bbd9f5832185597 100644 (file)
@@ -121,6 +121,7 @@ enum i40e_dyn_idx_t {
 /* Tx Descriptors needed, worst case */
 #define TXD_USE_COUNT(S) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD)
 #define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+#define I40E_MIN_DESC_PENDING  4
 
 #define I40E_TX_FLAGS_CSUM             (u32)(1)
 #define I40E_TX_FLAGS_HW_VLAN          (u32)(1 << 1)
index 38429fae4fcfa2ccb1db770e7e735e27303b8c2d..c51bc7a33bc50898dedf7f1fdfaa5100c45e501a 100644 (file)
@@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf";
 static const char i40evf_driver_string[] =
        "Intel(R) XL710/X710 Virtual Function Network Driver";
 
-#define DRV_VERSION "0.9.40"
+#define DRV_VERSION "1.0.5"
 const char i40evf_driver_version[] = DRV_VERSION;
 static const char i40evf_copyright[] =
        "Copyright (c) 2013 - 2014 Intel Corporation.";
index 236a6183a86523a3aef0430b3a575081b32ba7b5..051ea94bdcd3e8046181b361d8985c51d15ea19c 100644 (file)
@@ -2548,11 +2548,13 @@ s32 igb_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data)
 /**
  *  igb_set_eee_i350 - Enable/disable EEE support
  *  @hw: pointer to the HW structure
+ *  @adv1G: boolean flag enabling 1G EEE advertisement
+ *  @adv100m: boolean flag enabling 100M EEE advertisement
  *
  *  Enable/disable EEE based on setting in dev_spec structure.
  *
  **/
-s32 igb_set_eee_i350(struct e1000_hw *hw)
+s32 igb_set_eee_i350(struct e1000_hw *hw, bool adv1G, bool adv100M)
 {
        u32 ipcnfg, eeer;
 
@@ -2566,7 +2568,16 @@ s32 igb_set_eee_i350(struct e1000_hw *hw)
        if (!(hw->dev_spec._82575.eee_disable)) {
                u32 eee_su = rd32(E1000_EEE_SU);
 
-               ipcnfg |= (E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
+               if (adv100M)
+                       ipcnfg |= E1000_IPCNFG_EEE_100M_AN;
+               else
+                       ipcnfg &= ~E1000_IPCNFG_EEE_100M_AN;
+
+               if (adv1G)
+                       ipcnfg |= E1000_IPCNFG_EEE_1G_AN;
+               else
+                       ipcnfg &= ~E1000_IPCNFG_EEE_1G_AN;
+
                eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
                        E1000_EEER_LPI_FC);
 
@@ -2593,11 +2604,13 @@ out:
 /**
  *  igb_set_eee_i354 - Enable/disable EEE support
  *  @hw: pointer to the HW structure
+ *  @adv1G: boolean flag enabling 1G EEE advertisement
+ *  @adv100m: boolean flag enabling 100M EEE advertisement
  *
  *  Enable/disable EEE legacy mode based on setting in dev_spec structure.
  *
  **/
-s32 igb_set_eee_i354(struct e1000_hw *hw)
+s32 igb_set_eee_i354(struct e1000_hw *hw, bool adv1G, bool adv100M)
 {
        struct e1000_phy_info *phy = &hw->phy;
        s32 ret_val = 0;
@@ -2636,8 +2649,16 @@ s32 igb_set_eee_i354(struct e1000_hw *hw)
                if (ret_val)
                        goto out;
 
-               phy_data |= E1000_EEE_ADV_100_SUPPORTED |
-                           E1000_EEE_ADV_1000_SUPPORTED;
+               if (adv100M)
+                       phy_data |= E1000_EEE_ADV_100_SUPPORTED;
+               else
+                       phy_data &= ~E1000_EEE_ADV_100_SUPPORTED;
+
+               if (adv1G)
+                       phy_data |= E1000_EEE_ADV_1000_SUPPORTED;
+               else
+                       phy_data &= ~E1000_EEE_ADV_1000_SUPPORTED;
+
                ret_val = igb_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
                                                E1000_EEE_ADV_DEV_I354,
                                                phy_data);
index b407c55738fadf0a333ee7947fedd2c0c31638a1..2154aea7aa7e70c9d5083bc3631a37f885d48bd4 100644 (file)
@@ -263,8 +263,8 @@ void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
 void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
 u16 igb_rxpbs_adjust_82580(u32 data);
 s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data);
-s32 igb_set_eee_i350(struct e1000_hw *);
-s32 igb_set_eee_i354(struct e1000_hw *);
+s32 igb_set_eee_i350(struct e1000_hw *, bool adv1G, bool adv100M);
+s32 igb_set_eee_i354(struct e1000_hw *, bool adv1G, bool adv100M);
 s32 igb_get_eee_status_i354(struct e1000_hw *hw, bool *status);
 
 #define E1000_I2C_THERMAL_SENSOR_ADDR  0xF8
index c737d1f4083829ae0eed6e7ecff1d29b5c75239e..02cfd3b14762cbf884ef1b0f4586735f14bee3c9 100644 (file)
@@ -2675,6 +2675,7 @@ static int igb_set_eee(struct net_device *netdev,
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        struct ethtool_eee eee_curr;
+       bool adv1g_eee = true, adv100m_eee = true;
        s32 ret_val;
 
        if ((hw->mac.type < e1000_i350) ||
@@ -2701,12 +2702,14 @@ static int igb_set_eee(struct net_device *netdev,
                        return -EINVAL;
                }
 
-               if (edata->advertised &
-                   ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) {
+               if (!edata->advertised || (edata->advertised &
+                   ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL))) {
                        dev_err(&adapter->pdev->dev,
-                               "EEE Advertisement supports only 100Tx and or 100T full duplex\n");
+                               "EEE Advertisement supports only 100Tx and/or 100T full duplex\n");
                        return -EINVAL;
                }
+               adv100m_eee = !!(edata->advertised & ADVERTISE_100_FULL);
+               adv1g_eee = !!(edata->advertised & ADVERTISE_1000_FULL);
 
        } else if (!edata->eee_enabled) {
                dev_err(&adapter->pdev->dev,
@@ -2718,10 +2721,6 @@ static int igb_set_eee(struct net_device *netdev,
        if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {
                hw->dev_spec._82575.eee_disable = !edata->eee_enabled;
                adapter->flags |= IGB_FLAG_EEE;
-               if (hw->mac.type == e1000_i350)
-                       igb_set_eee_i350(hw);
-               else
-                       igb_set_eee_i354(hw);
 
                /* reset link */
                if (netif_running(netdev))
@@ -2730,6 +2729,17 @@ static int igb_set_eee(struct net_device *netdev,
                        igb_reset(adapter);
        }
 
+       if (hw->mac.type == e1000_i354)
+               ret_val = igb_set_eee_i354(hw, adv1g_eee, adv100m_eee);
+       else
+               ret_val = igb_set_eee_i350(hw, adv1g_eee, adv100m_eee);
+
+       if (ret_val) {
+               dev_err(&adapter->pdev->dev,
+                       "Problem setting EEE advertisement options\n");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
index cb14bbdfb0562df213253d18c83eaf78c6a63f2c..6cf0c17ad9c4abe03f5eb4e1b9ef474aefdc76d2 100644 (file)
@@ -2012,10 +2012,10 @@ void igb_reset(struct igb_adapter *adapter)
                case e1000_i350:
                case e1000_i210:
                case e1000_i211:
-                       igb_set_eee_i350(hw);
+                       igb_set_eee_i350(hw, true, true);
                        break;
                case e1000_i354:
-                       igb_set_eee_i354(hw);
+                       igb_set_eee_i354(hw, true, true);
                        break;
                default:
                        break;
@@ -2619,7 +2619,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                case e1000_i210:
                case e1000_i211:
                        /* Enable EEE for internal copper PHY devices */
-                       err = igb_set_eee_i350(hw);
+                       err = igb_set_eee_i350(hw, true, true);
                        if ((!err) &&
                            (!hw->dev_spec._82575.eee_disable)) {
                                adapter->eee_advert =
@@ -2630,7 +2630,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                case e1000_i354:
                        if ((rd32(E1000_CTRL_EXT) &
                            E1000_CTRL_EXT_LINK_MODE_SGMII)) {
-                               err = igb_set_eee_i354(hw);
+                               err = igb_set_eee_i354(hw, true, true);
                                if ((!err) &&
                                        (!hw->dev_spec._82575.eee_disable)) {
                                        adapter->eee_advert =
@@ -4813,6 +4813,41 @@ static void igb_tx_olinfo_status(struct igb_ring *tx_ring,
        tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
 }
 
+static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
+{
+       struct net_device *netdev = tx_ring->netdev;
+
+       netif_stop_subqueue(netdev, tx_ring->queue_index);
+
+       /* Herbert's original patch had:
+        *  smp_mb__after_netif_stop_queue();
+        * but since that doesn't exist yet, just open code it.
+        */
+       smp_mb();
+
+       /* We need to check again in a case another CPU has just
+        * made room available.
+        */
+       if (igb_desc_unused(tx_ring) < size)
+               return -EBUSY;
+
+       /* A reprieve! */
+       netif_wake_subqueue(netdev, tx_ring->queue_index);
+
+       u64_stats_update_begin(&tx_ring->tx_syncp2);
+       tx_ring->tx_stats.restart_queue2++;
+       u64_stats_update_end(&tx_ring->tx_syncp2);
+
+       return 0;
+}
+
+static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
+{
+       if (igb_desc_unused(tx_ring) >= size)
+               return 0;
+       return __igb_maybe_stop_tx(tx_ring, size);
+}
+
 static void igb_tx_map(struct igb_ring *tx_ring,
                       struct igb_tx_buffer *first,
                       const u8 hdr_len)
@@ -4915,13 +4950,17 @@ static void igb_tx_map(struct igb_ring *tx_ring,
 
        tx_ring->next_to_use = i;
 
-       writel(i, tx_ring->tail);
+       /* Make sure there is space in the ring for the next send. */
+       igb_maybe_stop_tx(tx_ring, DESC_NEEDED);
 
-       /* we need this if more than one processor can write to our tail
-        * at a time, it synchronizes IO on IA64/Altix systems
-        */
-       mmiowb();
+       if (netif_xmit_stopped(txring_txq(tx_ring)) || !skb->xmit_more) {
+               writel(i, tx_ring->tail);
 
+               /* we need this if more than one processor can write to our tail
+                * at a time, it synchronizes IO on IA64/Altix systems
+                */
+               mmiowb();
+       }
        return;
 
 dma_error:
@@ -4941,41 +4980,6 @@ dma_error:
        tx_ring->next_to_use = i;
 }
 
-static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
-{
-       struct net_device *netdev = tx_ring->netdev;
-
-       netif_stop_subqueue(netdev, tx_ring->queue_index);
-
-       /* Herbert's original patch had:
-        *  smp_mb__after_netif_stop_queue();
-        * but since that doesn't exist yet, just open code it.
-        */
-       smp_mb();
-
-       /* We need to check again in a case another CPU has just
-        * made room available.
-        */
-       if (igb_desc_unused(tx_ring) < size)
-               return -EBUSY;
-
-       /* A reprieve! */
-       netif_wake_subqueue(netdev, tx_ring->queue_index);
-
-       u64_stats_update_begin(&tx_ring->tx_syncp2);
-       tx_ring->tx_stats.restart_queue2++;
-       u64_stats_update_end(&tx_ring->tx_syncp2);
-
-       return 0;
-}
-
-static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
-{
-       if (igb_desc_unused(tx_ring) >= size)
-               return 0;
-       return __igb_maybe_stop_tx(tx_ring, size);
-}
-
 netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
                                struct igb_ring *tx_ring)
 {
@@ -5046,9 +5050,6 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
 
        igb_tx_map(tx_ring, first, hdr_len);
 
-       /* Make sure there is space in the ring for the next send. */
-       igb_maybe_stop_tx(tx_ring, DESC_NEEDED);
-
        return NETDEV_TX_OK;
 
 out_drop:
@@ -6767,113 +6768,6 @@ static bool igb_is_non_eop(struct igb_ring *rx_ring,
        return true;
 }
 
-/**
- *  igb_get_headlen - determine size of header for LRO/GRO
- *  @data: pointer to the start of the headers
- *  @max_len: total length of section to find headers in
- *
- *  This function is meant to determine the length of headers that will
- *  be recognized by hardware for LRO, and GRO offloads.  The main
- *  motivation of doing this is to only perform one pull for IPv4 TCP
- *  packets so that we can do basic things like calculating the gso_size
- *  based on the average data per packet.
- **/
-static unsigned int igb_get_headlen(unsigned char *data,
-                                   unsigned int max_len)
-{
-       union {
-               unsigned char *network;
-               /* l2 headers */
-               struct ethhdr *eth;
-               struct vlan_hdr *vlan;
-               /* l3 headers */
-               struct iphdr *ipv4;
-               struct ipv6hdr *ipv6;
-       } hdr;
-       __be16 protocol;
-       u8 nexthdr = 0; /* default to not TCP */
-       u8 hlen;
-
-       /* this should never happen, but better safe than sorry */
-       if (max_len < ETH_HLEN)
-               return max_len;
-
-       /* initialize network frame pointer */
-       hdr.network = data;
-
-       /* set first protocol and move network header forward */
-       protocol = hdr.eth->h_proto;
-       hdr.network += ETH_HLEN;
-
-       /* handle any vlan tag if present */
-       if (protocol == htons(ETH_P_8021Q)) {
-               if ((hdr.network - data) > (max_len - VLAN_HLEN))
-                       return max_len;
-
-               protocol = hdr.vlan->h_vlan_encapsulated_proto;
-               hdr.network += VLAN_HLEN;
-       }
-
-       /* handle L3 protocols */
-       if (protocol == htons(ETH_P_IP)) {
-               if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
-                       return max_len;
-
-               /* access ihl as a u8 to avoid unaligned access on ia64 */
-               hlen = (hdr.network[0] & 0x0F) << 2;
-
-               /* verify hlen meets minimum size requirements */
-               if (hlen < sizeof(struct iphdr))
-                       return hdr.network - data;
-
-               /* record next protocol if header is present */
-               if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
-                       nexthdr = hdr.ipv4->protocol;
-       } else if (protocol == htons(ETH_P_IPV6)) {
-               if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
-                       return max_len;
-
-               /* record next protocol */
-               nexthdr = hdr.ipv6->nexthdr;
-               hlen = sizeof(struct ipv6hdr);
-       } else {
-               return hdr.network - data;
-       }
-
-       /* relocate pointer to start of L4 header */
-       hdr.network += hlen;
-
-       /* finally sort out TCP */
-       if (nexthdr == IPPROTO_TCP) {
-               if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
-                       return max_len;
-
-               /* access doff as a u8 to avoid unaligned access on ia64 */
-               hlen = (hdr.network[12] & 0xF0) >> 2;
-
-               /* verify hlen meets minimum size requirements */
-               if (hlen < sizeof(struct tcphdr))
-                       return hdr.network - data;
-
-               hdr.network += hlen;
-       } else if (nexthdr == IPPROTO_UDP) {
-               if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
-                       return max_len;
-
-               hdr.network += sizeof(struct udphdr);
-       }
-
-       /* If everything has gone correctly hdr.network should be the
-        * data section of the packet and will be the end of the header.
-        * If not then it probably represents the end of the last recognized
-        * header.
-        */
-       if ((hdr.network - data) < max_len)
-               return hdr.network - data;
-       else
-               return max_len;
-}
-
 /**
  *  igb_pull_tail - igb specific version of skb_pull_tail
  *  @rx_ring: rx descriptor ring packet is being transacted on
@@ -6918,7 +6812,7 @@ static void igb_pull_tail(struct igb_ring *rx_ring,
        /* we need the header to contain the greater of either ETH_HLEN or
         * 60 bytes if the skb->len is less than 60 for skb_pad.
         */
-       pull_len = igb_get_headlen(va, IGB_RX_HDR_LEN);
+       pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN);
 
        /* align pull length to size of long to optimize memcpy performance */
        skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
index 2d9451e3968624db0b527dd00e9a106adfae16be..ae36fd61a3aa93374e603206dcf77a3f287a2984 100644 (file)
@@ -1086,6 +1086,11 @@ static void ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
                        return;
        }
 
+       /* At this point, we do not have MSI-X capabilities. We need to
+        * reconfigure or disable various features which require MSI-X
+        * capability.
+        */
+
        /* disable DCB if number of TCs exceeds 1 */
        if (netdev_get_num_tc(adapter->netdev) > 1) {
                e_err(probe, "num TCs exceeds number of queues - disabling DCB\n");
@@ -1107,6 +1112,9 @@ static void ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
        /* disable RSS */
        adapter->ring_feature[RING_F_RSS].limit = 1;
 
+       /* recalculate number of queues now that many features have been
+        * changed or disabled.
+        */
        ixgbe_set_num_queues(adapter);
        adapter->num_q_vectors = 1;
 
index 87bd53fdd209152dc14a09fbee8101582237c6e8..166dc0015a5e91b21ff2d03ac8cf7764732ecbdd 100644 (file)
@@ -1521,120 +1521,6 @@ void ixgbe_alloc_rx_buffers(struct ixgbe_ring *rx_ring, u16 cleaned_count)
                ixgbe_release_rx_desc(rx_ring, i);
 }
 
-/**
- * ixgbe_get_headlen - determine size of header for RSC/LRO/GRO/FCOE
- * @data: pointer to the start of the headers
- * @max_len: total length of section to find headers in
- *
- * This function is meant to determine the length of headers that will
- * be recognized by hardware for LRO, GRO, and RSC offloads.  The main
- * motivation of doing this is to only perform one pull for IPv4 TCP
- * packets so that we can do basic things like calculating the gso_size
- * based on the average data per packet.
- **/
-static unsigned int ixgbe_get_headlen(unsigned char *data,
-                                     unsigned int max_len)
-{
-       union {
-               unsigned char *network;
-               /* l2 headers */
-               struct ethhdr *eth;
-               struct vlan_hdr *vlan;
-               /* l3 headers */
-               struct iphdr *ipv4;
-               struct ipv6hdr *ipv6;
-       } hdr;
-       __be16 protocol;
-       u8 nexthdr = 0; /* default to not TCP */
-       u8 hlen;
-
-       /* this should never happen, but better safe than sorry */
-       if (max_len < ETH_HLEN)
-               return max_len;
-
-       /* initialize network frame pointer */
-       hdr.network = data;
-
-       /* set first protocol and move network header forward */
-       protocol = hdr.eth->h_proto;
-       hdr.network += ETH_HLEN;
-
-       /* handle any vlan tag if present */
-       if (protocol == htons(ETH_P_8021Q)) {
-               if ((hdr.network - data) > (max_len - VLAN_HLEN))
-                       return max_len;
-
-               protocol = hdr.vlan->h_vlan_encapsulated_proto;
-               hdr.network += VLAN_HLEN;
-       }
-
-       /* handle L3 protocols */
-       if (protocol == htons(ETH_P_IP)) {
-               if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
-                       return max_len;
-
-               /* access ihl as a u8 to avoid unaligned access on ia64 */
-               hlen = (hdr.network[0] & 0x0F) << 2;
-
-               /* verify hlen meets minimum size requirements */
-               if (hlen < sizeof(struct iphdr))
-                       return hdr.network - data;
-
-               /* record next protocol if header is present */
-               if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
-                       nexthdr = hdr.ipv4->protocol;
-       } else if (protocol == htons(ETH_P_IPV6)) {
-               if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
-                       return max_len;
-
-               /* record next protocol */
-               nexthdr = hdr.ipv6->nexthdr;
-               hlen = sizeof(struct ipv6hdr);
-#ifdef IXGBE_FCOE
-       } else if (protocol == htons(ETH_P_FCOE)) {
-               if ((hdr.network - data) > (max_len - FCOE_HEADER_LEN))
-                       return max_len;
-               hlen = FCOE_HEADER_LEN;
-#endif
-       } else {
-               return hdr.network - data;
-       }
-
-       /* relocate pointer to start of L4 header */
-       hdr.network += hlen;
-
-       /* finally sort out TCP/UDP */
-       if (nexthdr == IPPROTO_TCP) {
-               if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
-                       return max_len;
-
-               /* access doff as a u8 to avoid unaligned access on ia64 */
-               hlen = (hdr.network[12] & 0xF0) >> 2;
-
-               /* verify hlen meets minimum size requirements */
-               if (hlen < sizeof(struct tcphdr))
-                       return hdr.network - data;
-
-               hdr.network += hlen;
-       } else if (nexthdr == IPPROTO_UDP) {
-               if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
-                       return max_len;
-
-               hdr.network += sizeof(struct udphdr);
-       }
-
-       /*
-        * If everything has gone correctly hdr.network should be the
-        * data section of the packet and will be the end of the header.
-        * If not then it probably represents the end of the last recognized
-        * header.
-        */
-       if ((hdr.network - data) < max_len)
-               return hdr.network - data;
-       else
-               return max_len;
-}
-
 static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring,
                                   struct sk_buff *skb)
 {
@@ -1793,7 +1679,7 @@ static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring,
         * we need the header to contain the greater of either ETH_HLEN or
         * 60 bytes if the skb->len is less than 60 for skb_pad.
         */
-       pull_len = ixgbe_get_headlen(va, IXGBE_RX_HDR_SIZE);
+       pull_len = eth_get_headlen(va, IXGBE_RX_HDR_SIZE);
 
        /* align pull length to size of long to optimize memcpy performance */
        skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
@@ -6319,25 +6205,55 @@ static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *adapter)
        ixgbe_ping_all_vfs(adapter);
 }
 
+static bool ixgbe_ring_tx_pending(struct ixgbe_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
+
+               if (tx_ring->next_to_use != tx_ring->next_to_clean)
+                       return true;
+       }
+
+       return false;
+}
+
+static bool ixgbe_vf_tx_pending(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+       u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
+
+       int i, j;
+
+       if (!adapter->num_vfs)
+               return false;
+
+       for (i = 0; i < adapter->num_vfs; i++) {
+               for (j = 0; j < q_per_pool; j++) {
+                       u32 h, t;
+
+                       h = IXGBE_READ_REG(hw, IXGBE_PVFTDHN(q_per_pool, i, j));
+                       t = IXGBE_READ_REG(hw, IXGBE_PVFTDTN(q_per_pool, i, j));
+
+                       if (h != t)
+                               return true;
+               }
+       }
+
+       return false;
+}
+
 /**
  * ixgbe_watchdog_flush_tx - flush queues on link down
  * @adapter: pointer to the device adapter structure
  **/
 static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter)
 {
-       int i;
-       int some_tx_pending = 0;
-
        if (!netif_carrier_ok(adapter->netdev)) {
-               for (i = 0; i < adapter->num_tx_queues; i++) {
-                       struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
-                       if (tx_ring->next_to_use != tx_ring->next_to_clean) {
-                               some_tx_pending = 1;
-                               break;
-                       }
-               }
-
-               if (some_tx_pending) {
+               if (ixgbe_ring_tx_pending(adapter) ||
+                   ixgbe_vf_tx_pending(adapter)) {
                        /* We've lost link, so the controller stops DMA,
                         * but we've got queued Tx work that's never going
                         * to get done, so reset controller to flush Tx.
@@ -6837,6 +6753,36 @@ static void ixgbe_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc,
        tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
 }
 
+static int __ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
+{
+       netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+
+       /* Herbert's original patch had:
+        *  smp_mb__after_netif_stop_queue();
+        * but since that doesn't exist yet, just open code it.
+        */
+       smp_mb();
+
+       /* We need to check again in a case another CPU has just
+        * made room available.
+        */
+       if (likely(ixgbe_desc_unused(tx_ring) < size))
+               return -EBUSY;
+
+       /* A reprieve! - use start_queue because it doesn't call schedule */
+       netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
+       ++tx_ring->tx_stats.restart_queue;
+       return 0;
+}
+
+static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
+{
+       if (likely(ixgbe_desc_unused(tx_ring) >= size))
+               return 0;
+
+       return __ixgbe_maybe_stop_tx(tx_ring, size);
+}
+
 #define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \
                       IXGBE_TXD_CMD_RS)
 
@@ -6958,8 +6904,12 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
 
        tx_ring->next_to_use = i;
 
-       /* notify HW of packet */
-       ixgbe_write_tail(tx_ring, i);
+       ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
+
+       if (netif_xmit_stopped(txring_txq(tx_ring)) || !skb->xmit_more) {
+               /* notify HW of packet */
+               ixgbe_write_tail(tx_ring, i);
+       }
 
        return;
 dma_error:
@@ -7067,32 +7017,6 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
                                              input, common, ring->queue_index);
 }
 
-static int __ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
-{
-       netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
-       /* Herbert's original patch had:
-        *  smp_mb__after_netif_stop_queue();
-        * but since that doesn't exist yet, just open code it. */
-       smp_mb();
-
-       /* We need to check again in a case another CPU has just
-        * made room available. */
-       if (likely(ixgbe_desc_unused(tx_ring) < size))
-               return -EBUSY;
-
-       /* A reprieve! - use start_queue because it doesn't call schedule */
-       netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
-       ++tx_ring->tx_stats.restart_queue;
-       return 0;
-}
-
-static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
-{
-       if (likely(ixgbe_desc_unused(tx_ring) >= size))
-               return 0;
-       return __ixgbe_maybe_stop_tx(tx_ring, size);
-}
-
 static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
                              void *accel_priv, select_queue_fallback_t fallback)
 {
@@ -7261,8 +7185,6 @@ xmit_fcoe:
 #endif /* IXGBE_FCOE */
        ixgbe_tx_map(tx_ring, first, hdr_len);
 
-       ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
-
        return NETDEV_TX_OK;
 
 out_drop:
@@ -7735,39 +7657,13 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                             const unsigned char *addr,
                             u16 flags)
 {
-       struct ixgbe_adapter *adapter = netdev_priv(dev);
-       int err;
-
-       if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
-               return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
-
-       /* Hardware does not support aging addresses so if a
-        * ndm_state is given only allow permanent addresses
-        */
-       if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
-               pr_info("%s: FDB only supports static addresses\n",
-                       ixgbe_driver_name);
-               return -EINVAL;
-       }
-
+       /* guarantee we can provide a unique filter for the unicast address */
        if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) {
-               u32 rar_uc_entries = IXGBE_MAX_PF_MACVLANS;
-
-               if (netdev_uc_count(dev) < rar_uc_entries)
-                       err = dev_uc_add_excl(dev, addr);
-               else
-                       err = -ENOMEM;
-       } else if (is_multicast_ether_addr(addr)) {
-               err = dev_mc_add_excl(dev, addr);
-       } else {
-               err = -EINVAL;
+               if (IXGBE_MAX_PF_MACVLANS <= netdev_uc_count(dev))
+                       return -ENOMEM;
        }
 
-       /* Only return duplicate errors if NLM_F_EXCL is set */
-       if (err == -EEXIST && !(flags & NLM_F_EXCL))
-               err = 0;
-
-       return err;
+       return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
 }
 
 static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
@@ -7830,9 +7726,17 @@ static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)
 {
        struct ixgbe_fwd_adapter *fwd_adapter = NULL;
        struct ixgbe_adapter *adapter = netdev_priv(pdev);
+       int used_pools = adapter->num_vfs + adapter->num_rx_pools;
        unsigned int limit;
        int pool, err;
 
+       /* Hardware has a limited number of available pools. Each VF, and the
+        * PF require a pool. Check to ensure we don't attempt to use more
+        * then the available number of pools.
+        */
+       if (used_pools >= IXGBE_MAX_VF_FUNCTIONS)
+               return ERR_PTR(-EINVAL);
+
 #ifdef CONFIG_RPS
        if (vdev->num_rx_queues != vdev->num_tx_queues) {
                netdev_info(pdev, "%s: Only supports a single queue count for TX and RX\n",
index c14d4d89672ff7009168ecf14f98e444e9126ce5..706fc69aa0c51d3824d7c7e8ed0d47ff8f7adbe9 100644 (file)
@@ -250,13 +250,15 @@ static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs)
        if (err)
                return err;
 
-       /* While the SR-IOV capability structure reports total VFs to be
-        * 64 we limit the actual number that can be allocated to 63 so
-        * that some transmit/receive resources can be reserved to the
-        * PF.  The PCI bus driver already checks for other values out of
-        * range.
+       /* While the SR-IOV capability structure reports total VFs to be 64,
+        * we have to limit the actual number allocated based on two factors.
+        * First, we reserve some transmit/receive resources for the PF.
+        * Second, VMDQ also uses the same pools that SR-IOV does. We need to
+        * account for this, so that we don't accidentally allocate more VFs
+        * than we have available pools. The PCI bus driver already checks for
+        * other values out of range.
         */
-       if (num_vfs > IXGBE_MAX_VFS_DRV_LIMIT)
+       if ((num_vfs + adapter->num_rx_pools) > IXGBE_MAX_VF_FUNCTIONS)
                return -EPERM;
 
        adapter->num_vfs = num_vfs;
index e6b07c2a01fe3cfdc6458a73646a4754feab8026..dfd55d83bc0335ad46defa9f22923c5125e256d0 100644 (file)
@@ -2194,6 +2194,8 @@ enum {
 #define IXGBE_VFLRE(_i)                ((((_i) & 1) ? 0x001C0 : 0x00600))
 #define IXGBE_VFLREC(_i)               (0x00700 + ((_i) * 4))
 /* Translated register #defines */
+#define IXGBE_PVFTDH(P)                (0x06010 + (0x40 * (P)))
+#define IXGBE_PVFTDT(P)                (0x06018 + (0x40 * (P)))
 #define IXGBE_PVFTDWBAL(P)     (0x06038 + (0x40 * (P)))
 #define IXGBE_PVFTDWBAH(P)     (0x0603C + (0x40 * (P)))
 
@@ -2202,6 +2204,11 @@ enum {
 #define IXGBE_PVFTDWBAHn(q_per_pool, vf_number, vf_q_index) \
                (IXGBE_PVFTDWBAH((q_per_pool)*(vf_number) + (vf_q_index)))
 
+#define IXGBE_PVFTDHN(q_per_pool, vf_number, vf_q_index) \
+               (IXGBE_PVFTDH((q_per_pool)*(vf_number) + (vf_q_index)))
+#define IXGBE_PVFTDTN(q_per_pool, vf_number, vf_q_index) \
+               (IXGBE_PVFTDT((q_per_pool)*(vf_number) + (vf_q_index)))
+
 enum ixgbe_fdir_pballoc_type {
        IXGBE_FDIR_PBALLOC_NONE = 0,
        IXGBE_FDIR_PBALLOC_64K  = 1,
index 4d44d64ae3870c42dd62bb4d1cdfeb96fe9122b9..9cddd56d02c39305a69e13a25c2de88b4d92ccbb 100644 (file)
@@ -434,6 +434,21 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
        if (!(links_reg & IXGBE_LINKS_UP))
                goto out;
 
+       /* for SFP+ modules and DA cables on 82599 it can take up to 500usecs
+        * before the link status is correct
+        */
+       if (mac->type == ixgbe_mac_82599_vf) {
+               int i;
+
+               for (i = 0; i < 5; i++) {
+                       udelay(100);
+                       links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+
+                       if (!(links_reg & IXGBE_LINKS_UP))
+                               goto out;
+               }
+       }
+
        switch (links_reg & IXGBE_LINKS_SPEED_82599) {
        case IXGBE_LINKS_SPEED_10G_82599:
                *speed = IXGBE_LINK_SPEED_10GB_FULL;
index 9c909d23f14c4eda34ce8f03215b76aa29639894..14686b6f4bc591d1fd4d6e2f0c6dd9e71d0288b5 100644 (file)
@@ -588,6 +588,8 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
                skb_copy_to_linear_data(skb, va, length);
                skb->tail += length;
        } else {
+               unsigned int pull_len;
+
                /* Move relevant fragments to skb */
                used_frags = mlx4_en_complete_rx_desc(priv, rx_desc, frags,
                                                        skb, length);
@@ -597,16 +599,17 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
                }
                skb_shinfo(skb)->nr_frags = used_frags;
 
+               pull_len = eth_get_headlen(va, SMALL_PACKET_SIZE);
                /* Copy headers into the skb linear buffer */
-               memcpy(skb->data, va, HEADER_COPY_SIZE);
-               skb->tail += HEADER_COPY_SIZE;
+               memcpy(skb->data, va, pull_len);
+               skb->tail += pull_len;
 
                /* Skip headers in first fragment */
-               skb_shinfo(skb)->frags[0].page_offset += HEADER_COPY_SIZE;
+               skb_shinfo(skb)->frags[0].page_offset += pull_len;
 
                /* Adjust size of first fragment */
-               skb_frag_size_sub(&skb_shinfo(skb)->frags[0], HEADER_COPY_SIZE);
-               skb->data_len = length - HEADER_COPY_SIZE;
+               skb_frag_size_sub(&skb_shinfo(skb)->frags[0], pull_len);
+               skb->data_len = length - pull_len;
        }
        return skb;
 }
@@ -769,7 +772,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                                        gro_skb->ip_summed = CHECKSUM_UNNECESSARY;
 
                                        if (l2_tunnel)
-                                               gro_skb->encapsulation = 1;
+                                               gro_skb->csum_level = 1;
                                        if ((cqe->vlan_my_qpn &
                                            cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
                                            (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
@@ -823,8 +826,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                skb->protocol = eth_type_trans(skb, dev);
                skb_record_rx_queue(skb, cq->ring);
 
-               if (l2_tunnel)
-                       skb->encapsulation = 1;
+               if (l2_tunnel && ip_summed == CHECKSUM_UNNECESSARY)
+                       skb->csum_level = 1;
 
                if (dev->features & NETIF_F_RXHASH)
                        skb_set_hash(skb,
index dae3da6d8dd08979e4a4ba3f0f3c7413f10198cd..bc8f51c77d8082c1ab420a25394f32f1a59de20e 100644 (file)
@@ -319,7 +319,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                        }
                }
        }
-       dev_kfree_skb_any(skb);
+       dev_consume_skb_any(skb);
        return tx_info->nr_txbb;
 }
 
index 925b296d8ab84d8497d5a85b2bd5dda8b0c08aa9..f39cae620f61568688c79415c6dbf9ebbf96ff90 100644 (file)
@@ -1481,7 +1481,7 @@ static int phy_init(struct net_device *dev)
        }
 
        /* phy vendor specific configuration */
-       if ((np->phy_oui == PHY_OUI_CICADA)) {
+       if (np->phy_oui == PHY_OUI_CICADA) {
                if (init_cicada(dev, np, phyinterface)) {
                        netdev_info(dev, "%s: phy init failed\n",
                                    pci_name(np->pci_dev));
index b84f5ea3d659ee599e02db455296c54bf10e5fbe..e56c1bb361412144e2fa60cc6b2b21b3ecb35245 100644 (file)
@@ -39,8 +39,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 3
-#define _QLCNIC_LINUX_SUBVERSION 61
-#define QLCNIC_LINUX_VERSIONID  "5.3.61"
+#define _QLCNIC_LINUX_SUBVERSION 62
+#define QLCNIC_LINUX_VERSIONID  "5.3.62"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -540,6 +540,8 @@ struct qlcnic_hardware_context {
        u8 lb_mode;
        u16 vxlan_port;
        struct device *hwmon_dev;
+       u32 post_mode;
+       bool run_post;
 };
 
 struct qlcnic_adapter_stats {
@@ -2283,6 +2285,7 @@ extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
 
 #define PCI_DEVICE_ID_QLOGIC_QLE824X           0x8020
 #define PCI_DEVICE_ID_QLOGIC_QLE834X           0x8030
+#define PCI_DEVICE_ID_QLOGIC_QLE8830           0x8830
 #define PCI_DEVICE_ID_QLOGIC_VF_QLE834X        0x8430
 #define PCI_DEVICE_ID_QLOGIC_QLE844X           0x8040
 #define PCI_DEVICE_ID_QLOGIC_VF_QLE844X        0x8440
@@ -2307,6 +2310,7 @@ static inline bool qlcnic_83xx_check(struct qlcnic_adapter *adapter)
        bool status;
 
        status = ((device == PCI_DEVICE_ID_QLOGIC_QLE834X) ||
+                 (device == PCI_DEVICE_ID_QLOGIC_QLE8830) ||
                  (device == PCI_DEVICE_ID_QLOGIC_QLE844X) ||
                  (device == PCI_DEVICE_ID_QLOGIC_VF_QLE844X) ||
                  (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X)) ? true : false;
index 476e4998ef991693008818a4c559df1c0fc03e2d..840bf36b5e9d0d8ac5ddca14cc5e1afca26191f8 100644 (file)
@@ -35,6 +35,35 @@ static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *);
 #define QLC_SKIP_INACTIVE_PCI_REGS     7
 #define QLC_MAX_LEGACY_FUNC_SUPP       8
 
+/* 83xx Module type */
+#define QLC_83XX_MODULE_FIBRE_10GBASE_LRM      0x1 /* 10GBase-LRM */
+#define QLC_83XX_MODULE_FIBRE_10GBASE_LR       0x2 /* 10GBase-LR */
+#define QLC_83XX_MODULE_FIBRE_10GBASE_SR       0x3 /* 10GBase-SR */
+#define QLC_83XX_MODULE_DA_10GE_PASSIVE_CP     0x4 /* 10GE passive
+                                                    * copper(compliant)
+                                                    */
+#define QLC_83XX_MODULE_DA_10GE_ACTIVE_CP      0x5 /* 10GE active limiting
+                                                    * copper(compliant)
+                                                    */
+#define QLC_83XX_MODULE_DA_10GE_LEGACY_CP      0x6 /* 10GE passive copper
+                                                    * (legacy, best effort)
+                                                    */
+#define QLC_83XX_MODULE_FIBRE_1000BASE_SX      0x7 /* 1000Base-SX */
+#define QLC_83XX_MODULE_FIBRE_1000BASE_LX      0x8 /* 1000Base-LX */
+#define QLC_83XX_MODULE_FIBRE_1000BASE_CX      0x9 /* 1000Base-CX */
+#define QLC_83XX_MODULE_TP_1000BASE_T          0xa /* 1000Base-T*/
+#define QLC_83XX_MODULE_DA_1GE_PASSIVE_CP      0xb /* 1GE passive copper
+                                                    * (legacy, best effort)
+                                                    */
+#define QLC_83XX_MODULE_UNKNOWN                        0xf /* Unknown module type */
+
+/* Port types */
+#define QLC_83XX_10_CAPABLE     BIT_8
+#define QLC_83XX_100_CAPABLE    BIT_9
+#define QLC_83XX_1G_CAPABLE     BIT_10
+#define QLC_83XX_10G_CAPABLE    BIT_11
+#define QLC_83XX_AUTONEG_ENABLE         BIT_15
+
 static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
        {QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},
        {QLCNIC_CMD_CONFIG_INTRPT, 18, 34},
@@ -667,6 +696,7 @@ void qlcnic_83xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
 
 int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        int status;
 
        status = qlcnic_83xx_get_port_config(adapter);
@@ -674,13 +704,20 @@ int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
                dev_err(&adapter->pdev->dev,
                        "Get Port Info failed\n");
        } else {
-               if (QLC_83XX_SFP_10G_CAPABLE(adapter->ahw->port_config))
-                       adapter->ahw->port_type = QLCNIC_XGBE;
-               else
-                       adapter->ahw->port_type = QLCNIC_GBE;
 
-               if (QLC_83XX_AUTONEG(adapter->ahw->port_config))
-                       adapter->ahw->link_autoneg = AUTONEG_ENABLE;
+               if (ahw->port_config & QLC_83XX_10G_CAPABLE) {
+                       ahw->port_type = QLCNIC_XGBE;
+               } else if (ahw->port_config & QLC_83XX_10_CAPABLE ||
+                          ahw->port_config & QLC_83XX_100_CAPABLE ||
+                          ahw->port_config & QLC_83XX_1G_CAPABLE) {
+                       ahw->port_type = QLCNIC_GBE;
+               } else {
+                       ahw->port_type = QLCNIC_XGBE;
+               }
+
+               if (QLC_83XX_AUTONEG(ahw->port_config))
+                       ahw->link_autoneg = AUTONEG_ENABLE;
+
        }
        return status;
 }
@@ -2664,7 +2701,7 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
                    QLC_83XX_FLASH_STATUS_READY)
                        break;
 
-               msleep(QLC_83XX_FLASH_STATUS_REG_POLL_DELAY);
+               usleep_range(1000, 1100);
        } while (--retries);
 
        if (!retries)
@@ -3176,22 +3213,33 @@ int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
                        break;
                }
                config = cmd.rsp.arg[3];
-               if (QLC_83XX_SFP_PRESENT(config)) {
-                       switch (ahw->module_type) {
-                       case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
-                       case LINKEVENT_MODULE_OPTICAL_SRLR:
-                       case LINKEVENT_MODULE_OPTICAL_LRM:
-                       case LINKEVENT_MODULE_OPTICAL_SFP_1G:
-                               ahw->supported_type = PORT_FIBRE;
-                               break;
-                       case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
-                       case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
-                       case LINKEVENT_MODULE_TWINAX:
-                               ahw->supported_type = PORT_TP;
-                               break;
-                       default:
-                               ahw->supported_type = PORT_OTHER;
-                       }
+               switch (QLC_83XX_SFP_MODULE_TYPE(config)) {
+               case QLC_83XX_MODULE_FIBRE_10GBASE_LRM:
+               case QLC_83XX_MODULE_FIBRE_10GBASE_LR:
+               case QLC_83XX_MODULE_FIBRE_10GBASE_SR:
+                       ahw->supported_type = PORT_FIBRE;
+                       ahw->port_type = QLCNIC_XGBE;
+                       break;
+               case QLC_83XX_MODULE_FIBRE_1000BASE_SX:
+               case QLC_83XX_MODULE_FIBRE_1000BASE_LX:
+               case QLC_83XX_MODULE_FIBRE_1000BASE_CX:
+                       ahw->supported_type = PORT_FIBRE;
+                       ahw->port_type = QLCNIC_GBE;
+                       break;
+               case QLC_83XX_MODULE_TP_1000BASE_T:
+                       ahw->supported_type = PORT_TP;
+                       ahw->port_type = QLCNIC_GBE;
+                       break;
+               case QLC_83XX_MODULE_DA_10GE_PASSIVE_CP:
+               case QLC_83XX_MODULE_DA_10GE_ACTIVE_CP:
+               case QLC_83XX_MODULE_DA_10GE_LEGACY_CP:
+               case QLC_83XX_MODULE_DA_1GE_PASSIVE_CP:
+                       ahw->supported_type = PORT_DA;
+                       ahw->port_type = QLCNIC_XGBE;
+                       break;
+               default:
+                       ahw->supported_type = PORT_OTHER;
+                       ahw->port_type = QLCNIC_XGBE;
                }
                if (config & 1)
                        err = 1;
@@ -3204,9 +3252,9 @@ out:
 int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
                             struct ethtool_cmd *ecmd)
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        u32 config = 0;
        int status = 0;
-       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        if (!test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) {
                /* Get port configuration info */
@@ -3229,20 +3277,41 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
                ecmd->autoneg = AUTONEG_DISABLE;
        }
 
-       if (ahw->port_type == QLCNIC_XGBE) {
-               ecmd->supported = SUPPORTED_10000baseT_Full;
-               ecmd->advertising = ADVERTISED_10000baseT_Full;
+       ecmd->supported = (SUPPORTED_10baseT_Full |
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_10000baseT_Full |
+                          SUPPORTED_Autoneg);
+
+       if (ecmd->autoneg == AUTONEG_ENABLE) {
+               if (ahw->port_config & QLC_83XX_10_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_10baseT_Full;
+               if (ahw->port_config & QLC_83XX_100_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_100baseT_Full;
+               if (ahw->port_config & QLC_83XX_1G_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_1000baseT_Full;
+               if (ahw->port_config & QLC_83XX_10G_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_10000baseT_Full;
+               if (ahw->port_config & QLC_83XX_AUTONEG_ENABLE)
+                       ecmd->advertising |= ADVERTISED_Autoneg;
        } else {
-               ecmd->supported = (SUPPORTED_10baseT_Half |
-                                  SUPPORTED_10baseT_Full |
-                                  SUPPORTED_100baseT_Half |
-                                  SUPPORTED_100baseT_Full |
-                                  SUPPORTED_1000baseT_Half |
-                                  SUPPORTED_1000baseT_Full);
-               ecmd->advertising = (ADVERTISED_100baseT_Half |
-                                    ADVERTISED_100baseT_Full |
-                                    ADVERTISED_1000baseT_Half |
-                                    ADVERTISED_1000baseT_Full);
+               switch (ahw->link_speed) {
+               case SPEED_10:
+                       ecmd->advertising = SUPPORTED_10baseT_Full;
+                       break;
+               case SPEED_100:
+                       ecmd->advertising = SUPPORTED_100baseT_Full;
+                       break;
+               case SPEED_1000:
+                       ecmd->advertising = SUPPORTED_1000baseT_Full;
+                       break;
+               case SPEED_10000:
+                       ecmd->advertising = SUPPORTED_10000baseT_Full;
+                       break;
+               default:
+                       break;
+               }
+
        }
 
        switch (ahw->supported_type) {
@@ -3258,6 +3327,12 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
                ecmd->port = PORT_TP;
                ecmd->transceiver = XCVR_INTERNAL;
                break;
+       case PORT_DA:
+               ecmd->supported |= SUPPORTED_FIBRE;
+               ecmd->advertising |= ADVERTISED_FIBRE;
+               ecmd->port = PORT_DA;
+               ecmd->transceiver = XCVR_EXTERNAL;
+               break;
        default:
                ecmd->supported |= SUPPORTED_FIBRE;
                ecmd->advertising |= ADVERTISED_FIBRE;
@@ -3272,35 +3347,60 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
 int qlcnic_83xx_set_settings(struct qlcnic_adapter *adapter,
                             struct ethtool_cmd *ecmd)
 {
-       int status = 0;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        u32 config = adapter->ahw->port_config;
+       int status = 0;
 
-       if (ecmd->autoneg)
-               adapter->ahw->port_config |= BIT_15;
-
-       switch (ethtool_cmd_speed(ecmd)) {
-       case SPEED_10:
-               adapter->ahw->port_config |= BIT_8;
-               break;
-       case SPEED_100:
-               adapter->ahw->port_config |= BIT_9;
-               break;
-       case SPEED_1000:
-               adapter->ahw->port_config |= BIT_10;
-               break;
-       case SPEED_10000:
-               adapter->ahw->port_config |= BIT_11;
-               break;
-       default:
-               return -EINVAL;
+       /* 83xx devices do not support Half duplex */
+       if (ecmd->duplex == DUPLEX_HALF) {
+                       netdev_info(adapter->netdev,
+                                   "Half duplex mode not supported\n");
+                       return -EINVAL;
        }
 
+       if (ecmd->autoneg) {
+               ahw->port_config |= QLC_83XX_AUTONEG_ENABLE;
+               ahw->port_config |= (QLC_83XX_100_CAPABLE |
+                                    QLC_83XX_1G_CAPABLE |
+                                    QLC_83XX_10G_CAPABLE);
+       } else { /* force speed */
+               ahw->port_config &= ~QLC_83XX_AUTONEG_ENABLE;
+               switch (ethtool_cmd_speed(ecmd)) {
+               case SPEED_10:
+                       ahw->port_config &= ~(QLC_83XX_100_CAPABLE |
+                                             QLC_83XX_1G_CAPABLE |
+                                             QLC_83XX_10G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_10_CAPABLE;
+                       break;
+               case SPEED_100:
+                       ahw->port_config &= ~(QLC_83XX_10_CAPABLE |
+                                             QLC_83XX_1G_CAPABLE |
+                                             QLC_83XX_10G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_100_CAPABLE;
+                       break;
+               case SPEED_1000:
+                       ahw->port_config &= ~(QLC_83XX_10_CAPABLE |
+                                             QLC_83XX_100_CAPABLE |
+                                             QLC_83XX_10G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_1G_CAPABLE;
+                       break;
+               case SPEED_10000:
+                       ahw->port_config &= ~(QLC_83XX_10_CAPABLE |
+                                             QLC_83XX_100_CAPABLE |
+                                             QLC_83XX_1G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_10G_CAPABLE;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
        status = qlcnic_83xx_set_port_config(adapter);
        if (status) {
-               dev_info(&adapter->pdev->dev,
-                        "Failed to Set Link Speed and autoneg.\n");
-               adapter->ahw->port_config = config;
+               netdev_info(adapter->netdev,
+                           "Failed to Set Link Speed and autoneg.\n");
+               ahw->port_config = config;
        }
+
        return status;
 }
 
index 2bf101a47d02db1afbd153e032aab728f2ecb159..f3346a3779d3c36c2f91d4703feb75dc500e39df 100644 (file)
@@ -83,6 +83,7 @@
 /* Firmware image definitions */
 #define QLC_83XX_BOOTLOADER_FLASH_ADDR 0x10000
 #define QLC_83XX_FW_FILE_NAME          "83xx_fw.bin"
+#define QLC_83XX_POST_FW_FILE_NAME     "83xx_post_fw.bin"
 #define QLC_84XX_FW_FILE_NAME          "84xx_fw.bin"
 #define QLC_83XX_BOOT_FROM_FLASH       0
 #define QLC_83XX_BOOT_FROM_FILE                0x12345678
@@ -360,7 +361,6 @@ enum qlcnic_83xx_states {
 #define QLC_83XX_SFP_MODULE_TYPE(data)         (((data) >> 4) & 0x1F)
 #define QLC_83XX_SFP_CU_LENGTH(data)           (LSB((data) >> 16))
 #define QLC_83XX_SFP_TX_FAULT(data)            ((data) & BIT_10)
-#define QLC_83XX_SFP_10G_CAPABLE(data)         ((data) & BIT_11)
 #define QLC_83XX_LINK_STATS(data)              ((data) & BIT_0)
 #define QLC_83XX_CURRENT_LINK_SPEED(data)      (((data) >> 3) & 7)
 #define QLC_83XX_LINK_PAUSE(data)              (((data) >> 6) & 3)
index 86783e1afcf76d77176a079e4420a50f7b452b62..9a2cfe4efac64c4b3f6073c1f5790d82ceb61c3d 100644 (file)
@@ -2075,6 +2075,121 @@ static void qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev)
                dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
 }
 
+/* POST FW related definations*/
+#define QLC_83XX_POST_SIGNATURE_REG    0x41602014
+#define QLC_83XX_POST_MODE_REG         0x41602018
+#define QLC_83XX_POST_FAST_MODE                0
+#define QLC_83XX_POST_MEDIUM_MODE      1
+#define QLC_83XX_POST_SLOW_MODE                2
+
+/* POST Timeout values in milliseconds */
+#define QLC_83XX_POST_FAST_MODE_TIMEOUT        690
+#define QLC_83XX_POST_MED_MODE_TIMEOUT 2930
+#define QLC_83XX_POST_SLOW_MODE_TIMEOUT        7500
+
+/* POST result values */
+#define QLC_83XX_POST_PASS                     0xfffffff0
+#define QLC_83XX_POST_ASIC_STRESS_TEST_FAIL    0xffffffff
+#define QLC_83XX_POST_DDR_TEST_FAIL            0xfffffffe
+#define QLC_83XX_POST_ASIC_MEMORY_TEST_FAIL    0xfffffffc
+#define QLC_83XX_POST_FLASH_TEST_FAIL          0xfffffff8
+
+static int qlcnic_83xx_run_post(struct qlcnic_adapter *adapter)
+{
+       struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
+       struct device *dev = &adapter->pdev->dev;
+       int timeout, count, ret = 0;
+       u32 signature;
+
+       /* Set timeout values with extra 2 seconds of buffer */
+       switch (adapter->ahw->post_mode) {
+       case QLC_83XX_POST_FAST_MODE:
+               timeout = QLC_83XX_POST_FAST_MODE_TIMEOUT + 2000;
+               break;
+       case QLC_83XX_POST_MEDIUM_MODE:
+               timeout = QLC_83XX_POST_MED_MODE_TIMEOUT + 2000;
+               break;
+       case QLC_83XX_POST_SLOW_MODE:
+               timeout = QLC_83XX_POST_SLOW_MODE_TIMEOUT + 2000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       strncpy(fw_info->fw_file_name, QLC_83XX_POST_FW_FILE_NAME,
+               QLC_FW_FILE_NAME_LEN);
+
+       ret = request_firmware(&fw_info->fw, fw_info->fw_file_name, dev);
+       if (ret) {
+               dev_err(dev, "POST firmware can not be loaded, skipping POST\n");
+               return 0;
+       }
+
+       ret = qlcnic_83xx_copy_fw_file(adapter);
+       if (ret)
+               return ret;
+
+       /* clear QLC_83XX_POST_SIGNATURE_REG register */
+       qlcnic_ind_wr(adapter, QLC_83XX_POST_SIGNATURE_REG, 0);
+
+       /* Set POST mode */
+       qlcnic_ind_wr(adapter, QLC_83XX_POST_MODE_REG,
+                     adapter->ahw->post_mode);
+
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+                           QLC_83XX_BOOT_FROM_FILE);
+
+       qlcnic_83xx_start_hw(adapter);
+
+       count = 0;
+       do {
+               msleep(100);
+               count += 100;
+
+               signature = qlcnic_ind_rd(adapter, QLC_83XX_POST_SIGNATURE_REG);
+               if (signature == QLC_83XX_POST_PASS)
+                       break;
+       } while (timeout > count);
+
+       if (timeout <= count) {
+               dev_err(dev, "POST timed out, signature = 0x%08x\n", signature);
+               return -EIO;
+       }
+
+       switch (signature) {
+       case QLC_83XX_POST_PASS:
+               dev_info(dev, "POST passed, Signature = 0x%08x\n", signature);
+               break;
+       case QLC_83XX_POST_ASIC_STRESS_TEST_FAIL:
+               dev_err(dev, "POST failed, Test case : ASIC STRESS TEST, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       case QLC_83XX_POST_DDR_TEST_FAIL:
+               dev_err(dev, "POST failed, Test case : DDT TEST, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       case QLC_83XX_POST_ASIC_MEMORY_TEST_FAIL:
+               dev_err(dev, "POST failed, Test case : ASIC MEMORY TEST, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       case QLC_83XX_POST_FLASH_TEST_FAIL:
+               dev_err(dev, "POST failed, Test case : FLASH TEST, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       default:
+               dev_err(dev, "POST failed, Test case : INVALID, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       }
+
+       return ret;
+}
+
 static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter)
 {
        struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
@@ -2119,8 +2234,27 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
 
        if (qlcnic_83xx_copy_bootloader(adapter))
                return err;
+
+       /* Check if POST needs to be run */
+       if (adapter->ahw->run_post) {
+               err = qlcnic_83xx_run_post(adapter);
+               if (err)
+                       return err;
+
+               /* No need to run POST in next reset sequence */
+               adapter->ahw->run_post = false;
+
+               /* Again reset the adapter to load regular firmware  */
+               qlcnic_83xx_stop_hw(adapter);
+               qlcnic_83xx_init_hw(adapter);
+
+               err = qlcnic_83xx_copy_bootloader(adapter);
+               if (err)
+                       return err;
+       }
+
        /* Boot either flash image or firmware image from host file system */
-       if (qlcnic_load_fw_file) {
+       if (qlcnic_load_fw_file == 1) {
                if (qlcnic_83xx_load_fw_image_from_host(adapter))
                        return err;
        } else {
@@ -2284,6 +2418,7 @@ static int qlcnic_83xx_get_fw_info(struct qlcnic_adapter *adapter)
                fw_info = ahw->fw_info;
                switch (pdev->device) {
                case PCI_DEVICE_ID_QLOGIC_QLE834X:
+               case PCI_DEVICE_ID_QLOGIC_QLE8830:
                        strncpy(fw_info->fw_file_name, QLC_83XX_FW_FILE_NAME,
                                QLC_FW_FILE_NAME_LEN);
                        break;
@@ -2328,6 +2463,25 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        adapter->rx_mac_learn = false;
        ahw->msix_supported = !!qlcnic_use_msi_x;
 
+       /* Check if POST needs to be run */
+       switch (qlcnic_load_fw_file) {
+       case 2:
+               ahw->post_mode = QLC_83XX_POST_FAST_MODE;
+               ahw->run_post = true;
+               break;
+       case 3:
+               ahw->post_mode = QLC_83XX_POST_MEDIUM_MODE;
+               ahw->run_post = true;
+               break;
+       case 4:
+               ahw->post_mode = QLC_83XX_POST_SLOW_MODE;
+               ahw->run_post = true;
+               break;
+       default:
+               ahw->run_post = false;
+               break;
+       }
+
        qlcnic_83xx_init_rings(adapter);
 
        err = qlcnic_83xx_init_mailbox_work(adapter);
index 851cb4a80d50a6d4b2733ac2693fd799cca37885..8102673cb37f6931fd16f26d70357a594ef831ad 100644 (file)
@@ -341,7 +341,7 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
                        }
                        return -EIO;
                }
-               msleep(1);
+               usleep_range(1000, 1500);
        }
 
        if (id_reg)
index c4262c23ed7c77b009f6c5cebf233a54ebfd685b..be41e4c77b657285841c610c1f30a701dc2c87ee 100644 (file)
@@ -537,7 +537,7 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0xc, 0);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x8, 0);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0xc, 0);
-       msleep(1);
+       usleep_range(1000, 1500);
 
        QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
        QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
@@ -1198,7 +1198,7 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter)
                        flashaddr += 8;
                }
        }
-       msleep(1);
+       usleep_range(1000, 1500);
 
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x18, 0x1020);
        QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0x80001e);
@@ -1295,7 +1295,7 @@ next:
                rc = qlcnic_validate_firmware(adapter);
                if (rc != 0) {
                        release_firmware(adapter->fw);
-                       msleep(1);
+                       usleep_range(1000, 1500);
                        goto next;
                }
        }
index e45bf09af0c9fe4dbe9cdc629370af792ab88c01..18e5de72e9b4c2c9b95848bf444597251942039e 100644 (file)
@@ -1753,7 +1753,7 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
 
        if (qlcnic_encap_length(sts_data[1]) &&
            skb->ip_summed == CHECKSUM_UNNECESSARY) {
-               skb->encapsulation = 1;
+               skb->csum_level = 1;
                adapter->stats.encap_rx_csummed++;
        }
 
index cf08b2de071e4d602745d2dd5c7bc6e7b3b530df..f5e29f7bdae39b77eed8abc0b8e73360ceeda698 100644 (file)
@@ -52,7 +52,7 @@ MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled)");
 module_param_named(auto_fw_reset, qlcnic_auto_fw_reset, int, 0644);
 
 int qlcnic_load_fw_file;
-MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file)");
+MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file, 2=POST in fast mode, 3= POST in medium mode, 4=POST in slow mode)");
 module_param_named(load_fw_file, qlcnic_load_fw_file, int, 0444);
 
 static int qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -111,6 +111,7 @@ static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
 static const struct pci_device_id qlcnic_pci_tbl[] = {
        ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
        ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X),
+       ENTRY(PCI_DEVICE_ID_QLOGIC_QLE8830),
        ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE834X),
        ENTRY(PCI_DEVICE_ID_QLOGIC_QLE844X),
        ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE844X),
@@ -227,6 +228,11 @@ static const struct qlcnic_board_info qlcnic_boards[] = {
        { PCI_VENDOR_ID_QLOGIC,
          PCI_DEVICE_ID_QLOGIC_QLE834X,
          0x0, 0x0, "8300 Series 1/10GbE Controller" },
+       { PCI_VENDOR_ID_QLOGIC,
+         PCI_DEVICE_ID_QLOGIC_QLE8830,
+         0x0,
+         0x0,
+         "8830 Series 1/10GbE Controller" },
        { PCI_VENDOR_ID_QLOGIC,
          PCI_DEVICE_ID_QLOGIC_QLE824X,
          PCI_VENDOR_ID_QLOGIC,
@@ -1131,6 +1137,7 @@ static void qlcnic_get_bar_length(u32 dev_id, ulong *bar)
                *bar = QLCNIC_82XX_BAR0_LENGTH;
                break;
        case PCI_DEVICE_ID_QLOGIC_QLE834X:
+       case PCI_DEVICE_ID_QLOGIC_QLE8830:
        case PCI_DEVICE_ID_QLOGIC_QLE844X:
        case PCI_DEVICE_ID_QLOGIC_VF_QLE834X:
        case PCI_DEVICE_ID_QLOGIC_VF_QLE844X:
@@ -2474,6 +2481,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                ahw->reg_tbl = (u32 *) qlcnic_reg_tbl;
                break;
        case PCI_DEVICE_ID_QLOGIC_QLE834X:
+       case PCI_DEVICE_ID_QLOGIC_QLE8830:
        case PCI_DEVICE_ID_QLOGIC_QLE844X:
                qlcnic_83xx_register_map(ahw);
                break;
index 91652e7235e469be8c20a7ecd7a5b926178ab1af..02dd92ac1764cbe87195dcb6fa8d018450dc728b 100644 (file)
 #define FIRMWARE_8106E_2       "rtl_nic/rtl8106e-2.fw"
 #define FIRMWARE_8168G_2       "rtl_nic/rtl8168g-2.fw"
 #define FIRMWARE_8168G_3       "rtl_nic/rtl8168g-3.fw"
+#define FIRMWARE_8168H_1       "rtl_nic/rtl8168h-1.fw"
+#define FIRMWARE_8168H_2       "rtl_nic/rtl8168h-2.fw"
+#define FIRMWARE_8107E_1       "rtl_nic/rtl8107e-1.fw"
+#define FIRMWARE_8107E_2       "rtl_nic/rtl8107e-2.fw"
 
 #ifdef RTL8169_DEBUG
 #define assert(expr) \
@@ -147,6 +151,10 @@ enum mac_version {
        RTL_GIGA_MAC_VER_42,
        RTL_GIGA_MAC_VER_43,
        RTL_GIGA_MAC_VER_44,
+       RTL_GIGA_MAC_VER_45,
+       RTL_GIGA_MAC_VER_46,
+       RTL_GIGA_MAC_VER_47,
+       RTL_GIGA_MAC_VER_48,
        RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -282,6 +290,18 @@ static const struct {
        [RTL_GIGA_MAC_VER_44] =
                _R("RTL8411",           RTL_TD_1, FIRMWARE_8411_2,
                                                        JUMBO_9K, false),
+       [RTL_GIGA_MAC_VER_45] =
+               _R("RTL8168h/8111h",    RTL_TD_1, FIRMWARE_8168H_1,
+                                                       JUMBO_9K, false),
+       [RTL_GIGA_MAC_VER_46] =
+               _R("RTL8168h/8111h",    RTL_TD_1, FIRMWARE_8168H_2,
+                                                       JUMBO_9K, false),
+       [RTL_GIGA_MAC_VER_47] =
+               _R("RTL8107e",          RTL_TD_1, FIRMWARE_8107E_1,
+                                                       JUMBO_1K, false),
+       [RTL_GIGA_MAC_VER_48] =
+               _R("RTL8107e",          RTL_TD_1, FIRMWARE_8107E_2,
+                                                       JUMBO_1K, false),
 };
 #undef _R
 
@@ -410,6 +430,7 @@ enum rtl8168_8101_registers {
 #define        EPHYAR_DATA_MASK                0xffff
        DLLPR                   = 0xd0,
 #define        PFM_EN                          (1 << 6)
+#define        TX_10M_PS_EN                    (1 << 7)
        DBG_REG                 = 0xd1,
 #define        FIX_NAK_1                       (1 << 4)
 #define        FIX_NAK_2                       (1 << 3)
@@ -429,6 +450,8 @@ enum rtl8168_8101_registers {
 #define        EFUSEAR_REG_MASK                0x03ff
 #define        EFUSEAR_REG_SHIFT               8
 #define        EFUSEAR_DATA_MASK               0xff
+       MISC_1                  = 0xf2,
+#define        PFM_D3COLD_EN                   (1 << 6)
 };
 
 enum rtl8168_registers {
@@ -447,6 +470,7 @@ enum rtl8168_registers {
 #define ERIAR_MASK_SHIFT               12
 #define ERIAR_MASK_0001                        (0x1 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_0011                        (0x3 << ERIAR_MASK_SHIFT)
+#define ERIAR_MASK_0100                        (0x4 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_0101                        (0x5 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_1111                        (0xf << ERIAR_MASK_SHIFT)
        EPHY_RXER_NUM           = 0x7c,
@@ -598,6 +622,9 @@ enum rtl_register_content {
 
        /* DumpCounterCommand */
        CounterDump     = 0x8,
+
+       /* magic enable v2 */
+       MagicPacket_v2  = (1 << 16),    /* Wake up when receives a Magic Packet */
 };
 
 enum rtl_desc_bit {
@@ -823,6 +850,10 @@ MODULE_FIRMWARE(FIRMWARE_8106E_1);
 MODULE_FIRMWARE(FIRMWARE_8106E_2);
 MODULE_FIRMWARE(FIRMWARE_8168G_2);
 MODULE_FIRMWARE(FIRMWARE_8168G_3);
+MODULE_FIRMWARE(FIRMWARE_8168H_1);
+MODULE_FIRMWARE(FIRMWARE_8168H_2);
+MODULE_FIRMWARE(FIRMWARE_8107E_1);
+MODULE_FIRMWARE(FIRMWARE_8107E_2);
 
 static void rtl_lock_work(struct rtl8169_private *tp)
 {
@@ -1514,8 +1545,17 @@ static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
        options = RTL_R8(Config3);
        if (options & LinkUp)
                wolopts |= WAKE_PHY;
-       if (options & MagicPacket)
-               wolopts |= WAKE_MAGIC;
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               if (rtl_eri_read(tp, 0xdc, ERIAR_EXGMAC) & MagicPacket_v2)
+                       wolopts |= WAKE_MAGIC;
+               break;
+       default:
+               if (options & MagicPacket)
+                       wolopts |= WAKE_MAGIC;
+               break;
+       }
 
        options = RTL_R8(Config5);
        if (options & UWF)
@@ -1543,24 +1583,48 @@ static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
 {
        void __iomem *ioaddr = tp->mmio_addr;
-       unsigned int i;
+       unsigned int i, tmp;
        static const struct {
                u32 opt;
                u16 reg;
                u8  mask;
        } cfg[] = {
                { WAKE_PHY,   Config3, LinkUp },
-               { WAKE_MAGIC, Config3, MagicPacket },
                { WAKE_UCAST, Config5, UWF },
                { WAKE_BCAST, Config5, BWF },
                { WAKE_MCAST, Config5, MWF },
-               { WAKE_ANY,   Config5, LanWake }
+               { WAKE_ANY,   Config5, LanWake },
+               { WAKE_MAGIC, Config3, MagicPacket }
        };
        u8 options;
 
        RTL_W8(Cfg9346, Cfg9346_Unlock);
 
-       for (i = 0; i < ARRAY_SIZE(cfg); i++) {
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               tmp = ARRAY_SIZE(cfg) - 1;
+               if (wolopts & WAKE_MAGIC)
+                       rtl_w1w0_eri(tp,
+                                    0x0dc,
+                                    ERIAR_MASK_0100,
+                                    MagicPacket_v2,
+                                    0x0000,
+                                    ERIAR_EXGMAC);
+               else
+                       rtl_w1w0_eri(tp,
+                                    0x0dc,
+                                    ERIAR_MASK_0100,
+                                    0x0000,
+                                    MagicPacket_v2,
+                                    ERIAR_EXGMAC);
+               break;
+       default:
+               tmp = ARRAY_SIZE(cfg);
+               break;
+       }
+
+       for (i = 0; i < tmp; i++) {
                options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
                if (wolopts & cfg[i].opt)
                        options |= cfg[i].mask;
@@ -2044,6 +2108,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
                u32 val;
                int mac_version;
        } mac_info[] = {
+               /* 8168H family. */
+               { 0x7cf00000, 0x54100000,       RTL_GIGA_MAC_VER_46 },
+               { 0x7cf00000, 0x54000000,       RTL_GIGA_MAC_VER_45 },
+
                /* 8168G family. */
                { 0x7cf00000, 0x5c800000,       RTL_GIGA_MAC_VER_44 },
                { 0x7cf00000, 0x50900000,       RTL_GIGA_MAC_VER_42 },
@@ -2139,6 +2207,14 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
                tp->mac_version = tp->mii.supports_gmii ?
                                  RTL_GIGA_MAC_VER_42 :
                                  RTL_GIGA_MAC_VER_43;
+       } else if (tp->mac_version == RTL_GIGA_MAC_VER_45) {
+               tp->mac_version = tp->mii.supports_gmii ?
+                                 RTL_GIGA_MAC_VER_45 :
+                                 RTL_GIGA_MAC_VER_47;
+       } else if (tp->mac_version == RTL_GIGA_MAC_VER_46) {
+               tp->mac_version = tp->mii.supports_gmii ?
+                                 RTL_GIGA_MAC_VER_46 :
+                                 RTL_GIGA_MAC_VER_48;
        }
 }
 
@@ -3464,6 +3540,189 @@ static void rtl8168g_2_hw_phy_config(struct rtl8169_private *tp)
        rtl_apply_firmware(tp);
 }
 
+static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp)
+{
+       u16 dout_tapbin;
+       u32 data;
+
+       rtl_apply_firmware(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_writephy(tp, 0x13, 0x80a2);
+       rtl_w1w0_phy(tp, 0x14, 0x8000, 0xff00);
+       rtl_writephy(tp, 0x13, 0x80a4);
+       rtl_w1w0_phy(tp, 0x14, 0x8500, 0xff00);
+       rtl_writephy(tp, 0x13, 0x809c);
+       rtl_w1w0_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_writephy(tp, 0x13, 0x80b4);
+       rtl_w1w0_phy(tp, 0x14, 0x5000, 0xff00);
+       rtl_writephy(tp, 0x13, 0x80ac);
+       rtl_w1w0_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_writephy(tp, 0x13, 0x8090);
+       rtl_w1w0_phy(tp, 0x14, 0xe500, 0xff00);
+       rtl_writephy(tp, 0x13, 0x8092);
+       rtl_w1w0_phy(tp, 0x14, 0x9f00, 0xff00);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* enable R-tune & PGA-retune function */
+       dout_tapbin = 0;
+       rtl_writephy(tp, 0x1f, 0x0a46);
+       data = rtl_readphy(tp, 0x13);
+       data &= 3;
+       data <<= 2;
+       dout_tapbin |= data;
+       data = rtl_readphy(tp, 0x12);
+       data &= 0xc000;
+       data >>= 14;
+       dout_tapbin |= data;
+       dout_tapbin = ~(dout_tapbin^0x08);
+       dout_tapbin <<= 12;
+       dout_tapbin &= 0xf000;
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x827a);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+       rtl_writephy(tp, 0x13, 0x827b);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+       rtl_writephy(tp, 0x13, 0x827c);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+       rtl_writephy(tp, 0x13, 0x827d);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x0811);
+       rtl_w1w0_phy(tp, 0x14, 0x0800, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0a42);
+       rtl_w1w0_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_writephy(tp, 0x1f, 0x0000);
+
+       /* SAR ADC performance */
+       rtl_writephy(tp, 0x1f, 0x0bca);
+       rtl_w1w0_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_writephy(tp, 0x13, 0x8047);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x804f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x8057);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x805f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x8067);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x806f);
+       rtl_w1w0_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_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_writephy(tp, 0x1f, 0x0000);
+}
+
+static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp)
+{
+       u16 ioffset_p3, ioffset_p2, ioffset_p1, ioffset_p0;
+       u16 rlen;
+       u32 data;
+
+       rtl_apply_firmware(tp);
+
+       /* CHIN EST parameter update */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x808a);
+       rtl_w1w0_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_writephy(tp, 0x1f, 0x0a42);
+       rtl_w1w0_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_writephy(tp, 0x1f, 0x0000);
+
+       r8168_mac_ocp_write(tp, 0xdd02, 0x807d);
+       data = r8168_mac_ocp_read(tp, 0xdd02);
+       ioffset_p3 = ((data & 0x80)>>7);
+       ioffset_p3 <<= 3;
+
+       data = r8168_mac_ocp_read(tp, 0xdd00);
+       ioffset_p3 |= ((data & (0xe000))>>13);
+       ioffset_p2 = ((data & (0x1e00))>>9);
+       ioffset_p1 = ((data & (0x01e0))>>5);
+       ioffset_p0 = ((data & 0x0010)>>4);
+       ioffset_p0 <<= 3;
+       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)) {
+               rtl_writephy(tp, 0x1f, 0x0bcf);
+               rtl_writephy(tp, 0x16, data);
+               rtl_writephy(tp, 0x1f, 0x0000);
+       }
+
+       /* Modify rlen (TX LPF corner frequency) level */
+       rtl_writephy(tp, 0x1f, 0x0bcd);
+       data = rtl_readphy(tp, 0x16);
+       data &= 0x000f;
+       rlen = 0;
+       if (data > 3)
+               rlen = data - 3;
+       data = rlen | (rlen<<4) | (rlen<<8) | (rlen<<12);
+       rtl_writephy(tp, 0x17, data);
+       rtl_writephy(tp, 0x1f, 0x0bcd);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* disable phy pfm mode */
+       rtl_writephy(tp, 0x1f, 0x0a44);
+       rtl_w1w0_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_writephy(tp, 0x1f, 0x0000);
+}
+
 static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
 {
        static const struct phy_reg phy_reg_init[] = {
@@ -3654,6 +3913,14 @@ static void rtl_hw_phy_config(struct net_device *dev)
        case RTL_GIGA_MAC_VER_44:
                rtl8168g_2_hw_phy_config(tp);
                break;
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_47:
+               rtl8168h_1_hw_phy_config(tp);
+               break;
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_48:
+               rtl8168h_2_hw_phy_config(tp);
+               break;
 
        case RTL_GIGA_MAC_VER_41:
        default:
@@ -3865,6 +4132,10 @@ static void rtl_init_mdio_ops(struct rtl8169_private *tp)
        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:
                ops->write      = r8168g_mdio_write;
                ops->read       = r8168g_mdio_read;
                break;
@@ -3919,6 +4190,10 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
        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:
                RTL_W32(RxConfig, RTL_R32(RxConfig) |
                        AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
                break;
@@ -3987,6 +4262,10 @@ static void r810x_pll_power_up(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_13:
        case RTL_GIGA_MAC_VER_16:
                break;
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
+               RTL_W8(PMCH, RTL_R8(PMCH) | 0xC0);
+               break;
        default:
                RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
                break;
@@ -4087,6 +4366,8 @@ 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_45:
+       case RTL_GIGA_MAC_VER_46:
                RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
                break;
        case RTL_GIGA_MAC_VER_40:
@@ -4111,6 +4392,10 @@ 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_45:
+       case RTL_GIGA_MAC_VER_46:
+               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,
@@ -4153,6 +4438,8 @@ static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_37:
        case RTL_GIGA_MAC_VER_39:
        case RTL_GIGA_MAC_VER_43:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                ops->down       = r810x_pll_power_down;
                ops->up         = r810x_pll_power_up;
                break;
@@ -4182,6 +4469,8 @@ static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
                ops->down       = r8168_pll_power_down;
                ops->up         = r8168_pll_power_up;
                break;
@@ -4232,6 +4521,10 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
        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:
                RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
                break;
        default:
@@ -4393,6 +4686,10 @@ static void rtl_init_jumbo_ops(struct rtl8169_private *tp)
        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:
        default:
                ops->disable    = NULL;
                ops->enable     = NULL;
@@ -4495,15 +4792,19 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
            tp->mac_version == RTL_GIGA_MAC_VER_31) {
                rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
        } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
-                  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_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_38) {
+                  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) {
                RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
                rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
        } else {
@@ -5330,6 +5631,105 @@ static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
        rtl_ephy_init(tp, e_info_8411_2, ARRAY_SIZE(e_info_8411_2));
 }
 
+static void rtl_hw_start_8168h_1(struct rtl8169_private *tp)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
+       u16 rg_saw_cnt;
+       u32 data;
+       static const struct ephy_info e_info_8168h_1[] = {
+               { 0x1e, 0x0800, 0x0001 },
+               { 0x1d, 0x0000, 0x0800 },
+               { 0x05, 0xffff, 0x2089 },
+               { 0x06, 0xffff, 0x5881 },
+               { 0x04, 0xffff, 0x154a },
+               { 0x01, 0xffff, 0x068b }
+       };
+
+       /* disable aspm and clock request before access ephy */
+       RTL_W8(Config2, RTL_R8(Config2) & ~ClkReqEn);
+       RTL_W8(Config5, RTL_R8(Config5) & ~ASPM_en);
+       rtl_ephy_init(tp, e_info_8168h_1, ARRAY_SIZE(e_info_8168h_1));
+
+       RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
+
+       rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x00080002, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+
+       rtl_csi_access_enable_1(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_w1w0_eri(tp, 0xdc, ERIAR_MASK_1111, 0x0010, 0x00, ERIAR_EXGMAC);
+
+       rtl_w1w0_eri(tp, 0xd4, ERIAR_MASK_1111, 0x1f00, 0x00, ERIAR_EXGMAC);
+
+       rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87, ERIAR_EXGMAC);
+
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+       RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
+       RTL_W8(MaxTxPacketSize, EarlySize);
+
+       rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+
+       /* Adjust EEE LED frequency */
+       RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+
+       RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
+       RTL_W8(DLLPR, RTL_R8(MISC_1) & ~PFM_D3COLD_EN);
+
+       RTL_W8(DLLPR, RTL_R8(DLLPR) & ~TX_10M_PS_EN);
+
+       rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC);
+
+       rtl_pcie_state_l2l3_enable(tp, false);
+
+       rtl_writephy(tp, 0x1f, 0x0c42);
+       rg_saw_cnt = rtl_readphy(tp, 0x13);
+       rtl_writephy(tp, 0x1f, 0x0000);
+       if (rg_saw_cnt > 0) {
+               u16 sw_cnt_1ms_ini;
+
+               sw_cnt_1ms_ini = 16000000/rg_saw_cnt;
+               sw_cnt_1ms_ini &= 0x0fff;
+               data = r8168_mac_ocp_read(tp, 0xd412);
+               data &= 0x0fff;
+               data |= sw_cnt_1ms_ini;
+               r8168_mac_ocp_write(tp, 0xd412, data);
+       }
+
+       data = r8168_mac_ocp_read(tp, 0xe056);
+       data &= 0xf0;
+       data |= 0x07;
+       r8168_mac_ocp_write(tp, 0xe056, data);
+
+       data = r8168_mac_ocp_read(tp, 0xe052);
+       data &= 0x8008;
+       data |= 0x6000;
+       r8168_mac_ocp_write(tp, 0xe052, data);
+
+       data = r8168_mac_ocp_read(tp, 0xe0d6);
+       data &= 0x01ff;
+       data |= 0x017f;
+       r8168_mac_ocp_write(tp, 0xe0d6, data);
+
+       data = r8168_mac_ocp_read(tp, 0xd420);
+       data &= 0x0fff;
+       data |= 0x047f;
+       r8168_mac_ocp_write(tp, 0xd420, data);
+
+       r8168_mac_ocp_write(tp, 0xe63e, 0x0001);
+       r8168_mac_ocp_write(tp, 0xe63e, 0x0000);
+       r8168_mac_ocp_write(tp, 0xc094, 0x0000);
+       r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
+}
+
 static void rtl_hw_start_8168(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -5440,6 +5840,11 @@ static void rtl_hw_start_8168(struct net_device *dev)
                rtl_hw_start_8411_2(tp);
                break;
 
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               rtl_hw_start_8168h_1(tp);
+               break;
+
        default:
                printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
                        dev->name, tp->mac_version);
@@ -5655,6 +6060,10 @@ static void rtl_hw_start_8101(struct net_device *dev)
        case RTL_GIGA_MAC_VER_43:
                rtl_hw_start_8168g_2(tp);
                break;
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
+               rtl_hw_start_8168h_1(tp);
+               break;
        }
 
        RTL_W8(Cfg9346, Cfg9346_Lock);
@@ -5895,7 +6304,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
 {
        struct skb_shared_info *info = skb_shinfo(skb);
        unsigned int cur_frag, entry;
-       struct TxDesc * uninitialized_var(txd);
+       struct TxDesc *uninitialized_var(txd);
        struct device *d = &tp->pci_dev->dev;
 
        entry = tp->cur_tx;
@@ -7110,6 +7519,10 @@ static void rtl_hw_initialize(struct rtl8169_private *tp)
        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:
                rtl_hw_init_8168g(tp);
                break;
 
@@ -7255,8 +7668,19 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        RTL_W8(Cfg9346, Cfg9346_Unlock);
        RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
        RTL_W8(Config5, RTL_R8(Config5) & (BWF | MWF | UWF | LanWake | PMEStatus));
-       if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
-               tp->features |= RTL_FEATURE_WOL;
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               if (rtl_eri_read(tp, 0xdc, ERIAR_EXGMAC) & MagicPacket_v2)
+                       tp->features |= RTL_FEATURE_WOL;
+               if ((RTL_R8(Config3) & LinkUp) != 0)
+                       tp->features |= RTL_FEATURE_WOL;
+               break;
+       default:
+               if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
+                       tp->features |= RTL_FEATURE_WOL;
+               break;
+       }
        if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
                tp->features |= RTL_FEATURE_WOL;
        tp->features |= rtl_try_msi(tp, cfg);
@@ -7283,6 +7707,18 @@ 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 ||
+           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);
+
+               if (is_valid_ether_addr((u8 *)mac_addr))
+                       rtl_rar_set(tp, (u8 *)mac_addr);
+       }
        for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = RTL_R8(MAC0 + i);
 
index ec632e666c56ad5138384cae4f23e43b45ad4d34..ddc6115720a332794a6488f41a86ff4ae6b6fa32 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_net.h>
 #include <linux/phy.h>
 #include <linux/regmap.h>
 #define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2
 #define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003
 
+#define EMAC_SPLITTER_CTRL_REG                 0x0
+#define EMAC_SPLITTER_CTRL_SPEED_MASK          0x3
+#define EMAC_SPLITTER_CTRL_SPEED_10            0x2
+#define EMAC_SPLITTER_CTRL_SPEED_100           0x3
+#define EMAC_SPLITTER_CTRL_SPEED_1000          0x0
+
 struct socfpga_dwmac {
        int     interface;
        u32     reg_offset;
@@ -37,14 +44,46 @@ struct socfpga_dwmac {
        struct  device *dev;
        struct regmap *sys_mgr_base_addr;
        struct reset_control *stmmac_rst;
+       void __iomem *splitter_base;
 };
 
+static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed)
+{
+       struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv;
+       void __iomem *splitter_base = dwmac->splitter_base;
+       u32 val;
+
+       if (!splitter_base)
+               return;
+
+       val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG);
+       val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK;
+
+       switch (speed) {
+       case 1000:
+               val |= EMAC_SPLITTER_CTRL_SPEED_1000;
+               break;
+       case 100:
+               val |= EMAC_SPLITTER_CTRL_SPEED_100;
+               break;
+       case 10:
+               val |= EMAC_SPLITTER_CTRL_SPEED_10;
+               break;
+       default:
+               return;
+       }
+
+       writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG);
+}
+
 static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
 {
        struct device_node *np = dev->of_node;
        struct regmap *sys_mgr_base_addr;
        u32 reg_offset, reg_shift;
        int ret;
+       struct device_node *np_splitter;
+       struct resource res_splitter;
 
        dwmac->stmmac_rst = devm_reset_control_get(dev,
                                                  STMMAC_RESOURCE_NAME);
@@ -73,6 +112,20 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
                return -EINVAL;
        }
 
+       np_splitter = of_parse_phandle(np, "altr,emac-splitter", 0);
+       if (np_splitter) {
+               if (of_address_to_resource(np_splitter, 0, &res_splitter)) {
+                       dev_info(dev, "Missing emac splitter address\n");
+                       return -EINVAL;
+               }
+
+               dwmac->splitter_base = devm_ioremap_resource(dev, &res_splitter);
+               if (!dwmac->splitter_base) {
+                       dev_info(dev, "Failed to mapping emac splitter\n");
+                       return -EINVAL;
+               }
+       }
+
        dwmac->reg_offset = reg_offset;
        dwmac->reg_shift = reg_shift;
        dwmac->sys_mgr_base_addr = sys_mgr_base_addr;
@@ -91,6 +144,7 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac)
 
        switch (phymode) {
        case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
                val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
                break;
        case PHY_INTERFACE_MODE_MII:
@@ -102,6 +156,13 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac)
                return -EINVAL;
        }
 
+       /* Overwrite val to GMII if splitter core is enabled. The phymode here
+        * is the actual phy mode on phy hardware, but phy interface from
+        * EMAC core is GMII.
+        */
+       if (dwmac->splitter_base)
+               val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
+
        regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
        ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift);
        ctrl |= val << reg_shift;
@@ -196,4 +257,5 @@ const struct stmmac_of_data socfpga_gmac_data = {
        .setup = socfpga_dwmac_probe,
        .init = socfpga_dwmac_init,
        .exit = socfpga_dwmac_exit,
+       .fix_mac_speed = socfpga_dwmac_fix_mac_speed,
 };
index cf4f38db1c0a60338c1d7479b0cfe28f50b6b558..3a08a1f78c732b49992cc711907131d74b5e18e8 100644 (file)
@@ -261,11 +261,11 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
                ethtool_cmd_speed_set(cmd, priv->xstats.pcs_speed);
 
                /* Get and convert ADV/LP_ADV from the HW AN registers */
-               if (priv->hw->mac->get_adv)
-                       priv->hw->mac->get_adv(priv->hw, &adv);
-               else
+               if (!priv->hw->mac->get_adv)
                        return -EOPNOTSUPP;     /* should never happen indeed */
 
+               priv->hw->mac->get_adv(priv->hw, &adv);
+
                /* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
 
                if (adv.pause & STMMAC_PCS_PAUSE)
@@ -340,19 +340,17 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
                if (cmd->autoneg != AUTONEG_ENABLE)
                        return -EINVAL;
 
-               if (cmd->autoneg == AUTONEG_ENABLE) {
-                       mask &= (ADVERTISED_1000baseT_Half |
+               mask &= (ADVERTISED_1000baseT_Half |
                        ADVERTISED_1000baseT_Full |
                        ADVERTISED_100baseT_Half |
                        ADVERTISED_100baseT_Full |
                        ADVERTISED_10baseT_Half |
                        ADVERTISED_10baseT_Full);
 
-                       spin_lock(&priv->lock);
-                       if (priv->hw->mac->ctrl_ane)
-                               priv->hw->mac->ctrl_ane(priv->hw, 1);
-                       spin_unlock(&priv->lock);
-               }
+               spin_lock(&priv->lock);
+               if (priv->hw->mac->ctrl_ane)
+                       priv->hw->mac->ctrl_ane(priv->hw, 1);
+               spin_unlock(&priv->lock);
 
                return 0;
        }
index 6e6ee226de04f60dc8511334db8ca48310fd5cff..9dbb02d9d9c255c9c2515cac80340affe266617a 100644 (file)
@@ -834,7 +834,7 @@ static int stmmac_init_phy(struct net_device *dev)
        /* Stop Advertising 1000BASE Capability if interface is not GMII */
        if ((interface == PHY_INTERFACE_MODE_MII) ||
            (interface == PHY_INTERFACE_MODE_RMII) ||
-               (max_speed < 1000 &&  max_speed > 0))
+               (max_speed < 1000 && max_speed > 0))
                phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
                                         SUPPORTED_1000baseT_Full);
 
index a5b1e1b776fe3313c5c9852062ed66ea1547c285..8dd040827c69381c5fd5441350fcc7511e84c704 100644 (file)
@@ -253,7 +253,7 @@ int stmmac_mdio_register(struct net_device *ndev)
                        }
 
                        /*
-                        * If we're  going to bind the MAC to this PHY bus,
+                        * If we're going to bind the MAC to this PHY bus,
                         * and no PHY number was provided to the MAC,
                         * use the one probed here.
                         */
index f7415b6bf141caf5359986ae5de290937e01c7e9..fef5dec2cffe9c3bb7f09bbe728ab2dc54b0cba9 100644 (file)
@@ -115,7 +115,7 @@ static const struct pci_device_id gem_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, gem_pci_tbl);
 
-static u16 __phy_read(struct gem *gp, int phy_addr, int reg)
+static u16 __sungem_phy_read(struct gem *gp, int phy_addr, int reg)
 {
        u32 cmd;
        int limit = 10000;
@@ -141,18 +141,18 @@ static u16 __phy_read(struct gem *gp, int phy_addr, int reg)
        return cmd & MIF_FRAME_DATA;
 }
 
-static inline int _phy_read(struct net_device *dev, int mii_id, int reg)
+static inline int _sungem_phy_read(struct net_device *dev, int mii_id, int reg)
 {
        struct gem *gp = netdev_priv(dev);
-       return __phy_read(gp, mii_id, reg);
+       return __sungem_phy_read(gp, mii_id, reg);
 }
 
-static inline u16 phy_read(struct gem *gp, int reg)
+static inline u16 sungem_phy_read(struct gem *gp, int reg)
 {
-       return __phy_read(gp, gp->mii_phy_addr, reg);
+       return __sungem_phy_read(gp, gp->mii_phy_addr, reg);
 }
 
-static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val)
+static void __sungem_phy_write(struct gem *gp, int phy_addr, int reg, u16 val)
 {
        u32 cmd;
        int limit = 10000;
@@ -174,15 +174,15 @@ static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val)
        }
 }
 
-static inline void _phy_write(struct net_device *dev, int mii_id, int reg, int val)
+static inline void _sungem_phy_write(struct net_device *dev, int mii_id, int reg, int val)
 {
        struct gem *gp = netdev_priv(dev);
-       __phy_write(gp, mii_id, reg, val & 0xffff);
+       __sungem_phy_write(gp, mii_id, reg, val & 0xffff);
 }
 
-static inline void phy_write(struct gem *gp, int reg, u16 val)
+static inline void sungem_phy_write(struct gem *gp, int reg, u16 val)
 {
-       __phy_write(gp, gp->mii_phy_addr, reg, val);
+       __sungem_phy_write(gp, gp->mii_phy_addr, reg, val);
 }
 
 static inline void gem_enable_ints(struct gem *gp)
@@ -1687,9 +1687,9 @@ static void gem_init_phy(struct gem *gp)
                        /* Some PHYs used by apple have problem getting back to us,
                         * we do an additional reset here
                         */
-                       phy_write(gp, MII_BMCR, BMCR_RESET);
+                       sungem_phy_write(gp, MII_BMCR, BMCR_RESET);
                        msleep(20);
-                       if (phy_read(gp, MII_BMCR) != 0xffff)
+                       if (sungem_phy_read(gp, MII_BMCR) != 0xffff)
                                break;
                        if (i == 2)
                                netdev_warn(gp->dev, "GMAC PHY not responding !\n");
@@ -2012,7 +2012,7 @@ static int gem_check_invariants(struct gem *gp)
 
                for (i = 0; i < 32; i++) {
                        gp->mii_phy_addr = i;
-                       if (phy_read(gp, MII_BMCR) != 0xffff)
+                       if (sungem_phy_read(gp, MII_BMCR) != 0xffff)
                                break;
                }
                if (i == 32) {
@@ -2696,13 +2696,13 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                /* Fallthrough... */
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
-               data->val_out = __phy_read(gp, data->phy_id & 0x1f,
+               data->val_out = __sungem_phy_read(gp, data->phy_id & 0x1f,
                                           data->reg_num & 0x1f);
                rc = 0;
                break;
 
        case SIOCSMIIREG:               /* Write MII PHY register. */
-               __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f,
+               __sungem_phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f,
                            data->val_in);
                rc = 0;
                break;
@@ -2933,8 +2933,8 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* Fill up the mii_phy structure (even if we won't use it) */
        gp->phy_mii.dev = dev;
-       gp->phy_mii.mdio_read = _phy_read;
-       gp->phy_mii.mdio_write = _phy_write;
+       gp->phy_mii.mdio_read = _sungem_phy_read;
+       gp->phy_mii.mdio_write = _sungem_phy_write;
 #ifdef CONFIG_PPC_PMAC
        gp->phy_mii.platform_data = gp->of_node;
 #endif
index 999fb72688d226317d0565c936a286386ae6dd98..03b409988566d33e04c2cf8d5566be1b4ac297d5 100644 (file)
@@ -2232,18 +2232,24 @@ static int cpsw_probe(struct platform_device *pdev)
        }
 
        while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
-               for (i = res->start; i <= res->end; i++) {
-                       if (devm_request_irq(&pdev->dev, i, cpsw_interrupt, 0,
-                                            dev_name(&pdev->dev), priv)) {
-                               dev_err(priv->dev, "error attaching irq\n");
-                               goto clean_ale_ret;
-                       }
-                       priv->irqs_table[k] = i;
-                       priv->num_irqs = k + 1;
+               if (k >= ARRAY_SIZE(priv->irqs_table)) {
+                       ret = -EINVAL;
+                       goto clean_ale_ret;
                }
+
+               ret = devm_request_irq(&pdev->dev, res->start, cpsw_interrupt,
+                                      0, dev_name(&pdev->dev), priv);
+               if (ret < 0) {
+                       dev_err(priv->dev, "error attaching irq (%d)\n", ret);
+                       goto clean_ale_ret;
+               }
+
+               priv->irqs_table[k] = res->start;
                k++;
        }
 
+       priv->num_irqs = k;
+
        ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 
        ndev->netdev_ops = &cpsw_netdev_ops;
index d5e07def6a598ca3ccb7abda3c80e1732dc64413..2f48f790c9b43e983f44107a97f42f2268262099 100644 (file)
@@ -591,7 +591,7 @@ struct nvsp_message {
 
 #define NETVSC_RECEIVE_BUFFER_ID               0xcafe
 
-#define NETVSC_PACKET_SIZE                      2048
+#define NETVSC_PACKET_SIZE                      4096
 
 #define VRSS_SEND_TAB_SIZE 16
 
@@ -642,7 +642,7 @@ struct netvsc_device {
        int ring_size;
 
        /* The primary channel callback buffer */
-       unsigned char cb_buffer[NETVSC_PACKET_SIZE];
+       unsigned char *cb_buffer;
        /* The sub channel callback buffer */
        unsigned char *sub_cb_buf;
 };
index 66979cf7fca6a3d68d88a7c908c45aad2a7b58aa..977984bc238a1e0cc374c6ef5fd08f07546369d9 100644 (file)
@@ -42,6 +42,12 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
        if (!net_device)
                return NULL;
 
+       net_device->cb_buffer = kzalloc(NETVSC_PACKET_SIZE, GFP_KERNEL);
+       if (!net_device->cb_buffer) {
+               kfree(net_device);
+               return NULL;
+       }
+
        init_waitqueue_head(&net_device->wait_drain);
        net_device->start_remove = false;
        net_device->destroy = false;
@@ -52,6 +58,12 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
        return net_device;
 }
 
+static void free_netvsc_device(struct netvsc_device *nvdev)
+{
+       kfree(nvdev->cb_buffer);
+       kfree(nvdev);
+}
+
 static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 {
        struct netvsc_device *net_device;
@@ -551,7 +563,7 @@ int netvsc_device_remove(struct hv_device *device)
        if (net_device->sub_cb_buf)
                vfree(net_device->sub_cb_buf);
 
-       kfree(net_device);
+       free_netvsc_device(net_device);
        return 0;
 }
 
@@ -1042,10 +1054,8 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
        struct net_device *ndev;
 
        net_device = alloc_net_device(device);
-       if (!net_device) {
-               ret = -ENOMEM;
-               goto cleanup;
-       }
+       if (!net_device)
+               return -ENOMEM;
 
        net_device->ring_size = ring_size;
 
@@ -1093,7 +1103,7 @@ close:
        vmbus_close(device->channel);
 
 cleanup:
-       kfree(net_device);
+       free_netvsc_device(net_device);
 
        return ret;
 }
index 65de0cab8d07795c5c2255d7397a95e3720477fc..14afa4f2442427131396e4690cb46d3eceec6c2d 100644 (file)
@@ -159,8 +159,6 @@ config MDIO_OCTEON
 config MDIO_SUN4I
        tristate "Allwinner sun4i MDIO interface support"
        depends on ARCH_SUNXI
-       select REGULATOR
-       select REGULATOR_FIXED_VOLTAGE
        help
          This driver supports the MDIO interface found in the network
          interface units of the Allwinner SoC that have an EMAC (A10,
@@ -205,6 +203,14 @@ config MDIO_BUS_MUX_MMIOREG
 
          Currently, only 8-bit registers are supported.
 
+config MDIO_BCM_UNIMAC
+       tristate "Broadcom UniMAC MDIO bus controller"
+       help
+         This module provides a driver for the Broadcom UniMAC MDIO busses.
+         This hardware can be found in the Broadcom GENET Ethernet MAC
+         controllers as well as some Broadcom Ethernet switches such as the
+         Starfighter 2 switches.
+
 endif # PHYLIB
 
 config MICREL_KS8995MA
index 7dc3d5b304cfc250a2618e096abecf428ed05bad..eb3b18b5978b33ec7441a2ca2e0f4aa33906cdd5 100644 (file)
@@ -34,3 +34,4 @@ obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
 obj-$(CONFIG_MDIO_SUN4I)       += mdio-sun4i.o
 obj-$(CONFIG_MDIO_MOXART)      += mdio-moxart.o
 obj-$(CONFIG_AMD_XGBE_PHY)     += amd-xgbe-phy.o
+obj-$(CONFIG_MDIO_BCM_UNIMAC)  += mdio-bcm-unimac.o
index f3230eef41fda7a09442571bb26553ca86b14768..c456559f6e7f2ea3ae713e98c93e58148aaa7776 100644 (file)
@@ -75,7 +75,6 @@
 #include <linux/of_device.h>
 #include <linux/uaccess.h>
 
-
 MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION("1.0.0-a");
@@ -100,9 +99,11 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #ifndef MDIO_PMA_10GBR_PMD_CTRL
 #define MDIO_PMA_10GBR_PMD_CTRL                0x0096
 #endif
+
 #ifndef MDIO_PMA_10GBR_FEC_CTRL
 #define MDIO_PMA_10GBR_FEC_CTRL                0x00ab
 #endif
+
 #ifndef MDIO_AN_XNP
 #define MDIO_AN_XNP                    0x0016
 #endif
@@ -110,14 +111,23 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #ifndef MDIO_AN_INTMASK
 #define MDIO_AN_INTMASK                        0x8001
 #endif
+
 #ifndef MDIO_AN_INT
 #define MDIO_AN_INT                    0x8002
 #endif
 
+#ifndef MDIO_AN_KR_CTRL
+#define MDIO_AN_KR_CTRL                        0x8003
+#endif
+
 #ifndef MDIO_CTRL1_SPEED1G
 #define MDIO_CTRL1_SPEED1G             (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
 #endif
 
+#ifndef MDIO_KR_CTRL_PDETECT
+#define MDIO_KR_CTRL_PDETECT           0x01
+#endif
+
 /* SerDes integration register offsets */
 #define SIR0_KR_RT_1                   0x002c
 #define SIR0_STATUS                    0x0040
@@ -161,7 +171,6 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_1000_TXAMP               0xf
 #define SPEED_1000_WORD                        0x1
 
-
 /* SerDes RxTx register offsets */
 #define RXTX_REG20                     0x0050
 #define RXTX_REG114                    0x01c8
@@ -255,7 +264,6 @@ do {                                                                        \
        XSIR1_IOWRITE((_priv), _reg, reg_val);                          \
 } while (0)
 
-
 /* Macros for reading or writing SerDes RxTx registers
  *  The ioread macros will get bit fields or full values using the
  *  register definitions formed using the input names
@@ -283,7 +291,6 @@ do {                                                                        \
        XRXTX_IOWRITE((_priv), _reg, reg_val);                          \
 } while (0)
 
-
 enum amd_xgbe_phy_an {
        AMD_XGBE_AN_READY = 0,
        AMD_XGBE_AN_START,
@@ -331,7 +338,6 @@ struct amd_xgbe_phy_priv {
 
        /* Maintain link status for re-starting auto-negotiation */
        unsigned int link;
-       enum amd_xgbe_phy_mode mode;
        unsigned int speed_set;
 
        /* Auto-negotiation state machine support */
@@ -342,6 +348,7 @@ struct amd_xgbe_phy_priv {
        enum amd_xgbe_phy_rx kx_state;
        struct work_struct an_work;
        struct workqueue_struct *an_workqueue;
+       unsigned int parallel_detect;
 };
 
 static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev)
@@ -468,8 +475,6 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
-       priv->mode = AMD_XGBE_MODE_KR;
-
        return 0;
 }
 
@@ -518,8 +523,6 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
-       priv->mode = AMD_XGBE_MODE_KX;
-
        return 0;
 }
 
@@ -568,18 +571,43 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev)
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
-       priv->mode = AMD_XGBE_MODE_KX;
+       return 0;
+}
+
+static int amd_xgbe_phy_cur_mode(struct phy_device *phydev,
+                                enum amd_xgbe_phy_mode *mode)
+{
+       int ret;
+
+       ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
+       if (ret < 0)
+               return ret;
+
+       if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
+               *mode = AMD_XGBE_MODE_KR;
+       else
+               *mode = AMD_XGBE_MODE_KX;
 
        return 0;
 }
 
+static bool amd_xgbe_phy_in_kr_mode(struct phy_device *phydev)
+{
+       enum amd_xgbe_phy_mode mode;
+
+       if (amd_xgbe_phy_cur_mode(phydev, &mode))
+               return false;
+
+       return (mode == AMD_XGBE_MODE_KR);
+}
+
 static int amd_xgbe_phy_switch_mode(struct phy_device *phydev)
 {
        struct amd_xgbe_phy_priv *priv = phydev->priv;
        int ret;
 
        /* If we are in KR switch to KX, and vice-versa */
-       if (priv->mode == AMD_XGBE_MODE_KR) {
+       if (amd_xgbe_phy_in_kr_mode(phydev)) {
                if (priv->speed_set == AMD_XGBE_PHY_SPEEDSET_1000_10000)
                        ret = amd_xgbe_phy_gmii_mode(phydev);
                else
@@ -591,15 +619,20 @@ static int amd_xgbe_phy_switch_mode(struct phy_device *phydev)
        return ret;
 }
 
-static enum amd_xgbe_phy_an amd_xgbe_an_switch_mode(struct phy_device *phydev)
+static int amd_xgbe_phy_set_mode(struct phy_device *phydev,
+                                enum amd_xgbe_phy_mode mode)
 {
+       enum amd_xgbe_phy_mode cur_mode;
        int ret;
 
-       ret = amd_xgbe_phy_switch_mode(phydev);
-       if (ret < 0)
-               return AMD_XGBE_AN_ERROR;
+       ret = amd_xgbe_phy_cur_mode(phydev, &cur_mode);
+       if (ret)
+               return ret;
 
-       return AMD_XGBE_AN_START;
+       if (mode != cur_mode)
+               ret = amd_xgbe_phy_switch_mode(phydev);
+
+       return ret;
 }
 
 static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
@@ -610,8 +643,8 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
 
        *state = AMD_XGBE_RX_COMPLETE;
 
-       /* If we're in KX mode then we're done */
-       if (priv->mode == AMD_XGBE_MODE_KX)
+       /* If we're not in KR mode then we're done */
+       if (!amd_xgbe_phy_in_kr_mode(phydev))
                return AMD_XGBE_AN_EVENT;
 
        /* Enable/Disable FEC */
@@ -669,7 +702,6 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev,
 static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev,
                                               enum amd_xgbe_phy_rx *state)
 {
-       struct amd_xgbe_phy_priv *priv = phydev->priv;
        unsigned int link_support;
        int ret, ad_reg, lp_reg;
 
@@ -679,9 +711,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev,
                return AMD_XGBE_AN_ERROR;
 
        /* Check for a supported mode, otherwise restart in a different one */
-       link_support = (priv->mode == AMD_XGBE_MODE_KR) ? 0x80 : 0x20;
+       link_support = amd_xgbe_phy_in_kr_mode(phydev) ? 0x80 : 0x20;
        if (!(ret & link_support))
-               return amd_xgbe_an_switch_mode(phydev);
+               return AMD_XGBE_AN_INCOMPAT_LINK;
 
        /* Check Extended Next Page support */
        ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
@@ -722,7 +754,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev)
        int ret;
 
        /* Be sure we aren't looping trying to negotiate */
-       if (priv->mode == AMD_XGBE_MODE_KR) {
+       if (amd_xgbe_phy_in_kr_mode(phydev)) {
                if (priv->kr_state != AMD_XGBE_RX_READY)
                        return AMD_XGBE_AN_NO_LINK;
                priv->kr_state = AMD_XGBE_RX_BPA;
@@ -785,6 +817,13 @@ static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev)
        /* Enable and start auto-negotiation */
        phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
 
+       ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL);
+       if (ret < 0)
+               return AMD_XGBE_AN_ERROR;
+
+       ret |= MDIO_KR_CTRL_PDETECT;
+       phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL, ret);
+
        ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
        if (ret < 0)
                return AMD_XGBE_AN_ERROR;
@@ -825,8 +864,8 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
        enum amd_xgbe_phy_rx *state;
        int ret;
 
-       state = (priv->mode == AMD_XGBE_MODE_KR) ? &priv->kr_state
-                                                : &priv->kx_state;
+       state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state
+                                               : &priv->kx_state;
 
        switch (*state) {
        case AMD_XGBE_RX_BPA:
@@ -846,7 +885,13 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
 
 static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev)
 {
-       return amd_xgbe_an_switch_mode(phydev);
+       int ret;
+
+       ret = amd_xgbe_phy_switch_mode(phydev);
+       if (ret)
+               return AMD_XGBE_AN_ERROR;
+
+       return AMD_XGBE_AN_START;
 }
 
 static void amd_xgbe_an_state_machine(struct work_struct *work)
@@ -859,6 +904,10 @@ static void amd_xgbe_an_state_machine(struct work_struct *work)
        int sleep;
        unsigned int an_supported = 0;
 
+       /* Start in KX mode */
+       if (amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX))
+               priv->an_state = AMD_XGBE_AN_ERROR;
+
        while (1) {
                mutex_lock(&priv->an_mutex);
 
@@ -866,8 +915,9 @@ static void amd_xgbe_an_state_machine(struct work_struct *work)
 
                switch (priv->an_state) {
                case AMD_XGBE_AN_START:
-                       priv->an_state = amd_xgbe_an_start(phydev);
                        an_supported = 0;
+                       priv->parallel_detect = 0;
+                       priv->an_state = amd_xgbe_an_start(phydev);
                        break;
 
                case AMD_XGBE_AN_EVENT:
@@ -884,6 +934,7 @@ static void amd_xgbe_an_state_machine(struct work_struct *work)
                        break;
 
                case AMD_XGBE_AN_COMPLETE:
+                       priv->parallel_detect = an_supported ? 0 : 1;
                        netdev_info(phydev->attached_dev, "%s successful\n",
                                    an_supported ? "Auto negotiation"
                                                 : "Parallel detection");
@@ -1018,7 +1069,6 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
 {
        struct amd_xgbe_phy_priv *priv = phydev->priv;
        u32 mmd_mask = phydev->c45_ids.devices_in_package;
-       int ret;
 
        if (phydev->autoneg != AUTONEG_ENABLE)
                return amd_xgbe_phy_setup_forced(phydev);
@@ -1027,11 +1077,6 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
        if (!(mmd_mask & MDIO_DEVS_AN))
                return -EINVAL;
 
-       /* Get the current speed mode */
-       ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
-       if (ret < 0)
-               return ret;
-
        /* Start/Restart the auto-negotiation state machine */
        mutex_lock(&priv->an_mutex);
        priv->an_result = AMD_XGBE_AN_READY;
@@ -1121,18 +1166,14 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev)
 {
        struct amd_xgbe_phy_priv *priv = phydev->priv;
        u32 mmd_mask = phydev->c45_ids.devices_in_package;
-       int ret, mode, ad_ret, lp_ret;
+       int ret, ad_ret, lp_ret;
 
        ret = amd_xgbe_phy_update_link(phydev);
        if (ret)
                return ret;
 
-       mode = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
-       if (mode < 0)
-               return mode;
-       mode &= MDIO_PCS_CTRL2_TYPE;
-
-       if (phydev->autoneg == AUTONEG_ENABLE) {
+       if ((phydev->autoneg == AUTONEG_ENABLE) &&
+           !priv->parallel_detect) {
                if (!(mmd_mask & MDIO_DEVS_AN))
                        return -EINVAL;
 
@@ -1163,40 +1204,39 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev)
                ad_ret &= lp_ret;
                if (ad_ret & 0x80) {
                        phydev->speed = SPEED_10000;
-                       if (mode != MDIO_PCS_CTRL2_10GBR) {
-                               ret = amd_xgbe_phy_xgmii_mode(phydev);
-                               if (ret < 0)
-                                       return ret;
-                       }
+                       ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR);
+                       if (ret)
+                               return ret;
                } else {
-                       int (*mode_fcn)(struct phy_device *);
-
-                       if (priv->speed_set ==
-                           AMD_XGBE_PHY_SPEEDSET_1000_10000) {
+                       switch (priv->speed_set) {
+                       case AMD_XGBE_PHY_SPEEDSET_1000_10000:
                                phydev->speed = SPEED_1000;
-                               mode_fcn = amd_xgbe_phy_gmii_mode;
-                       } else {
+                               break;
+
+                       case AMD_XGBE_PHY_SPEEDSET_2500_10000:
                                phydev->speed = SPEED_2500;
-                               mode_fcn = amd_xgbe_phy_gmii_2500_mode;
+                               break;
                        }
 
-                       if (mode == MDIO_PCS_CTRL2_10GBR) {
-                               ret = mode_fcn(phydev);
-                               if (ret < 0)
-                                       return ret;
-                       }
+                       ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX);
+                       if (ret)
+                               return ret;
                }
 
                phydev->duplex = DUPLEX_FULL;
        } else {
-               if (mode == MDIO_PCS_CTRL2_10GBR) {
+               if (amd_xgbe_phy_in_kr_mode(phydev)) {
                        phydev->speed = SPEED_10000;
                } else {
-                       if (priv->speed_set ==
-                           AMD_XGBE_PHY_SPEEDSET_1000_10000)
+                       switch (priv->speed_set) {
+                       case AMD_XGBE_PHY_SPEEDSET_1000_10000:
                                phydev->speed = SPEED_1000;
-                       else
+                               break;
+
+                       case AMD_XGBE_PHY_SPEEDSET_2500_10000:
                                phydev->speed = SPEED_2500;
+                               break;
+                       }
                }
                phydev->duplex = DUPLEX_FULL;
                phydev->pause = 0;
@@ -1329,14 +1369,6 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev)
 
        priv->link = 1;
 
-       ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
-       if (ret < 0)
-               goto err_sir1;
-       if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
-               priv->mode = AMD_XGBE_MODE_KR;
-       else
-               priv->mode = AMD_XGBE_MODE_KX;
-
        mutex_init(&priv->an_mutex);
        INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine);
        priv->an_workqueue = create_singlethread_workqueue(wq_name);
index fdce1ea28790c4e9ae0d56e9995d1a299782f4ec..09dd6e1dc6e12ccb59a6640bc97b2fb5116dd768 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/bitops.h>
 #include <linux/brcmphy.h>
+#include <linux/mdio.h>
 
 /* Broadcom BCM7xxx internal PHY registers */
 #define MII_BCM7XXX_CHANNEL_WIDTH      0x2000
@@ -146,6 +147,53 @@ static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev)
        return 0;
 }
 
+static int bcm7xxx_apd_enable(struct phy_device *phydev)
+{
+       int val;
+
+       /* Enable powering down of the DLL during auto-power down */
+       val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
+       if (val < 0)
+               return val;
+
+       val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
+       bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
+
+       /* Enable auto-power down */
+       val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
+       if (val < 0)
+               return val;
+
+       val |= BCM54XX_SHD_APD_EN;
+       return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
+}
+
+static int bcm7xxx_eee_enable(struct phy_device *phydev)
+{
+       int val;
+
+       val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
+                                   MDIO_MMD_AN, phydev->addr);
+       if (val < 0)
+               return val;
+
+       /* Enable general EEE feature at the PHY level */
+       val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
+
+       phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
+                              MDIO_MMD_AN, phydev->addr, val);
+
+       /* Advertise supported modes */
+       val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
+                                   MDIO_MMD_AN, phydev->addr);
+
+       val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
+       phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
+                              MDIO_MMD_AN, phydev->addr, val);
+
+       return 0;
+}
+
 static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
 {
        int ret;
@@ -154,7 +202,15 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
        if (ret)
                return ret;
 
-       return bcm7xxx_28nm_afe_config_init(phydev);
+       ret = bcm7xxx_28nm_afe_config_init(phydev);
+       if (ret)
+               return ret;
+
+       ret = bcm7xxx_eee_enable(phydev);
+       if (ret)
+               return ret;
+
+       return bcm7xxx_apd_enable(phydev);
 }
 
 static int bcm7xxx_28nm_resume(struct phy_device *phydev)
@@ -263,44 +319,28 @@ static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
        return 0;
 }
 
+#define BCM7XXX_28NM_GPHY(_oui, _name)                                 \
+{                                                                      \
+       .phy_id         = (_oui),                                       \
+       .phy_id_mask    = 0xfffffff0,                                   \
+       .name           = _name,                                        \
+       .features       = PHY_GBIT_FEATURES |                           \
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,       \
+       .flags          = PHY_IS_INTERNAL,                              \
+       .config_init    = bcm7xxx_28nm_afe_config_init,                 \
+       .config_aneg    = genphy_config_aneg,                           \
+       .read_status    = genphy_read_status,                           \
+       .resume         = bcm7xxx_28nm_resume,                          \
+       .driver         = { .owner = THIS_MODULE },                     \
+}
+
 static struct phy_driver bcm7xxx_driver[] = {
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
 {
-       .phy_id         = PHY_ID_BCM7366,
-       .phy_id_mask    = 0xfffffff0,
-       .name           = "Broadcom BCM7366",
-       .features       = PHY_GBIT_FEATURES |
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = PHY_IS_INTERNAL,
-       .config_init    = bcm7xxx_28nm_afe_config_init,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .resume         = bcm7xxx_28nm_resume,
-       .driver         = { .owner = THIS_MODULE },
-}, {
-       .phy_id         = PHY_ID_BCM7439,
-       .phy_id_mask    = 0xfffffff0,
-       .name           = "Broadcom BCM7439",
-       .features       = PHY_GBIT_FEATURES |
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = PHY_IS_INTERNAL,
-       .config_init    = bcm7xxx_28nm_afe_config_init,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .resume         = bcm7xxx_28nm_resume,
-       .driver         = { .owner = THIS_MODULE },
-}, {
-       .phy_id         = PHY_ID_BCM7445,
-       .phy_id_mask    = 0xfffffff0,
-       .name           = "Broadcom BCM7445",
-       .features       = PHY_GBIT_FEATURES |
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = PHY_IS_INTERNAL,
-       .config_init    = bcm7xxx_28nm_config_init,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .resume         = bcm7xxx_28nm_afe_config_init,
-       .driver         = { .owner = THIS_MODULE },
-}, {
        .phy_id         = PHY_BCM_OUI_4,
        .phy_id_mask    = 0xffff0000,
        .name           = "Broadcom BCM7XXX 40nm",
@@ -329,6 +369,8 @@ static struct phy_driver bcm7xxx_driver[] = {
 } };
 
 static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
+       { PHY_ID_BCM7250, 0xfffffff0, },
+       { PHY_ID_BCM7364, 0xfffffff0, },
        { PHY_ID_BCM7366, 0xfffffff0, },
        { PHY_ID_BCM7439, 0xfffffff0, },
        { PHY_ID_BCM7445, 0xfffffff0, },
index 34088d60da74613cd007916ddd4844ee5420f90a..854f2c9a7b2b5224f1dab808d16d8f514cdd486a 100644 (file)
 #define BRCM_PHY_REV(phydev) \
        ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
 
-/*
- * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
- * BCM5482, and possibly some others.
- */
-#define BCM_LED_SRC_LINKSPD1   0x0
-#define BCM_LED_SRC_LINKSPD2   0x1
-#define BCM_LED_SRC_XMITLED    0x2
-#define BCM_LED_SRC_ACTIVITYLED        0x3
-#define BCM_LED_SRC_FDXLED     0x4
-#define BCM_LED_SRC_SLAVE      0x5
-#define BCM_LED_SRC_INTR       0x6
-#define BCM_LED_SRC_QUALITY    0x7
-#define BCM_LED_SRC_RCVLED     0x8
-#define BCM_LED_SRC_MULTICOLOR1        0xa
-#define BCM_LED_SRC_OPENSHORT  0xb
-#define BCM_LED_SRC_OFF                0xe     /* Tied high */
-#define BCM_LED_SRC_ON         0xf     /* Tied low */
-
-
-/*
- * BCM5482: Shadow registers
- * Shadow values go into bits [14:10] of register 0x1c to select a shadow
- * register to access.
- */
-/* 00101: Spare Control Register 3 */
-#define BCM54XX_SHD_SCR3               0x05
-#define  BCM54XX_SHD_SCR3_DEF_CLK125   0x0001
-#define  BCM54XX_SHD_SCR3_DLLAPD_DIS   0x0002
-#define  BCM54XX_SHD_SCR3_TRDDAPD      0x0004
-
-/* 01010: Auto Power-Down */
-#define BCM54XX_SHD_APD                        0x0a
-#define  BCM54XX_SHD_APD_EN            0x0020
-
-#define BCM5482_SHD_LEDS1      0x0d    /* 01101: LED Selector 1 */
-                                       /* LED3 / ~LINKSPD[2] selector */
-#define BCM5482_SHD_LEDS1_LED3(src)    ((src & 0xf) << 4)
-                                       /* LED1 / ~LINKSPD[1] selector */
-#define BCM5482_SHD_LEDS1_LED1(src)    ((src & 0xf) << 0)
-#define BCM54XX_SHD_RGMII_MODE 0x0b    /* 01011: RGMII Mode Selector */
-#define BCM5482_SHD_SSD                0x14    /* 10100: Secondary SerDes control */
-#define BCM5482_SHD_SSD_LEDM   0x0008  /* SSD LED Mode enable */
-#define BCM5482_SHD_SSD_EN     0x0001  /* SSD enable */
-#define BCM5482_SHD_MODE       0x1f    /* 11111: Mode Control Register */
-#define BCM5482_SHD_MODE_1000BX        0x0001  /* Enable 1000BASE-X registers */
-
-
-/*
- * EXPANSION SHADOW ACCESS REGISTERS.  (PHY REG 0x15, 0x16, and 0x17)
- */
-#define MII_BCM54XX_EXP_AADJ1CH0               0x001f
-#define  MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200
-#define  MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF   0x0100
-#define MII_BCM54XX_EXP_AADJ1CH3               0x601f
-#define  MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ     0x0002
-#define MII_BCM54XX_EXP_EXP08                  0x0F08
-#define  MII_BCM54XX_EXP_EXP08_RJCT_2MHZ       0x0001
-#define  MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE  0x0200
-#define MII_BCM54XX_EXP_EXP75                  0x0f75
-#define  MII_BCM54XX_EXP_EXP75_VDACCTRL                0x003c
-#define  MII_BCM54XX_EXP_EXP75_CM_OSC          0x0001
-#define MII_BCM54XX_EXP_EXP96                  0x0f96
-#define  MII_BCM54XX_EXP_EXP96_MYST            0x0010
-#define MII_BCM54XX_EXP_EXP97                  0x0f97
-#define  MII_BCM54XX_EXP_EXP97_MYST            0x0c0c
-
-/*
- * BCM5482: Secondary SerDes registers
- */
-#define BCM5482_SSD_1000BX_CTL         0x00    /* 1000BASE-X Control */
-#define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800  /* Power-down SSD */
-#define BCM5482_SSD_SGMII_SLAVE                0x15    /* SGMII Slave Register */
-#define BCM5482_SSD_SGMII_SLAVE_EN     0x0002  /* Slave mode enable */
-#define BCM5482_SSD_SGMII_SLAVE_AD     0x0001  /* Slave auto-detection */
-
-
-/*****************************************************************************/
-/* Fast Ethernet Transceiver definitions. */
-/*****************************************************************************/
-
-#define MII_BRCM_FET_INTREG            0x1a    /* Interrupt register */
-#define MII_BRCM_FET_IR_MASK           0x0100  /* Mask all interrupts */
-#define MII_BRCM_FET_IR_LINK_EN                0x0200  /* Link status change enable */
-#define MII_BRCM_FET_IR_SPEED_EN       0x0400  /* Link speed change enable */
-#define MII_BRCM_FET_IR_DUPLEX_EN      0x0800  /* Duplex mode change enable */
-#define MII_BRCM_FET_IR_ENABLE         0x4000  /* Interrupt enable */
-
-#define MII_BRCM_FET_BRCMTEST          0x1f    /* Brcm test register */
-#define MII_BRCM_FET_BT_SRE            0x0080  /* Shadow register enable */
-
-
-/*** Shadow register definitions ***/
-
-#define MII_BRCM_FET_SHDW_MISCCTRL     0x10    /* Shadow misc ctrl */
-#define MII_BRCM_FET_SHDW_MC_FAME      0x4000  /* Force Auto MDIX enable */
-
-#define MII_BRCM_FET_SHDW_AUXMODE4     0x1a    /* Auxiliary mode 4 */
-#define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003
-#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001
-
-#define MII_BRCM_FET_SHDW_AUXSTAT2     0x1b    /* Auxiliary status 2 */
-#define MII_BRCM_FET_SHDW_AS2_APDE     0x0020  /* Auto power down enable */
-
-
 MODULE_DESCRIPTION("Broadcom PHY driver");
 MODULE_AUTHOR("Maciej W. Rozycki");
 MODULE_LICENSE("GPL");
 
-/*
- * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
- * 0x1c shadow registers.
- */
-static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
-{
-       phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
-       return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
-}
-
-static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
-{
-       return phy_write(phydev, MII_BCM54XX_SHD,
-                        MII_BCM54XX_SHD_WRITE |
-                        MII_BCM54XX_SHD_VAL(shadow) |
-                        MII_BCM54XX_SHD_DATA(val));
-}
-
 /* Indirect register access functions for the Expansion Registers */
 static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
 {
index c301e4cb37cacc3b77645afb265871242abac37a..87648b3065515294c05c77ffbfddbe822fd901c2 100644 (file)
@@ -721,7 +721,7 @@ static inline u16 exts_chan_to_edata(int ch)
 }
 
 static int decode_evnt(struct dp83640_private *dp83640,
-                      void *data, u16 ests)
+                      void *data, int len, u16 ests)
 {
        struct phy_txts *phy_txts;
        struct ptp_clock_event event;
@@ -729,6 +729,16 @@ static int decode_evnt(struct dp83640_private *dp83640,
        int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
        u16 ext_status = 0;
 
+       /* calculate length of the event timestamp status message */
+       if (ests & MULT_EVNT)
+               parsed = (words + 2) * sizeof(u16);
+       else
+               parsed = (words + 1) * sizeof(u16);
+
+       /* check if enough data is available */
+       if (len < parsed)
+               return len;
+
        if (ests & MULT_EVNT) {
                ext_status = *(u16 *) data;
                data += sizeof(ext_status);
@@ -747,10 +757,7 @@ static int decode_evnt(struct dp83640_private *dp83640,
                dp83640->edata.ns_lo = phy_txts->ns_lo;
        }
 
-       if (ext_status) {
-               parsed = words + 2;
-       } else {
-               parsed = words + 1;
+       if (!ext_status) {
                i = ((ests >> EVNT_NUM_SHIFT) & EVNT_NUM_MASK) - EXT_EVENT;
                ext_status = exts_chan_to_edata(i);
        }
@@ -768,7 +775,7 @@ static int decode_evnt(struct dp83640_private *dp83640,
                }
        }
 
-       return parsed * sizeof(u16);
+       return parsed;
 }
 
 static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
@@ -905,9 +912,9 @@ static void decode_status_frame(struct dp83640_private *dp83640,
                        decode_txts(dp83640, phy_txts);
                        size = sizeof(*phy_txts);
 
-               } else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) {
+               } else if (PSF_EVNT == type) {
 
-                       size = decode_evnt(dp83640, ptr, ests);
+                       size = decode_evnt(dp83640, ptr, len, ests);
 
                } else {
                        size = 0;
@@ -1141,7 +1148,7 @@ static void dp83640_remove(struct phy_device *phydev)
                kfree_skb(skb);
 
        while ((skb = skb_dequeue(&dp83640->tx_queue)) != NULL)
-               skb_complete_tx_timestamp(skb, NULL);
+               kfree_skb(skb);
 
        clock = dp83640_clock_get(dp83640->clock);
 
@@ -1398,7 +1405,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
 
        case HWTSTAMP_TX_ONESTEP_SYNC:
                if (is_sync(skb, type)) {
-                       skb_complete_tx_timestamp(skb, NULL);
+                       kfree_skb(skb);
                        return;
                }
                /* fall through */
@@ -1409,7 +1416,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
 
        case HWTSTAMP_TX_OFF:
        default:
-               skb_complete_tx_timestamp(skb, NULL);
+               kfree_skb(skb);
                break;
        }
 }
index d60d875cb4450ab6cf72114c35b4c816e2e031fd..5b19fbbda6d4fd4e2826d873470b60197017999f 100644 (file)
@@ -124,6 +124,17 @@ static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
        if (reg_num >= MII_REGS_NUM)
                return -1;
 
+       /* We do not support emulating Clause 45 over Clause 22 register reads
+        * return an error instead of bogus data.
+        */
+       switch (reg_num) {
+       case MII_MMD_CTRL:
+       case MII_MMD_DATA:
+               return -1;
+       default:
+               break;
+       }
+
        list_for_each_entry(fp, &fmb->phys, node) {
                if (fp->addr == phy_addr) {
                        /* Issue callback if user registered it. */
diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c
new file mode 100644 (file)
index 0000000..5b643e5
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Broadcom UniMAC MDIO bus controller driver
+ *
+ * Copyright (C) 2014, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+
+#define MDIO_CMD               0x00
+#define  MDIO_START_BUSY       (1 << 29)
+#define  MDIO_READ_FAIL                (1 << 28)
+#define  MDIO_RD               (2 << 26)
+#define  MDIO_WR               (1 << 26)
+#define  MDIO_PMD_SHIFT                21
+#define  MDIO_PMD_MASK         0x1F
+#define  MDIO_REG_SHIFT                16
+#define  MDIO_REG_MASK         0x1F
+
+#define MDIO_CFG               0x04
+#define  MDIO_C22              (1 << 0)
+#define  MDIO_C45              0
+#define  MDIO_CLK_DIV_SHIFT    4
+#define  MDIO_CLK_DIV_MASK     0x3F
+#define  MDIO_SUPP_PREAMBLE    (1 << 12)
+
+struct unimac_mdio_priv {
+       struct mii_bus          *mii_bus;
+       void __iomem            *base;
+};
+
+static inline void unimac_mdio_start(struct unimac_mdio_priv *priv)
+{
+       u32 reg;
+
+       reg = __raw_readl(priv->base + MDIO_CMD);
+       reg |= MDIO_START_BUSY;
+       __raw_writel(reg, priv->base + MDIO_CMD);
+}
+
+static inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv *priv)
+{
+       return __raw_readl(priv->base + MDIO_CMD) & MDIO_START_BUSY;
+}
+
+static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+       struct unimac_mdio_priv *priv = bus->priv;
+       unsigned int timeout = 1000;
+       u32 cmd;
+
+       /* Prepare the read operation */
+       cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT);
+       __raw_writel(cmd, priv->base + MDIO_CMD);
+
+       /* Start MDIO transaction */
+       unimac_mdio_start(priv);
+
+       do {
+               if (!unimac_mdio_busy(priv))
+                       break;
+
+               usleep_range(1000, 2000);
+       } while (timeout--);
+
+       if (!timeout)
+               return -ETIMEDOUT;
+
+       cmd = __raw_readl(priv->base + MDIO_CMD);
+       if (cmd & MDIO_READ_FAIL)
+               return -EIO;
+
+       return cmd & 0xffff;
+}
+
+static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
+                            int reg, u16 val)
+{
+       struct unimac_mdio_priv *priv = bus->priv;
+       unsigned int timeout = 1000;
+       u32 cmd;
+
+       /* Prepare the write operation */
+       cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
+               (reg << MDIO_REG_SHIFT) | (0xffff & val);
+       __raw_writel(cmd, priv->base + MDIO_CMD);
+
+       unimac_mdio_start(priv);
+
+       do {
+               if (!unimac_mdio_busy(priv))
+                       break;
+
+               usleep_range(1000, 2000);
+       } while (timeout--);
+
+       if (!timeout)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int unimac_mdio_probe(struct platform_device *pdev)
+{
+       struct unimac_mdio_priv *priv;
+       struct device_node *np;
+       struct mii_bus *bus;
+       struct resource *r;
+       int ret;
+
+       np = pdev->dev.of_node;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       /* Just ioremap, as this MDIO block is usually integrated into an
+        * Ethernet MAC controller register range
+        */
+       priv->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+       if (!priv->base) {
+               dev_err(&pdev->dev, "failed to remap register\n");
+               return -ENOMEM;
+       }
+
+       priv->mii_bus = mdiobus_alloc();
+       if (!priv->mii_bus)
+               return -ENOMEM;
+
+       bus = priv->mii_bus;
+       bus->priv = priv;
+       bus->name = "unimac MII bus";
+       bus->parent = &pdev->dev;
+       bus->read = unimac_mdio_read;
+       bus->write = unimac_mdio_write;
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+
+       bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+       if (!bus->irq) {
+               ret = -ENOMEM;
+               goto out_mdio_free;
+       }
+
+       ret = of_mdiobus_register(bus, np);
+       if (ret) {
+               dev_err(&pdev->dev, "MDIO bus registration failed\n");
+               goto out_mdio_irq;
+       }
+
+       platform_set_drvdata(pdev, priv);
+
+       dev_info(&pdev->dev, "Broadcom UniMAC MDIO bus at 0x%p\n", priv->base);
+
+       return 0;
+
+out_mdio_irq:
+       kfree(bus->irq);
+out_mdio_free:
+       mdiobus_free(bus);
+       return ret;
+}
+
+static int unimac_mdio_remove(struct platform_device *pdev)
+{
+       struct unimac_mdio_priv *priv = platform_get_drvdata(pdev);
+
+       mdiobus_unregister(priv->mii_bus);
+       kfree(priv->mii_bus->irq);
+       mdiobus_free(priv->mii_bus);
+
+       return 0;
+}
+
+static struct of_device_id unimac_mdio_ids[] = {
+       { .compatible = "brcm,genet-mdio-v4", },
+       { .compatible = "brcm,genet-mdio-v3", },
+       { .compatible = "brcm,genet-mdio-v2", },
+       { .compatible = "brcm,genet-mdio-v1", },
+       { .compatible = "brcm,unimac-mdio", },
+       { /* sentinel */ },
+};
+
+static struct platform_driver unimac_mdio_driver = {
+       .driver = {
+               .name = "unimac-mdio",
+               .owner = THIS_MODULE,
+               .of_match_table = unimac_mdio_ids,
+       },
+       .probe  = unimac_mdio_probe,
+       .remove = unimac_mdio_remove,
+};
+module_platform_driver(unimac_mdio_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom UniMAC MDIO bus controller");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:unimac-mdio");
index 4eaadcfcb0fe5ed2d5bd82a4632989916ade90e2..50051f271b10e8c02f34fae073f8d48ee15b8a97 100644 (file)
@@ -553,8 +553,14 @@ static ssize_t
 phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct phy_device *phydev = to_phy_device(dev);
+       const char *mode = NULL;
 
-       return sprintf(buf, "%s\n", phy_modes(phydev->interface));
+       if (phy_is_internal(phydev))
+               mode = "internal";
+       else
+               mode = phy_modes(phydev->interface);
+
+       return sprintf(buf, "%s\n", mode);
 }
 static DEVICE_ATTR_RO(phy_interface);
 
index a854d38c231dfebc983a3bcd4840fdd5a2257bd2..1dfffdc9dfc3577bd6893688da191c38539e243f 100644 (file)
@@ -955,7 +955,7 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
  * 3) Write reg 13 // MMD Data Command for MMD DEVAD
  * 3) Read  reg 14 // Read MMD data
  */
-static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
+int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
                                 int devad, int addr)
 {
        struct phy_driver *phydrv = phydev->drv;
@@ -971,6 +971,7 @@ static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
        }
        return value;
 }
+EXPORT_SYMBOL(phy_read_mmd_indirect);
 
 /**
  * phy_write_mmd_indirect - writes data to the MMD registers
@@ -988,7 +989,7 @@ static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
  * 3) Write reg 13 // MMD Data Command for MMD DEVAD
  * 3) Write reg 14 // Write MMD data
  */
-static void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
+void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
                                   int devad, int addr, u32 data)
 {
        struct phy_driver *phydrv = phydev->drv;
@@ -1002,6 +1003,7 @@ static void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
                phydrv->write_mmd_indirect(phydev, prtad, devad, addr, data);
        }
 }
+EXPORT_SYMBOL(phy_write_mmd_indirect);
 
 /**
  * phy_init_eee - init and check the EEE feature
@@ -1017,12 +1019,14 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
 {
        /* According to 802.3az,the EEE is supported only in full duplex-mode.
         * Also EEE feature is active when core is operating with MII, GMII
-        * or RGMII.
+        * or RGMII. Internal PHYs are also allowed to proceed and should
+        * return an error if they do not support EEE.
         */
        if ((phydev->duplex == DUPLEX_FULL) &&
            ((phydev->interface == PHY_INTERFACE_MODE_MII) ||
            (phydev->interface == PHY_INTERFACE_MODE_GMII) ||
-           (phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
+           (phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+            phy_is_internal(phydev))) {
                int eee_lp, eee_cap, eee_adv;
                u32 lp, cap, adv;
                int status;
index ca5ec3e18d3662daeebd999291cc6a78c73e79de..3fc91e89f5a564bb36ab251c81ec083fc7cab68d 100644 (file)
@@ -230,13 +230,13 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr, u32 *phy_id,
        for (i = 1;
             i < num_ids && c45_ids->devices_in_package == 0;
             i++) {
-               reg_addr = MII_ADDR_C45 | i << 16 | 6;
+               reg_addr = MII_ADDR_C45 | i << 16 | MDIO_DEVS2;
                phy_reg = mdiobus_read(bus, addr, reg_addr);
                if (phy_reg < 0)
                        return -EIO;
                c45_ids->devices_in_package = (phy_reg & 0xffff) << 16;
 
-               reg_addr = MII_ADDR_C45 | i << 16 | 5;
+               reg_addr = MII_ADDR_C45 | i << 16 | MDIO_DEVS1;
                phy_reg = mdiobus_read(bus, addr, reg_addr);
                if (phy_reg < 0)
                        return -EIO;
index ae7cd7f3656d04174b74ae534814029795217f18..92578d72e4ee51ce26d3e23d4b86099a0097801d 100644 (file)
@@ -47,22 +47,22 @@ static const int phy_BCM5400_link_table[8][3] = {
        { 1, 0, 1 },    /* 1000BT */
 };
 
-static inline int __phy_read(struct mii_phy* phy, int id, int reg)
+static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
 {
        return phy->mdio_read(phy->dev, id, reg);
 }
 
-static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
+static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
 {
        phy->mdio_write(phy->dev, id, reg, val);
 }
 
-static inline int phy_read(struct mii_phy* phy, int reg)
+static inline int sungem_phy_read(struct mii_phy* phy, int reg)
 {
        return phy->mdio_read(phy->dev, phy->mii_id, reg);
 }
 
-static inline void phy_write(struct mii_phy* phy, int reg, int val)
+static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
 {
        phy->mdio_write(phy->dev, phy->mii_id, reg, val);
 }
@@ -72,21 +72,21 @@ static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
        u16 val;
        int limit = 10000;
 
-       val = __phy_read(phy, phy_id, MII_BMCR);
+       val = __sungem_phy_read(phy, phy_id, MII_BMCR);
        val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
        val |= BMCR_RESET;
-       __phy_write(phy, phy_id, MII_BMCR, val);
+       __sungem_phy_write(phy, phy_id, MII_BMCR, val);
 
        udelay(100);
 
        while (--limit) {
-               val = __phy_read(phy, phy_id, MII_BMCR);
+               val = __sungem_phy_read(phy, phy_id, MII_BMCR);
                if ((val & BMCR_RESET) == 0)
                        break;
                udelay(10);
        }
        if ((val & BMCR_ISOLATE) && limit > 0)
-               __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
+               __sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
 
        return limit <= 0;
 }
@@ -95,19 +95,19 @@ static int bcm5201_init(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5201_MULTIPHY);
+       data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
        data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
-       phy_write(phy, MII_BCM5201_MULTIPHY, data);
+       sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
 
-       phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+       sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
 
        return 0;
 }
 
 static int bcm5201_suspend(struct mii_phy* phy)
 {
-       phy_write(phy, MII_BCM5201_INTERRUPT, 0);
-       phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
+       sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+       sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
 
        return 0;
 }
@@ -116,20 +116,20 @@ static int bcm5221_init(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
                data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
                data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
 
        return 0;
@@ -139,12 +139,12 @@ static int bcm5221_suspend(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
                  data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
 
        return 0;
@@ -154,20 +154,20 @@ static int bcm5241_init(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
                data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
                data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
 
        return 0;
@@ -177,12 +177,12 @@ static int bcm5241_suspend(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
                  data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
 
        return 0;
@@ -193,26 +193,26 @@ static int bcm5400_init(struct mii_phy* phy)
        u16 data;
 
        /* Configure for gigabit full duplex */
-       data = phy_read(phy, MII_BCM5400_AUXCONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
        data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
-       phy_write(phy, MII_BCM5400_AUXCONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
 
-       data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
 
        udelay(100);
 
        /* Reset and configure cascaded 10/100 PHY */
        (void)reset_one_mii_phy(phy, 0x1f);
 
-       data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+       data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
        data |= MII_BCM5201_MULTIPHY_SERIALMODE;
-       __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+       __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
 
-       data = phy_read(phy, MII_BCM5400_AUXCONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
        data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
-       phy_write(phy, MII_BCM5400_AUXCONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
 
        return 0;
 }
@@ -220,7 +220,7 @@ static int bcm5400_init(struct mii_phy* phy)
 static int bcm5400_suspend(struct mii_phy* phy)
 {
 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
-       phy_write(phy, MII_BMCR, BMCR_PDOWN);
+       sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
 #endif
        return 0;
 }
@@ -230,7 +230,7 @@ static int bcm5401_init(struct mii_phy* phy)
        u16 data;
        int rev;
 
-       rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+       rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
        if (rev == 0 || rev == 3) {
                /* Some revisions of 5401 appear to need this
                 * initialisation sequence to disable, according
@@ -243,32 +243,32 @@ static int bcm5401_init(struct mii_phy* phy)
                 * Note: This should (and does) match tg3_init_5401phy_dsp
                 *       in the tg3.c driver. -DaveM
                 */
-               phy_write(phy, 0x18, 0x0c20);
-               phy_write(phy, 0x17, 0x0012);
-               phy_write(phy, 0x15, 0x1804);
-               phy_write(phy, 0x17, 0x0013);
-               phy_write(phy, 0x15, 0x1204);
-               phy_write(phy, 0x17, 0x8006);
-               phy_write(phy, 0x15, 0x0132);
-               phy_write(phy, 0x17, 0x8006);
-               phy_write(phy, 0x15, 0x0232);
-               phy_write(phy, 0x17, 0x201f);
-               phy_write(phy, 0x15, 0x0a20);
+               sungem_phy_write(phy, 0x18, 0x0c20);
+               sungem_phy_write(phy, 0x17, 0x0012);
+               sungem_phy_write(phy, 0x15, 0x1804);
+               sungem_phy_write(phy, 0x17, 0x0013);
+               sungem_phy_write(phy, 0x15, 0x1204);
+               sungem_phy_write(phy, 0x17, 0x8006);
+               sungem_phy_write(phy, 0x15, 0x0132);
+               sungem_phy_write(phy, 0x17, 0x8006);
+               sungem_phy_write(phy, 0x15, 0x0232);
+               sungem_phy_write(phy, 0x17, 0x201f);
+               sungem_phy_write(phy, 0x15, 0x0a20);
        }
 
        /* Configure for gigabit full duplex */
-       data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
 
        udelay(10);
 
        /* Reset and configure cascaded 10/100 PHY */
        (void)reset_one_mii_phy(phy, 0x1f);
 
-       data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+       data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
        data |= MII_BCM5201_MULTIPHY_SERIALMODE;
-       __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+       __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
 
        return 0;
 }
@@ -276,7 +276,7 @@ static int bcm5401_init(struct mii_phy* phy)
 static int bcm5401_suspend(struct mii_phy* phy)
 {
 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
-       phy_write(phy, MII_BMCR, BMCR_PDOWN);
+       sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
 #endif
        return 0;
 }
@@ -288,19 +288,19 @@ static int bcm5411_init(struct mii_phy* phy)
        /* Here's some more Apple black magic to setup
         * some voltage stuffs.
         */
-       phy_write(phy, 0x1c, 0x8c23);
-       phy_write(phy, 0x1c, 0x8ca3);
-       phy_write(phy, 0x1c, 0x8c23);
+       sungem_phy_write(phy, 0x1c, 0x8c23);
+       sungem_phy_write(phy, 0x1c, 0x8ca3);
+       sungem_phy_write(phy, 0x1c, 0x8c23);
 
        /* Here, Apple seems to want to reset it, do
         * it as well
         */
-       phy_write(phy, MII_BMCR, BMCR_RESET);
-       phy_write(phy, MII_BMCR, 0x1340);
+       sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
+       sungem_phy_write(phy, MII_BMCR, 0x1340);
 
-       data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
 
        udelay(10);
 
@@ -321,7 +321,7 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
        phy->advertising = advertise;
 
        /* Setup standard advertise */
-       adv = phy_read(phy, MII_ADVERTISE);
+       adv = sungem_phy_read(phy, MII_ADVERTISE);
        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
        if (advertise & ADVERTISED_10baseT_Half)
                adv |= ADVERTISE_10HALF;
@@ -331,12 +331,12 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= ADVERTISE_100HALF;
        if (advertise & ADVERTISED_100baseT_Full)
                adv |= ADVERTISE_100FULL;
-       phy_write(phy, MII_ADVERTISE, adv);
+       sungem_phy_write(phy, MII_ADVERTISE, adv);
 
        /* Start/Restart aneg */
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -350,11 +350,11 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
        phy->duplex = fd;
        phy->pause = 0;
 
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
 
        /* First reset the PHY */
-       phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+       sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
 
        /* Select speed & duplex */
        switch(speed) {
@@ -369,7 +369,7 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
        }
        if (fd == DUPLEX_FULL)
                ctl |= BMCR_FULLDPLX;
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -378,8 +378,8 @@ static int genmii_poll_link(struct mii_phy *phy)
 {
        u16 status;
 
-       (void)phy_read(phy, MII_BMSR);
-       status = phy_read(phy, MII_BMSR);
+       (void)sungem_phy_read(phy, MII_BMSR);
+       status = sungem_phy_read(phy, MII_BMSR);
        if ((status & BMSR_LSTATUS) == 0)
                return 0;
        if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
@@ -392,7 +392,7 @@ static int genmii_read_link(struct mii_phy *phy)
        u16 lpa;
 
        if (phy->autoneg) {
-               lpa = phy_read(phy, MII_LPA);
+               lpa = sungem_phy_read(phy, MII_LPA);
 
                if (lpa & (LPA_10FULL | LPA_100FULL))
                        phy->duplex = DUPLEX_FULL;
@@ -413,7 +413,7 @@ static int genmii_read_link(struct mii_phy *phy)
 
 static int generic_suspend(struct mii_phy* phy)
 {
-       phy_write(phy, MII_BMCR, BMCR_PDOWN);
+       sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
 
        return 0;
 }
@@ -423,27 +423,27 @@ static int bcm5421_init(struct mii_phy* phy)
        u16 data;
        unsigned int id;
 
-       id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+       id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
 
        /* Revision 0 of 5421 needs some fixups */
        if (id == 0x002060e0) {
                /* This is borrowed from MacOS
                 */
-               phy_write(phy, 0x18, 0x1007);
-               data = phy_read(phy, 0x18);
-               phy_write(phy, 0x18, data | 0x0400);
-               phy_write(phy, 0x18, 0x0007);
-               data = phy_read(phy, 0x18);
-               phy_write(phy, 0x18, data | 0x0800);
-               phy_write(phy, 0x17, 0x000a);
-               data = phy_read(phy, 0x15);
-               phy_write(phy, 0x15, data | 0x0200);
+               sungem_phy_write(phy, 0x18, 0x1007);
+               data = sungem_phy_read(phy, 0x18);
+               sungem_phy_write(phy, 0x18, data | 0x0400);
+               sungem_phy_write(phy, 0x18, 0x0007);
+               data = sungem_phy_read(phy, 0x18);
+               sungem_phy_write(phy, 0x18, data | 0x0800);
+               sungem_phy_write(phy, 0x17, 0x000a);
+               data = sungem_phy_read(phy, 0x15);
+               sungem_phy_write(phy, 0x15, data | 0x0200);
        }
 
        /* Pick up some init code from OF for K2 version */
        if ((id & 0xfffffff0) == 0x002062e0) {
-               phy_write(phy, 4, 0x01e1);
-               phy_write(phy, 9, 0x0300);
+               sungem_phy_write(phy, 4, 0x01e1);
+               sungem_phy_write(phy, 9, 0x0300);
        }
 
        /* Check if we can enable automatic low power */
@@ -455,9 +455,9 @@ static int bcm5421_init(struct mii_phy* phy)
                        can_low_power = 0;
                if (can_low_power) {
                        /* Enable automatic low-power */
-                       phy_write(phy, 0x1c, 0x9002);
-                       phy_write(phy, 0x1c, 0xa821);
-                       phy_write(phy, 0x1c, 0x941d);
+                       sungem_phy_write(phy, 0x1c, 0x9002);
+                       sungem_phy_write(phy, 0x1c, 0xa821);
+                       sungem_phy_write(phy, 0x1c, 0x941d);
                }
        }
 #endif /* CONFIG_PPC_PMAC */
@@ -476,7 +476,7 @@ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
        phy->advertising = advertise;
 
        /* Setup standard advertise */
-       adv = phy_read(phy, MII_ADVERTISE);
+       adv = sungem_phy_read(phy, MII_ADVERTISE);
        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
        if (advertise & ADVERTISED_10baseT_Half)
                adv |= ADVERTISE_10HALF;
@@ -490,21 +490,21 @@ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= ADVERTISE_PAUSE_CAP;
        if (advertise & ADVERTISED_Asym_Pause)
                adv |= ADVERTISE_PAUSE_ASYM;
-       phy_write(phy, MII_ADVERTISE, adv);
+       sungem_phy_write(phy, MII_ADVERTISE, adv);
 
        /* Setup 1000BT advertise */
-       adv = phy_read(phy, MII_1000BASETCONTROL);
+       adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
        adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
        if (advertise & SUPPORTED_1000baseT_Half)
                adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
        if (advertise & SUPPORTED_1000baseT_Full)
                adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_1000BASETCONTROL, adv);
+       sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
 
        /* Start/Restart aneg */
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -518,11 +518,11 @@ static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
        phy->duplex = fd;
        phy->pause = 0;
 
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
 
        /* First reset the PHY */
-       phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+       sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
 
        /* Select speed & duplex */
        switch(speed) {
@@ -539,7 +539,7 @@ static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
 
        // XXX Should we set the sungem to GII now on 1000BT ?
 
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -550,7 +550,7 @@ static int bcm54xx_read_link(struct mii_phy *phy)
        u16 val;
 
        if (phy->autoneg) {
-               val = phy_read(phy, MII_BCM5400_AUXSTATUS);
+               val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
                link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
                             MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
                phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
@@ -559,7 +559,7 @@ static int bcm54xx_read_link(struct mii_phy *phy)
                                SPEED_1000 :
                                (phy_BCM5400_link_table[link_mode][1] ?
                                 SPEED_100 : SPEED_10);
-               val = phy_read(phy, MII_LPA);
+               val = sungem_phy_read(phy, MII_LPA);
                phy->pause = (phy->duplex == DUPLEX_FULL) &&
                        ((val & LPA_PAUSE) != 0);
        }
@@ -575,19 +575,19 @@ static int marvell88e1111_init(struct mii_phy* phy)
        u16 rev;
 
        /* magic init sequence for rev 0 */
-       rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+       rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
        if (rev == 0) {
-               phy_write(phy, 0x1d, 0x000a);
-               phy_write(phy, 0x1e, 0x0821);
+               sungem_phy_write(phy, 0x1d, 0x000a);
+               sungem_phy_write(phy, 0x1e, 0x0821);
 
-               phy_write(phy, 0x1d, 0x0006);
-               phy_write(phy, 0x1e, 0x8600);
+               sungem_phy_write(phy, 0x1d, 0x0006);
+               sungem_phy_write(phy, 0x1e, 0x8600);
 
-               phy_write(phy, 0x1d, 0x000b);
-               phy_write(phy, 0x1e, 0x0100);
+               sungem_phy_write(phy, 0x1d, 0x000b);
+               sungem_phy_write(phy, 0x1e, 0x0100);
 
-               phy_write(phy, 0x1d, 0x0004);
-               phy_write(phy, 0x1e, 0x4850);
+               sungem_phy_write(phy, 0x1d, 0x0004);
+               sungem_phy_write(phy, 0x1e, 0x4850);
        }
        return 0;
 }
@@ -600,8 +600,8 @@ static int bcm5421_poll_link(struct mii_phy* phy)
        int mode;
 
        /* find out in what mode we are */
-       phy_write(phy, MII_NCONFIG, 0x1000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x1000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
 
@@ -609,8 +609,8 @@ static int bcm5421_poll_link(struct mii_phy* phy)
                return genmii_poll_link(phy);
 
        /* try to find out whether we have a link */
-       phy_write(phy, MII_NCONFIG, 0x2000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x2000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        if (phy_reg & 0x0020)
                return 0;
@@ -624,8 +624,8 @@ static int bcm5421_read_link(struct mii_phy* phy)
        int mode;
 
        /* find out in what mode we are */
-       phy_write(phy, MII_NCONFIG, 0x1000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x1000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
 
@@ -635,8 +635,8 @@ static int bcm5421_read_link(struct mii_phy* phy)
        phy->speed = SPEED_1000;
 
        /* find out whether we are running half- or full duplex */
-       phy_write(phy, MII_NCONFIG, 0x2000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x2000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        if ( (phy_reg & 0x0080) >> 7)
                phy->duplex |=  DUPLEX_HALF;
@@ -649,14 +649,14 @@ static int bcm5421_read_link(struct mii_phy* phy)
 static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
 {
        /* enable fiber mode */
-       phy_write(phy, MII_NCONFIG, 0x9020);
+       sungem_phy_write(phy, MII_NCONFIG, 0x9020);
        /* LEDs active in both modes, autosense prio = fiber */
-       phy_write(phy, MII_NCONFIG, 0x945f);
+       sungem_phy_write(phy, MII_NCONFIG, 0x945f);
 
        if (!autoneg) {
                /* switch off fibre autoneg */
-               phy_write(phy, MII_NCONFIG, 0xfc01);
-               phy_write(phy, 0x0b, 0x0004);
+               sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
+               sungem_phy_write(phy, 0x0b, 0x0004);
        }
 
        phy->autoneg = autoneg;
@@ -673,8 +673,8 @@ static int bcm5461_poll_link(struct mii_phy* phy)
        int mode;
 
        /* find out in what mode we are */
-       phy_write(phy, MII_NCONFIG, 0x7c00);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
 
@@ -682,8 +682,8 @@ static int bcm5461_poll_link(struct mii_phy* phy)
                return genmii_poll_link(phy);
 
        /* find out whether we have a link */
-       phy_write(phy, MII_NCONFIG, 0x7000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x7000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        if (phy_reg & BCM5461_FIBER_LINK)
                return 1;
@@ -699,8 +699,8 @@ static int bcm5461_read_link(struct mii_phy* phy)
        int mode;
 
        /* find out in what mode we are */
-       phy_write(phy, MII_NCONFIG, 0x7c00);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
 
@@ -711,8 +711,8 @@ static int bcm5461_read_link(struct mii_phy* phy)
        phy->speed = SPEED_1000;
 
        /* find out whether we are running half- or full duplex */
-       phy_write(phy, MII_NCONFIG, 0x7000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x7000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        if (phy_reg & BCM5461_FIBER_DUPLEX)
                phy->duplex |=  DUPLEX_FULL;
@@ -725,15 +725,15 @@ static int bcm5461_read_link(struct mii_phy* phy)
 static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
 {
        /* select fiber mode, enable 1000 base-X registers */
-       phy_write(phy, MII_NCONFIG, 0xfc0b);
+       sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
 
        if (autoneg) {
                /* enable fiber with no autonegotiation */
-               phy_write(phy, MII_ADVERTISE, 0x01e0);
-               phy_write(phy, MII_BMCR, 0x1140);
+               sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
+               sungem_phy_write(phy, MII_BMCR, 0x1140);
        } else {
                /* enable fiber with autonegotiation */
-               phy_write(phy, MII_BMCR, 0x0140);
+               sungem_phy_write(phy, MII_BMCR, 0x0140);
        }
 
        phy->autoneg = autoneg;
@@ -752,7 +752,7 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
        phy->advertising = advertise;
 
        /* Setup standard advertise */
-       adv = phy_read(phy, MII_ADVERTISE);
+       adv = sungem_phy_read(phy, MII_ADVERTISE);
        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
        if (advertise & ADVERTISED_10baseT_Half)
                adv |= ADVERTISE_10HALF;
@@ -766,7 +766,7 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= ADVERTISE_PAUSE_CAP;
        if (advertise & ADVERTISED_Asym_Pause)
                adv |= ADVERTISE_PAUSE_ASYM;
-       phy_write(phy, MII_ADVERTISE, adv);
+       sungem_phy_write(phy, MII_ADVERTISE, adv);
 
        /* Setup 1000BT advertise & enable crossover detect
         * XXX How do we advertise 1000BT ? Darwin source is
@@ -774,7 +774,7 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
         * write to control... Someone has specs for those
         * beasts ?
         */
-       adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
+       adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
        adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
        adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
                        MII_1000BASETCONTROL_HALFDUPLEXCAP);
@@ -782,12 +782,12 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
        if (advertise & SUPPORTED_1000baseT_Full)
                adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_1000BASETCONTROL, adv);
+       sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
 
        /* Start/Restart aneg */
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -801,7 +801,7 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
        phy->duplex = fd;
        phy->pause = 0;
 
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
        ctl |= BMCR_RESET;
 
@@ -824,7 +824,7 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
        /* Disable crossover. Again, the way Apple does it is strange,
         * though I don't assume they are wrong ;)
         */
-       ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
+       ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
        ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
                MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
                MII_1000BASETCONTROL_FULLDUPLEXCAP |
@@ -833,11 +833,11 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
                ctl2 |= (fd == DUPLEX_FULL) ?
                        MII_1000BASETCONTROL_FULLDUPLEXCAP :
                        MII_1000BASETCONTROL_HALFDUPLEXCAP;
-       phy_write(phy, MII_1000BASETCONTROL, ctl2);
+       sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
 
        // XXX Should we set the sungem to GII now on 1000BT ?
 
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -847,7 +847,7 @@ static int marvell_read_link(struct mii_phy *phy)
        u16 status, pmask;
 
        if (phy->autoneg) {
-               status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
+               status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
                if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
                        return -EAGAIN;
                if (status & MII_M1011_PHY_SPEC_STATUS_1000)
@@ -1174,7 +1174,7 @@ int sungem_phy_probe(struct mii_phy *phy, int mii_id)
                goto fail;
 
        /* Read ID and find matching entry */
-       id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+       id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
        printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
               id, mii_id);
        for (i=0; (def = mii_phy_table[i]) != NULL; i++)
index ef10302ec936ee5969001bb9da484b80d573c1ee..2277c3679a518e5b68ded6ff7e9bbe9404f71a1e 100644 (file)
@@ -1003,7 +1003,6 @@ static int team_port_enter(struct team *team, struct team_port *port)
        int err = 0;
 
        dev_hold(team->dev);
-       port->dev->priv_flags |= IFF_TEAM_PORT;
        if (team->ops.port_enter) {
                err = team->ops.port_enter(team, port);
                if (err) {
@@ -1016,7 +1015,6 @@ static int team_port_enter(struct team *team, struct team_port *port)
        return 0;
 
 err_port_enter:
-       port->dev->priv_flags &= ~IFF_TEAM_PORT;
        dev_put(team->dev);
 
        return err;
@@ -1026,7 +1024,6 @@ static void team_port_leave(struct team *team, struct team_port *port)
 {
        if (team->ops.port_leave)
                team->ops.port_leave(team, port);
-       port->dev->priv_flags &= ~IFF_TEAM_PORT;
        dev_put(team->dev);
 }
 
@@ -1075,6 +1072,25 @@ static void team_port_disable_netpoll(struct team_port *port)
 }
 #endif
 
+static int team_upper_dev_link(struct net_device *dev,
+                              struct net_device *port_dev)
+{
+       int err;
+
+       err = netdev_master_upper_dev_link(port_dev, dev);
+       if (err)
+               return err;
+       port_dev->priv_flags |= IFF_TEAM_PORT;
+       return 0;
+}
+
+static void team_upper_dev_unlink(struct net_device *dev,
+                                 struct net_device *port_dev)
+{
+       netdev_upper_dev_unlink(port_dev, dev);
+       port_dev->priv_flags &= ~IFF_TEAM_PORT;
+}
+
 static void __team_port_change_port_added(struct team_port *port, bool linkup);
 static int team_dev_type_check_change(struct net_device *dev,
                                      struct net_device *port_dev);
@@ -1161,13 +1177,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_enable_netpoll;
        }
 
-       err = netdev_master_upper_dev_link(port_dev, dev);
-       if (err) {
-               netdev_err(dev, "Device %s failed to set upper link\n",
-                          portname);
-               goto err_set_upper_link;
-       }
-
        err = netdev_rx_handler_register(port_dev, team_handle_frame,
                                         port);
        if (err) {
@@ -1176,6 +1185,13 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_handler_register;
        }
 
+       err = team_upper_dev_link(dev, port_dev);
+       if (err) {
+               netdev_err(dev, "Device %s failed to set upper link\n",
+                          portname);
+               goto err_set_upper_link;
+       }
+
        err = __team_option_inst_add_port(team, port);
        if (err) {
                netdev_err(dev, "Device %s failed to add per-port options\n",
@@ -1195,12 +1211,12 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
        return 0;
 
 err_option_port_add:
+       team_upper_dev_unlink(dev, port_dev);
+
+err_set_upper_link:
        netdev_rx_handler_unregister(port_dev);
 
 err_handler_register:
-       netdev_upper_dev_unlink(port_dev, dev);
-
-err_set_upper_link:
        team_port_disable_netpoll(port);
 
 err_enable_netpoll:
@@ -1239,8 +1255,8 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
 
        team_port_disable(team, port);
        list_del_rcu(&port->list);
+       team_upper_dev_unlink(dev, port_dev);
        netdev_rx_handler_unregister(port_dev);
-       netdev_upper_dev_unlink(port_dev, dev);
        team_port_disable_netpoll(port);
        vlan_vids_del_by_dev(port_dev, dev);
        dev_uc_unsync(port_dev, dev);
index 87f710476217d8a02cc496925d57ac5fcd0021c8..f95e678cb69ddbf1e1b78fa8f9a2e0bb6a945065 100644 (file)
@@ -424,7 +424,7 @@ enum rtl_register_content {
        FULL_DUP        = 0x01,
 };
 
-#define RTL8152_MAX_TX         10
+#define RTL8152_MAX_TX         4
 #define RTL8152_MAX_RX         10
 #define INTBUFSIZE             2
 #define CRC_SIZE               4
@@ -607,9 +607,9 @@ enum tx_csum_stat {
  * The RTL chips use a 64 element hash table based on the Ethernet CRC.
  */
 static const int multicast_filter_limit = 32;
-static unsigned int rx_buf_sz = 16384;
+static unsigned int agg_buf_sz = 16384;
 
-#define RTL_LIMITED_TSO_SIZE   (rx_buf_sz - sizeof(struct tx_desc) - \
+#define RTL_LIMITED_TSO_SIZE   (agg_buf_sz - sizeof(struct tx_desc) - \
                                 VLAN_ETH_HLEN - VLAN_HLEN)
 
 static
@@ -623,8 +623,8 @@ int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
                return -ENOMEM;
 
        ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
-                              RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-                              value, index, tmp, size, 500);
+                             RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
+                             value, index, tmp, size, 500);
 
        memcpy(data, tmp, size);
        kfree(tmp);
@@ -643,8 +643,8 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
                return -ENOMEM;
 
        ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
-                              RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
-                              value, index, tmp, size, 500);
+                             RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
+                             value, index, tmp, size, 500);
 
        kfree(tmp);
 
@@ -652,7 +652,7 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 }
 
 static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
-                               void *data, u16 type)
+                           void *data, u16 type)
 {
        u16 limit = 64;
        int ret = 0;
@@ -692,7 +692,7 @@ static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
 }
 
 static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
-                               u16 size, void *data, u16 type)
+                            u16 size, void *data, u16 type)
 {
        int ret;
        u16 byteen_start, byteen_end, byen;
@@ -726,8 +726,8 @@ static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
                while (size) {
                        if (size > limit) {
                                ret = set_registers(tp, index,
-                                       type | BYTE_EN_DWORD,
-                                       limit, data);
+                                                   type | BYTE_EN_DWORD,
+                                                   limit, data);
                                if (ret < 0)
                                        goto error1;
 
@@ -736,8 +736,8 @@ static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
                                size -= limit;
                        } else {
                                ret = set_registers(tp, index,
-                                       type | BYTE_EN_DWORD,
-                                       size, data);
+                                                   type | BYTE_EN_DWORD,
+                                                   size, data);
                                if (ret < 0)
                                        goto error1;
 
@@ -972,36 +972,8 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
        usb_autopm_put_interface(tp->intf);
 }
 
-static
-int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
-
-static inline void set_ethernet_addr(struct r8152 *tp)
-{
-       struct net_device *dev = tp->netdev;
-       int ret;
-       u8 node_id[8] = {0};
-
-       if (tp->version == RTL_VER_01)
-               ret = pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id);
-       else
-               ret = pla_ocp_read(tp, PLA_BACKUP, sizeof(node_id), node_id);
-
-       if (ret < 0) {
-               netif_notice(tp, probe, dev, "inet addr fail\n");
-       } else {
-               if (tp->version != RTL_VER_01) {
-                       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR,
-                                      CRWECR_CONFIG);
-                       pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES,
-                                     sizeof(node_id), node_id);
-                       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR,
-                                      CRWECR_NORAML);
-               }
-
-               memcpy(dev->dev_addr, node_id, dev->addr_len);
-               memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-       }
-}
+static int
+r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
 
 static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
 {
@@ -1020,6 +992,37 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
        return 0;
 }
 
+static int set_ethernet_addr(struct r8152 *tp)
+{
+       struct net_device *dev = tp->netdev;
+       struct sockaddr sa;
+       int ret;
+
+       if (tp->version == RTL_VER_01)
+               ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data);
+       else
+               ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data);
+
+       if (ret < 0) {
+               netif_err(tp, probe, dev, "Get ether addr fail\n");
+       } else if (!is_valid_ether_addr(sa.sa_data)) {
+               netif_err(tp, probe, dev, "Invalid ether addr %pM\n",
+                         sa.sa_data);
+               eth_hw_addr_random(dev);
+               ether_addr_copy(sa.sa_data, dev->dev_addr);
+               ret = rtl8152_set_mac_address(dev, &sa);
+               netif_info(tp, probe, dev, "Random ether addr %pM\n",
+                          sa.sa_data);
+       } else {
+               if (tp->version == RTL_VER_01)
+                       ether_addr_copy(dev->dev_addr, sa.sa_data);
+               else
+                       ret = rtl8152_set_mac_address(dev, &sa);
+       }
+
+       return ret;
+}
+
 static void read_bulk_callback(struct urb *urb)
 {
        struct net_device *netdev;
@@ -1248,13 +1251,13 @@ static int alloc_all_mem(struct r8152 *tp)
        skb_queue_head_init(&tp->tx_queue);
 
        for (i = 0; i < RTL8152_MAX_RX; i++) {
-               buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
+               buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node);
                if (!buf)
                        goto err1;
 
                if (buf != rx_agg_align(buf)) {
                        kfree(buf);
-                       buf = kmalloc_node(rx_buf_sz + RX_ALIGN, GFP_KERNEL,
+                       buf = kmalloc_node(agg_buf_sz + RX_ALIGN, GFP_KERNEL,
                                           node);
                        if (!buf)
                                goto err1;
@@ -1274,13 +1277,13 @@ static int alloc_all_mem(struct r8152 *tp)
        }
 
        for (i = 0; i < RTL8152_MAX_TX; i++) {
-               buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
+               buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node);
                if (!buf)
                        goto err1;
 
                if (buf != tx_agg_align(buf)) {
                        kfree(buf);
-                       buf = kmalloc_node(rx_buf_sz + TX_ALIGN, GFP_KERNEL,
+                       buf = kmalloc_node(agg_buf_sz + TX_ALIGN, GFP_KERNEL,
                                           node);
                        if (!buf)
                                goto err1;
@@ -1311,8 +1314,8 @@ static int alloc_all_mem(struct r8152 *tp)
 
        tp->intr_interval = (int)ep_intr->desc.bInterval;
        usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3),
-                    tp->intr_buff, INTBUFSIZE, intr_callback,
-                    tp, tp->intr_interval);
+                        tp->intr_buff, INTBUFSIZE, intr_callback,
+                        tp, tp->intr_interval);
 
        return 0;
 
@@ -1354,8 +1357,7 @@ static inline __be16 get_protocol(struct sk_buff *skb)
        return protocol;
 }
 
-/*
- * r8152_csum_workaround()
+/* r8152_csum_workaround()
  * The hw limites the value the transport offset. When the offset is out of the
  * range, calculate the checksum by sw.
  */
@@ -1398,8 +1400,7 @@ drop:
        }
 }
 
-/*
- * msdn_giant_send_check()
+/* msdn_giant_send_check()
  * According to the document of microsoft, the TCP Pseudo Header excludes the
  * packet length for IPv6 TCP large packets.
  */
@@ -1518,8 +1519,9 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
        spin_unlock(&tx_queue->lock);
 
        tx_data = agg->head;
-       agg->skb_num = agg->skb_len = 0;
-       remain = rx_buf_sz;
+       agg->skb_num = 0;
+       agg->skb_len = 0;
+       remain = agg_buf_sz;
 
        while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) {
                struct tx_desc *tx_desc;
@@ -1566,7 +1568,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
 
                dev_kfree_skb_any(skb);
 
-               remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
+               remain = agg_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
        }
 
        if (!skb_queue_empty(&skb_head)) {
@@ -1772,8 +1774,8 @@ static
 int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
 {
        usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
-                     agg->head, rx_buf_sz,
-                     (usb_complete_t)read_bulk_callback, agg);
+                         agg->head, agg_buf_sz,
+                         (usb_complete_t)read_bulk_callback, agg);
 
        return usb_submit_urb(agg->urb, mem_flags);
 }
@@ -1835,18 +1837,22 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
                /* Unconditionally log net taps. */
                netif_notice(tp, link, netdev, "Promiscuous mode enabled\n");
                ocp_data |= RCR_AM | RCR_AAP;
-               mc_filter[1] = mc_filter[0] = 0xffffffff;
+               mc_filter[1] = 0xffffffff;
+               mc_filter[0] = 0xffffffff;
        } else if ((netdev_mc_count(netdev) > multicast_filter_limit) ||
                   (netdev->flags & IFF_ALLMULTI)) {
                /* Too many to filter perfectly -- accept all multicasts. */
                ocp_data |= RCR_AM;
-               mc_filter[1] = mc_filter[0] = 0xffffffff;
+               mc_filter[1] = 0xffffffff;
+               mc_filter[0] = 0xffffffff;
        } else {
                struct netdev_hw_addr *ha;
 
-               mc_filter[1] = mc_filter[0] = 0;
+               mc_filter[1] = 0;
+               mc_filter[0] = 0;
                netdev_for_each_mc_addr(ha, netdev) {
                        int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
+
                        mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
                        ocp_data |= RCR_AM;
                }
@@ -1861,7 +1867,7 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
 }
 
 static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
-                                       struct net_device *netdev)
+                                     struct net_device *netdev)
 {
        struct r8152 *tp = netdev_priv(netdev);
 
@@ -1877,8 +1883,9 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
                        usb_mark_last_busy(tp->udev);
                        tasklet_schedule(&tp->tl);
                }
-       } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
+       } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) {
                netif_stop_queue(netdev);
+       }
 
        return NETDEV_TX_OK;
 }
@@ -1903,7 +1910,7 @@ static void rtl8152_nic_reset(struct r8152 *tp)
        for (i = 0; i < 1000; i++) {
                if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST))
                        break;
-               udelay(100);
+               usleep_range(100, 400);
        }
 }
 
@@ -1911,8 +1918,8 @@ static void set_tx_qlen(struct r8152 *tp)
 {
        struct net_device *netdev = tp->netdev;
 
-       tp->tx_qlen = rx_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN +
-                                  sizeof(struct tx_desc));
+       tp->tx_qlen = agg_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN +
+                                   sizeof(struct tx_desc));
 }
 
 static inline u8 rtl8152_get_speed(struct r8152 *tp)
@@ -2861,8 +2868,7 @@ static int rtl8152_close(struct net_device *netdev)
        if (res < 0) {
                rtl_drop_queued_tx(tp);
        } else {
-               /*
-                * The autosuspend may have been enabled and wouldn't
+               /* The autosuspend may have been enabled and wouldn't
                 * be disable when autoresume occurs, because the
                 * netif_running() would be false.
                 */
@@ -3085,8 +3091,9 @@ static int rtl8152_resume(struct usb_interface *intf)
                } else {
                        tp->rtl_ops.up(tp);
                        rtl8152_set_speed(tp, AUTONEG_ENABLE,
-                               tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
-                               DUPLEX_FULL);
+                                         tp->mii.supports_gmii ?
+                                         SPEED_1000 : SPEED_100,
+                                         DUPLEX_FULL);
                }
                tp->speed = 0;
                netif_carrier_off(tp->netdev);
@@ -3147,8 +3154,8 @@ static void rtl8152_get_drvinfo(struct net_device *netdev,
 {
        struct r8152 *tp = netdev_priv(netdev);
 
-       strncpy(info->driver, MODULENAME, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+       strlcpy(info->driver, MODULENAME, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
        usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info));
 }
 
index 59caa06f34a6b3b17fa3cbce41ea3fb1b08b14a3..9359a13d285ad19bf33602f514b8275fb8e725d1 100644 (file)
@@ -934,7 +934,6 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
                dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
-       virtqueue_kick(sq->vq);
 
        /* Don't wait up for transmitted skbs to be freed. */
        skb_orphan(skb);
@@ -954,6 +953,9 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
+       if (__netif_subqueue_stopped(dev, qnum) || !skb->xmit_more)
+               virtqueue_kick(sq->vq);
+
        return NETDEV_TX_OK;
 }
 
index beb377b2d4b78e67e15fa2c7fe6404bef240eba0..53c3ec19807cfd4b880c9bc7f4348847dd8c38c1 100644 (file)
@@ -1158,8 +1158,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
        if (!vs)
                goto drop;
 
-       skb_pop_rcv_encapsulation(skb);
-
        vs->rcv(vs, skb, vxh->vx_vni);
        return 0;
 
@@ -2372,6 +2370,8 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6,
        /* Disable multicast loopback */
        inet_sk(sock->sk)->mc_loop = 0;
 
+       udp_set_convert_csum(sock->sk, true);
+
        return sock;
 }
 
index 43c9960dce1c4bd89195add029eefe26d0bfd1a6..ae6ecf4011892f4fa50861cfff6ee4bf158639fe 100644 (file)
@@ -192,8 +192,10 @@ static netdev_tx_t dlci_transmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dlci_local *dlp = netdev_priv(dev);
 
-       if (skb)
-               dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave);
+       if (skb) {
+               struct netdev_queue *txq = skb_get_tx_queue(dev, skb);
+               netdev_start_xmit(skb, dlp->slave, txq, false);
+       }
        return NETDEV_TX_OK;
 }
 
index bcdc882cd4157af2a0bd56a89248b7d3969d4b35..146f48cc65d7fb9c000565448121337f914c694c 100644 (file)
@@ -1101,7 +1101,15 @@ static void ncm_tx_tasklet(unsigned long data)
        /* Only send if data is available. */
        if (ncm->skb_tx_data) {
                ncm->timer_force_tx = true;
+
+               /* XXX This allowance of a NULL skb argument to ndo_start_xmit
+                * XXX is not sane.  The gadget layer should be redesigned so
+                * XXX that the dev->wrap() invocations to build SKBs is transparent
+                * XXX and performed in some way outside of the ndo_start_xmit
+                * XXX interface.
+                */
                ncm->netdev->netdev_ops->ndo_start_xmit(NULL, ncm->netdev);
+
                ncm->timer_force_tx = false;
        }
 }
index 61219b9b34458862c9be600652006d8ac84b8705..5bd35cc0d4715b44f886fff63b7f04a8db5f4969 100644 (file)
@@ -13,6 +13,8 @@
 #define PHY_ID_BCM5461                 0x002060c0
 #define PHY_ID_BCM57780                        0x03625d90
 
+#define PHY_ID_BCM7250                 0xae025280
+#define PHY_ID_BCM7364                 0xae025260
 #define PHY_ID_BCM7366                 0x600d8490
 #define PHY_ID_BCM7439                 0x600d8480
 #define PHY_ID_BCM7445                 0x600d8510
@@ -21,9 +23,9 @@
 #define PHY_BCM_OUI_1                  0x00206000
 #define PHY_BCM_OUI_2                  0x0143bc00
 #define PHY_BCM_OUI_3                  0x03625c00
-#define PHY_BCM_OUI_4                  0x600d0000
+#define PHY_BCM_OUI_4                  0x600d8400
 #define PHY_BCM_OUI_5                  0x03625e00
-
+#define PHY_BCM_OUI_6                  0xae025000
 
 #define PHY_BCM_FLAGS_MODE_COPPER      0x00000001
 #define PHY_BCM_FLAGS_MODE_1000BX      0x00000002
 
 #define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL      0x0000
 
+/*
+ * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
+ * BCM5482, and possibly some others.
+ */
+#define BCM_LED_SRC_LINKSPD1   0x0
+#define BCM_LED_SRC_LINKSPD2   0x1
+#define BCM_LED_SRC_XMITLED    0x2
+#define BCM_LED_SRC_ACTIVITYLED        0x3
+#define BCM_LED_SRC_FDXLED     0x4
+#define BCM_LED_SRC_SLAVE      0x5
+#define BCM_LED_SRC_INTR       0x6
+#define BCM_LED_SRC_QUALITY    0x7
+#define BCM_LED_SRC_RCVLED     0x8
+#define BCM_LED_SRC_MULTICOLOR1        0xa
+#define BCM_LED_SRC_OPENSHORT  0xb
+#define BCM_LED_SRC_OFF                0xe     /* Tied high */
+#define BCM_LED_SRC_ON         0xf     /* Tied low */
+
+
+/*
+ * BCM5482: Shadow registers
+ * Shadow values go into bits [14:10] of register 0x1c to select a shadow
+ * register to access.
+ */
+/* 00101: Spare Control Register 3 */
+#define BCM54XX_SHD_SCR3               0x05
+#define  BCM54XX_SHD_SCR3_DEF_CLK125   0x0001
+#define  BCM54XX_SHD_SCR3_DLLAPD_DIS   0x0002
+#define  BCM54XX_SHD_SCR3_TRDDAPD      0x0004
+
+/* 01010: Auto Power-Down */
+#define BCM54XX_SHD_APD                        0x0a
+#define  BCM54XX_SHD_APD_EN            0x0020
+
+#define BCM5482_SHD_LEDS1      0x0d    /* 01101: LED Selector 1 */
+                                       /* LED3 / ~LINKSPD[2] selector */
+#define BCM5482_SHD_LEDS1_LED3(src)    ((src & 0xf) << 4)
+                                       /* LED1 / ~LINKSPD[1] selector */
+#define BCM5482_SHD_LEDS1_LED1(src)    ((src & 0xf) << 0)
+#define BCM54XX_SHD_RGMII_MODE 0x0b    /* 01011: RGMII Mode Selector */
+#define BCM5482_SHD_SSD                0x14    /* 10100: Secondary SerDes control */
+#define BCM5482_SHD_SSD_LEDM   0x0008  /* SSD LED Mode enable */
+#define BCM5482_SHD_SSD_EN     0x0001  /* SSD enable */
+#define BCM5482_SHD_MODE       0x1f    /* 11111: Mode Control Register */
+#define BCM5482_SHD_MODE_1000BX        0x0001  /* Enable 1000BASE-X registers */
+
+
+/*
+ * EXPANSION SHADOW ACCESS REGISTERS.  (PHY REG 0x15, 0x16, and 0x17)
+ */
+#define MII_BCM54XX_EXP_AADJ1CH0               0x001f
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF   0x0100
+#define MII_BCM54XX_EXP_AADJ1CH3               0x601f
+#define  MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ     0x0002
+#define MII_BCM54XX_EXP_EXP08                  0x0F08
+#define  MII_BCM54XX_EXP_EXP08_RJCT_2MHZ       0x0001
+#define  MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE  0x0200
+#define MII_BCM54XX_EXP_EXP75                  0x0f75
+#define  MII_BCM54XX_EXP_EXP75_VDACCTRL                0x003c
+#define  MII_BCM54XX_EXP_EXP75_CM_OSC          0x0001
+#define MII_BCM54XX_EXP_EXP96                  0x0f96
+#define  MII_BCM54XX_EXP_EXP96_MYST            0x0010
+#define MII_BCM54XX_EXP_EXP97                  0x0f97
+#define  MII_BCM54XX_EXP_EXP97_MYST            0x0c0c
+
+/*
+ * BCM5482: Secondary SerDes registers
+ */
+#define BCM5482_SSD_1000BX_CTL         0x00    /* 1000BASE-X Control */
+#define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800  /* Power-down SSD */
+#define BCM5482_SSD_SGMII_SLAVE                0x15    /* SGMII Slave Register */
+#define BCM5482_SSD_SGMII_SLAVE_EN     0x0002  /* Slave mode enable */
+#define BCM5482_SSD_SGMII_SLAVE_AD     0x0001  /* Slave auto-detection */
+
+
+/*****************************************************************************/
+/* Fast Ethernet Transceiver definitions. */
+/*****************************************************************************/
+
+#define MII_BRCM_FET_INTREG            0x1a    /* Interrupt register */
+#define MII_BRCM_FET_IR_MASK           0x0100  /* Mask all interrupts */
+#define MII_BRCM_FET_IR_LINK_EN                0x0200  /* Link status change enable */
+#define MII_BRCM_FET_IR_SPEED_EN       0x0400  /* Link speed change enable */
+#define MII_BRCM_FET_IR_DUPLEX_EN      0x0800  /* Duplex mode change enable */
+#define MII_BRCM_FET_IR_ENABLE         0x4000  /* Interrupt enable */
+
+#define MII_BRCM_FET_BRCMTEST          0x1f    /* Brcm test register */
+#define MII_BRCM_FET_BT_SRE            0x0080  /* Shadow register enable */
+
+
+/*** Shadow register definitions ***/
+
+#define MII_BRCM_FET_SHDW_MISCCTRL     0x10    /* Shadow misc ctrl */
+#define MII_BRCM_FET_SHDW_MC_FAME      0x4000  /* Force Auto MDIX enable */
+
+#define MII_BRCM_FET_SHDW_AUXMODE4     0x1a    /* Auxiliary mode 4 */
+#define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003
+#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001
+
+#define MII_BRCM_FET_SHDW_AUXSTAT2     0x1b    /* Auxiliary status 2 */
+#define MII_BRCM_FET_SHDW_AS2_APDE     0x0020  /* Auto power down enable */
+
+/*
+ * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
+ * 0x1c shadow registers.
+ */
+static inline int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
+{
+       phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
+       return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
+}
+
+static inline int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow,
+                                      u16 val)
+{
+       return phy_write(phydev, MII_BCM54XX_SHD,
+                        MII_BCM54XX_SHD_WRITE |
+                        MII_BCM54XX_SHD_VAL(shadow) |
+                        MII_BCM54XX_SHD_DATA(val));
+}
+
+#define BRCM_CL45VEN_EEE_CONTROL       0x803d
+#define LPI_FEATURE_EN                 0x8000
+#define LPI_FEATURE_EN_DIG1000X                0x4000
+
 #endif /* _LINUX_BRCMPHY_H */
diff --git a/include/linux/cycx_x25.h b/include/linux/cycx_x25.h
deleted file mode 100644 (file)
index 362bf19..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifndef        _CYCX_X25_H
-#define        _CYCX_X25_H
-/*
-* cycx_x25.h   Cyclom X.25 firmware API definitions.
-*
-* Author:      Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Copyright:   (c) 1998-2003 Arnaldo Carvalho de Melo
-*
-* Based on sdla_x25.h by Gene Kozin <74604.152@compuserve.com>
-*
-*              This program is free software; you can redistribute it and/or
-*              modify it under the terms of the GNU General Public License
-*              as published by the Free Software Foundation; either version
-*              2 of the License, or (at your option) any later version.
-* ============================================================================
-* 2000/04/02   acme            dprintk and cycx_debug
-* 1999/01/03   acme            judicious use of data types
-* 1999/01/02   acme            #define X25_ACK_N3      0x4411
-* 1998/12/28   acme            cleanup: lot'o'things removed
-*                                       commands listed,
-*                                       TX25Cmd & TX25Config structs
-*                                       typedef'ed
-*/
-#ifndef PACKED
-#define PACKED __attribute__((packed))
-#endif 
-
-/* X.25 shared memory layout. */
-#define        X25_MBOX_OFFS   0x300   /* general mailbox block */
-#define        X25_RXMBOX_OFFS 0x340   /* receive mailbox */
-
-/* Debug */
-#define dprintk(level, format, a...) if (cycx_debug >= level) printk(format, ##a)
-
-extern unsigned int cycx_debug;
-
-/* Data Structures */
-/* X.25 Command Block. */
-struct cycx_x25_cmd {
-       u16 command;
-       u16 link;       /* values: 0 or 1 */
-       u16 len;        /* values: 0 thru 0x205 (517) */
-       u32 buf;
-} PACKED;
-
-/* Defines for the 'command' field. */
-#define X25_CONNECT_REQUEST             0x4401
-#define X25_CONNECT_RESPONSE            0x4402
-#define X25_DISCONNECT_REQUEST          0x4403
-#define X25_DISCONNECT_RESPONSE         0x4404
-#define X25_DATA_REQUEST                0x4405
-#define X25_ACK_TO_VC                  0x4406
-#define X25_INTERRUPT_RESPONSE          0x4407
-#define X25_CONFIG                      0x4408
-#define X25_CONNECT_INDICATION          0x4409
-#define X25_CONNECT_CONFIRM             0x440A
-#define X25_DISCONNECT_INDICATION       0x440B
-#define X25_DISCONNECT_CONFIRM          0x440C
-#define X25_DATA_INDICATION             0x440E
-#define X25_INTERRUPT_INDICATION        0x440F
-#define X25_ACK_FROM_VC                        0x4410
-#define X25_ACK_N3                     0x4411
-#define X25_CONNECT_COLLISION           0x4413
-#define X25_N3WIN                       0x4414
-#define X25_LINE_ON                     0x4415
-#define X25_LINE_OFF                    0x4416
-#define X25_RESET_REQUEST               0x4417
-#define X25_LOG                         0x4500
-#define X25_STATISTIC                   0x4600
-#define X25_TRACE                       0x4700
-#define X25_N2TRACEXC                   0x4702
-#define X25_N3TRACEXC                   0x4703
-
-/**
- *     struct cycx_x25_config - cyclom2x x25 firmware configuration
- *     @link - link number
- *     @speed - line speed
- *     @clock - internal/external
- *     @n2 - # of level 2 retransm.(values: 1 thru FF)
- *     @n2win - level 2 window (values: 1 thru 7)
- *     @n3win - level 3 window (values: 1 thru 7)
- *     @nvc - # of logical channels (values: 1 thru 64)
- *     @pktlen - level 3 packet length - log base 2 of size
- *     @locaddr - my address
- *     @remaddr - remote address
- *     @t1 - time, in seconds
- *     @t2 - time, in seconds
- *     @t21 - time, in seconds
- *     @npvc - # of permanent virt. circuits (1 thru nvc)
- *     @t23 - time, in seconds
- *     @flags - see dosx25.doc, in portuguese, for details
- */
-struct cycx_x25_config {
-       u8  link;
-       u8  speed;
-       u8  clock;
-       u8  n2;
-       u8  n2win;
-       u8  n3win;
-       u8  nvc;
-       u8  pktlen;
-       u8  locaddr;
-       u8  remaddr;
-       u16 t1;
-       u16 t2;
-       u8  t21;
-       u8  npvc;
-       u8  t23;
-       u8  flags;
-} PACKED;
-
-struct cycx_x25_stats {
-       u16 rx_crc_errors;
-       u16 rx_over_errors;
-       u16 n2_tx_frames;
-       u16 n2_rx_frames;
-       u16 tx_timeouts;
-       u16 rx_timeouts;
-       u16 n3_tx_packets;
-       u16 n3_rx_packets;
-       u16 tx_aborts;
-       u16 rx_aborts;
-} PACKED;
-#endif /* _CYCX_X25_H */
index 9c5529dc6d0776b83888a3e77c0268e00e8f6585..733980fce8e30d6ddd2b442d407a3fac877a759a 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/bitsperlong.h>
 
 #ifdef __KERNEL__
+u32 eth_get_headlen(void *data, unsigned int max_len);
 __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
 extern const struct header_ops eth_header_ops;
 
index e658229fee39c17ea8673eadcf7b49cfdce508e1..c1a2d60dfb82769c42b65dc2adc324517ed7e79c 100644 (file)
@@ -257,6 +257,10 @@ struct ethtool_ops {
                                     struct ethtool_eeprom *, u8 *);
        int     (*get_eee)(struct net_device *, struct ethtool_eee *);
        int     (*set_eee)(struct net_device *, struct ethtool_eee *);
+       int     (*get_tunable)(struct net_device *,
+                              const struct ethtool_tunable *, void *);
+       int     (*set_tunable)(struct net_device *,
+                              const struct ethtool_tunable *, const void *);
 
 
 };
index a5227ab8ccb17ebd4cf9ed7a55f80c352a2d6fb3..c78994593355979ad4ce9fa2273e32c3b31a8065 100644 (file)
@@ -9,6 +9,11 @@
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <uapi/linux/filter.h>
+#include <asm/cacheflush.h>
+
+struct sk_buff;
+struct sock;
+struct seccomp_data;
 
 /* Internally used and optimized filter representation with extended
  * instruction set based on top of classic BPF.
@@ -320,20 +325,23 @@ struct sock_fprog_kern {
        struct sock_filter      *filter;
 };
 
-struct sk_buff;
-struct sock;
-struct seccomp_data;
+struct bpf_work_struct {
+       struct bpf_prog *prog;
+       struct work_struct work;
+};
 
 struct bpf_prog {
+       u32                     pages;          /* Number of allocated pages */
        u32                     jited:1,        /* Is our filter JIT'ed? */
                                len:31;         /* Number of filter blocks */
        struct sock_fprog_kern  *orig_prog;     /* Original BPF program */
+       struct bpf_work_struct  *work;          /* Deferred free work struct */
        unsigned int            (*bpf_func)(const struct sk_buff *skb,
                                            const struct bpf_insn *filter);
+       /* Instructions for interpreter */
        union {
                struct sock_filter      insns[0];
                struct bpf_insn         insnsi[0];
-               struct work_struct      work;
        };
 };
 
@@ -353,6 +361,26 @@ static inline unsigned int bpf_prog_size(unsigned int proglen)
 
 #define bpf_classic_proglen(fprog) (fprog->len * sizeof(fprog->filter[0]))
 
+#ifdef CONFIG_DEBUG_SET_MODULE_RONX
+static inline void bpf_prog_lock_ro(struct bpf_prog *fp)
+{
+       set_memory_ro((unsigned long)fp, fp->pages);
+}
+
+static inline void bpf_prog_unlock_ro(struct bpf_prog *fp)
+{
+       set_memory_rw((unsigned long)fp, fp->pages);
+}
+#else
+static inline void bpf_prog_lock_ro(struct bpf_prog *fp)
+{
+}
+
+static inline void bpf_prog_unlock_ro(struct bpf_prog *fp)
+{
+}
+#endif /* CONFIG_DEBUG_SET_MODULE_RONX */
+
 int sk_filter(struct sock *sk, struct sk_buff *skb);
 
 void bpf_prog_select_runtime(struct bpf_prog *fp);
@@ -361,6 +389,17 @@ void bpf_prog_free(struct bpf_prog *fp);
 int bpf_convert_filter(struct sock_filter *prog, int len,
                       struct bpf_insn *new_prog, int *new_len);
 
+struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags);
+struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
+                                 gfp_t gfp_extra_flags);
+void __bpf_prog_free(struct bpf_prog *fp);
+
+static inline void bpf_prog_unlock_free(struct bpf_prog *fp)
+{
+       bpf_prog_unlock_ro(fp);
+       __bpf_prog_free(fp);
+}
+
 int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog);
 void bpf_prog_destroy(struct bpf_prog *fp);
 
@@ -450,7 +489,7 @@ static inline void bpf_jit_compile(struct bpf_prog *fp)
 
 static inline void bpf_jit_free(struct bpf_prog *fp)
 {
-       kfree(fp);
+       bpf_prog_unlock_free(fp);
 }
 #endif /* CONFIG_BPF_JIT */
 
diff --git a/include/linux/i82593.h b/include/linux/i82593.h
deleted file mode 100644 (file)
index afac5c7..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Definitions for Intel 82593 CSMA/CD Core LAN Controller
- * The definitions are taken from the 1992 users manual with Intel
- * order number 297125-001.
- *
- * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp
- *
- * Copyright 1994, Anders Klemets <klemets@it.kth.se>
- *
- * HISTORY
- * i82593.h,v
- * Revision 1.4  2005/11/4  09:15:00  baroniunas
- * Modified copyright with permission of author as follows:
- *
- *   "If I82539.H is the only file with my copyright statement
- *    that is included in the Source Forge project, then you have
- *    my approval to change the copyright statement to be a GPL
- *    license, in the way you proposed on October 10."
- *
- * Revision 1.1  1996/07/17 15:23:12  root
- * Initial revision
- *
- * Revision 1.3  1995/04/05  15:13:58  adj
- * Initial alpha release
- *
- * Revision 1.2  1994/06/16  23:57:31  klemets
- * Mirrored all the fields in the configuration block.
- *
- * Revision 1.1  1994/06/02  20:25:34  klemets
- * Initial revision
- *
- *
- */
-#ifndef        _I82593_H
-#define        _I82593_H
-
-/* Intel 82593 CSMA/CD Core LAN Controller */
-
-/* Port 0 Command Register definitions */
-
-/* Execution operations */
-#define OP0_NOP                        0       /* CHNL = 0 */
-#define OP0_SWIT_TO_PORT_1     0       /* CHNL = 1 */
-#define OP0_IA_SETUP           1
-#define OP0_CONFIGURE          2
-#define OP0_MC_SETUP           3
-#define OP0_TRANSMIT           4
-#define OP0_TDR                        5
-#define OP0_DUMP               6
-#define OP0_DIAGNOSE           7
-#define OP0_TRANSMIT_NO_CRC    9
-#define OP0_RETRANSMIT         12
-#define OP0_ABORT              13
-/* Reception operations */
-#define OP0_RCV_ENABLE         8
-#define OP0_RCV_DISABLE                10
-#define OP0_STOP_RCV           11
-/* Status pointer control operations */
-#define OP0_FIX_PTR            15      /* CHNL = 1 */
-#define OP0_RLS_PTR            15      /* CHNL = 0 */
-#define OP0_RESET              14
-
-#define CR0_CHNL               (1 << 4)        /* 0=Channel 0, 1=Channel 1 */
-#define CR0_STATUS_0           0x00
-#define CR0_STATUS_1           0x20
-#define CR0_STATUS_2           0x40
-#define CR0_STATUS_3           0x60
-#define CR0_INT_ACK            (1 << 7)        /* 0=No ack, 1=acknowledge */
-
-/* Port 0 Status Register definitions */
-
-#define SR0_NO_RESULT          0               /* dummy */
-#define SR0_EVENT_MASK         0x0f
-#define SR0_IA_SETUP_DONE      1
-#define SR0_CONFIGURE_DONE     2
-#define SR0_MC_SETUP_DONE      3
-#define SR0_TRANSMIT_DONE      4
-#define SR0_TDR_DONE           5
-#define SR0_DUMP_DONE          6
-#define SR0_DIAGNOSE_PASSED    7
-#define SR0_TRANSMIT_NO_CRC_DONE 9
-#define SR0_RETRANSMIT_DONE    12
-#define SR0_EXECUTION_ABORTED  13
-#define SR0_END_OF_FRAME       8
-#define SR0_RECEPTION_ABORTED  10
-#define SR0_DIAGNOSE_FAILED    15
-#define SR0_STOP_REG_HIT       11
-
-#define SR0_CHNL               (1 << 4)
-#define SR0_EXECUTION          (1 << 5)
-#define SR0_RECEPTION          (1 << 6)
-#define SR0_INTERRUPT          (1 << 7)
-#define SR0_BOTH_RX_TX         (SR0_EXECUTION | SR0_RECEPTION)
-
-#define SR3_EXEC_STATE_MASK    0x03
-#define SR3_EXEC_IDLE          0
-#define SR3_TX_ABORT_IN_PROGRESS 1
-#define SR3_EXEC_ACTIVE                2
-#define SR3_ABORT_IN_PROGRESS  3
-#define SR3_EXEC_CHNL          (1 << 2)
-#define SR3_STP_ON_NO_RSRC     (1 << 3)
-#define SR3_RCVING_NO_RSRC     (1 << 4)
-#define SR3_RCV_STATE_MASK     0x60
-#define SR3_RCV_IDLE           0x00
-#define SR3_RCV_READY          0x20
-#define SR3_RCV_ACTIVE         0x40
-#define SR3_RCV_STOP_IN_PROG   0x60
-#define SR3_RCV_CHNL           (1 << 7)
-
-/* Port 1 Command Register definitions */
-
-#define OP1_NOP                        0
-#define OP1_SWIT_TO_PORT_0     1
-#define OP1_INT_DISABLE                2
-#define OP1_INT_ENABLE         3
-#define OP1_SET_TS             5
-#define OP1_RST_TS             7
-#define OP1_POWER_DOWN         8
-#define OP1_RESET_RING_MNGMT   11
-#define OP1_RESET              14
-#define OP1_SEL_RST            15
-
-#define CR1_STATUS_4           0x00
-#define CR1_STATUS_5           0x20
-#define CR1_STATUS_6           0x40
-#define CR1_STOP_REG_UPDATE    (1 << 7)
-
-/* Receive frame status bits */
-
-#define        RX_RCLD                 (1 << 0)
-#define RX_IA_MATCH            (1 << 1)
-#define        RX_NO_AD_MATCH          (1 << 2)
-#define RX_NO_SFD              (1 << 3)
-#define RX_SRT_FRM             (1 << 7)
-#define RX_OVRRUN              (1 << 8)
-#define RX_ALG_ERR             (1 << 10)
-#define RX_CRC_ERR             (1 << 11)
-#define RX_LEN_ERR             (1 << 12)
-#define RX_RCV_OK              (1 << 13)
-#define RX_TYP_LEN             (1 << 15)
-
-/* Transmit status bits */
-
-#define TX_NCOL_MASK           0x0f
-#define TX_FRTL                        (1 << 4)
-#define TX_MAX_COL             (1 << 5)
-#define TX_HRT_BEAT            (1 << 6)
-#define TX_DEFER               (1 << 7)
-#define TX_UND_RUN             (1 << 8)
-#define TX_LOST_CTS            (1 << 9)
-#define TX_LOST_CRS            (1 << 10)
-#define TX_LTCOL               (1 << 11)
-#define TX_OK                  (1 << 13)
-#define TX_COLL                        (1 << 15)
-
-struct i82593_conf_block {
-  u_char fifo_limit : 4,
-        forgnesi   : 1,
-        fifo_32    : 1,
-        d6mod      : 1,
-        throttle_enb : 1;
-  u_char throttle   : 6,
-        cntrxint   : 1,
-        contin     : 1;
-  u_char addr_len   : 3,
-        acloc      : 1,
-        preamb_len : 2,
-        loopback   : 2;
-  u_char lin_prio   : 3,
-        tbofstop   : 1,
-        exp_prio   : 3,
-        bof_met    : 1;
-  u_char           : 4,
-        ifrm_spc   : 4;
-  u_char           : 5,
-        slottim_low : 3;
-  u_char slottim_hi : 3,
-                   : 1,
-        max_retr   : 4;
-  u_char prmisc     : 1,
-        bc_dis     : 1,
-                   : 1,
-        crs_1      : 1,
-        nocrc_ins  : 1,
-        crc_1632   : 1,
-                   : 1,
-        crs_cdt    : 1;
-  u_char cs_filter  : 3,
-        crs_src    : 1,
-        cd_filter  : 3,
-                   : 1;
-  u_char           : 2,
-        min_fr_len : 6;
-  u_char lng_typ    : 1,
-        lng_fld    : 1,
-        rxcrc_xf   : 1,
-        artx       : 1,
-        sarec      : 1,
-        tx_jabber  : 1,        /* why is this called max_len in the manual? */
-        hash_1     : 1,
-        lbpkpol    : 1;
-  u_char           : 6,
-        fdx        : 1,
-                   : 1;
-  u_char dummy_6    : 6,       /* supposed to be ones */
-        mult_ia    : 1,
-        dis_bof    : 1;
-  u_char dummy_1    : 1,       /* supposed to be one */
-        tx_ifs_retrig : 2,
-        mc_all     : 1,
-        rcv_mon    : 2,
-        frag_acpt  : 1,
-        tstrttrs   : 1;
-  u_char fretx     : 1,
-        runt_eop   : 1,
-        hw_sw_pin  : 1,
-        big_endn   : 1,
-        syncrqs    : 1,
-        sttlen     : 1,
-        tx_eop     : 1,
-        rx_eop     : 1;
-  u_char rbuf_size  : 5,
-        rcvstop    : 1,
-                   : 2;
-};
-
-#define I82593_MAX_MULTICAST_ADDRESSES 128     /* Hardware hashed filter */
-
-#endif /* _I82593_H */
index f47550d75f85fddd53186c92f0e1383c8f693b90..2c677afeea4782c96b79d0d8ede4846d87783b99 100644 (file)
@@ -39,6 +39,7 @@ static inline struct igmpv3_query *
 
 extern int sysctl_igmp_max_memberships;
 extern int sysctl_igmp_max_msf;
+extern int sysctl_igmp_qrv;
 
 struct ip_sf_socklist {
        unsigned int            sl_max;
index 511c6e0d21a9ab0045c9dd8b2dc7f9c488730279..1befd8df9cfc98d9dc190ed0db98f16f15810cfd 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/completion.h>
 #include <linux/radix-tree.h>
 #include <linux/cpu_rmap.h>
+#include <linux/crash_dump.h>
 
 #include <linux/atomic.h>
 
@@ -1278,7 +1279,7 @@ int mlx4_mr_rereg_mem_write(struct mlx4_dev *dev, struct mlx4_mr *mr,
 /* Returns true if running in low memory profile (kdump kernel) */
 static inline bool mlx4_low_memory_profile(void)
 {
-       return reset_devices;
+       return is_kdump_kernel();
 }
 
 #endif /* MLX4_DEVICE_H */
index c8e388e5fcccfa604d087ce33ccee5ace528e598..ba72f6baae1a9030318f6d769bc513e9682d9bf2 100644 (file)
@@ -1747,6 +1747,12 @@ struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev,
        return &dev->_tx[index];
 }
 
+static inline struct netdev_queue *skb_get_tx_queue(const struct net_device *dev,
+                                                   const struct sk_buff *skb)
+{
+       return netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
+}
+
 static inline void netdev_for_each_tx_queue(struct net_device *dev,
                                            void (*f)(struct net_device *,
                                                      struct netdev_queue *,
@@ -1781,24 +1787,13 @@ void dev_net_set(struct net_device *dev, struct net *net)
 #endif
 }
 
-static inline bool netdev_uses_dsa_tags(struct net_device *dev)
+static inline bool netdev_uses_dsa(struct net_device *dev)
 {
-#ifdef CONFIG_NET_DSA_TAG_DSA
+#ifdef CONFIG_NET_DSA
        if (dev->dsa_ptr != NULL)
-               return dsa_uses_dsa_tags(dev->dsa_ptr);
+               return dsa_uses_tagged_protocol(dev->dsa_ptr);
 #endif
-
-       return 0;
-}
-
-static inline bool netdev_uses_trailer_tags(struct net_device *dev)
-{
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-       if (dev->dsa_ptr != NULL)
-               return dsa_uses_trailer_tags(dev->dsa_ptr);
-#endif
-
-       return 0;
+       return false;
 }
 
 /**
@@ -1883,7 +1878,13 @@ struct napi_gro_cb {
        u16     proto;
 
        /* Used in udp_gro_receive */
-       u16     udp_mark;
+       u8      udp_mark:1;
+
+       /* GRO checksum is valid */
+       u8      csum_valid:1;
+
+       /* Number of checksums via CHECKSUM_UNNECESSARY */
+       u8      csum_cnt:3;
 
        /* used to support CHECKSUM_COMPLETE for tunneling protocols */
        __wsum  csum;
@@ -1927,6 +1928,13 @@ struct udp_offload {
        struct offload_callbacks callbacks;
 };
 
+struct dsa_device_ops {
+       netdev_tx_t (*xmit)(struct sk_buff *skb, struct net_device *dev);
+       int (*rcv)(struct sk_buff *skb, struct net_device *dev,
+                  struct packet_type *pt, struct net_device *orig_dev);
+};
+
+
 /* often modified stats are per cpu, other are shared (netdev->stats) */
 struct pcpu_sw_netstats {
        u64     rx_packets;
@@ -1982,6 +1990,7 @@ struct pcpu_sw_netstats {
 #define NETDEV_CHANGEUPPER     0x0015
 #define NETDEV_RESEND_IGMP     0x0016
 #define NETDEV_PRECHANGEMTU    0x0017 /* notify before mtu change happened */
+#define NETDEV_CHANGEINFODATA  0x0018
 
 int register_netdevice_notifier(struct notifier_block *nb);
 int unregister_netdevice_notifier(struct notifier_block *nb);
@@ -2153,11 +2162,97 @@ static inline void *skb_gro_network_header(struct sk_buff *skb)
 static inline void skb_gro_postpull_rcsum(struct sk_buff *skb,
                                        const void *start, unsigned int len)
 {
-       if (skb->ip_summed == CHECKSUM_COMPLETE)
+       if (NAPI_GRO_CB(skb)->csum_valid)
                NAPI_GRO_CB(skb)->csum = csum_sub(NAPI_GRO_CB(skb)->csum,
                                                  csum_partial(start, len, 0));
 }
 
+/* GRO checksum functions. These are logical equivalents of the normal
+ * checksum functions (in skbuff.h) except that they operate on the GRO
+ * offsets and fields in sk_buff.
+ */
+
+__sum16 __skb_gro_checksum_complete(struct sk_buff *skb);
+
+static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb,
+                                                     bool zero_okay,
+                                                     __sum16 check)
+{
+       return (skb->ip_summed != CHECKSUM_PARTIAL &&
+               NAPI_GRO_CB(skb)->csum_cnt == 0 &&
+               (!zero_okay || check));
+}
+
+static inline __sum16 __skb_gro_checksum_validate_complete(struct sk_buff *skb,
+                                                          __wsum psum)
+{
+       if (NAPI_GRO_CB(skb)->csum_valid &&
+           !csum_fold(csum_add(psum, NAPI_GRO_CB(skb)->csum)))
+               return 0;
+
+       NAPI_GRO_CB(skb)->csum = psum;
+
+       return __skb_gro_checksum_complete(skb);
+}
+
+static inline void skb_gro_incr_csum_unnecessary(struct sk_buff *skb)
+{
+       if (NAPI_GRO_CB(skb)->csum_cnt > 0) {
+               /* Consume a checksum from CHECKSUM_UNNECESSARY */
+               NAPI_GRO_CB(skb)->csum_cnt--;
+       } else {
+               /* Update skb for CHECKSUM_UNNECESSARY and csum_level when we
+                * verified a new top level checksum or an encapsulated one
+                * during GRO. This saves work if we fallback to normal path.
+                */
+               __skb_incr_checksum_unnecessary(skb);
+       }
+}
+
+#define __skb_gro_checksum_validate(skb, proto, zero_okay, check,      \
+                                   compute_pseudo)                     \
+({                                                                     \
+       __sum16 __ret = 0;                                              \
+       if (__skb_gro_checksum_validate_needed(skb, zero_okay, check))  \
+               __ret = __skb_gro_checksum_validate_complete(skb,       \
+                               compute_pseudo(skb, proto));            \
+       if (__ret)                                                      \
+               __skb_mark_checksum_bad(skb);                           \
+       else                                                            \
+               skb_gro_incr_csum_unnecessary(skb);                     \
+       __ret;                                                          \
+})
+
+#define skb_gro_checksum_validate(skb, proto, compute_pseudo)          \
+       __skb_gro_checksum_validate(skb, proto, false, 0, compute_pseudo)
+
+#define skb_gro_checksum_validate_zero_check(skb, proto, check,                \
+                                            compute_pseudo)            \
+       __skb_gro_checksum_validate(skb, proto, true, check, compute_pseudo)
+
+#define skb_gro_checksum_simple_validate(skb)                          \
+       __skb_gro_checksum_validate(skb, 0, false, 0, null_compute_pseudo)
+
+static inline bool __skb_gro_checksum_convert_check(struct sk_buff *skb)
+{
+       return (NAPI_GRO_CB(skb)->csum_cnt == 0 &&
+               !NAPI_GRO_CB(skb)->csum_valid);
+}
+
+static inline void __skb_gro_checksum_convert(struct sk_buff *skb,
+                                             __sum16 check, __wsum pseudo)
+{
+       NAPI_GRO_CB(skb)->csum = ~pseudo;
+       NAPI_GRO_CB(skb)->csum_valid = 1;
+}
+
+#define skb_gro_checksum_try_convert(skb, proto, check, compute_pseudo)        \
+do {                                                                   \
+       if (__skb_gro_checksum_convert_check(skb))                      \
+               __skb_gro_checksum_convert(skb, check,                  \
+                                          compute_pseudo(skb, proto)); \
+} while (0)
+
 static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
                                  unsigned short type,
                                  const void *daddr, const void *saddr,
@@ -2754,8 +2849,9 @@ 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);
-int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
-                       struct netdev_queue *txq);
+struct sk_buff *validate_xmit_skb(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);
 int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
 bool is_skb_forwardable(struct net_device *dev, struct sk_buff *skb);
@@ -3357,6 +3453,27 @@ int __init dev_proc_init(void);
 #define dev_proc_init() 0
 #endif
 
+static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops,
+                                             struct sk_buff *skb, struct net_device *dev,
+                                             bool more)
+{
+       skb->xmit_more = more ? 1 : 0;
+       return ops->ndo_start_xmit(skb, dev);
+}
+
+static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev,
+                                           struct netdev_queue *txq, bool more)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+       int rc;
+
+       rc = __netdev_start_xmit(ops, skb, dev, more);
+       if (rc == NETDEV_TX_OK)
+               txq_trans_update(txq);
+
+       return rc;
+}
+
 int netdev_class_create_file_ns(struct class_attribute *class_attr,
                                const void *ns);
 void netdev_class_remove_file_ns(struct class_attribute *class_attr,
diff --git a/include/linux/phonedev.h b/include/linux/phonedev.h
deleted file mode 100644 (file)
index 4269de9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __LINUX_PHONEDEV_H
-#define __LINUX_PHONEDEV_H
-
-#include <linux/types.h>
-
-#ifdef __KERNEL__
-
-#include <linux/poll.h>
-
-struct phone_device {
-       struct phone_device *next;
-       const struct file_operations *f_op;
-       int (*open) (struct phone_device *, struct file *);
-       int board;              /* Device private index */
-       int minor;
-};
-
-extern int phonedev_init(void);
-#define PHONE_MAJOR    100
-extern int phone_register_device(struct phone_device *, int unit);
-#define PHONE_UNIT_ANY -1
-extern void phone_unregister_device(struct phone_device *);
-
-#endif
-#endif
index ed39956b5613f98b95a5edd94bfb3f422abe71c7..d090cfcaa167fe33a4fc0e63562219a813f37c28 100644 (file)
@@ -597,6 +597,19 @@ static inline int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
                            MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff));
 }
 
+/**
+ * phy_read_mmd_indirect - reads data from the MMD registers
+ * @phydev: The PHY device bus
+ * @prtad: MMD Address
+ * @devad: MMD DEVAD
+ * @addr: PHY address on the MII bus
+ *
+ * Description: it reads data from the MMD registers (clause 22 to access to
+ * clause 45) of the specified phy address.
+ */
+int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
+                         int devad, int addr);
+
 /**
  * phy_read - Convenience function for reading a given PHY register
  * @phydev: the phy_device struct
@@ -668,6 +681,20 @@ static inline int phy_write_mmd(struct phy_device *phydev, int devad,
        return mdiobus_write(phydev->bus, phydev->addr, regnum, val);
 }
 
+/**
+ * phy_write_mmd_indirect - writes data to the MMD registers
+ * @phydev: The PHY device
+ * @prtad: MMD Address
+ * @devad: MMD DEVAD
+ * @addr: PHY address on the MII bus
+ * @data: data to write in the MMD register
+ *
+ * Description: Write data from the MMD registers of the specified
+ * phy address.
+ */
+void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
+                           int devad, int addr, u32 data);
+
 struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
                                     bool is_c45,
                                     struct phy_c45_device_ids *c45_ids);
index ae612acebb53d2f0bf121226afde877cb4d32f91..941138664c1db88c61e83fe53fdaf6fc31c73b7b 100644 (file)
@@ -18,6 +18,9 @@ extern int fixed_phy_register(unsigned int irq,
                              struct fixed_phy_status *status,
                              struct device_node *np);
 extern void fixed_phy_del(int phy_addr);
+extern int fixed_phy_set_link_update(struct phy_device *phydev,
+                       int (*link_update)(struct net_device *,
+                                          struct fixed_phy_status *));
 #else
 static inline int fixed_phy_add(unsigned int irq, int phy_id,
                                struct fixed_phy_status *status)
@@ -34,14 +37,12 @@ static inline int fixed_phy_del(int phy_addr)
 {
        return -ENODEV;
 }
-#endif /* CONFIG_FIXED_PHY */
-
-/*
- * This function issued only by fixed_phy-aware drivers, no need
- * protect it with #ifdef
- */
-extern int fixed_phy_set_link_update(struct phy_device *phydev,
+static inline int fixed_phy_set_link_update(struct phy_device *phydev,
                        int (*link_update)(struct net_device *,
-                                          struct fixed_phy_status *));
+                                          struct fixed_phy_status *))
+{
+       return -ENODEV;
+}
+#endif /* CONFIG_FIXED_PHY */
 
 #endif /* __PHY_FIXED_H */
index 57fbbffd77a0406fe57ce2abb5c2a24d819c45f9..b05856e16b75be8b7dea5015a5a6ff6afcb021eb 100644 (file)
@@ -26,7 +26,7 @@ unsigned int get_random_int(void);
 unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);
 
 u32 prandom_u32(void);
-void prandom_bytes(void *buf, int nbytes);
+void prandom_bytes(void *buf, size_t nbytes);
 void prandom_seed(u32 seed);
 void prandom_reseed_late(void);
 
@@ -35,7 +35,7 @@ struct rnd_state {
 };
 
 u32 prandom_u32_state(struct rnd_state *state);
-void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes);
+void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
 
 /**
  * prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro)
index 36826c0166c5f5af0d3a8e7601944f0e93946e09..fb298e9d6d3a8e75c280162f21e04c5112eebeac 100644 (file)
@@ -44,6 +44,7 @@ struct rhashtable;
  * @head_offset: Offset of rhash_head in struct to be hashed
  * @hash_rnd: Seed to use while hashing
  * @max_shift: Maximum number of shifts while expanding
+ * @min_shift: Minimum number of shifts while shrinking
  * @hashfn: Function to hash key
  * @obj_hashfn: Function to hash object
  * @grow_decision: If defined, may return true if table should expand
@@ -57,6 +58,7 @@ struct rhashtable_params {
        size_t                  head_offset;
        u32                     hash_rnd;
        size_t                  max_shift;
+       size_t                  min_shift;
        rht_hashfn_t            hashfn;
        rht_obj_hashfn_t        obj_hashfn;
        bool                    (*grow_decision)(const struct rhashtable *ht,
index abde271c18ae30989e6675708e70a6c9bb656300..07c9fdd0c1266a72f3c1a4536586b5109cbe4f27 100644 (file)
  *
  *   The hardware you're dealing with doesn't calculate the full checksum
  *   (as in CHECKSUM_COMPLETE), but it does parse headers and verify checksums
- *   for specific protocols e.g. TCP/UDP/SCTP, then, for such packets it will
- *   set CHECKSUM_UNNECESSARY if their checksums are okay. skb->csum is still
- *   undefined in this case though. It is a bad option, but, unfortunately,
- *   nowadays most vendors do this. Apparently with the secret goal to sell
- *   you new devices, when you will add new protocol to your host, f.e. IPv6 8)
+ *   for specific protocols. For such packets it will set CHECKSUM_UNNECESSARY
+ *   if their checksums are okay. skb->csum is still undefined in this case
+ *   though. It is a bad option, but, unfortunately, nowadays most vendors do
+ *   this. Apparently with the secret goal to sell you new devices, when you
+ *   will add new protocol to your host, f.e. IPv6 8)
+ *
+ *   CHECKSUM_UNNECESSARY is applicable to following protocols:
+ *     TCP: IPv6 and IPv4.
+ *     UDP: IPv4 and IPv6. A device may apply CHECKSUM_UNNECESSARY to a
+ *       zero UDP checksum for either IPv4 or IPv6, the networking stack
+ *       may perform further validation in this case.
+ *     GRE: only if the checksum is present in the header.
+ *     SCTP: indicates the CRC in SCTP header has been validated.
+ *
+ *   skb->csum_level indicates the number of consecutive checksums found in
+ *   the packet minus one that have been verified as CHECKSUM_UNNECESSARY.
+ *   For instance if a device receives an IPv6->UDP->GRE->IPv4->TCP packet
+ *   and a device is able to verify the checksums for UDP (possibly zero),
+ *   GRE (checksum flag is set), and TCP-- skb->csum_level would be set to
+ *   two. If the device were only able to verify the UDP checksum and not
+ *   GRE, either because it doesn't support GRE checksum of because GRE
+ *   checksum is bad, skb->csum_level would be set to zero (TCP checksum is
+ *   not considered in this case).
  *
  * CHECKSUM_COMPLETE:
  *
 #define CHECKSUM_COMPLETE      2
 #define CHECKSUM_PARTIAL       3
 
+/* Maximum value in skb->csum_level */
+#define SKB_MAX_CSUM_LEVEL     3
+
 #define SKB_DATA_ALIGN(X)      ALIGN(X, SMP_CACHE_BYTES)
 #define SKB_WITH_OVERHEAD(X)   \
        ((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
@@ -452,6 +473,7 @@ static inline u32 skb_mstamp_us_delta(const struct skb_mstamp *t1,
  *     @tc_verd: traffic control verdict
  *     @hash: the packet hash
  *     @queue_mapping: Queue mapping for multiqueue devices
+ *     @xmit_more: More SKBs are pending for this queue
  *     @ndisc_nodetype: router type (from link layer)
  *     @ooo_okay: allow the mapping of a socket to a queue to be changed
  *     @l4_hash: indicate hash is a canonical 4-tuple hash over transport
@@ -558,6 +580,7 @@ struct sk_buff {
 
        __u16                   queue_mapping;
        kmemcheck_bitfield_begin(flags2);
+       __u8                    xmit_more:1;
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        __u8                    ndisc_nodetype:2;
 #endif
@@ -569,16 +592,12 @@ struct sk_buff {
        __u8                    wifi_acked:1;
        __u8                    no_fcs:1;
        __u8                    head_frag:1;
-       /* Encapsulation protocol and NIC drivers should use
-        * this flag to indicate to each other if the skb contains
-        * encapsulated packet or not and maybe use the inner packet
-        * headers if needed
-        */
+       /* Indicates the inner headers are valid in the skbuff. */
        __u8                    encapsulation:1;
        __u8                    encap_hdr_csum:1;
        __u8                    csum_valid:1;
        __u8                    csum_complete_sw:1;
-       /* 2/4 bit hole (depending on ndisc_nodetype presence) */
+       /* 1/3 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
 #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
@@ -596,6 +615,12 @@ struct sk_buff {
                __u32           reserved_tailroom;
        };
 
+       kmemcheck_bitfield_begin(flags3);
+       __u8                    csum_level:2;
+       __u8                    csum_bad:1;
+       /* 13 bit hole */
+       kmemcheck_bitfield_end(flags3);
+
        __be16                  inner_protocol;
        __u16                   inner_transport_header;
        __u16                   inner_network_header;
@@ -1860,18 +1885,6 @@ static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len)
        return pskb_may_pull(skb, skb_network_offset(skb) + len);
 }
 
-static inline void skb_pop_rcv_encapsulation(struct sk_buff *skb)
-{
-       /* Only continue with checksum unnecessary if device indicated
-        * it is valid across encapsulation (skb->encapsulation was set).
-        */
-       if (skb->ip_summed == CHECKSUM_UNNECESSARY && !skb->encapsulation)
-               skb->ip_summed = CHECKSUM_NONE;
-
-       skb->encapsulation = 0;
-       skb->csum_valid = 0;
-}
-
 /*
  * CPUs often take a performance hit when accessing unaligned memory
  * locations. The actual performance hit varies, it can be small if the
@@ -2567,20 +2580,26 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
 __wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
                    __wsum csum);
 
-static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
-                                      int len, void *buffer)
+static inline void *__skb_header_pointer(const struct sk_buff *skb, int offset,
+                                        int len, void *data, int hlen, void *buffer)
 {
-       int hlen = skb_headlen(skb);
-
        if (hlen - offset >= len)
-               return skb->data + offset;
+               return data + offset;
 
-       if (skb_copy_bits(skb, offset, buffer, len) < 0)
+       if (!skb ||
+           skb_copy_bits(skb, offset, buffer, len) < 0)
                return NULL;
 
        return buffer;
 }
 
+static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
+                                      int len, void *buffer)
+{
+       return __skb_header_pointer(skb, offset, len, skb->data,
+                                   skb_headlen(skb), buffer);
+}
+
 /**
  *     skb_needs_linearize - check if we need to linearize a given skb
  *                           depending on the given device features.
@@ -2671,6 +2690,8 @@ static inline ktime_t net_invalid_timestamp(void)
        return ktime_set(0, 0);
 }
 
+struct sk_buff *skb_clone_sk(struct sk_buff *skb);
+
 #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
 
 void skb_clone_tx_timestamp(struct sk_buff *skb);
@@ -2786,6 +2807,42 @@ static inline __sum16 skb_checksum_complete(struct sk_buff *skb)
               0 : __skb_checksum_complete(skb);
 }
 
+static inline void __skb_decr_checksum_unnecessary(struct sk_buff *skb)
+{
+       if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+               if (skb->csum_level == 0)
+                       skb->ip_summed = CHECKSUM_NONE;
+               else
+                       skb->csum_level--;
+       }
+}
+
+static inline void __skb_incr_checksum_unnecessary(struct sk_buff *skb)
+{
+       if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+               if (skb->csum_level < SKB_MAX_CSUM_LEVEL)
+                       skb->csum_level++;
+       } else if (skb->ip_summed == CHECKSUM_NONE) {
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+               skb->csum_level = 0;
+       }
+}
+
+static inline void __skb_mark_checksum_bad(struct sk_buff *skb)
+{
+       /* Mark current checksum as bad (typically called from GRO
+        * path). In the case that ip_summed is CHECKSUM_NONE
+        * this must be the first checksum encountered in the packet.
+        * When ip_summed is CHECKSUM_UNNECESSARY, this is the first
+        * checksum after the last one validated. For UDP, a zero
+        * checksum can not be marked as bad.
+        */
+
+       if (skb->ip_summed == CHECKSUM_NONE ||
+           skb->ip_summed == CHECKSUM_UNNECESSARY)
+               skb->csum_bad = 1;
+}
+
 /* Check if we need to perform checksum complete validation.
  *
  * Returns true if checksum complete is needed, false otherwise
@@ -2797,6 +2854,7 @@ static inline bool __skb_checksum_validate_needed(struct sk_buff *skb,
 {
        if (skb_csum_unnecessary(skb) || (zero_okay && !check)) {
                skb->csum_valid = 1;
+               __skb_decr_checksum_unnecessary(skb);
                return false;
        }
 
@@ -2826,6 +2884,9 @@ static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb,
                        skb->csum_valid = 1;
                        return 0;
                }
+       } else if (skb->csum_bad) {
+               /* ip_summed == CHECKSUM_NONE in this case */
+               return 1;
        }
 
        skb->csum = psum;
@@ -2883,6 +2944,26 @@ static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto)
 #define skb_checksum_simple_validate(skb)                              \
        __skb_checksum_validate(skb, 0, true, false, 0, null_compute_pseudo)
 
+static inline bool __skb_checksum_convert_check(struct sk_buff *skb)
+{
+       return (skb->ip_summed == CHECKSUM_NONE &&
+               skb->csum_valid && !skb->csum_bad);
+}
+
+static inline void __skb_checksum_convert(struct sk_buff *skb,
+                                         __sum16 check, __wsum pseudo)
+{
+       skb->csum = ~pseudo;
+       skb->ip_summed = CHECKSUM_COMPLETE;
+}
+
+#define skb_checksum_try_convert(skb, proto, check, compute_pseudo)    \
+do {                                                                   \
+       if (__skb_checksum_convert_check(skb))                          \
+               __skb_checksum_convert(skb, check,                      \
+                                      compute_pseudo(skb, proto));     \
+} while (0)
+
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 void nf_conntrack_destroy(struct nf_conntrack *nfct);
 static inline void nf_conntrack_put(struct nf_conntrack *nfct)
@@ -3137,7 +3218,9 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
 
 int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
 
-u32 __skb_get_poff(const struct sk_buff *skb);
+u32 skb_get_poff(const struct sk_buff *skb);
+u32 __skb_get_poff(const struct sk_buff *skb, void *data,
+                  const struct flow_keys *keys, int hlen);
 
 /**
  * skb_head_is_locked - Determine if the skb->head is locked down
index fa5258f322e7998664a257e2d17f8397cd4346b2..e567f0dbf2828d24bff4ab38cf705c6e20034ebb 100644 (file)
@@ -276,7 +276,7 @@ struct tcp_sock {
        u32     retrans_stamp;  /* Timestamp of the last retransmit,
                                 * also used in SYN-SENT to remember stamp of
                                 * the first SYN. */
-       u32     undo_marker;    /* tracking retrans started here. */
+       u32     undo_marker;    /* snd_una upon a new recovery episode. */
        int     undo_retrans;   /* number of undoable retransmissions. */
        u32     total_retrans;  /* Total retransmits for entire connection */
 
index 247cfdcc4b08bbf377ff5819ebd02683806b0c83..ee3277593222cf314f9b030eec6ec09d0c38c4e4 100644 (file)
@@ -49,7 +49,11 @@ struct udp_sock {
        unsigned int     corkflag;      /* Cork is required */
        __u8             encap_type;    /* Is this an Encapsulation socket? */
        unsigned char    no_check6_tx:1,/* Send zero UDP6 checksums on TX? */
-                        no_check6_rx:1;/* Allow zero UDP6 checksums on RX? */
+                        no_check6_rx:1,/* Allow zero UDP6 checksums on RX? */
+                        convert_csum:1;/* On receive, convert checksum
+                                        * unnecessary to checksum complete
+                                        * if possible.
+                                        */
        /*
         * Following member retains the information to create a UDP header
         * when the socket is uncorked.
@@ -98,6 +102,16 @@ static inline bool udp_get_no_check6_rx(struct sock *sk)
        return udp_sk(sk)->no_check6_rx;
 }
 
+static inline void udp_set_convert_csum(struct sock *sk, bool val)
+{
+       udp_sk(sk)->convert_csum = val;
+}
+
+static inline bool udp_get_convert_csum(struct sock *sk)
+{
+       return udp_sk(sk)->convert_csum;
+}
+
 #define udp_portaddr_for_each_entry(__sk, node, list) \
        hlist_nulls_for_each_entry(__sk, node, list, __sk_common.skc_portaddr_node)
 
index fe0eab32ce76dd42845e8bc466c8bade5f429157..aeee28081245c9215f10badd611f58ba0124fcd0 100644 (file)
@@ -66,7 +66,7 @@ typedef s32 codel_tdiff_t;
 
 static inline codel_time_t codel_get_time(void)
 {
-       u64 ns = ktime_to_ns(ktime_get());
+       u64 ns = ktime_get_ns();
 
        return ns >> CODEL_SHIFT;
 }
index 6efce384451e56f16d8aab0847a6a7be4e94e0a0..97712927a9d2a5f50f09932ec54e7db01f25ef6b 100644 (file)
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+
+/* Not an official ethertype value, used only internally for DSA
+ * demultiplexing
+ */
+#define ETH_P_BRCMTAG          (ETH_P_XDSA + 1)
 
 #define DSA_MAX_SWITCHES       4
 #define DSA_MAX_PORTS          12
@@ -26,6 +34,12 @@ struct dsa_chip_data {
        struct device   *mii_bus;
        int             sw_addr;
 
+       /* Device tree node pointer for this specific switch chip
+        * used during switch setup in case additional properties
+        * and resources needs to be used
+        */
+       struct device_node *of_node;
+
        /*
         * The names of the switch's ports.  Use "cpu" to
         * designate the switch port that the cpu is connected to,
@@ -34,6 +48,7 @@ struct dsa_chip_data {
         * or any other string to indicate this is a physical port.
         */
        char            *port_names[DSA_MAX_PORTS];
+       struct device_node *port_dn[DSA_MAX_PORTS];
 
        /*
         * An array (with nr_chips elements) of which element [a]
@@ -59,6 +74,8 @@ struct dsa_platform_data {
        struct dsa_chip_data    *chip;
 };
 
+struct dsa_device_ops;
+
 struct dsa_switch_tree {
        /*
         * Configuration data for the platform device that owns
@@ -71,6 +88,7 @@ struct dsa_switch_tree {
         * protocol to use.
         */
        struct net_device       *master_netdev;
+       const struct dsa_device_ops     *ops;
        __be16                  tag_protocol;
 
        /*
@@ -119,6 +137,7 @@ struct dsa_switch {
         */
        u32                     dsa_port_mask;
        u32                     phys_port_mask;
+       u32                     phys_mii_mask;
        struct mii_bus          *slave_mii_bus;
        struct net_device       *ports[DSA_MAX_PORTS];
 };
@@ -169,6 +188,14 @@ struct dsa_switch_driver {
         */
        void    (*poll_link)(struct dsa_switch *ds);
 
+       /*
+        * Link state adjustment (called from libphy)
+        */
+       void    (*adjust_link)(struct dsa_switch *ds, int port,
+                               struct phy_device *phydev);
+       void    (*fixed_link_update)(struct dsa_switch *ds, int port,
+                               struct fixed_phy_status *st);
+
        /*
         * ethtool hardware statistics.
         */
@@ -186,21 +213,9 @@ static inline void *ds_to_priv(struct dsa_switch *ds)
        return (void *)(ds + 1);
 }
 
-/*
- * The original DSA tag format and some other tag formats have no
- * ethertype, which means that we need to add a little hack to the
- * networking receive path to make sure that received frames get
- * the right ->protocol assigned to them when one of those tag
- * formats is in use.
- */
-static inline bool dsa_uses_dsa_tags(struct dsa_switch_tree *dst)
-{
-       return !!(dst->tag_protocol == htons(ETH_P_DSA));
-}
-
-static inline bool dsa_uses_trailer_tags(struct dsa_switch_tree *dst)
+static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
 {
-       return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
+       return dst->tag_protocol != 0;
 }
 
 #endif
index 6667a054763adfad3407d59d0f6810fb13f56a14..7ee2df083542365e9d317fa1dbc2bbcfbbe34aa6 100644 (file)
@@ -27,7 +27,19 @@ struct flow_keys {
        u8 ip_proto;
 };
 
-bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow);
-__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto);
+bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
+                       void *data, __be16 proto, int nhoff, int hlen);
+static inline bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
+{
+       return __skb_flow_dissect(skb, flow, NULL, 0, 0, 0);
+}
+__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
+                           void *data, int hlen_proto);
+static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto)
+{
+       return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0);
+}
 u32 flow_hash_from_keys(struct flow_keys *keys);
+unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len,
+                          __be16 protocol);
 #endif
index db4a771b9ef3a6893bb2ae5d5f8692bfec5c571d..c8fd6112bd0b49f772557b4ec56c3737ad65594e 100644 (file)
@@ -364,6 +364,14 @@ static inline void inet_set_txhash(struct sock *sk)
        sk->sk_txhash = flow_hash_from_keys(&keys);
 }
 
+static inline __wsum inet_gro_compute_pseudo(struct sk_buff *skb, int proto)
+{
+       const struct iphdr *iph = skb_gro_network_header(skb);
+
+       return csum_tcpudp_nofold(iph->saddr, iph->daddr,
+                                 skb_gro_len(skb), proto, 0);
+}
+
 /*
  *     Map a multicast IP onto multicast MAC for type ethernet.
  */
index 55236cb711745fc76ef4c897bcf70e957b34611c..1a49b73f7f6e372381f9d1f3b7cffdc5649794c6 100644 (file)
@@ -48,6 +48,14 @@ static inline __wsum ip6_compute_pseudo(struct sk_buff *skb, int proto)
                                            skb->len, proto, 0));
 }
 
+static inline __wsum ip6_gro_compute_pseudo(struct sk_buff *skb, int proto)
+{
+       const struct ipv6hdr *iph = skb_gro_network_header(skb);
+
+       return ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr,
+                                           skb_gro_len(skb), proto, 0));
+}
+
 static __inline__ __sum16 tcp_v6_check(int len,
                                   const struct in6_addr *saddr,
                                   const struct in6_addr *daddr,
index 9922093f575e20fa2e53a903a68da7773469c600..dc9d2a27c3158115b927b3f4b93e5bd98799d749 100644 (file)
@@ -65,7 +65,8 @@ struct fnhe_hash_bucket {
        struct fib_nh_exception __rcu   *chain;
 };
 
-#define FNHE_HASH_SIZE         2048
+#define FNHE_HASH_SHIFT                11
+#define FNHE_HASH_SIZE         (1 << FNHE_HASH_SHIFT)
 #define FNHE_RECLAIM_DEPTH     5
 
 struct fib_nh {
@@ -87,7 +88,7 @@ struct fib_nh {
        int                     nh_saddr_genid;
        struct rtable __rcu * __percpu *nh_pcpu_rth_output;
        struct rtable __rcu     *nh_rth_input;
-       struct fnhe_hash_bucket *nh_exceptions;
+       struct fnhe_hash_bucket __rcu *nh_exceptions;
 };
 
 /*
index a2db816e8461cff706f23c725cf69372ab8bfcaa..7e247e9b87654bb99cabc2288d14ade201b3f965 100644 (file)
@@ -121,6 +121,7 @@ struct frag_hdr {
 
 /* sysctls */
 extern int sysctl_mld_max_msf;
+extern int sysctl_mld_qrv;
 
 #define _DEVINC(net, statname, modifier, idev, field)                  \
 ({                                                                     \
index ec030cd7661693d3812035d350e242f9b271edc4..8bbe626e9ece3d927047fa59b8717301c65c6130 100644 (file)
@@ -50,7 +50,7 @@ typedef long  psched_tdiff_t;
 
 static inline psched_time_t psched_get_time(void)
 {
-       return PSCHED_NS2TICKS(ktime_to_ns(ktime_get()));
+       return PSCHED_NS2TICKS(ktime_get_ns());
 }
 
 static inline psched_tdiff_t
index b9a5bd0ed9f3a6b7bc0d087b2b2ae5563b4a0304..049ab1b732a65e7059b8dd8826af042426101024 100644 (file)
@@ -1574,7 +1574,12 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
 void sock_wfree(struct sk_buff *skb);
 void skb_orphan_partial(struct sk_buff *skb);
 void sock_rfree(struct sk_buff *skb);
+void sock_efree(struct sk_buff *skb);
+#ifdef CONFIG_INET
 void sock_edemux(struct sk_buff *skb);
+#else
+#define sock_edemux(skb) sock_efree(skb)
+#endif
 
 int sock_setsockopt(struct socket *sock, int level, int op,
                    char __user *optval, unsigned int optlen);
@@ -2041,6 +2046,7 @@ void sk_stop_timer(struct sock *sk, struct timer_list *timer);
 int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
 
 int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb);
+struct sk_buff *sock_dequeue_err_skb(struct sock *sk);
 
 /*
  *     Recover an error report and clear atomically
index 590e01a476acc913464322e8e54a1858d78b3bf7..a4201ef216e83849678f700e89fd35e143c96368 100644 (file)
@@ -672,6 +672,12 @@ void tcp_send_window_probe(struct sock *sk);
  */
 #define tcp_time_stamp         ((__u32)(jiffies))
 
+static inline u32 tcp_skb_timestamp(const struct sk_buff *skb)
+{
+       return skb->skb_mstamp.stamp_jiffies;
+}
+
+
 #define tcp_flag_byte(th) (((u_int8_t *)th)[13])
 
 #define TCPHDR_FIN 0x01
@@ -698,7 +704,7 @@ struct tcp_skb_cb {
        } header;       /* For incoming frames          */
        __u32           seq;            /* Starting sequence number     */
        __u32           end_seq;        /* SEQ + FIN + SYN + datalen    */
-       __u32           when;           /* used to compute rtt's        */
+       __u32           tcp_tw_isn;     /* isn chosen by tcp_timewait_state_process() */
        __u8            tcp_flags;      /* TCP header flags. (tcp[13])  */
 
        __u8            sacked;         /* State flags for SACK/FACK.   */
index 70f941368ace488dc93f4e78f81b1dca935cd87f..16f4e80f0519c6dc0b180a9aec58c9231eda506e 100644 (file)
@@ -158,6 +158,24 @@ static inline __sum16 udp_v4_check(int len, __be32 saddr,
 void udp_set_csum(bool nocheck, struct sk_buff *skb,
                  __be32 saddr, __be32 daddr, int len);
 
+struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
+                                struct udphdr *uh);
+int udp_gro_complete(struct sk_buff *skb, int nhoff);
+
+static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb)
+{
+       struct udphdr *uh;
+       unsigned int hlen, off;
+
+       off  = skb_gro_offset(skb);
+       hlen = off + sizeof(*uh);
+       uh   = skb_gro_header_fast(skb, off);
+       if (skb_gro_header_hard(skb, hlen))
+               uh = skb_gro_header_slow(skb, hlen, off);
+
+       return uh;
+}
+
 /* hash routines shared between UDPv4/6 and UDP-Litev4/6 */
 static inline void udp_lib_hash(struct sock *sk)
 {
diff --git a/include/rxrpc/types.h b/include/rxrpc/types.h
deleted file mode 100644 (file)
index 30d48f6..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* types.h: Rx types
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_TYPES_H
-#define _LINUX_RXRPC_TYPES_H
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/spinlock.h>
-#include <linux/atomic.h>
-
-typedef uint32_t       rxrpc_seq_t;    /* Rx message sequence number */
-typedef uint32_t       rxrpc_serial_t; /* Rx message serial number */
-typedef __be32 rxrpc_seq_net_t; /* on-the-wire Rx message sequence number */
-typedef __be32 rxrpc_serial_net_t; /* on-the-wire Rx message serial number */
-
-struct rxrpc_call;
-struct rxrpc_connection;
-struct rxrpc_header;
-struct rxrpc_message;
-struct rxrpc_operation;
-struct rxrpc_peer;
-struct rxrpc_service;
-typedef struct rxrpc_timer rxrpc_timer_t;
-struct rxrpc_transport;
-
-typedef void (*rxrpc_call_attn_func_t)(struct rxrpc_call *call);
-typedef void (*rxrpc_call_error_func_t)(struct rxrpc_call *call);
-typedef void (*rxrpc_call_aemap_func_t)(struct rxrpc_call *call);
-
-#endif /* _LINUX_RXRPC_TYPES_H */
index e3c7a719c76b4a586c40da9506adaa095857ede4..7a364f2f3d3faf71a6febe653eed26d24bb79708 100644 (file)
@@ -209,6 +209,32 @@ struct ethtool_value {
        __u32   data;
 };
 
+enum tunable_id {
+       ETHTOOL_ID_UNSPEC,
+       ETHTOOL_RX_COPYBREAK,
+};
+
+enum tunable_type_id {
+       ETHTOOL_TUNABLE_UNSPEC,
+       ETHTOOL_TUNABLE_U8,
+       ETHTOOL_TUNABLE_U16,
+       ETHTOOL_TUNABLE_U32,
+       ETHTOOL_TUNABLE_U64,
+       ETHTOOL_TUNABLE_STRING,
+       ETHTOOL_TUNABLE_S8,
+       ETHTOOL_TUNABLE_S16,
+       ETHTOOL_TUNABLE_S32,
+       ETHTOOL_TUNABLE_S64,
+};
+
+struct ethtool_tunable {
+       __u32   cmd;
+       __u32   id;
+       __u32   type_id;
+       __u32   len;
+       void    *data[0];
+};
+
 /**
  * struct ethtool_regs - hardware register dump
  * @cmd: Command number = %ETHTOOL_GREGS
@@ -1152,6 +1178,8 @@ enum ethtool_sfeatures_retval_bits {
 
 #define ETHTOOL_GRSSH          0x00000046 /* Get RX flow hash configuration */
 #define ETHTOOL_SRSSH          0x00000047 /* Set RX flow hash configuration */
+#define ETHTOOL_GTUNABLE       0x00000048 /* Get tunable configuration */
+#define ETHTOOL_STUNABLE       0x00000049 /* Set tunable configuration */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
index 0f8210b8e0bc47ac0b7faab45a12ca6dcfbdf72d..aa63ed023c2b96b61b42231f9dd9b34b6ae46b66 100644 (file)
 #define ETH_P_PHONET   0x00F5          /* Nokia Phonet frames          */
 #define ETH_P_IEEE802154 0x00F6                /* IEEE802.15.4 frame           */
 #define ETH_P_CAIF     0x00F7          /* ST-Ericsson CAIF protocol    */
+#define ETH_P_XDSA     0x00F8          /* Multiplexed DSA protocol     */
 
 /*
  *     This is an Ethernet frame header.
index 7f0dbcbb34af1559657adea42b7c726f145a3986..b54bb2c2e494e086ee1e34ee39b8972fd9d6f344 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include <linux/filter.h>
 #include <linux/skbuff.h>
+#include <linux/vmalloc.h>
 #include <asm/unaligned.h>
 
 /* Registers */
@@ -63,6 +64,67 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns
        return NULL;
 }
 
+struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags)
+{
+       gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO |
+                         gfp_extra_flags;
+       struct bpf_work_struct *ws;
+       struct bpf_prog *fp;
+
+       size = round_up(size, PAGE_SIZE);
+       fp = __vmalloc(size, gfp_flags, PAGE_KERNEL);
+       if (fp == NULL)
+               return NULL;
+
+       ws = kmalloc(sizeof(*ws), GFP_KERNEL | gfp_extra_flags);
+       if (ws == NULL) {
+               vfree(fp);
+               return NULL;
+       }
+
+       fp->pages = size / PAGE_SIZE;
+       fp->work = ws;
+
+       return fp;
+}
+EXPORT_SYMBOL_GPL(bpf_prog_alloc);
+
+struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
+                                 gfp_t gfp_extra_flags)
+{
+       gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO |
+                         gfp_extra_flags;
+       struct bpf_prog *fp;
+
+       BUG_ON(fp_old == NULL);
+
+       size = round_up(size, PAGE_SIZE);
+       if (size <= fp_old->pages * PAGE_SIZE)
+               return fp_old;
+
+       fp = __vmalloc(size, gfp_flags, PAGE_KERNEL);
+       if (fp != NULL) {
+               memcpy(fp, fp_old, fp_old->pages * PAGE_SIZE);
+               fp->pages = size / PAGE_SIZE;
+
+               /* We keep fp->work from fp_old around in the new
+                * reallocated structure.
+                */
+               fp_old->work = NULL;
+               __bpf_prog_free(fp_old);
+       }
+
+       return fp;
+}
+EXPORT_SYMBOL_GPL(bpf_prog_realloc);
+
+void __bpf_prog_free(struct bpf_prog *fp)
+{
+       kfree(fp->work);
+       vfree(fp);
+}
+EXPORT_SYMBOL_GPL(__bpf_prog_free);
+
 /* Base function for offset calculation. Needs to go into .text section,
  * therefore keeping it non-static as well; will also be used by JITs
  * anyway later on, so do not let the compiler omit it.
@@ -523,12 +585,26 @@ void bpf_prog_select_runtime(struct bpf_prog *fp)
 
        /* Probe if internal BPF can be JITed */
        bpf_int_jit_compile(fp);
+       /* Lock whole bpf_prog as read-only */
+       bpf_prog_lock_ro(fp);
 }
 EXPORT_SYMBOL_GPL(bpf_prog_select_runtime);
 
-/* free internal BPF program */
+static void bpf_prog_free_deferred(struct work_struct *work)
+{
+       struct bpf_work_struct *ws;
+
+       ws = container_of(work, struct bpf_work_struct, work);
+       bpf_jit_free(ws->prog);
+}
+
+/* Free internal BPF program */
 void bpf_prog_free(struct bpf_prog *fp)
 {
-       bpf_jit_free(fp);
+       struct bpf_work_struct *ws = fp->work;
+
+       INIT_WORK(&ws->work, bpf_prog_free_deferred);
+       ws->prog = fp;
+       schedule_work(&ws->work);
 }
 EXPORT_SYMBOL_GPL(bpf_prog_free);
index c766ee54c0b18bd27f87d4fcfb7f3caa24781343..b64e238b553b9430361127b223d2a003b70b1c99 100644 (file)
@@ -18,6 +18,7 @@ unsigned long saved_max_pfn;
  * it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
  */
 unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
+EXPORT_SYMBOL_GPL(elfcorehdr_addr);
 
 /*
  * stores the size of elf header of crash image
index 44eb005c6695010e79a5041b837914a12c69aa45..84922befea8414468eafe1330ffc372ec9bdb8da 100644 (file)
@@ -395,16 +395,15 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
        if (!filter)
                goto free_prog;
 
-       filter->prog = kzalloc(bpf_prog_size(new_len),
-                              GFP_KERNEL|__GFP_NOWARN);
+       filter->prog = bpf_prog_alloc(bpf_prog_size(new_len), __GFP_NOWARN);
        if (!filter->prog)
                goto free_filter;
 
        ret = bpf_convert_filter(fp, fprog->len, filter->prog->insnsi, &new_len);
        if (ret)
                goto free_filter_prog;
-       kfree(fp);
 
+       kfree(fp);
        atomic_set(&filter->usage, 1);
        filter->prog->len = new_len;
 
@@ -413,7 +412,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
        return filter;
 
 free_filter_prog:
-       kfree(filter->prog);
+       __bpf_prog_free(filter->prog);
 free_filter:
        kfree(filter);
 free_prog:
index c9b6bf3afe0cbfd833f34304416ad21b5a7c94fc..0bee183fa18faaf3314ac37244469f111408cd26 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/jiffies.h>
 #include <linux/random.h>
 #include <linux/sched.h>
+#include <asm/unaligned.h>
 
 #ifdef CONFIG_RANDOM32_SELFTEST
 static void __init prandom_state_selftest(void);
@@ -96,27 +97,23 @@ EXPORT_SYMBOL(prandom_u32);
  *     This is used for pseudo-randomness with no outside seeding.
  *     For more random results, use prandom_bytes().
  */
-void prandom_bytes_state(struct rnd_state *state, void *buf, int bytes)
+void prandom_bytes_state(struct rnd_state *state, void *buf, size_t bytes)
 {
-       unsigned char *p = buf;
-       int i;
-
-       for (i = 0; i < round_down(bytes, sizeof(u32)); i += sizeof(u32)) {
-               u32 random = prandom_u32_state(state);
-               int j;
+       u8 *ptr = buf;
 
-               for (j = 0; j < sizeof(u32); j++) {
-                       p[i + j] = random;
-                       random >>= BITS_PER_BYTE;
-               }
+       while (bytes >= sizeof(u32)) {
+               put_unaligned(prandom_u32_state(state), (u32 *) ptr);
+               ptr += sizeof(u32);
+               bytes -= sizeof(u32);
        }
-       if (i < bytes) {
-               u32 random = prandom_u32_state(state);
 
-               for (; i < bytes; i++) {
-                       p[i] = random;
-                       random >>= BITS_PER_BYTE;
-               }
+       if (bytes > 0) {
+               u32 rem = prandom_u32_state(state);
+               do {
+                       *ptr++ = (u8) rem;
+                       bytes--;
+                       rem >>= BITS_PER_BYTE;
+               } while (bytes > 0);
        }
 }
 EXPORT_SYMBOL(prandom_bytes_state);
@@ -126,7 +123,7 @@ EXPORT_SYMBOL(prandom_bytes_state);
  *     @buf: where to copy the pseudo-random bytes to
  *     @bytes: the requested number of bytes
  */
-void prandom_bytes(void *buf, int bytes)
+void prandom_bytes(void *buf, size_t bytes)
 {
        struct rnd_state *state = &get_cpu_var(net_rand_state);
 
@@ -137,7 +134,7 @@ EXPORT_SYMBOL(prandom_bytes);
 
 static void prandom_warmup(struct rnd_state *state)
 {
-       /* Calling RNG ten times to satify recurrence condition */
+       /* Calling RNG ten times to satisfy recurrence condition */
        prandom_u32_state(state);
        prandom_u32_state(state);
        prandom_u32_state(state);
@@ -152,7 +149,7 @@ static void prandom_warmup(struct rnd_state *state)
 
 static u32 __extract_hwseed(void)
 {
-       u32 val = 0;
+       unsigned int val = 0;
 
        (void)(arch_get_random_seed_int(&val) ||
               arch_get_random_int(&val));
@@ -228,7 +225,7 @@ static void __prandom_timer(unsigned long dontcare)
        prandom_seed(entropy);
 
        /* reseed every ~60 seconds, in [40 .. 80) interval with slack */
-       expires = 40 + (prandom_u32() % 40);
+       expires = 40 + prandom_u32_max(40);
        seed_timer.expires = jiffies + msecs_to_jiffies(expires * MSEC_PER_SEC);
 
        add_timer(&seed_timer);
index a2c78810ebc1a64a95903645dec6d14eed6ba1b6..8dfec3f26d4c4729f7fb96247d17ba86a7bc90c2 100644 (file)
@@ -298,7 +298,7 @@ int rhashtable_shrink(struct rhashtable *ht, gfp_t flags)
 
        ASSERT_RHT_MUTEX(ht);
 
-       if (tbl->size <= HASH_MIN_SIZE)
+       if (ht->shift <= ht->p.min_shift)
                return 0;
 
        ntbl = bucket_table_alloc(tbl->size / 2, flags);
@@ -506,9 +506,10 @@ void *rhashtable_lookup_compare(const struct rhashtable *ht, u32 hash,
 }
 EXPORT_SYMBOL_GPL(rhashtable_lookup_compare);
 
-static size_t rounded_hashtable_size(unsigned int nelem)
+static size_t rounded_hashtable_size(struct rhashtable_params *params)
 {
-       return max(roundup_pow_of_two(nelem * 4 / 3), HASH_MIN_SIZE);
+       return max(roundup_pow_of_two(params->nelem_hint * 4 / 3),
+                  1UL << params->min_shift);
 }
 
 /**
@@ -566,8 +567,11 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params)
            (!params->key_len && !params->obj_hashfn))
                return -EINVAL;
 
+       params->min_shift = max_t(size_t, params->min_shift,
+                                 ilog2(HASH_MIN_SIZE));
+
        if (params->nelem_hint)
-               size = rounded_hashtable_size(params->nelem_hint);
+               size = rounded_hashtable_size(params);
 
        tbl = bucket_table_alloc(size, GFP_KERNEL);
        if (tbl == NULL)
index 89e0345733bd33db9bc9ab1f6184a1d376ec9c89..9a67456ba29a2ee24b63e3367dd7f58b3d2e922b 100644 (file)
@@ -1341,6 +1341,44 @@ static struct bpf_test tests[] = {
                { },
                { { 0, -1 } }
        },
+       {
+               "INT: shifts by register",
+               .u.insns_int = {
+                       BPF_MOV64_IMM(R0, -1234),
+                       BPF_MOV64_IMM(R1, 1),
+                       BPF_ALU32_REG(BPF_RSH, R0, R1),
+                       BPF_JMP_IMM(BPF_JEQ, R0, 0x7ffffd97, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R2, 1),
+                       BPF_ALU64_REG(BPF_LSH, R0, R2),
+                       BPF_MOV32_IMM(R4, -1234),
+                       BPF_JMP_REG(BPF_JEQ, R0, R4, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_ALU64_IMM(BPF_AND, R4, 63),
+                       BPF_ALU64_REG(BPF_LSH, R0, R4), /* R0 <= 46 */
+                       BPF_MOV64_IMM(R3, 47),
+                       BPF_ALU64_REG(BPF_ARSH, R0, R3),
+                       BPF_JMP_IMM(BPF_JEQ, R0, -617, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R2, 1),
+                       BPF_ALU64_REG(BPF_LSH, R4, R2), /* R4 = 46 << 1 */
+                       BPF_JMP_IMM(BPF_JEQ, R4, 92, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R4, 4),
+                       BPF_ALU64_REG(BPF_LSH, R4, R4), /* R4 = 4 << 4 */
+                       BPF_JMP_IMM(BPF_JEQ, R4, 64, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R4, 5),
+                       BPF_ALU32_REG(BPF_LSH, R4, R4), /* R4 = 5 << 5 */
+                       BPF_JMP_IMM(BPF_JEQ, R4, 160, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R0, -1),
+                       BPF_EXIT_INSN(),
+               },
+               INTERNAL,
+               { },
+               { { 0, -1 } }
+       },
        {
                "INT: DIV + ABS",
                .u.insns_int = {
@@ -1798,7 +1836,7 @@ static struct bpf_prog *generate_filter(int which, int *err)
                break;
 
        case INTERNAL:
-               fp = kzalloc(bpf_prog_size(flen), GFP_KERNEL);
+               fp = bpf_prog_alloc(bpf_prog_size(flen), 0);
                if (fp == NULL) {
                        pr_cont("UNEXPECTED_FAIL no memory left\n");
                        *err = -ENOMEM;
index e8e0e7a8a23d12029440b2f01b1c10b6e6326f27..0e982222d4255dbbc5ec9818e65af1145e086a03 100644 (file)
@@ -599,7 +599,7 @@ static netdev_tx_t mpc_send_packet(struct sk_buff *skb,
        }
 
 non_ip:
-       return mpc->old_ops->ndo_start_xmit(skb, dev);
+       return __netdev_start_xmit(mpc->old_ops, skb, dev, false);
 }
 
 static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
index 7751c92c8c57fc24b0c18e4d20a095bfa02e9ff0..648d79ccf46244a5769c1703361cf35db4cfeb09 100644 (file)
@@ -1822,7 +1822,7 @@ static void br_multicast_query_expired(struct net_bridge *br,
        if (query->startup_sent < br->multicast_startup_query_count)
                query->startup_sent++;
 
-       rcu_assign_pointer(querier, NULL);
+       RCU_INIT_POINTER(querier, NULL);
        br_multicast_send_query(br, NULL, query);
        spin_unlock(&br->multicast_lock);
 }
index ab9a16530c3684b2e1ff39f6f0587fb6e4aa7f24..3c6a967e583070f35f3b8c173c7314ac5030a0a3 100644 (file)
@@ -2485,52 +2485,6 @@ static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
        return 0;
 }
 
-struct dev_gso_cb {
-       void (*destructor)(struct sk_buff *skb);
-};
-
-#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
-
-static void dev_gso_skb_destructor(struct sk_buff *skb)
-{
-       struct dev_gso_cb *cb;
-
-       kfree_skb_list(skb->next);
-       skb->next = NULL;
-
-       cb = DEV_GSO_CB(skb);
-       if (cb->destructor)
-               cb->destructor(skb);
-}
-
-/**
- *     dev_gso_segment - Perform emulated hardware segmentation on skb.
- *     @skb: buffer to segment
- *     @features: device features as applicable to this skb
- *
- *     This function segments the given skb and stores the list of segments
- *     in skb->next.
- */
-static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
-{
-       struct sk_buff *segs;
-
-       segs = skb_gso_segment(skb, features);
-
-       /* Verifying header integrity only. */
-       if (!segs)
-               return 0;
-
-       if (IS_ERR(segs))
-               return PTR_ERR(segs);
-
-       skb->next = segs;
-       DEV_GSO_CB(skb)->destructor = skb->destructor;
-       skb->destructor = dev_gso_skb_destructor;
-
-       return 0;
-}
-
 /* If MPLS offload request, verify we are testing hardware MPLS features
  * instead of standard features for the netdev.
  */
@@ -2605,119 +2559,125 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(netif_skb_features);
 
-int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
-                       struct netdev_queue *txq)
+static int xmit_one(struct sk_buff *skb, struct net_device *dev,
+                   struct netdev_queue *txq, bool more)
 {
-       const struct net_device_ops *ops = dev->netdev_ops;
+       unsigned int len;
+       int rc;
+
+       if (!list_empty(&ptype_all))
+               dev_queue_xmit_nit(skb, dev);
+
+       len = skb->len;
+       trace_net_dev_start_xmit(skb, dev);
+       rc = netdev_start_xmit(skb, dev, txq, more);
+       trace_net_dev_xmit(skb, rc, dev, len);
+
+       return rc;
+}
+
+struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *dev,
+                                   struct netdev_queue *txq, int *ret)
+{
+       struct sk_buff *skb = first;
        int rc = NETDEV_TX_OK;
-       unsigned int skb_len;
 
-       if (likely(!skb->next)) {
-               netdev_features_t features;
+       while (skb) {
+               struct sk_buff *next = skb->next;
 
-               /*
-                * If device doesn't need skb->dst, release it right now while
-                * its hot in this cpu cache
-                */
-               if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
-                       skb_dst_drop(skb);
+               skb->next = NULL;
+               rc = xmit_one(skb, dev, txq, next != NULL);
+               if (unlikely(!dev_xmit_complete(rc))) {
+                       skb->next = next;
+                       goto out;
+               }
 
-               features = netif_skb_features(skb);
+               skb = next;
+               if (netif_xmit_stopped(txq) && skb) {
+                       rc = NETDEV_TX_BUSY;
+                       break;
+               }
+       }
 
-               if (vlan_tx_tag_present(skb) &&
-                   !vlan_hw_offload_capable(features, skb->vlan_proto)) {
-                       skb = __vlan_put_tag(skb, skb->vlan_proto,
-                                            vlan_tx_tag_get(skb));
-                       if (unlikely(!skb))
-                               goto out;
+out:
+       *ret = rc;
+       return skb;
+}
 
+struct sk_buff *validate_xmit_vlan(struct sk_buff *skb, netdev_features_t features)
+{
+       if (vlan_tx_tag_present(skb) &&
+           !vlan_hw_offload_capable(features, skb->vlan_proto)) {
+               skb = __vlan_put_tag(skb, skb->vlan_proto,
+                                    vlan_tx_tag_get(skb));
+               if (skb)
                        skb->vlan_tci = 0;
-               }
+       }
+       return skb;
+}
 
-               /* If encapsulation offload request, verify we are testing
-                * hardware encapsulation features instead of standard
-                * features for the netdev
-                */
-               if (skb->encapsulation)
-                       features &= dev->hw_enc_features;
+struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
+{
+       netdev_features_t features;
 
-               if (netif_needs_gso(skb, features)) {
-                       if (unlikely(dev_gso_segment(skb, features)))
-                               goto out_kfree_skb;
-                       if (skb->next)
-                               goto gso;
-               } else {
-                       if (skb_needs_linearize(skb, features) &&
-                           __skb_linearize(skb))
-                               goto out_kfree_skb;
+       if (skb->next)
+               return skb;
 
-                       /* If packet is not checksummed and device does not
-                        * support checksumming for this protocol, complete
-                        * checksumming here.
-                        */
-                       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                               if (skb->encapsulation)
-                                       skb_set_inner_transport_header(skb,
-                                               skb_checksum_start_offset(skb));
-                               else
-                                       skb_set_transport_header(skb,
-                                               skb_checksum_start_offset(skb));
-                               if (!(features & NETIF_F_ALL_CSUM) &&
-                                    skb_checksum_help(skb))
-                                       goto out_kfree_skb;
-                       }
-               }
+       /* If device doesn't need skb->dst, release it right now while
+        * its hot in this cpu cache
+        */
+       if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
+               skb_dst_drop(skb);
 
-               if (!list_empty(&ptype_all))
-                       dev_queue_xmit_nit(skb, dev);
+       features = netif_skb_features(skb);
+       skb = validate_xmit_vlan(skb, features);
+       if (unlikely(!skb))
+               goto out_null;
 
-               skb_len = skb->len;
-               trace_net_dev_start_xmit(skb, dev);
-               rc = ops->ndo_start_xmit(skb, dev);
-               trace_net_dev_xmit(skb, rc, dev, skb_len);
-               if (rc == NETDEV_TX_OK)
-                       txq_trans_update(txq);
-               return rc;
-       }
+       /* If encapsulation offload request, verify we are testing
+        * hardware encapsulation features instead of standard
+        * features for the netdev
+        */
+       if (skb->encapsulation)
+               features &= dev->hw_enc_features;
 
-gso:
-       do {
-               struct sk_buff *nskb = skb->next;
+       if (netif_needs_gso(skb, features)) {
+               struct sk_buff *segs;
 
-               skb->next = nskb->next;
-               nskb->next = NULL;
+               segs = skb_gso_segment(skb, features);
+               kfree_skb(skb);
+               if (IS_ERR(segs))
+                       segs = NULL;
+               skb = segs;
+       } else {
+               if (skb_needs_linearize(skb, features) &&
+                   __skb_linearize(skb))
+                       goto out_kfree_skb;
 
-               if (!list_empty(&ptype_all))
-                       dev_queue_xmit_nit(nskb, dev);
-
-               skb_len = nskb->len;
-               trace_net_dev_start_xmit(nskb, dev);
-               rc = ops->ndo_start_xmit(nskb, dev);
-               trace_net_dev_xmit(nskb, rc, dev, skb_len);
-               if (unlikely(rc != NETDEV_TX_OK)) {
-                       if (rc & ~NETDEV_TX_MASK)
-                               goto out_kfree_gso_skb;
-                       nskb->next = skb->next;
-                       skb->next = nskb;
-                       return rc;
+               /* If packet is not checksummed and device does not
+                * support checksumming for this protocol, complete
+                * checksumming here.
+                */
+               if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       if (skb->encapsulation)
+                               skb_set_inner_transport_header(skb,
+                                                              skb_checksum_start_offset(skb));
+                       else
+                               skb_set_transport_header(skb,
+                                                        skb_checksum_start_offset(skb));
+                       if (!(features & NETIF_F_ALL_CSUM) &&
+                           skb_checksum_help(skb))
+                               goto out_kfree_skb;
                }
-               txq_trans_update(txq);
-               if (unlikely(netif_xmit_stopped(txq) && skb->next))
-                       return NETDEV_TX_BUSY;
-       } while (skb->next);
-
-out_kfree_gso_skb:
-       if (likely(skb->next == NULL)) {
-               skb->destructor = DEV_GSO_CB(skb)->destructor;
-               consume_skb(skb);
-               return rc;
        }
+
+       return skb;
+
 out_kfree_skb:
        kfree_skb(skb);
-out:
-       return rc;
+out_null:
+       return NULL;
 }
-EXPORT_SYMBOL_GPL(dev_hard_start_xmit);
 
 static void qdisc_pkt_len_init(struct sk_buff *skb)
 {
@@ -2785,7 +2745,8 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
 
                qdisc_bstats_update(q, skb);
 
-               if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
+               skb = validate_xmit_skb(skb, dev);
+               if (skb && sch_direct_xmit(skb, q, dev, txq, root_lock)) {
                        if (unlikely(contended)) {
                                spin_unlock(&q->busylock);
                                contended = false;
@@ -2925,11 +2886,15 @@ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
                        if (__this_cpu_read(xmit_recursion) > RECURSION_LIMIT)
                                goto recursion_alert;
 
+                       skb = validate_xmit_skb(skb, dev);
+                       if (!skb)
+                               goto drop;
+
                        HARD_TX_LOCK(dev, txq, cpu);
 
                        if (!netif_xmit_stopped(txq)) {
                                __this_cpu_inc(xmit_recursion);
-                               rc = dev_hard_start_xmit(skb, dev, txq);
+                               skb = dev_hard_start_xmit(skb, dev, txq, &rc);
                                __this_cpu_dec(xmit_recursion);
                                if (dev_xmit_complete(rc)) {
                                        HARD_TX_UNLOCK(dev, txq);
@@ -2950,10 +2915,11 @@ recursion_alert:
        }
 
        rc = -ENETDOWN;
+drop:
        rcu_read_unlock_bh();
 
        atomic_long_inc(&dev->tx_dropped);
-       kfree_skb(skb);
+       kfree_skb_list(skb);
        return rc;
 out:
        rcu_read_unlock_bh();
@@ -3130,8 +3096,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
        }
 
        if (map) {
-               tcpu = map->cpus[((u64) hash * map->len) >> 32];
-
+               tcpu = map->cpus[reciprocal_scale(hash, map->len)];
                if (cpu_online(tcpu)) {
                        cpu = tcpu;
                        goto done;
@@ -3965,11 +3930,10 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
        if (!(skb->dev->features & NETIF_F_GRO))
                goto normal;
 
-       if (skb_is_gso(skb) || skb_has_frag_list(skb))
+       if (skb_is_gso(skb) || skb_has_frag_list(skb) || skb->csum_bad)
                goto normal;
 
        gro_list_prepare(napi, skb);
-       NAPI_GRO_CB(skb)->csum = skb->csum; /* Needed for CHECKSUM_COMPLETE */
 
        rcu_read_lock();
        list_for_each_entry_rcu(ptype, head, list) {
@@ -3983,6 +3947,22 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
                NAPI_GRO_CB(skb)->free = 0;
                NAPI_GRO_CB(skb)->udp_mark = 0;
 
+               /* Setup for GRO checksum validation */
+               switch (skb->ip_summed) {
+               case CHECKSUM_COMPLETE:
+                       NAPI_GRO_CB(skb)->csum = skb->csum;
+                       NAPI_GRO_CB(skb)->csum_valid = 1;
+                       NAPI_GRO_CB(skb)->csum_cnt = 0;
+                       break;
+               case CHECKSUM_UNNECESSARY:
+                       NAPI_GRO_CB(skb)->csum_cnt = skb->csum_level + 1;
+                       NAPI_GRO_CB(skb)->csum_valid = 0;
+                       break;
+               default:
+                       NAPI_GRO_CB(skb)->csum_cnt = 0;
+                       NAPI_GRO_CB(skb)->csum_valid = 0;
+               }
+
                pp = ptype->callbacks.gro_receive(&napi->gro_list, skb);
                break;
        }
@@ -4212,6 +4192,31 @@ gro_result_t napi_gro_frags(struct napi_struct *napi)
 }
 EXPORT_SYMBOL(napi_gro_frags);
 
+/* Compute the checksum from gro_offset and return the folded value
+ * after adding in any pseudo checksum.
+ */
+__sum16 __skb_gro_checksum_complete(struct sk_buff *skb)
+{
+       __wsum wsum;
+       __sum16 sum;
+
+       wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb), 0);
+
+       /* NAPI_GRO_CB(skb)->csum holds pseudo checksum */
+       sum = csum_fold(csum_add(NAPI_GRO_CB(skb)->csum, wsum));
+       if (likely(!sum)) {
+               if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
+                   !skb->csum_complete_sw)
+                       netdev_rx_csum_fault(skb->dev);
+       }
+
+       NAPI_GRO_CB(skb)->csum = wsum;
+       NAPI_GRO_CB(skb)->csum_valid = 1;
+
+       return sum;
+}
+EXPORT_SYMBOL(__skb_gro_checksum_complete);
+
 /*
  * net_rps_action_and_irq_enable sends any pending IPI's for rps.
  * Note: called with local irq disabled, but exits with local irq enabled.
index cf999e09bcd2c23654826b8c7e7b3d3dde2a7a59..72e899a3efdaadd82877550d4991b70424cff5a2 100644 (file)
@@ -365,11 +365,8 @@ void dev_load(struct net *net, const char *name)
        no_module = !dev;
        if (no_module && capable(CAP_NET_ADMIN))
                no_module = request_module("netdev-%s", name);
-       if (no_module && capable(CAP_SYS_MODULE)) {
-               if (!request_module("%s", name))
-                       pr_warn("Loading kernel module for a network device with CAP_SYS_MODULE (deprecated).  Use CAP_NET_ADMIN and alias netdev-%s instead.\n",
-                               name);
-       }
+       if (no_module && capable(CAP_SYS_MODULE))
+               request_module("%s", name);
 }
 EXPORT_SYMBOL(dev_load);
 
index 17cb912793fa5ef0d221abda0dfb447b216b4268..27e61b886520895995e6e946555b0d766bf4a55e 100644 (file)
@@ -1621,6 +1621,80 @@ static int ethtool_get_module_eeprom(struct net_device *dev,
                                      modinfo.eeprom_len);
 }
 
+static int ethtool_tunable_valid(const struct ethtool_tunable *tuna)
+{
+       switch (tuna->id) {
+       case ETHTOOL_RX_COPYBREAK:
+               if (tuna->len != sizeof(u32) ||
+                   tuna->type_id != ETHTOOL_TUNABLE_U32)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ethtool_get_tunable(struct net_device *dev, void __user *useraddr)
+{
+       int ret;
+       struct ethtool_tunable tuna;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       void *data;
+
+       if (!ops->get_tunable)
+               return -EOPNOTSUPP;
+       if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
+               return -EFAULT;
+       ret = ethtool_tunable_valid(&tuna);
+       if (ret)
+               return ret;
+       data = kmalloc(tuna.len, GFP_USER);
+       if (!data)
+               return -ENOMEM;
+       ret = ops->get_tunable(dev, &tuna, data);
+       if (ret)
+               goto out;
+       useraddr += sizeof(tuna);
+       ret = -EFAULT;
+       if (copy_to_user(useraddr, data, tuna.len))
+               goto out;
+       ret = 0;
+
+out:
+       kfree(data);
+       return ret;
+}
+
+static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr)
+{
+       int ret;
+       struct ethtool_tunable tuna;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       void *data;
+
+       if (!ops->set_tunable)
+               return -EOPNOTSUPP;
+       if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
+               return -EFAULT;
+       ret = ethtool_tunable_valid(&tuna);
+       if (ret)
+               return ret;
+       data = kmalloc(tuna.len, GFP_USER);
+       if (!data)
+               return -ENOMEM;
+       useraddr += sizeof(tuna);
+       ret = -EFAULT;
+       if (copy_from_user(data, useraddr, tuna.len))
+               goto out;
+       ret = ops->set_tunable(dev, &tuna, data);
+
+out:
+       kfree(data);
+       return ret;
+}
+
 /* The main entry point in this file.  Called from net/core/dev_ioctl.c */
 
 int dev_ethtool(struct net *net, struct ifreq *ifr)
@@ -1670,6 +1744,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GCHANNELS:
        case ETHTOOL_GET_TS_INFO:
        case ETHTOOL_GEEE:
+       case ETHTOOL_GTUNABLE:
                break;
        default:
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
@@ -1857,6 +1932,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GMODULEEEPROM:
                rc = ethtool_get_module_eeprom(dev, useraddr);
                break;
+       case ETHTOOL_GTUNABLE:
+               rc = ethtool_get_tunable(dev, useraddr);
+               break;
+       case ETHTOOL_STUNABLE:
+               rc = ethtool_set_tunable(dev, useraddr);
+               break;
        default:
                rc = -EOPNOTSUPP;
        }
index d814b8a89d0f2f65efb95858f2e4fe26bf5a4ca9..fa5b7d0f77acb1f8fbc2d3face7bd6a700394daf 100644 (file)
@@ -113,7 +113,7 @@ static unsigned int pkt_type_offset(void)
 
 static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
 {
-       return __skb_get_poff((struct sk_buff *)(unsigned long) ctx);
+       return skb_get_poff((struct sk_buff *)(unsigned long) ctx);
 }
 
 static u64 __skb_get_nlattr(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
@@ -933,7 +933,7 @@ static struct bpf_prog *bpf_migrate_filter(struct bpf_prog *fp)
 
        /* Expand fp for appending the new filter representation. */
        old_fp = fp;
-       fp = krealloc(old_fp, bpf_prog_size(new_len), GFP_KERNEL);
+       fp = bpf_prog_realloc(old_fp, bpf_prog_size(new_len), 0);
        if (!fp) {
                /* The old_fp is still around in case we couldn't
                 * allocate new memory, so uncharge on that one.
@@ -1013,7 +1013,7 @@ int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog)
        if (fprog->filter == NULL)
                return -EINVAL;
 
-       fp = kmalloc(bpf_prog_size(fprog->len), GFP_KERNEL);
+       fp = bpf_prog_alloc(bpf_prog_size(fprog->len), 0);
        if (!fp)
                return -ENOMEM;
 
@@ -1069,7 +1069,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        if (fprog->filter == NULL)
                return -EINVAL;
 
-       prog = kmalloc(bpf_fsize, GFP_KERNEL);
+       prog = bpf_prog_alloc(bpf_fsize, 0);
        if (!prog)
                return -ENOMEM;
 
index 5f362c1d03322692da59509c7d594f72255330b8..8560dea58803f947842e0be44d10464fb54127f6 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/if_pppox.h>
 #include <linux/ppp_defs.h>
 #include <net/flow_keys.h>
+#include <scsi/fc/fc_fcoe.h>
 
 /* copy saddr & daddr, possibly using 64bit load/store
  * Equivalent to :     flow->src = iph->saddr;
@@ -26,36 +27,61 @@ static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *i
 }
 
 /**
- * skb_flow_get_ports - extract the upper layer ports and return them
- * @skb: buffer to extract the ports from
+ * __skb_flow_get_ports - extract the upper layer ports and return them
+ * @skb: sk_buff to extract the ports from
  * @thoff: transport header offset
  * @ip_proto: protocol for which to get port offset
+ * @data: raw buffer pointer to the packet, if NULL use skb->data
+ * @hlen: packet header length, if @data is NULL use skb_headlen(skb)
  *
  * The function will try to retrieve the ports at offset thoff + poff where poff
  * is the protocol port offset returned from proto_ports_offset
  */
-__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto)
+__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
+                           void *data, int hlen)
 {
        int poff = proto_ports_offset(ip_proto);
 
+       if (!data) {
+               data = skb->data;
+               hlen = skb_headlen(skb);
+       }
+
        if (poff >= 0) {
                __be32 *ports, _ports;
 
-               ports = skb_header_pointer(skb, thoff + poff,
-                                          sizeof(_ports), &_ports);
+               ports = __skb_header_pointer(skb, thoff + poff,
+                                            sizeof(_ports), data, hlen, &_ports);
                if (ports)
                        return *ports;
        }
 
        return 0;
 }
-EXPORT_SYMBOL(skb_flow_get_ports);
+EXPORT_SYMBOL(__skb_flow_get_ports);
 
-bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
+/**
+ * __skb_flow_dissect - extract the flow_keys struct and return it
+ * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified
+ * @data: raw buffer pointer to the packet, if NULL use skb->data
+ * @proto: protocol for which to get the flow, if @data is NULL use skb->protocol
+ * @nhoff: network header offset, if @data is NULL use skb_network_offset(skb)
+ * @hlen: packet header length, if @data is NULL use skb_headlen(skb)
+ *
+ * The function will try to retrieve the struct flow_keys from either the skbuff
+ * or a raw buffer specified by the rest parameters
+ */
+bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
+                       void *data, __be16 proto, int nhoff, int hlen)
 {
-       int nhoff = skb_network_offset(skb);
        u8 ip_proto;
-       __be16 proto = skb->protocol;
+
+       if (!data) {
+               data = skb->data;
+               proto = skb->protocol;
+               nhoff = skb_network_offset(skb);
+               hlen = skb_headlen(skb);
+       }
 
        memset(flow, 0, sizeof(*flow));
 
@@ -65,7 +91,7 @@ again:
                const struct iphdr *iph;
                struct iphdr _iph;
 ip:
-               iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+               iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
                if (!iph || iph->ihl < 5)
                        return false;
                nhoff += iph->ihl * 4;
@@ -83,7 +109,7 @@ ip:
                __be32 flow_label;
 
 ipv6:
-               iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+               iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
                if (!iph)
                        return false;
 
@@ -92,6 +118,13 @@ ipv6:
                flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr);
                nhoff += sizeof(struct ipv6hdr);
 
+               /* skip the flow label processing if skb is NULL.  The
+                * assumption here is that if there is no skb we are not
+                * looking for flow info as much as we are length.
+                */
+               if (!skb)
+                       break;
+
                flow_label = ip6_flowlabel(iph);
                if (flow_label) {
                        /* Awesome, IPv6 packet has a flow label so we can
@@ -113,7 +146,7 @@ ipv6:
                const struct vlan_hdr *vlan;
                struct vlan_hdr _vlan;
 
-               vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan);
+               vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), data, hlen, &_vlan);
                if (!vlan)
                        return false;
 
@@ -126,7 +159,7 @@ ipv6:
                        struct pppoe_hdr hdr;
                        __be16 proto;
                } *hdr, _hdr;
-               hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
+               hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
                if (!hdr)
                        return false;
                proto = hdr->proto;
@@ -140,6 +173,9 @@ ipv6:
                        return false;
                }
        }
+       case htons(ETH_P_FCOE):
+               flow->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
+               /* fall through */
        default:
                return false;
        }
@@ -151,7 +187,7 @@ ipv6:
                        __be16 proto;
                } *hdr, _hdr;
 
-               hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
+               hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
                if (!hdr)
                        return false;
                /*
@@ -171,8 +207,9 @@ ipv6:
                                const struct ethhdr *eth;
                                struct ethhdr _eth;
 
-                               eth = skb_header_pointer(skb, nhoff,
-                                                        sizeof(_eth), &_eth);
+                               eth = __skb_header_pointer(skb, nhoff,
+                                                          sizeof(_eth),
+                                                          data, hlen, &_eth);
                                if (!eth)
                                        return false;
                                proto = eth->h_proto;
@@ -194,12 +231,12 @@ ipv6:
 
        flow->n_proto = proto;
        flow->ip_proto = ip_proto;
-       flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto);
+       flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, data, hlen);
        flow->thoff = (u16) nhoff;
 
        return true;
 }
-EXPORT_SYMBOL(skb_flow_dissect);
+EXPORT_SYMBOL(__skb_flow_dissect);
 
 static u32 hashrnd __read_mostly;
 static __always_inline void __flow_hash_secret_init(void)
@@ -286,30 +323,22 @@ u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb,
                qcount = dev->tc_to_txq[tc].count;
        }
 
-       return (u16) (((u64)skb_get_hash(skb) * qcount) >> 32) + qoffset;
+       return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset;
 }
 EXPORT_SYMBOL(__skb_tx_hash);
 
-/* __skb_get_poff() returns the offset to the payload as far as it could
- * be dissected. The main user is currently BPF, so that we can dynamically
- * truncate packets without needing to push actual payload to the user
- * space and can analyze headers only, instead.
- */
-u32 __skb_get_poff(const struct sk_buff *skb)
+u32 __skb_get_poff(const struct sk_buff *skb, void *data,
+                  const struct flow_keys *keys, int hlen)
 {
-       struct flow_keys keys;
-       u32 poff = 0;
-
-       if (!skb_flow_dissect(skb, &keys))
-               return 0;
+       u32 poff = keys->thoff;
 
-       poff += keys.thoff;
-       switch (keys.ip_proto) {
+       switch (keys->ip_proto) {
        case IPPROTO_TCP: {
                const struct tcphdr *tcph;
                struct tcphdr _tcph;
 
-               tcph = skb_header_pointer(skb, poff, sizeof(_tcph), &_tcph);
+               tcph = __skb_header_pointer(skb, poff, sizeof(_tcph),
+                                           data, hlen, &_tcph);
                if (!tcph)
                        return poff;
 
@@ -343,6 +372,21 @@ u32 __skb_get_poff(const struct sk_buff *skb)
        return poff;
 }
 
+/* skb_get_poff() returns the offset to the payload as far as it could
+ * be dissected. The main user is currently BPF, so that we can dynamically
+ * truncate packets without needing to push actual payload to the user
+ * space and can analyze headers only, instead.
+ */
+u32 skb_get_poff(const struct sk_buff *skb)
+{
+       struct flow_keys keys;
+
+       if (!skb_flow_dissect(skb, &keys))
+               return 0;
+
+       return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb));
+}
+
 static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
 {
 #ifdef CONFIG_XPS
@@ -359,9 +403,8 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
                        if (map->len == 1)
                                queue_index = map->queues[0];
                        else
-                               queue_index = map->queues[
-                                   ((u64)skb_get_hash(skb) * map->len) >> 32];
-
+                               queue_index = map->queues[reciprocal_scale(skb_get_hash(skb),
+                                                                          map->len)];
                        if (unlikely(queue_index >= dev->real_num_tx_queues))
                                queue_index = -1;
                }
index 907fb5e36c02e54794734abe4dc1225bf9af9c7d..e6645b4f330af1d16607ca0d6d9c9c95fd163dc6 100644 (file)
@@ -72,7 +72,6 @@ module_param(carrier_timeout, uint, 0644);
 static int netpoll_start_xmit(struct sk_buff *skb, struct net_device *dev,
                              struct netdev_queue *txq)
 {
-       const struct net_device_ops *ops = dev->netdev_ops;
        int status = NETDEV_TX_OK;
        netdev_features_t features;
 
@@ -92,9 +91,7 @@ static int netpoll_start_xmit(struct sk_buff *skb, struct net_device *dev,
                skb->vlan_tci = 0;
        }
 
-       status = ops->ndo_start_xmit(skb, dev);
-       if (status == NETDEV_TX_OK)
-               txq_trans_update(txq);
+       status = netdev_start_xmit(skb, dev, txq, false);
 
 out:
        return status;
@@ -116,7 +113,7 @@ static void queue_process(struct work_struct *work)
                        continue;
                }
 
-               txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
+               txq = skb_get_tx_queue(dev, skb);
 
                local_irq_save(flags);
                HARD_TX_LOCK(dev, txq, smp_processor_id());
index 8b849ddfef2e743676fe35642cd49d36188dd74d..21cb4839bc9782568ea58fd494c86127066b9fac 100644 (file)
 #define F_QUEUE_MAP_CPU (1<<14)        /* queue map mirrors smp_processor_id() */
 #define F_NODE          (1<<15)        /* Node memory alloc*/
 #define F_UDPCSUM       (1<<16)        /* Include UDP checksum */
+#define F_NO_TIMESTAMP  (1<<17)        /* Don't timestamp packets (default TS) */
 
 /* Thread control flag bits */
 #define T_STOP        (1<<0)   /* Stop run */
@@ -638,6 +639,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->flags & F_UDPCSUM)
                seq_puts(seq, "UDPCSUM  ");
 
+       if (pkt_dev->flags & F_NO_TIMESTAMP)
+               seq_puts(seq, "NO_TIMESTAMP  ");
+
        if (pkt_dev->flags & F_MPLS_RND)
                seq_puts(seq,  "MPLS_RND  ");
 
@@ -1243,6 +1247,9 @@ static ssize_t pktgen_if_write(struct file *file,
                else if (strcmp(f, "!UDPCSUM") == 0)
                        pkt_dev->flags &= ~F_UDPCSUM;
 
+               else if (strcmp(f, "NO_TIMESTAMP") == 0)
+                       pkt_dev->flags |= F_NO_TIMESTAMP;
+
                else {
                        sprintf(pg_result,
                                "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
@@ -1251,6 +1258,7 @@ static ssize_t pktgen_if_write(struct file *file,
                                "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, "
                                "MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, "
                                "QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, "
+                               "NO_TIMESTAMP, "
 #ifdef CONFIG_XFRM
                                "IPSEC, "
 #endif
@@ -2685,9 +2693,14 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
        pgh->pgh_magic = htonl(PKTGEN_MAGIC);
        pgh->seq_num = htonl(pkt_dev->seq_num);
 
-       do_gettimeofday(&timestamp);
-       pgh->tv_sec = htonl(timestamp.tv_sec);
-       pgh->tv_usec = htonl(timestamp.tv_usec);
+       if (pkt_dev->flags & F_NO_TIMESTAMP) {
+               pgh->tv_sec = 0;
+               pgh->tv_usec = 0;
+       } else {
+               do_gettimeofday(&timestamp);
+               pgh->tv_sec = htonl(timestamp.tv_sec);
+               pgh->tv_usec = htonl(timestamp.tv_usec);
+       }
 }
 
 static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
@@ -3285,10 +3298,7 @@ static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
 static void pktgen_xmit(struct pktgen_dev *pkt_dev)
 {
        struct net_device *odev = pkt_dev->odev;
-       netdev_tx_t (*xmit)(struct sk_buff *, struct net_device *)
-               = odev->netdev_ops->ndo_start_xmit;
        struct netdev_queue *txq;
-       u16 queue_map;
        int ret;
 
        /* If device is offline, then don't send */
@@ -3326,8 +3336,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
        if (pkt_dev->delay && pkt_dev->last_ok)
                spin(pkt_dev, pkt_dev->next_tx);
 
-       queue_map = skb_get_queue_mapping(pkt_dev->skb);
-       txq = netdev_get_tx_queue(odev, queue_map);
+       txq = skb_get_tx_queue(odev, pkt_dev->skb);
 
        local_bh_disable();
 
@@ -3339,11 +3348,10 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
                goto unlock;
        }
        atomic_inc(&(pkt_dev->skb->users));
-       ret = (*xmit)(pkt_dev->skb, odev);
+       ret = netdev_start_xmit(pkt_dev->skb, odev, txq, false);
 
        switch (ret) {
        case NETDEV_TX_OK:
-               txq_trans_update(txq);
                pkt_dev->last_ok = 1;
                pkt_dev->sofar++;
                pkt_dev->seq_num++;
index f0493e3b7471099f0245b0ea0c4b52de4a03034f..a6882686ca3a10fc3be7ced6299dc7385ffd239d 100644 (file)
@@ -1481,9 +1481,12 @@ static int do_set_master(struct net_device *dev, int ifindex)
        return 0;
 }
 
+#define DO_SETLINK_MODIFIED    0x01
+/* notify flag means notify + modified. */
+#define DO_SETLINK_NOTIFY      0x03
 static int do_setlink(const struct sk_buff *skb,
                      struct net_device *dev, struct ifinfomsg *ifm,
-                     struct nlattr **tb, char *ifname, int modified)
+                     struct nlattr **tb, char *ifname, int status)
 {
        const struct net_device_ops *ops = dev->netdev_ops;
        int err;
@@ -1502,7 +1505,7 @@ static int do_setlink(const struct sk_buff *skb,
                put_net(net);
                if (err)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_MAP]) {
@@ -1531,7 +1534,7 @@ static int do_setlink(const struct sk_buff *skb,
                if (err < 0)
                        goto errout;
 
-               modified = 1;
+               status |= DO_SETLINK_NOTIFY;
        }
 
        if (tb[IFLA_ADDRESS]) {
@@ -1551,19 +1554,19 @@ static int do_setlink(const struct sk_buff *skb,
                kfree(sa);
                if (err)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_MTU]) {
                err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
                if (err < 0)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_GROUP]) {
                dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP]));
-               modified = 1;
+               status |= DO_SETLINK_NOTIFY;
        }
 
        /*
@@ -1575,7 +1578,7 @@ static int do_setlink(const struct sk_buff *skb,
                err = dev_change_name(dev, ifname);
                if (err < 0)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_IFALIAS]) {
@@ -1583,7 +1586,7 @@ static int do_setlink(const struct sk_buff *skb,
                                    nla_len(tb[IFLA_IFALIAS]));
                if (err < 0)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_NOTIFY;
        }
 
        if (tb[IFLA_BROADCAST]) {
@@ -1601,25 +1604,35 @@ static int do_setlink(const struct sk_buff *skb,
                err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]));
                if (err)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_CARRIER]) {
                err = dev_change_carrier(dev, nla_get_u8(tb[IFLA_CARRIER]));
                if (err)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
-       if (tb[IFLA_TXQLEN])
-               dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
+       if (tb[IFLA_TXQLEN]) {
+               unsigned long value = nla_get_u32(tb[IFLA_TXQLEN]);
+
+               if (dev->tx_queue_len ^ value)
+                       status |= DO_SETLINK_NOTIFY;
+
+               dev->tx_queue_len = value;
+       }
 
        if (tb[IFLA_OPERSTATE])
                set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
 
        if (tb[IFLA_LINKMODE]) {
+               unsigned char value = nla_get_u8(tb[IFLA_LINKMODE]);
+
                write_lock_bh(&dev_base_lock);
-               dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
+               if (dev->link_mode ^ value)
+                       status |= DO_SETLINK_NOTIFY;
+               dev->link_mode = value;
                write_unlock_bh(&dev_base_lock);
        }
 
@@ -1634,7 +1647,7 @@ static int do_setlink(const struct sk_buff *skb,
                        err = do_setvfinfo(dev, attr);
                        if (err < 0)
                                goto errout;
-                       modified = 1;
+                       status |= DO_SETLINK_NOTIFY;
                }
        }
        err = 0;
@@ -1664,7 +1677,7 @@ static int do_setlink(const struct sk_buff *skb,
                        err = ops->ndo_set_vf_port(dev, vf, port);
                        if (err < 0)
                                goto errout;
-                       modified = 1;
+                       status |= DO_SETLINK_NOTIFY;
                }
        }
        err = 0;
@@ -1682,7 +1695,7 @@ static int do_setlink(const struct sk_buff *skb,
                        err = ops->ndo_set_vf_port(dev, PORT_SELF_VF, port);
                if (err < 0)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_NOTIFY;
        }
 
        if (tb[IFLA_AF_SPEC]) {
@@ -1699,15 +1712,20 @@ static int do_setlink(const struct sk_buff *skb,
                        if (err < 0)
                                goto errout;
 
-                       modified = 1;
+                       status |= DO_SETLINK_NOTIFY;
                }
        }
        err = 0;
 
 errout:
-       if (err < 0 && modified)
-               net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n",
-                                    dev->name);
+       if (status & DO_SETLINK_MODIFIED) {
+               if (status & DO_SETLINK_NOTIFY)
+                       netdev_state_change(dev);
+
+               if (err < 0)
+                       net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n",
+                                            dev->name);
+       }
 
        return err;
 }
@@ -1989,7 +2007,7 @@ replay:
                }
 
                if (dev) {
-                       int modified = 0;
+                       int status = 0;
 
                        if (nlh->nlmsg_flags & NLM_F_EXCL)
                                return -EEXIST;
@@ -2004,7 +2022,7 @@ replay:
                                err = ops->changelink(dev, tb, data);
                                if (err < 0)
                                        return err;
-                               modified = 1;
+                               status |= DO_SETLINK_NOTIFY;
                        }
 
                        if (linkinfo[IFLA_INFO_SLAVE_DATA]) {
@@ -2015,10 +2033,10 @@ replay:
                                                              tb, slave_data);
                                if (err < 0)
                                        return err;
-                               modified = 1;
+                               status |= DO_SETLINK_NOTIFY;
                        }
 
-                       return do_setlink(skb, dev, ifm, tb, ifname, modified);
+                       return do_setlink(skb, dev, ifm, tb, ifname, status);
                }
 
                if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
index ba71212f0251218c3c41599838e36aa8e169fea7..51dd3193a33ebb26ea3c008e752d1f2832f791d8 100644 (file)
@@ -35,7 +35,7 @@ static u32 seq_scale(u32 seq)
         *      overlaps less than one time per MSL (2 minutes).
         *      Choosing a clock of 64 ns period is OK. (period of 274 s)
         */
-       return seq + (ktime_to_ns(ktime_get_real()) >> 6);
+       return seq + (ktime_get_real_ns() >> 6);
 }
 #endif
 
@@ -135,7 +135,7 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
        md5_transform(hash, net_secret);
 
        seq = hash[0] | (((u64)hash[1]) << 32);
-       seq += ktime_to_ns(ktime_get_real());
+       seq += ktime_get_real_ns();
        seq &= (1ull << 48) - 1;
 
        return seq;
@@ -163,7 +163,7 @@ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
        md5_transform(hash, secret);
 
        seq = hash[0] | (((u64)hash[1]) << 32);
-       seq += ktime_to_ns(ktime_get_real());
+       seq += ktime_get_real_ns();
        seq &= (1ull << 48) - 1;
 
        return seq;
index da1378a3e2c72e0f23e9e21581dfd2ece5491d09..a18dfb02d94492647a50a88797e47d0f698ad62b 100644 (file)
@@ -3491,32 +3491,53 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_queue_err_skb);
 
-void __skb_tstamp_tx(struct sk_buff *orig_skb,
-                    struct skb_shared_hwtstamps *hwtstamps,
-                    struct sock *sk, int tstype)
+struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
 {
-       struct sock_exterr_skb *serr;
-       struct sk_buff *skb;
-       int err;
+       struct sk_buff_head *q = &sk->sk_error_queue;
+       struct sk_buff *skb, *skb_next;
+       int err = 0;
 
-       if (!sk)
-               return;
+       spin_lock_bh(&q->lock);
+       skb = __skb_dequeue(q);
+       if (skb && (skb_next = skb_peek(q)))
+               err = SKB_EXT_ERR(skb_next)->ee.ee_errno;
+       spin_unlock_bh(&q->lock);
 
-       if (hwtstamps) {
-               *skb_hwtstamps(orig_skb) =
-                       *hwtstamps;
-       } else {
-               /*
-                * no hardware time stamps available,
-                * so keep the shared tx_flags and only
-                * store software time stamp
-                */
-               orig_skb->tstamp = ktime_get_real();
+       sk->sk_err = err;
+       if (err)
+               sk->sk_error_report(sk);
+
+       return skb;
+}
+EXPORT_SYMBOL(sock_dequeue_err_skb);
+
+struct sk_buff *skb_clone_sk(struct sk_buff *skb)
+{
+       struct sock *sk = skb->sk;
+       struct sk_buff *clone;
+
+       if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
+               return NULL;
+
+       clone = skb_clone(skb, GFP_ATOMIC);
+       if (!clone) {
+               sock_put(sk);
+               return NULL;
        }
 
-       skb = skb_clone(orig_skb, GFP_ATOMIC);
-       if (!skb)
-               return;
+       clone->sk = sk;
+       clone->destructor = sock_efree;
+
+       return clone;
+}
+EXPORT_SYMBOL(skb_clone_sk);
+
+static void __skb_complete_tx_timestamp(struct sk_buff *skb,
+                                       struct sock *sk,
+                                       int tstype)
+{
+       struct sock_exterr_skb *serr;
+       int err;
 
        serr = SKB_EXT_ERR(skb);
        memset(serr, 0, sizeof(*serr));
@@ -3534,6 +3555,42 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
        if (err)
                kfree_skb(skb);
 }
+
+void skb_complete_tx_timestamp(struct sk_buff *skb,
+                              struct skb_shared_hwtstamps *hwtstamps)
+{
+       struct sock *sk = skb->sk;
+
+       /* take a reference to prevent skb_orphan() from freeing the socket */
+       sock_hold(sk);
+
+       *skb_hwtstamps(skb) = *hwtstamps;
+       __skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND);
+
+       sock_put(sk);
+}
+EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
+
+void __skb_tstamp_tx(struct sk_buff *orig_skb,
+                    struct skb_shared_hwtstamps *hwtstamps,
+                    struct sock *sk, int tstype)
+{
+       struct sk_buff *skb;
+
+       if (!sk)
+               return;
+
+       if (hwtstamps)
+               *skb_hwtstamps(orig_skb) = *hwtstamps;
+       else
+               orig_skb->tstamp = ktime_get_real();
+
+       skb = skb_clone(orig_skb, GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       __skb_complete_tx_timestamp(skb, sk, tstype);
+}
 EXPORT_SYMBOL_GPL(__skb_tstamp_tx);
 
 void skb_tstamp_tx(struct sk_buff *orig_skb,
index d372b4bd3f996dd3248e86748b7d16c912c9b5d7..6f436b5e49611aee6d0e21fc3cdcccdbd8a82a08 100644 (file)
@@ -437,7 +437,6 @@ static void sock_disable_timestamp(struct sock *sk, unsigned long flags)
 int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int err;
-       int skb_len;
        unsigned long flags;
        struct sk_buff_head *list = &sk->sk_receive_queue;
 
@@ -459,13 +458,6 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        skb->dev = NULL;
        skb_set_owner_r(skb, sk);
 
-       /* Cache the SKB length before we tack it onto the receive
-        * queue.  Once it is added it no longer belongs to us and
-        * may be freed by other threads of control pulling packets
-        * from the queue.
-        */
-       skb_len = skb->len;
-
        /* we escape from rcu protected region, make sure we dont leak
         * a norefcounted dst
         */
@@ -1645,18 +1637,24 @@ void sock_rfree(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_rfree);
 
+void sock_efree(struct sk_buff *skb)
+{
+       sock_put(skb->sk);
+}
+EXPORT_SYMBOL(sock_efree);
+
+#ifdef CONFIG_INET
 void sock_edemux(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
 
-#ifdef CONFIG_INET
        if (sk->sk_state == TCP_TIME_WAIT)
                inet_twsk_put(inet_twsk(sk));
        else
-#endif
                sock_put(sk);
 }
 EXPORT_SYMBOL(sock_edemux);
+#endif
 
 kuid_t sock_i_uid(struct sock *sk)
 {
@@ -2498,11 +2496,11 @@ int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
                       int level, int type)
 {
        struct sock_exterr_skb *serr;
-       struct sk_buff *skb, *skb2;
+       struct sk_buff *skb;
        int copied, err;
 
        err = -EAGAIN;
-       skb = skb_dequeue(&sk->sk_error_queue);
+       skb = sock_dequeue_err_skb(sk);
        if (skb == NULL)
                goto out;
 
@@ -2523,16 +2521,6 @@ int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
        msg->msg_flags |= MSG_ERRQUEUE;
        err = copied;
 
-       /* Reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
-               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-
 out_free_skb:
        kfree_skb(skb);
 out:
index a8770391ea5bfc0db85135cf913c84d09f55cedb..43d3dd62fcc8eccd95a4618f68b0553cf7309c01 100644 (file)
@@ -36,10 +36,9 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
 {
        struct phy_device *phydev;
        struct sk_buff *clone;
-       struct sock *sk = skb->sk;
        unsigned int type;
 
-       if (!sk)
+       if (!skb->sk)
                return;
 
        type = classify(skb);
@@ -48,50 +47,14 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
 
        phydev = skb->dev->phydev;
        if (likely(phydev->drv->txtstamp)) {
-               if (!atomic_inc_not_zero(&sk->sk_refcnt))
+               clone = skb_clone_sk(skb);
+               if (!clone)
                        return;
-
-               clone = skb_clone(skb, GFP_ATOMIC);
-               if (!clone) {
-                       sock_put(sk);
-                       return;
-               }
-
-               clone->sk = sk;
                phydev->drv->txtstamp(phydev, clone, type);
        }
 }
 EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
 
-void skb_complete_tx_timestamp(struct sk_buff *skb,
-                              struct skb_shared_hwtstamps *hwtstamps)
-{
-       struct sock *sk = skb->sk;
-       struct sock_exterr_skb *serr;
-       int err;
-
-       if (!hwtstamps) {
-               sock_put(sk);
-               kfree_skb(skb);
-               return;
-       }
-
-       *skb_hwtstamps(skb) = *hwtstamps;
-
-       serr = SKB_EXT_ERR(skb);
-       memset(serr, 0, sizeof(*serr));
-       serr->ee.ee_errno = ENOMSG;
-       serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
-       skb->sk = NULL;
-
-       err = sock_queue_err_skb(sk, skb);
-
-       sock_put(sk);
-       if (err)
-               kfree_skb(skb);
-}
-EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
-
 bool skb_defer_rx_timestamp(struct sk_buff *skb)
 {
        struct phy_device *phydev;
index ae011b46c0710fc96204deda6bddb1d912d78f22..25733d53814763c85e49a612df3bbcdb202992d6 100644 (file)
@@ -127,6 +127,7 @@ Version 0.0.6    2.1.110   07-aug-98   Eduardo Marcelo Serrat
 #include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/jiffies.h>
 #include <net/net_namespace.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
@@ -598,7 +599,7 @@ int dn_destroy_timer(struct sock *sk)
        if (sk->sk_socket)
                return 0;
 
-       if ((jiffies - scp->stamp) >= (HZ * decnet_time_wait)) {
+       if (time_after_eq(jiffies, scp->stamp + HZ * decnet_time_wait)) {
                dn_unhash_sock(sk);
                sock_put(sk);
                return 1;
index 3b726f31c64c0b88efcfacd4d64df7177260ad5c..4400da7739dafb3c3d42e52829086b9d3e418505 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/sysctl.h>
 #include <linux/notifier.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <asm/uaccess.h>
 #include <net/net_namespace.h>
 #include <net/neighbour.h>
@@ -875,7 +876,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn_ifaddr *ifa)
 {
        /* First check time since device went up */
-       if ((jiffies - dn_db->uptime) < DRDELAY)
+       if (time_before(jiffies, dn_db->uptime + DRDELAY))
                return 0;
 
        /* If there is no router, then yes... */
index d9c150cc59a952ac86585b6c600acc398b80bc14..1d330fd43dc7e177d162f77796d2142a4e563fdb 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/spinlock.h>
 #include <net/sock.h>
 #include <linux/atomic.h>
+#include <linux/jiffies.h>
 #include <net/flow.h>
 #include <net/dn.h>
 
@@ -91,7 +92,7 @@ static void dn_slow_timer(unsigned long arg)
         * since the last successful transmission.
         */
        if (scp->keepalive && scp->keepalive_fxn && (scp->state == DN_RUN)) {
-               if ((jiffies - scp->stamp) >= scp->keepalive)
+               if (time_after_eq(jiffies, scp->stamp + scp->keepalive))
                        scp->keepalive_fxn(sk);
        }
 
index f5eede1d6cb8eb92cbf97b1b37de1362f13ac095..a585fd6352ebaf8e8bdf0e9772653857def08811 100644 (file)
@@ -12,6 +12,9 @@ config NET_DSA
 if NET_DSA
 
 # tagging formats
+config NET_DSA_TAG_BRCM
+       bool
+
 config NET_DSA_TAG_DSA
        bool
 
index 7b9fcbbeda5d0d80678ba909f76b0b30d8436a2d..da06ed1df620fc620a90ab06cfadad29ce26f3bf 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA) += dsa_core.o
 dsa_core-y += dsa.o slave.o
 
 # tagging formats
+dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
 dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
 dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
 dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
index 0a49632fac478f1ac17b3f0159cbdf748fe25110..61f145c445557b6aea185dc1d0c4a7504d582888 100644 (file)
@@ -144,6 +144,11 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
                goto out;
        }
 
+       /* Make the built-in MII bus mask match the number of ports,
+        * switch drivers can override this later
+        */
+       ds->phys_mii_mask = ds->phys_port_mask;
+
        /*
         * If the CPU connects to this switch, set the switch tree
         * tagging protocol to the preferred tagging format of this
@@ -410,6 +415,7 @@ static int dsa_of_probe(struct platform_device *pdev)
                chip_index++;
                cd = &pd->chip[chip_index];
 
+               cd->of_node = child;
                cd->mii_bus = &mdio_bus->dev;
 
                sw_addr = of_get_property(child, "reg", NULL);
@@ -431,6 +437,8 @@ static int dsa_of_probe(struct platform_device *pdev)
                        if (!port_name)
                                continue;
 
+                       cd->port_dn[port_index] = port;
+
                        cd->port_names[port_index] = kstrdup(port_name,
                                        GFP_KERNEL);
                        if (!cd->port_names[port_index]) {
@@ -608,7 +616,26 @@ static void dsa_shutdown(struct platform_device *pdev)
 {
 }
 
+static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
+                         struct packet_type *pt, struct net_device *orig_dev)
+{
+       struct dsa_switch_tree *dst = dev->dsa_ptr;
+
+       if (unlikely(dst == NULL)) {
+               kfree_skb(skb);
+               return 0;
+       }
+
+       return dst->ops->rcv(skb, dev, pt, orig_dev);
+}
+
+static struct packet_type dsa_pack_type __read_mostly = {
+       .type   = cpu_to_be16(ETH_P_XDSA),
+       .func   = dsa_switch_rcv,
+};
+
 static const struct of_device_id dsa_of_match_table[] = {
+       { .compatible = "brcm,bcm7445-switch-v4.0" },
        { .compatible = "marvell,dsa", },
        {}
 };
@@ -633,30 +660,15 @@ static int __init dsa_init_module(void)
        if (rc)
                return rc;
 
-#ifdef CONFIG_NET_DSA_TAG_DSA
-       dev_add_pack(&dsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-       dev_add_pack(&edsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-       dev_add_pack(&trailer_packet_type);
-#endif
+       dev_add_pack(&dsa_pack_type);
+
        return 0;
 }
 module_init(dsa_init_module);
 
 static void __exit dsa_cleanup_module(void)
 {
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-       dev_remove_pack(&trailer_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-       dev_remove_pack(&edsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_DSA
-       dev_remove_pack(&dsa_packet_type);
-#endif
+       dev_remove_pack(&dsa_pack_type);
        platform_driver_unregister(&dsa_driver);
 }
 module_exit(dsa_cleanup_module);
index d4cf5cc747e3569f4d41855d9894b7a4fa98253d..98afed4d92baa4859615d91805a524b1bc68f25e 100644 (file)
@@ -33,6 +33,10 @@ struct dsa_slave_priv {
         * to this port.
         */
        struct phy_device       *phy;
+       phy_interface_t         phy_interface;
+       int                     old_link;
+       int                     old_pause;
+       int                     old_duplex;
 };
 
 /* dsa.c */
@@ -45,16 +49,16 @@ struct net_device *dsa_slave_create(struct dsa_switch *ds,
                                    int port, char *name);
 
 /* tag_dsa.c */
-netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev);
-extern struct packet_type dsa_packet_type;
+extern const struct dsa_device_ops dsa_netdev_ops;
 
 /* tag_edsa.c */
-netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev);
-extern struct packet_type edsa_packet_type;
+extern const struct dsa_device_ops edsa_netdev_ops;
 
 /* tag_trailer.c */
-netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev);
-extern struct packet_type trailer_packet_type;
+extern const struct dsa_device_ops trailer_netdev_ops;
+
+/* tag_brcm.c */
+extern const struct dsa_device_ops brcm_netdev_ops;
 
 
 #endif
index 45a1e34c89e0d975dd9f361a73a5617d69a10301..7333a4aebb7de2bdecf7496c681f7d4b6392f5d3 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
 #include "dsa_priv.h"
 
 /* slave mii_bus handling ***************************************************/
@@ -19,7 +21,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
 {
        struct dsa_switch *ds = bus->priv;
 
-       if (ds->phys_port_mask & (1 << addr))
+       if (ds->phys_mii_mask & (1 << addr))
                return ds->drv->phy_read(ds, addr, reg);
 
        return 0xffff;
@@ -29,7 +31,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
 {
        struct dsa_switch *ds = bus->priv;
 
-       if (ds->phys_port_mask & (1 << addr))
+       if (ds->phys_mii_mask & (1 << addr))
                return ds->drv->phy_write(ds, addr, reg, val);
 
        return 0;
@@ -171,6 +173,25 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EOPNOTSUPP;
 }
 
+static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch_tree *dst = p->parent->dst;
+
+       return dst->ops->xmit(skb, dev);
+}
+
+static netdev_tx_t dsa_slave_notag_xmit(struct sk_buff *skb,
+                                       struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+
+       skb->dev = p->parent->dst->master_netdev;
+       dev_queue_xmit(skb);
+
+       return NETDEV_TX_OK;
+}
+
 
 /* ethtool operations *******************************************************/
 static int
@@ -293,44 +314,107 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
        .get_sset_count         = dsa_slave_get_sset_count,
 };
 
-#ifdef CONFIG_NET_DSA_TAG_DSA
-static const struct net_device_ops dsa_netdev_ops = {
-       .ndo_init               = dsa_slave_init,
-       .ndo_open               = dsa_slave_open,
-       .ndo_stop               = dsa_slave_close,
-       .ndo_start_xmit         = dsa_xmit,
-       .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
-       .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
-       .ndo_set_mac_address    = dsa_slave_set_mac_address,
-       .ndo_do_ioctl           = dsa_slave_ioctl,
-};
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-static const struct net_device_ops edsa_netdev_ops = {
+static const struct net_device_ops dsa_slave_netdev_ops = {
        .ndo_init               = dsa_slave_init,
        .ndo_open               = dsa_slave_open,
        .ndo_stop               = dsa_slave_close,
-       .ndo_start_xmit         = edsa_xmit,
+       .ndo_start_xmit         = dsa_slave_xmit,
        .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
        .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
        .ndo_set_mac_address    = dsa_slave_set_mac_address,
        .ndo_do_ioctl           = dsa_slave_ioctl,
 };
-#endif
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-static const struct net_device_ops trailer_netdev_ops = {
-       .ndo_init               = dsa_slave_init,
-       .ndo_open               = dsa_slave_open,
-       .ndo_stop               = dsa_slave_close,
-       .ndo_start_xmit         = trailer_xmit,
-       .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
-       .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
-       .ndo_set_mac_address    = dsa_slave_set_mac_address,
-       .ndo_do_ioctl           = dsa_slave_ioctl,
+
+static const struct dsa_device_ops notag_netdev_ops = {
+       .xmit   = dsa_slave_notag_xmit,
+       .rcv    = NULL,
 };
-#endif
+
+static void dsa_slave_adjust_link(struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+       unsigned int status_changed = 0;
+
+       if (p->old_link != p->phy->link) {
+               status_changed = 1;
+               p->old_link = p->phy->link;
+       }
+
+       if (p->old_duplex != p->phy->duplex) {
+               status_changed = 1;
+               p->old_duplex = p->phy->duplex;
+       }
+
+       if (p->old_pause != p->phy->pause) {
+               status_changed = 1;
+               p->old_pause = p->phy->pause;
+       }
+
+       if (ds->drv->adjust_link && status_changed)
+               ds->drv->adjust_link(ds, p->port, p->phy);
+
+       if (status_changed)
+               phy_print_status(p->phy);
+}
+
+static int dsa_slave_fixed_link_update(struct net_device *dev,
+                                      struct fixed_phy_status *status)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+
+       if (ds->drv->fixed_link_update)
+               ds->drv->fixed_link_update(ds, p->port, status);
+
+       return 0;
+}
 
 /* slave device setup *******************************************************/
+static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
+                               struct net_device *slave_dev)
+{
+       struct dsa_switch *ds = p->parent;
+       struct dsa_chip_data *cd = ds->pd;
+       struct device_node *phy_dn, *port_dn;
+       bool phy_is_fixed = false;
+       int ret;
+
+       port_dn = cd->port_dn[p->port];
+       p->phy_interface = of_get_phy_mode(port_dn);
+
+       phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
+       if (of_phy_is_fixed_link(port_dn)) {
+               /* In the case of a fixed PHY, the DT node associated
+                * to the fixed PHY is the Port DT node
+                */
+               ret = of_phy_register_fixed_link(port_dn);
+               if (ret) {
+                       pr_err("failed to register fixed PHY\n");
+                       return;
+               }
+               phy_is_fixed = true;
+               phy_dn = port_dn;
+       }
+
+       if (phy_dn)
+               p->phy = of_phy_connect(slave_dev, phy_dn,
+                                       dsa_slave_adjust_link, 0,
+                                       p->phy_interface);
+
+       if (p->phy && phy_is_fixed)
+               fixed_phy_set_link_update(p->phy, dsa_slave_fixed_link_update);
+
+       /* We could not connect to a designated PHY, so use the switch internal
+        * MDIO bus instead
+        */
+       if (!p->phy)
+               p->phy = ds->slave_mii_bus->phy_map[p->port];
+       else
+               pr_info("attached PHY at address %d [%s]\n",
+                       p->phy->addr, p->phy->drv->name);
+}
+
 struct net_device *
 dsa_slave_create(struct dsa_switch *ds, struct device *parent,
                 int port, char *name)
@@ -349,35 +433,48 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
        slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
        eth_hw_addr_inherit(slave_dev, master);
        slave_dev->tx_queue_len = 0;
+       slave_dev->netdev_ops = &dsa_slave_netdev_ops;
 
        switch (ds->dst->tag_protocol) {
 #ifdef CONFIG_NET_DSA_TAG_DSA
        case htons(ETH_P_DSA):
-               slave_dev->netdev_ops = &dsa_netdev_ops;
+               ds->dst->ops = &dsa_netdev_ops;
                break;
 #endif
 #ifdef CONFIG_NET_DSA_TAG_EDSA
        case htons(ETH_P_EDSA):
-               slave_dev->netdev_ops = &edsa_netdev_ops;
+               ds->dst->ops = &edsa_netdev_ops;
                break;
 #endif
 #ifdef CONFIG_NET_DSA_TAG_TRAILER
        case htons(ETH_P_TRAILER):
-               slave_dev->netdev_ops = &trailer_netdev_ops;
+               ds->dst->ops = &trailer_netdev_ops;
+               break;
+#endif
+#ifdef CONFIG_NET_DSA_TAG_BRCM
+       case htons(ETH_P_BRCMTAG):
+               ds->dst->ops = &brcm_netdev_ops;
                break;
 #endif
        default:
-               BUG();
+               ds->dst->ops = &notag_netdev_ops;
+               break;
        }
 
        SET_NETDEV_DEV(slave_dev, parent);
+       slave_dev->dev.of_node = ds->pd->port_dn[port];
        slave_dev->vlan_features = master->vlan_features;
 
        p = netdev_priv(slave_dev);
        p->dev = slave_dev;
        p->parent = ds;
        p->port = port;
-       p->phy = ds->slave_mii_bus->phy_map[port];
+
+       p->old_pause = -1;
+       p->old_link = -1;
+       p->old_duplex = -1;
+
+       dsa_slave_phy_setup(p, slave_dev);
 
        ret = register_netdev(slave_dev);
        if (ret) {
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
new file mode 100644 (file)
index 0000000..e0b759e
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Broadcom tag support
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include "dsa_priv.h"
+
+/* This tag length is 4 bytes, older ones were 6 bytes, we do not
+ * handle them
+ */
+#define BRCM_TAG_LEN   4
+
+/* Tag is constructed and desconstructed using byte by byte access
+ * because the tag is placed after the MAC Source Address, which does
+ * not make it 4-bytes aligned, so this might cause unaligned accesses
+ * on most systems where this is used.
+ */
+
+/* Ingress and egress opcodes */
+#define BRCM_OPCODE_SHIFT      5
+#define BRCM_OPCODE_MASK       0x7
+
+/* Ingress fields */
+/* 1st byte in the tag */
+#define BRCM_IG_TC_SHIFT       2
+#define BRCM_IG_TC_MASK                0x7
+/* 2nd byte in the tag */
+#define BRCM_IG_TE_MASK                0x3
+#define BRCM_IG_TS_SHIFT       7
+/* 3rd byte in the tag */
+#define BRCM_IG_DSTMAP2_MASK   1
+#define BRCM_IG_DSTMAP1_MASK   0xff
+
+/* Egress fields */
+
+/* 2nd byte in the tag */
+#define BRCM_EG_CID_MASK       0xff
+
+/* 3rd byte in the tag */
+#define BRCM_EG_RC_MASK                0xff
+#define  BRCM_EG_RC_RSVD       (3 << 6)
+#define  BRCM_EG_RC_EXCEPTION  (1 << 5)
+#define  BRCM_EG_RC_PROT_SNOOP (1 << 4)
+#define  BRCM_EG_RC_PROT_TERM  (1 << 3)
+#define  BRCM_EG_RC_SWITCH     (1 << 2)
+#define  BRCM_EG_RC_MAC_LEARN  (1 << 1)
+#define  BRCM_EG_RC_MIRROR     (1 << 0)
+#define BRCM_EG_TC_SHIFT       5
+#define BRCM_EG_TC_MASK                0x7
+#define BRCM_EG_PID_MASK       0x1f
+
+static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       u8 *brcm_tag;
+
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
+               goto out_free;
+
+       skb_push(skb, BRCM_TAG_LEN);
+
+       memmove(skb->data, skb->data + BRCM_TAG_LEN, 2 * ETH_ALEN);
+
+       /* Build the tag after the MAC Source Address */
+       brcm_tag = skb->data + 2 * ETH_ALEN;
+
+       /* Set the ingress opcode, traffic class, tag enforcment is
+        * deprecated
+        */
+       brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) |
+                       ((skb->priority << BRCM_IG_TC_SHIFT) & BRCM_IG_TC_MASK);
+       brcm_tag[1] = 0;
+       brcm_tag[2] = 0;
+       if (p->port == 8)
+               brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
+       brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK;
+
+       /* Queue the SKB for transmission on the parent interface, but
+        * do not modify its EtherType
+        */
+       skb->protocol = htons(ETH_P_BRCMTAG);
+       skb->dev = p->parent->dst->master_netdev;
+       dev_queue_xmit(skb);
+
+       return NETDEV_TX_OK;
+
+out_free:
+       kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
+                       struct packet_type *pt, struct net_device *orig_dev)
+{
+       struct dsa_switch_tree *dst = dev->dsa_ptr;
+       struct dsa_switch *ds;
+       int source_port;
+       u8 *brcm_tag;
+
+       if (unlikely(dst == NULL))
+               goto out_drop;
+
+       ds = dst->ds[0];
+
+       skb = skb_unshare(skb, GFP_ATOMIC);
+       if (skb == NULL)
+               goto out;
+
+       if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
+               goto out_drop;
+
+       /* skb->data points to the EtherType, the tag is right before it */
+       brcm_tag = skb->data - 2;
+
+       /* The opcode should never be different than 0b000 */
+       if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
+               goto out_drop;
+
+       /* We should never see a reserved reason code without knowing how to
+        * handle it
+        */
+       WARN_ON(brcm_tag[2] & BRCM_EG_RC_RSVD);
+
+       /* Locate which port this is coming from */
+       source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
+
+       /* Validate port against switch setup, either the port is totally */
+       if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
+               goto out_drop;
+
+       /* Remove Broadcom tag and update checksum */
+       skb_pull_rcsum(skb, BRCM_TAG_LEN);
+
+       /* Move the Ethernet DA and SA */
+       memmove(skb->data - ETH_HLEN,
+               skb->data - ETH_HLEN - BRCM_TAG_LEN,
+               2 * ETH_ALEN);
+
+       skb_push(skb, ETH_HLEN);
+       skb->pkt_type = PACKET_HOST;
+       skb->dev = ds->ports[source_port];
+       skb->protocol = eth_type_trans(skb, skb->dev);
+
+       skb->dev->stats.rx_packets++;
+       skb->dev->stats.rx_bytes += skb->len;
+
+       netif_receive_skb(skb);
+
+       return 0;
+
+out_drop:
+       kfree_skb(skb);
+out:
+       return 0;
+}
+
+const struct dsa_device_ops brcm_netdev_ops = {
+       .xmit   = brcm_tag_xmit,
+       .rcv    = brcm_tag_rcv,
+};
index cacce1e22f9caa029c2374cd93c2e071932f365c..d7dbc5bda5c0f587571c8d15d37c8705c493bfb4 100644 (file)
@@ -16,7 +16,7 @@
 
 #define DSA_HLEN       4
 
-netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        u8 *dsa_header;
@@ -186,7 +186,7 @@ out:
        return 0;
 }
 
-struct packet_type dsa_packet_type __read_mostly = {
-       .type   = cpu_to_be16(ETH_P_DSA),
-       .func   = dsa_rcv,
+const struct dsa_device_ops dsa_netdev_ops = {
+       .xmit   = dsa_xmit,
+       .rcv    = dsa_rcv,
 };
index e70c43c25e64c9310d3d5a61b407d8eeb76402d2..6b30abe89183f4de5e8ff7f105be1b593e749d79 100644 (file)
@@ -17,7 +17,7 @@
 #define DSA_HLEN       4
 #define EDSA_HLEN      8
 
-netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        u8 *edsa_header;
@@ -205,7 +205,7 @@ out:
        return 0;
 }
 
-struct packet_type edsa_packet_type __read_mostly = {
-       .type   = cpu_to_be16(ETH_P_EDSA),
-       .func   = edsa_rcv,
+const struct dsa_device_ops edsa_netdev_ops = {
+       .xmit   = edsa_xmit,
+       .rcv    = edsa_rcv,
 };
index 94bc260d015d11f1a321ca3f3876c7b901716302..5fe9444842c573b7b251266a166719887068c739 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/slab.h>
 #include "dsa_priv.h"
 
-netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        struct sk_buff *nskb;
@@ -114,7 +114,7 @@ out:
        return 0;
 }
 
-struct packet_type trailer_packet_type __read_mostly = {
-       .type   = cpu_to_be16(ETH_P_TRAILER),
-       .func   = trailer_rcv,
+const struct dsa_device_ops trailer_netdev_ops = {
+       .xmit   = trailer_xmit,
+       .rcv    = trailer_rcv,
 };
index f405e05924078b2d30f45139cd698843a16256da..33a140e1583449bcf2816bb91792e810f7c1734f 100644 (file)
@@ -145,6 +145,33 @@ int eth_rebuild_header(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(eth_rebuild_header);
 
+/**
+ * eth_get_headlen - determine the the length of header for an ethernet frame
+ * @data: pointer to start of frame
+ * @len: total length of frame
+ *
+ * Make a best effort attempt to pull the length for all of the headers for
+ * a given frame in a linear buffer.
+ */
+u32 eth_get_headlen(void *data, unsigned int len)
+{
+       const struct ethhdr *eth = (const struct ethhdr *)data;
+       struct flow_keys keys;
+
+       /* this should never happen, but better safe than sorry */
+       if (len < sizeof(*eth))
+               return len;
+
+       /* parse any remaining L2/L3 headers, check for L4 */
+       if (!__skb_flow_dissect(NULL, &keys, data,
+                               eth->h_proto, sizeof(*eth), len))
+               return max_t(u32, keys.thoff, sizeof(*eth));
+
+       /* parse for any L4 headers */
+       return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len);
+}
+EXPORT_SYMBOL(eth_get_headlen);
+
 /**
  * eth_type_trans - determine the packet's protocol ID.
  * @skb: received socket data
@@ -181,11 +208,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
         * variants has been configured on the receiving interface,
         * and if so, set skb->protocol without looking at the packet.
         */
-       if (unlikely(netdev_uses_dsa_tags(dev)))
-               return htons(ETH_P_DSA);
-
-       if (unlikely(netdev_uses_trailer_tags(dev)))
-               return htons(ETH_P_TRAILER);
+       if (unlikely(netdev_uses_dsa(dev)))
+               return htons(ETH_P_XDSA);
 
        if (likely(ntohs(eth->h_proto) >= ETH_P_802_3_MIN))
                return eth->h_proto;
index 255aa9946fe785a2577fbdb23560288599c1ba0a..23104a3f29245abeb682089185bd103ae4794cb2 100644 (file)
@@ -243,7 +243,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
                                 u8 tos, int oif, struct net_device *dev,
                                 int rpf, struct in_device *idev, u32 *itag)
 {
-       int ret, no_addr, accept_local;
+       int ret, no_addr;
        struct fib_result res;
        struct flowi4 fl4;
        struct net *net;
@@ -258,16 +258,17 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
 
        no_addr = idev->ifa_list == NULL;
 
-       accept_local = IN_DEV_ACCEPT_LOCAL(idev);
        fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0;
 
        net = dev_net(dev);
        if (fib_lookup(net, &fl4, &res))
                goto last_resort;
-       if (res.type != RTN_UNICAST) {
-               if (res.type != RTN_LOCAL || !accept_local)
-                       goto e_inval;
-       }
+       if (res.type != RTN_UNICAST &&
+           (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev)))
+               goto e_inval;
+       if (!rpf && !fib_num_tclassid_users(dev_net(dev)) &&
+           (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev)))
+               goto last_resort;
        fib_combine_itag(itag, &res);
        dev_match = false;
 
@@ -321,6 +322,7 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
        int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
 
        if (!r && !fib_num_tclassid_users(dev_net(dev)) &&
+           IN_DEV_ACCEPT_LOCAL(idev) &&
            (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) {
                *itag = 0;
                return 0;
index b10cd43a4722730205272d7822d699bc49ea71d3..5b6efb3d2308b0b40b22da7274ad611c4f3d0158 100644 (file)
@@ -157,9 +157,12 @@ static void rt_fibinfo_free(struct rtable __rcu **rtp)
 
 static void free_nh_exceptions(struct fib_nh *nh)
 {
-       struct fnhe_hash_bucket *hash = nh->nh_exceptions;
+       struct fnhe_hash_bucket *hash;
        int i;
 
+       hash = rcu_dereference_protected(nh->nh_exceptions, 1);
+       if (!hash)
+               return;
        for (i = 0; i < FNHE_HASH_SIZE; i++) {
                struct fib_nh_exception *fnhe;
 
@@ -205,8 +208,7 @@ static void free_fib_info_rcu(struct rcu_head *head)
        change_nexthops(fi) {
                if (nexthop_nh->nh_dev)
                        dev_put(nexthop_nh->nh_dev);
-               if (nexthop_nh->nh_exceptions)
-                       free_nh_exceptions(nexthop_nh);
+               free_nh_exceptions(nexthop_nh);
                rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output);
                rt_fibinfo_free(&nexthop_nh->nh_rth_input);
        } endfor_nexthops(fi);
index 0485bf7f8f030d59bc6e9ee499051e99d9ab53d6..7e0756da873776aad0e534d0c85ed08629878ed4 100644 (file)
@@ -125,6 +125,10 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
                        *csum_err = true;
                        return -EINVAL;
                }
+
+               skb_checksum_try_convert(skb, IPPROTO_GRE, 0,
+                                        null_compute_pseudo);
+
                options++;
        }
 
index 6556263c8fa52330efd6e4d9d4f5b491ac9dbe41..d3fe2ac05167230985e44a4cfc2150b279717dc0 100644 (file)
@@ -119,28 +119,6 @@ out:
        return segs;
 }
 
-/* Compute the whole skb csum in s/w and store it, then verify GRO csum
- * starting from gro_offset.
- */
-static __sum16 gro_skb_checksum(struct sk_buff *skb)
-{
-       __sum16 sum;
-
-       skb->csum = skb_checksum(skb, 0, skb->len, 0);
-       NAPI_GRO_CB(skb)->csum = csum_sub(skb->csum,
-               csum_partial(skb->data, skb_gro_offset(skb), 0));
-       sum = csum_fold(NAPI_GRO_CB(skb)->csum);
-       if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) {
-               if (unlikely(!sum) && !skb->csum_complete_sw)
-                       netdev_rx_csum_fault(skb->dev);
-       } else {
-               skb->ip_summed = CHECKSUM_COMPLETE;
-               skb->csum_complete_sw = 1;
-       }
-
-       return sum;
-}
-
 static struct sk_buff **gre_gro_receive(struct sk_buff **head,
                                        struct sk_buff *skb)
 {
@@ -192,22 +170,16 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
                if (unlikely(!greh))
                        goto out_unlock;
        }
-       if (greh->flags & GRE_CSUM) { /* Need to verify GRE csum first */
-               __sum16 csum = 0;
-
-               if (skb->ip_summed == CHECKSUM_COMPLETE)
-                       csum = csum_fold(NAPI_GRO_CB(skb)->csum);
-               /* Don't trust csum error calculated/reported by h/w */
-               if (skb->ip_summed == CHECKSUM_NONE || csum != 0)
-                       csum = gro_skb_checksum(skb);
-
-               /* GRE CSUM is the 1's complement of the 1's complement sum
-                * of the GRE hdr plus payload so it should add up to 0xffff
-                * (and 0 after csum_fold()) just like the IPv4 hdr csum.
-                */
-               if (csum)
+
+       /* Don't bother verifying checksum if we're going to flush anyway. */
+       if ((greh->flags & GRE_CSUM) && !NAPI_GRO_CB(skb)->flush) {
+               if (skb_gro_checksum_simple_validate(skb))
                        goto out_unlock;
+
+               skb_gro_checksum_try_convert(skb, IPPROTO_GRE, 0,
+                                            null_compute_pseudo);
        }
+
        flush = 0;
 
        for (p = *head; p; p = p->next) {
index f10eab462282b1afa80bcc3e7bac7f862ab9709f..4146153d875d3ea9a35fa1b53ac01f76bf420e45 100644 (file)
 #define IGMP_V2_Unsolicited_Report_Interval    (10*HZ)
 #define IGMP_V3_Unsolicited_Report_Interval    (1*HZ)
 #define IGMP_Query_Response_Interval           (10*HZ)
-#define IGMP_Unsolicited_Report_Count          2
+#define IGMP_Query_Robustness_Variable         2
 
 
 #define IGMP_Initial_Report_Delay              (1)
@@ -756,8 +756,7 @@ static void igmp_ifc_event(struct in_device *in_dev)
 {
        if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
                return;
-       in_dev->mr_ifc_count = in_dev->mr_qrv ? in_dev->mr_qrv :
-               IGMP_Unsolicited_Report_Count;
+       in_dev->mr_ifc_count = in_dev->mr_qrv ?: sysctl_igmp_qrv;
        igmp_ifc_start_timer(in_dev, 1);
 }
 
@@ -1086,8 +1085,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
        pmc->interface = im->interface;
        in_dev_hold(in_dev);
        pmc->multiaddr = im->multiaddr;
-       pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-               IGMP_Unsolicited_Report_Count;
+       pmc->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
        pmc->sfmode = im->sfmode;
        if (pmc->sfmode == MCAST_INCLUDE) {
                struct ip_sf_list *psf;
@@ -1226,8 +1224,7 @@ static void igmp_group_added(struct ip_mc_list *im)
        }
        /* else, v3 */
 
-       im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-               IGMP_Unsolicited_Report_Count;
+       im->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
        igmp_ifc_event(in_dev);
 #endif
 }
@@ -1322,7 +1319,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
        spin_lock_init(&im->lock);
 #ifdef CONFIG_IP_MULTICAST
        setup_timer(&im->timer, igmp_timer_expire, (unsigned long)im);
-       im->unsolicit_count = IGMP_Unsolicited_Report_Count;
+       im->unsolicit_count = sysctl_igmp_qrv;
 #endif
 
        im->next_rcu = in_dev->mc_list;
@@ -1460,7 +1457,7 @@ void ip_mc_init_dev(struct in_device *in_dev)
                        (unsigned long)in_dev);
        setup_timer(&in_dev->mr_ifc_timer, igmp_ifc_timer_expire,
                        (unsigned long)in_dev);
-       in_dev->mr_qrv = IGMP_Unsolicited_Report_Count;
+       in_dev->mr_qrv = sysctl_igmp_qrv;
 #endif
 
        spin_lock_init(&in_dev->mc_tomb_lock);
@@ -1474,6 +1471,9 @@ void ip_mc_up(struct in_device *in_dev)
 
        ASSERT_RTNL();
 
+#ifdef CONFIG_IP_MULTICAST
+       in_dev->mr_qrv = sysctl_igmp_qrv;
+#endif
        ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
 
        for_each_pmc_rtnl(in_dev, pmc)
@@ -1540,7 +1540,9 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
  */
 int sysctl_igmp_max_memberships __read_mostly = IP_MAX_MEMBERSHIPS;
 int sysctl_igmp_max_msf __read_mostly = IP_MAX_MSF;
-
+#ifdef CONFIG_IP_MULTICAST
+int sysctl_igmp_qrv __read_mostly = IGMP_Query_Robustness_Variable;
+#endif
 
 static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
        __be32 *psfsrc)
@@ -1575,8 +1577,7 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
 #ifdef CONFIG_IP_MULTICAST
                if (psf->sf_oldin &&
                    !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
-                       psf->sf_crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-                               IGMP_Unsolicited_Report_Count;
+                       psf->sf_crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
                        psf->sf_next = pmc->tomb;
                        pmc->tomb = psf;
                        rv = 1;
@@ -1639,8 +1640,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
                /* filter mode change */
                pmc->sfmode = MCAST_INCLUDE;
 #ifdef CONFIG_IP_MULTICAST
-               pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-                       IGMP_Unsolicited_Report_Count;
+               pmc->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
                in_dev->mr_ifc_count = pmc->crcount;
                for (psf = pmc->sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
@@ -1818,8 +1818,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
 #ifdef CONFIG_IP_MULTICAST
                /* else no filters; keep old mode for reports */
 
-               pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-                       IGMP_Unsolicited_Report_Count;
+               pmc->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
                in_dev->mr_ifc_count = pmc->crcount;
                for (psf = pmc->sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
@@ -2539,7 +2538,7 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
                querier = "NONE";
 #endif
 
-               if (rcu_dereference(state->in_dev->mc_list) == im) {
+               if (rcu_access_pointer(state->in_dev->mc_list) == im) {
                        seq_printf(seq, "%d\t%-10s: %5d %7s\n",
                                   state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier);
                }
index 43116e8c8e1323cdd8d902c5b88e42187c8df991..9111a4e221557173df0ce08e95632ee059d00b61 100644 (file)
@@ -229,7 +229,7 @@ begin:
                        }
                } else if (score == hiscore && reuseport) {
                        matches++;
-                       if (((u64)phash * matches) >> 32 == 0)
+                       if (reciprocal_scale(phash, matches) == 0)
                                result = sk;
                        phash = next_pseudo_random32(phash);
                }
index 5cb830c78990a8642aed4df591b7109260de685c..455e75bcb1677dd6bcf4b5c65bae18d607d95137 100644 (file)
@@ -405,7 +405,7 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf
 int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 {
        struct sock_exterr_skb *serr;
-       struct sk_buff *skb, *skb2;
+       struct sk_buff *skb;
        DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
        struct {
                struct sock_extended_err ee;
@@ -415,7 +415,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        int copied;
 
        err = -EAGAIN;
-       skb = skb_dequeue(&sk->sk_error_queue);
+       skb = sock_dequeue_err_skb(sk);
        if (skb == NULL)
                goto out;
 
@@ -462,17 +462,6 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        msg->msg_flags |= MSG_ERRQUEUE;
        err = copied;
 
-       /* Reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       skb2 = skb_peek(&sk->sk_error_queue);
-       if (skb2 != NULL) {
-               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-
 out_free_skb:
        kfree_skb(skb);
 out:
index 5bbef4fdcb439f7c3445278dc580b3f0aaacf907..648fa1490ea7f96d1f373b4f8e6b167ed70e82e3 100644 (file)
@@ -262,7 +262,8 @@ static int __init ic_open_devs(void)
        /* wait for a carrier on at least one device */
        start = jiffies;
        next_msg = start + msecs_to_jiffies(CONF_CARRIER_TIMEOUT/12);
-       while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) {
+       while (time_before(jiffies, start +
+                          msecs_to_jiffies(CONF_CARRIER_TIMEOUT))) {
                int wait, elapsed;
 
                for_each_netdev(&init_net, dev)
index 2510c02c2d2168ffcd27f286c7eab3ca75165f26..e90f83a3415b464014cecf0f072b2188f6889b7a 100644 (file)
@@ -285,7 +285,7 @@ clusterip_hashfn(const struct sk_buff *skb,
        }
 
        /* node numbers are 1..n, not 0..n */
-       return (((u64)hashval * config->num_total_nodes) >> 32) + 1;
+       return reciprocal_scale(hashval, config->num_total_nodes) + 1;
 }
 
 static inline int
index eaa4b000c7b443898be7c5ce36f4da4eb20158a6..234a43e233dcf0b64252817deea8d8d969de6ccb 100644 (file)
@@ -596,12 +596,12 @@ static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash)
 
 static inline u32 fnhe_hashfun(__be32 daddr)
 {
+       static u32 fnhe_hashrnd __read_mostly;
        u32 hval;
 
-       hval = (__force u32) daddr;
-       hval ^= (hval >> 11) ^ (hval >> 22);
-
-       return hval & (FNHE_HASH_SIZE - 1);
+       net_get_random_once(&fnhe_hashrnd, sizeof(fnhe_hashrnd));
+       hval = jhash_1word((__force u32) daddr, fnhe_hashrnd);
+       return hash_32(hval, FNHE_HASH_SHIFT);
 }
 
 static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe)
@@ -628,12 +628,12 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
 
        spin_lock_bh(&fnhe_lock);
 
-       hash = nh->nh_exceptions;
+       hash = rcu_dereference(nh->nh_exceptions);
        if (!hash) {
                hash = kzalloc(FNHE_HASH_SIZE * sizeof(*hash), GFP_ATOMIC);
                if (!hash)
                        goto out_unlock;
-               nh->nh_exceptions = hash;
+               rcu_assign_pointer(nh->nh_exceptions, hash);
        }
 
        hash += hval;
@@ -1242,7 +1242,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
 
 static struct fib_nh_exception *find_exception(struct fib_nh *nh, __be32 daddr)
 {
-       struct fnhe_hash_bucket *hash = nh->nh_exceptions;
+       struct fnhe_hash_bucket *hash = rcu_dereference(nh->nh_exceptions);
        struct fib_nh_exception *fnhe;
        u32 hval;
 
index c0c75688896e06bd1b64384c94e7db758f842d0b..0431a8f3c8f458538e37543a0b37a091da0c04bb 100644 (file)
@@ -25,7 +25,7 @@
 
 extern int sysctl_tcp_syncookies;
 
-static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
+static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
 
 #define COOKIEBITS 24  /* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
index 79a007c5255883f9d96011682c67ea8aac15a835..45d156dacd61cec096afe0b41940c8babff89971 100644 (file)
@@ -450,6 +450,16 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+#ifdef CONFIG_IP_MULTICAST
+       {
+               .procname       = "igmp_qrv",
+               .data           = &sysctl_igmp_qrv,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one
+       },
+#endif
        {
                .procname       = "inet_peer_threshold",
                .data           = &inet_peer_threshold,
index d5de69bc04f581ac589ae0f6fe7fcc3646b2cc3e..bb395d46a3898136afe615c73ac311fd2832f6f1 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/module.h>
 #include <net/tcp.h>
 
-
 #define BICTCP_BETA_SCALE    1024      /* Scale factor beta calculation
                                         * max_cwnd = snd_cwnd * beta
                                         */
@@ -46,11 +45,10 @@ MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold");
 module_param(smooth_part, int, 0644);
 MODULE_PARM_DESC(smooth_part, "log(B/(B*Smin))/log(B/(B-1))+B, # of RTT from Wmax-B to Wmax");
 
-
 /* BIC TCP Parameters */
 struct bictcp {
        u32     cnt;            /* increase cwnd by 1 after ACKs */
-       u32     last_max_cwnd;  /* last maximum snd_cwnd */
+       u32     last_max_cwnd;  /* last maximum snd_cwnd */
        u32     loss_cwnd;      /* congestion window at last loss */
        u32     last_cwnd;      /* the last snd_cwnd */
        u32     last_time;      /* time when updated last_cwnd */
@@ -103,7 +101,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 
        /* binary increase */
        if (cwnd < ca->last_max_cwnd) {
-               __u32   dist = (ca->last_max_cwnd - cwnd)
+               __u32   dist = (ca->last_max_cwnd - cwnd)
                        / BICTCP_B;
 
                if (dist > max_increment)
@@ -154,7 +152,6 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                bictcp_update(ca, tp->snd_cwnd);
                tcp_cong_avoid_ai(tp, ca->cnt);
        }
-
 }
 
 /*
@@ -177,7 +174,6 @@ static u32 bictcp_recalc_ssthresh(struct sock *sk)
 
        ca->loss_cwnd = tp->snd_cwnd;
 
-
        if (tp->snd_cwnd <= low_window)
                return max(tp->snd_cwnd >> 1U, 2U);
        else
@@ -188,6 +184,7 @@ static u32 bictcp_undo_cwnd(struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
        const struct bictcp *ca = inet_csk_ca(sk);
+
        return max(tp->snd_cwnd, ca->loss_cwnd);
 }
 
@@ -206,12 +203,12 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt)
 
        if (icsk->icsk_ca_state == TCP_CA_Open) {
                struct bictcp *ca = inet_csk_ca(sk);
+
                cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT;
                ca->delayed_ack += cnt;
        }
 }
 
-
 static struct tcp_congestion_ops bictcp __read_mostly = {
        .init           = bictcp_init,
        .ssthresh       = bictcp_recalc_ssthresh,
index 7b09d8b49fa51271cc0fa99a3fcda9f017c0f469..80248f56c89f0b3dc8481aea2212fac819924772 100644 (file)
@@ -142,7 +142,6 @@ static int __init tcp_congestion_default(void)
 }
 late_initcall(tcp_congestion_default);
 
-
 /* Build string with list of available congestion control values */
 void tcp_get_available_congestion_control(char *buf, size_t maxlen)
 {
@@ -154,7 +153,6 @@ void tcp_get_available_congestion_control(char *buf, size_t maxlen)
                offs += snprintf(buf + offs, maxlen - offs,
                                 "%s%s",
                                 offs == 0 ? "" : " ", ca->name);
-
        }
        rcu_read_unlock();
 }
@@ -186,7 +184,6 @@ void tcp_get_allowed_congestion_control(char *buf, size_t maxlen)
                offs += snprintf(buf + offs, maxlen - offs,
                                 "%s%s",
                                 offs == 0 ? "" : " ", ca->name);
-
        }
        rcu_read_unlock();
 }
@@ -230,7 +227,6 @@ out:
        return ret;
 }
 
-
 /* Change congestion control for socket */
 int tcp_set_congestion_control(struct sock *sk, const char *name)
 {
@@ -337,6 +333,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid);
 u32 tcp_reno_ssthresh(struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
+
        return max(tp->snd_cwnd >> 1U, 2U);
 }
 EXPORT_SYMBOL_GPL(tcp_reno_ssthresh);
index a9bd8a4828a9e5c2da275626c11c6c953a1b3dd6..20de0118c98e455447128513610ba04b13f3cd61 100644 (file)
@@ -82,12 +82,13 @@ MODULE_PARM_DESC(hystart_ack_delta, "spacing between ack's indicating train (mse
 /* BIC TCP Parameters */
 struct bictcp {
        u32     cnt;            /* increase cwnd by 1 after ACKs */
-       u32     last_max_cwnd;  /* last maximum snd_cwnd */
+       u32     last_max_cwnd;  /* last maximum snd_cwnd */
        u32     loss_cwnd;      /* congestion window at last loss */
        u32     last_cwnd;      /* the last snd_cwnd */
        u32     last_time;      /* time when updated last_cwnd */
        u32     bic_origin_point;/* origin point of bic function */
-       u32     bic_K;          /* time to origin point from the beginning of the current epoch */
+       u32     bic_K;          /* time to origin point
+                                  from the beginning of the current epoch */
        u32     delay_min;      /* min delay (msec << 3) */
        u32     epoch_start;    /* beginning of an epoch */
        u32     ack_cnt;        /* number of acks */
@@ -219,7 +220,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
        ca->last_time = tcp_time_stamp;
 
        if (ca->epoch_start == 0) {
-               ca->epoch_start = tcp_time_stamp;       /* record the beginning of an epoch */
+               ca->epoch_start = tcp_time_stamp;       /* record beginning */
                ca->ack_cnt = 1;                        /* start counting */
                ca->tcp_cwnd = cwnd;                    /* syn with cubic */
 
@@ -263,9 +264,9 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 
        /* c/rtt * (t-K)^3 */
        delta = (cube_rtt_scale * offs * offs * offs) >> (10+3*BICTCP_HZ);
-       if (t < ca->bic_K)                                      /* below origin*/
+       if (t < ca->bic_K)                            /* below origin*/
                bic_target = ca->bic_origin_point - delta;
-       else                                                    /* above origin*/
+       else                                          /* above origin*/
                bic_target = ca->bic_origin_point + delta;
 
        /* cubic function - calc bictcp_cnt*/
@@ -285,13 +286,14 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
        /* TCP Friendly */
        if (tcp_friendliness) {
                u32 scale = beta_scale;
+
                delta = (cwnd * scale) >> 3;
                while (ca->ack_cnt > delta) {           /* update tcp cwnd */
                        ca->ack_cnt -= delta;
                        ca->tcp_cwnd++;
                }
 
-               if (ca->tcp_cwnd > cwnd)      /* if bic is slower than tcp */
+               if (ca->tcp_cwnd > cwnd) {      /* if bic is slower than tcp */
                        delta = ca->tcp_cwnd - cwnd;
                        max_cnt = cwnd / delta;
                        if (ca->cnt > max_cnt)
@@ -320,7 +322,6 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                bictcp_update(ca, tp->snd_cwnd);
                tcp_cong_avoid_ai(tp, ca->cnt);
        }
-
 }
 
 static u32 bictcp_recalc_ssthresh(struct sock *sk)
@@ -452,7 +453,8 @@ static int __init cubictcp_register(void)
         * based on SRTT of 100ms
         */
 
-       beta_scale = 8*(BICTCP_BETA_SCALE+beta)/ 3 / (BICTCP_BETA_SCALE - beta);
+       beta_scale = 8*(BICTCP_BETA_SCALE+beta) / 3
+               / (BICTCP_BETA_SCALE - beta);
 
        cube_rtt_scale = (bic_scale * 10);      /* 1024*c/rtt */
 
index ed3f2ad42e0f0ea881e507d8c91e7962d336d824..0d73f9ddb55b8d55204643541dad651cd9d6eb06 100644 (file)
@@ -9,7 +9,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-
 #include <linux/module.h>
 #include <linux/inet_diag.h>
 
@@ -35,13 +34,13 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 }
 
 static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req_v2 *r, struct nlattr *bc)
+                         struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc);
 }
 
 static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req_v2 *req)
+                            struct inet_diag_req_v2 *req)
 {
        return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req);
 }
index 1c4908280d921fbe9a9e21e4fd55d1a87f2db706..882c08aae2f58d02bb78212a4eba4d25d7e9c123 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/module.h>
 #include <net/tcp.h>
 
-
 /* From AIMD tables from RFC 3649 appendix B,
  * with fixed-point MD scaled <<8.
  */
@@ -17,78 +16,78 @@ static const struct hstcp_aimd_val {
        unsigned int cwnd;
        unsigned int md;
 } hstcp_aimd_vals[] = {
- {     38,  128, /*  0.50 */ },
- {    118,  112, /*  0.44 */ },
- {    221,  104, /*  0.41 */ },
- {    347,   98, /*  0.38 */ },
- {    495,   93, /*  0.37 */ },
- {    663,   89, /*  0.35 */ },
- {    851,   86, /*  0.34 */ },
- {   1058,   83, /*  0.33 */ },
- {   1284,   81, /*  0.32 */ },
- {   1529,   78, /*  0.31 */ },
- {   1793,   76, /*  0.30 */ },
- {   2076,   74, /*  0.29 */ },
- {   2378,   72, /*  0.28 */ },
- {   2699,   71, /*  0.28 */ },
- {   3039,   69, /*  0.27 */ },
- {   3399,   68, /*  0.27 */ },
- {   3778,   66, /*  0.26 */ },
- {   4177,   65, /*  0.26 */ },
- {   4596,   64, /*  0.25 */ },
- {   5036,   62, /*  0.25 */ },
- {   5497,   61, /*  0.24 */ },
- {   5979,   60, /*  0.24 */ },
- {   6483,   59, /*  0.23 */ },
- {   7009,   58, /*  0.23 */ },
- {   7558,   57, /*  0.22 */ },
- {   8130,   56, /*  0.22 */ },
- {   8726,   55, /*  0.22 */ },
- {   9346,   54, /*  0.21 */ },
- {   9991,   53, /*  0.21 */ },
- {  10661,   52, /*  0.21 */ },
- {  11358,   52, /*  0.20 */ },
- {  12082,   51, /*  0.20 */ },
- {  12834,   50, /*  0.20 */ },
- {  13614,   49, /*  0.19 */ },
- {  14424,   48, /*  0.19 */ },
- {  15265,   48, /*  0.19 */ },
- {  16137,   47, /*  0.19 */ },
- {  17042,   46, /*  0.18 */ },
- {  17981,   45, /*  0.18 */ },
- {  18955,   45, /*  0.18 */ },
- {  19965,   44, /*  0.17 */ },
- {  21013,   43, /*  0.17 */ },
- {  22101,   43, /*  0.17 */ },
- {  23230,   42, /*  0.17 */ },
- {  24402,   41, /*  0.16 */ },
- {  25618,   41, /*  0.16 */ },
- {  26881,   40, /*  0.16 */ },
- {  28193,   39, /*  0.16 */ },
- {  29557,   39, /*  0.15 */ },
- {  30975,   38, /*  0.15 */ },
- {  32450,   38, /*  0.15 */ },
- {  33986,   37, /*  0.15 */ },
- {  35586,   36, /*  0.14 */ },
- {  37253,   36, /*  0.14 */ },
- {  38992,   35, /*  0.14 */ },
- {  40808,   35, /*  0.14 */ },
- {  42707,   34, /*  0.13 */ },
- {  44694,   33, /*  0.13 */ },
- {  46776,   33, /*  0.13 */ },
- {  48961,   32, /*  0.13 */ },
- {  51258,   32, /*  0.13 */ },
- {  53677,   31, /*  0.12 */ },
- {  56230,   30, /*  0.12 */ },
- {  58932,   30, /*  0.12 */ },
- {  61799,   29, /*  0.12 */ },
- {  64851,   28, /*  0.11 */ },
- {  68113,   28, /*  0.11 */ },
- {  71617,   27, /*  0.11 */ },
- {  75401,   26, /*  0.10 */ },
- {  79517,   26, /*  0.10 */ },
- {  84035,   25, /*  0.10 */ },
- {  89053,   24, /*  0.10 */ },
      {     38,  128, /*  0.50 */ },
      {    118,  112, /*  0.44 */ },
      {    221,  104, /*  0.41 */ },
      {    347,   98, /*  0.38 */ },
      {    495,   93, /*  0.37 */ },
      {    663,   89, /*  0.35 */ },
      {    851,   86, /*  0.34 */ },
      {   1058,   83, /*  0.33 */ },
      {   1284,   81, /*  0.32 */ },
      {   1529,   78, /*  0.31 */ },
      {   1793,   76, /*  0.30 */ },
      {   2076,   74, /*  0.29 */ },
      {   2378,   72, /*  0.28 */ },
      {   2699,   71, /*  0.28 */ },
      {   3039,   69, /*  0.27 */ },
      {   3399,   68, /*  0.27 */ },
      {   3778,   66, /*  0.26 */ },
      {   4177,   65, /*  0.26 */ },
      {   4596,   64, /*  0.25 */ },
      {   5036,   62, /*  0.25 */ },
      {   5497,   61, /*  0.24 */ },
      {   5979,   60, /*  0.24 */ },
      {   6483,   59, /*  0.23 */ },
      {   7009,   58, /*  0.23 */ },
      {   7558,   57, /*  0.22 */ },
      {   8130,   56, /*  0.22 */ },
      {   8726,   55, /*  0.22 */ },
      {   9346,   54, /*  0.21 */ },
      {   9991,   53, /*  0.21 */ },
      {  10661,   52, /*  0.21 */ },
      {  11358,   52, /*  0.20 */ },
      {  12082,   51, /*  0.20 */ },
      {  12834,   50, /*  0.20 */ },
      {  13614,   49, /*  0.19 */ },
      {  14424,   48, /*  0.19 */ },
      {  15265,   48, /*  0.19 */ },
      {  16137,   47, /*  0.19 */ },
      {  17042,   46, /*  0.18 */ },
      {  17981,   45, /*  0.18 */ },
      {  18955,   45, /*  0.18 */ },
      {  19965,   44, /*  0.17 */ },
      {  21013,   43, /*  0.17 */ },
      {  22101,   43, /*  0.17 */ },
      {  23230,   42, /*  0.17 */ },
      {  24402,   41, /*  0.16 */ },
      {  25618,   41, /*  0.16 */ },
      {  26881,   40, /*  0.16 */ },
      {  28193,   39, /*  0.16 */ },
      {  29557,   39, /*  0.15 */ },
      {  30975,   38, /*  0.15 */ },
      {  32450,   38, /*  0.15 */ },
      {  33986,   37, /*  0.15 */ },
      {  35586,   36, /*  0.14 */ },
      {  37253,   36, /*  0.14 */ },
      {  38992,   35, /*  0.14 */ },
      {  40808,   35, /*  0.14 */ },
      {  42707,   34, /*  0.13 */ },
      {  44694,   33, /*  0.13 */ },
      {  46776,   33, /*  0.13 */ },
      {  48961,   32, /*  0.13 */ },
      {  51258,   32, /*  0.13 */ },
      {  53677,   31, /*  0.12 */ },
      {  56230,   30, /*  0.12 */ },
      {  58932,   30, /*  0.12 */ },
      {  61799,   29, /*  0.12 */ },
      {  64851,   28, /*  0.11 */ },
      {  68113,   28, /*  0.11 */ },
      {  71617,   27, /*  0.11 */ },
      {  75401,   26, /*  0.10 */ },
      {  79517,   26, /*  0.10 */ },
      {  84035,   25, /*  0.10 */ },
      {  89053,   24, /*  0.10 */ },
 };
 
 #define HSTCP_AIMD_MAX ARRAY_SIZE(hstcp_aimd_vals)
index 031361311a8b92b1f7ab1172fb00e3bbb0503129..58469fff6c18fd444c95366caa04ab60965d654a 100644 (file)
@@ -98,7 +98,8 @@ static inline void measure_rtt(struct sock *sk, u32 srtt)
        }
 }
 
-static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked, s32 rtt)
+static void measure_achieved_throughput(struct sock *sk,
+                                       u32 pkts_acked, s32 rtt)
 {
        const struct inet_connection_sock *icsk = inet_csk(sk);
        const struct tcp_sock *tp = tcp_sk(sk);
@@ -148,8 +149,8 @@ static inline void htcp_beta_update(struct htcp *ca, u32 minRTT, u32 maxRTT)
        if (use_bandwidth_switch) {
                u32 maxB = ca->maxB;
                u32 old_maxB = ca->old_maxB;
-               ca->old_maxB = ca->maxB;
 
+               ca->old_maxB = ca->maxB;
                if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) {
                        ca->beta = BETA_MIN;
                        ca->modeswitch = 0;
@@ -270,6 +271,7 @@ static void htcp_state(struct sock *sk, u8 new_state)
        case TCP_CA_Open:
                {
                        struct htcp *ca = inet_csk_ca(sk);
+
                        if (ca->undo_last_cong) {
                                ca->last_cong = jiffies;
                                ca->undo_last_cong = 0;
index d8f8f05a49516ec2d9213f10af77b82fbf32bff7..f963b274f2b0436755ebe8bb5586b1ec9682c336 100644 (file)
@@ -29,7 +29,6 @@ static int rtt0 = 25;
 module_param(rtt0, int, 0644);
 MODULE_PARM_DESC(rtt0, "reference rout trip time (ms)");
 
-
 /* This is called to refresh values for hybla parameters */
 static inline void hybla_recalc_param (struct sock *sk)
 {
index 5999b3972e6449d616facb628d27116ab8876ac2..1d5a30a90adf6194d3b2d2215276f52c0a3f4632 100644 (file)
@@ -284,7 +284,7 @@ static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                delta = (tp->snd_cwnd_cnt * ca->alpha) >> ALPHA_SHIFT;
                if (delta >= tp->snd_cwnd) {
                        tp->snd_cwnd = min(tp->snd_cwnd + delta / tp->snd_cwnd,
-                                          (u32) tp->snd_cwnd_clamp);
+                                          (u32)tp->snd_cwnd_clamp);
                        tp->snd_cwnd_cnt = 0;
                }
        }
@@ -299,7 +299,6 @@ static u32 tcp_illinois_ssthresh(struct sock *sk)
        return max(tp->snd_cwnd - ((tp->snd_cwnd * ca->beta) >> BETA_SHIFT), 2U);
 }
 
-
 /* Extract info for Tcp socket info provided via netlink. */
 static void tcp_illinois_info(struct sock *sk, u32 ext,
                              struct sk_buff *skb)
index a906e0200ff26144727a1c6c90718cf1fa492dde..f97003ad0af55998df0be629f3c99cd093fd4e43 100644 (file)
@@ -1888,21 +1888,21 @@ static inline void tcp_reset_reno_sack(struct tcp_sock *tp)
        tp->sacked_out = 0;
 }
 
-static void tcp_clear_retrans_partial(struct tcp_sock *tp)
+void tcp_clear_retrans(struct tcp_sock *tp)
 {
        tp->retrans_out = 0;
        tp->lost_out = 0;
-
        tp->undo_marker = 0;
        tp->undo_retrans = -1;
+       tp->fackets_out = 0;
+       tp->sacked_out = 0;
 }
 
-void tcp_clear_retrans(struct tcp_sock *tp)
+static inline void tcp_init_undo(struct tcp_sock *tp)
 {
-       tcp_clear_retrans_partial(tp);
-
-       tp->fackets_out = 0;
-       tp->sacked_out = 0;
+       tp->undo_marker = tp->snd_una;
+       /* Retransmission still in flight may cause DSACKs later. */
+       tp->undo_retrans = tp->retrans_out ? : -1;
 }
 
 /* Enter Loss state. If we detect SACK reneging, forget all SACK information
@@ -1925,18 +1925,18 @@ void tcp_enter_loss(struct sock *sk)
                tp->prior_ssthresh = tcp_current_ssthresh(sk);
                tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
                tcp_ca_event(sk, CA_EVENT_LOSS);
+               tcp_init_undo(tp);
        }
        tp->snd_cwnd       = 1;
        tp->snd_cwnd_cnt   = 0;
        tp->snd_cwnd_stamp = tcp_time_stamp;
 
-       tcp_clear_retrans_partial(tp);
+       tp->retrans_out = 0;
+       tp->lost_out = 0;
 
        if (tcp_is_reno(tp))
                tcp_reset_reno_sack(tp);
 
-       tp->undo_marker = tp->snd_una;
-
        skb = tcp_write_queue_head(sk);
        is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED);
        if (is_reneg) {
@@ -1950,9 +1950,6 @@ void tcp_enter_loss(struct sock *sk)
                if (skb == tcp_send_head(sk))
                        break;
 
-               if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
-                       tp->undo_marker = 0;
-
                TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED;
                if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || is_reneg) {
                        TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
@@ -2671,8 +2668,7 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack)
        NET_INC_STATS_BH(sock_net(sk), mib_idx);
 
        tp->prior_ssthresh = 0;
-       tp->undo_marker = tp->snd_una;
-       tp->undo_retrans = tp->retrans_out ? : -1;
+       tcp_init_undo(tp);
 
        if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) {
                if (!ece_ack)
@@ -2971,7 +2967,8 @@ void tcp_rearm_rto(struct sock *sk)
                if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
                    icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
                        struct sk_buff *skb = tcp_write_queue_head(sk);
-                       const u32 rto_time_stamp = TCP_SKB_CB(skb)->when + rto;
+                       const u32 rto_time_stamp =
+                               tcp_skb_timestamp(skb) + rto;
                        s32 delta = (s32)(rto_time_stamp - tcp_time_stamp);
                        /* delta may not be positive if the socket is locked
                         * when the retrans timer fires and is rescheduled.
@@ -5910,7 +5907,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
        struct request_sock *req;
        struct tcp_sock *tp = tcp_sk(sk);
        struct dst_entry *dst = NULL;
-       __u32 isn = TCP_SKB_CB(skb)->when;
+       __u32 isn = TCP_SKB_CB(skb)->tcp_tw_isn;
        bool want_cookie = false, fastopen;
        struct flowi fl;
        struct tcp_fastopen_cookie foc = { .len = -1 };
index cd17f009aede03524f741b84a413478b2d38ef7c..3f9bc3f0bba0f8b7e7fab8df084667384fba1732 100644 (file)
@@ -90,7 +90,6 @@ int sysctl_tcp_tw_reuse __read_mostly;
 int sysctl_tcp_low_latency __read_mostly;
 EXPORT_SYMBOL(sysctl_tcp_low_latency);
 
-
 #ifdef CONFIG_TCP_MD5SIG
 static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
                               __be32 daddr, __be32 saddr, const struct tcphdr *th);
@@ -438,8 +437,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
                skb = tcp_write_queue_head(sk);
                BUG_ON(!skb);
 
-               remaining = icsk->icsk_rto - min(icsk->icsk_rto,
-                               tcp_time_stamp - TCP_SKB_CB(skb)->when);
+               remaining = icsk->icsk_rto -
+                           min(icsk->icsk_rto,
+                               tcp_time_stamp - tcp_skb_timestamp(skb));
 
                if (remaining) {
                        inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
@@ -1269,7 +1269,7 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = {
        .send_ack       =       tcp_v4_reqsk_send_ack,
        .destructor     =       tcp_v4_reqsk_destructor,
        .send_reset     =       tcp_v4_send_reset,
-       .syn_ack_timeout =      tcp_syn_ack_timeout,
+       .syn_ack_timeout =      tcp_syn_ack_timeout,
 };
 
 static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {
@@ -1628,7 +1628,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
        TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
                                    skb->len - th->doff * 4);
        TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
-       TCP_SKB_CB(skb)->when    = 0;
+       TCP_SKB_CB(skb)->tcp_tw_isn = 0;
        TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);
        TCP_SKB_CB(skb)->sacked  = 0;
 
@@ -2183,7 +2183,7 @@ int tcp_seq_open(struct inode *inode, struct file *file)
 
        s = ((struct seq_file *)file->private_data)->private;
        s->family               = afinfo->family;
-       s->last_pos             = 0;
+       s->last_pos             = 0;
        return 0;
 }
 EXPORT_SYMBOL(tcp_seq_open);
index 1649988bd1b632f09506da9e685dc643c64161fd..a058f411d3a6bd1441282e39da5d34152435513e 100644 (file)
@@ -232,7 +232,7 @@ kill:
                u32 isn = tcptw->tw_snd_nxt + 65535 + 2;
                if (isn == 0)
                        isn++;
-               TCP_SKB_CB(skb)->when = isn;
+               TCP_SKB_CB(skb)->tcp_tw_isn = isn;
                return TCP_TW_SYN;
        }
 
index bc1b83cb8309f5d4737d7751e9542823e044b587..72912533a191ba0335bc8c0d3ec3817d5af45f23 100644 (file)
@@ -288,35 +288,14 @@ static int tcp_v4_gso_send_check(struct sk_buff *skb)
 
 static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 {
-       /* Use the IP hdr immediately proceeding for this transport */
-       const struct iphdr *iph = skb_gro_network_header(skb);
-       __wsum wsum;
-
        /* Don't bother verifying checksum if we're going to flush anyway. */
-       if (NAPI_GRO_CB(skb)->flush)
-               goto skip_csum;
-
-       wsum = NAPI_GRO_CB(skb)->csum;
-
-       switch (skb->ip_summed) {
-       case CHECKSUM_NONE:
-               wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb),
-                                   0);
-
-               /* fall through */
-
-       case CHECKSUM_COMPLETE:
-               if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr,
-                                 wsum)) {
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       break;
-               }
-
+       if (!NAPI_GRO_CB(skb)->flush &&
+           skb_gro_checksum_validate(skb, IPPROTO_TCP,
+                                     inet_gro_compute_pseudo)) {
                NAPI_GRO_CB(skb)->flush = 1;
                return NULL;
        }
 
-skip_csum:
        return tcp_gro_receive(head, skb);
 }
 
index 5a7c41fbc6d3399686ff47ab5102ef7cc1a9ea42..7f1280dcad579315b393b0e2c7953fa05d0e3cf0 100644 (file)
@@ -550,7 +550,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
 
        if (likely(sysctl_tcp_timestamps && *md5 == NULL)) {
                opts->options |= OPTION_TS;
-               opts->tsval = TCP_SKB_CB(skb)->when + tp->tsoffset;
+               opts->tsval = tcp_skb_timestamp(skb) + tp->tsoffset;
                opts->tsecr = tp->rx_opt.ts_recent;
                remaining -= TCPOLEN_TSTAMP_ALIGNED;
        }
@@ -618,7 +618,7 @@ static unsigned int tcp_synack_options(struct sock *sk,
        }
        if (likely(ireq->tstamp_ok)) {
                opts->options |= OPTION_TS;
-               opts->tsval = TCP_SKB_CB(skb)->when;
+               opts->tsval = tcp_skb_timestamp(skb);
                opts->tsecr = req->ts_recent;
                remaining -= TCPOLEN_TSTAMP_ALIGNED;
        }
@@ -647,7 +647,6 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
                                        struct tcp_out_options *opts,
                                        struct tcp_md5sig_key **md5)
 {
-       struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL;
        struct tcp_sock *tp = tcp_sk(sk);
        unsigned int size = 0;
        unsigned int eff_sacks;
@@ -666,7 +665,7 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
 
        if (likely(tp->rx_opt.tstamp_ok)) {
                opts->options |= OPTION_TS;
-               opts->tsval = tcb ? tcb->when + tp->tsoffset : 0;
+               opts->tsval = skb ? tcp_skb_timestamp(skb) + tp->tsoffset : 0;
                opts->tsecr = tp->rx_opt.ts_recent;
                size += TCPOLEN_TSTAMP_ALIGNED;
        }
@@ -886,8 +885,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                        skb = skb_clone(skb, gfp_mask);
                if (unlikely(!skb))
                        return -ENOBUFS;
-               /* Our usage of tstamp should remain private */
-               skb->tstamp.tv64 = 0;
        }
 
        inet = inet_sk(sk);
@@ -975,7 +972,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS,
                              tcp_skb_pcount(skb));
 
+       /* Our usage of tstamp should remain private */
+       skb->tstamp.tv64 = 0;
        err = icsk->icsk_af_ops->queue_xmit(sk, skb, &inet->cork.fl);
+
        if (likely(err <= 0))
                return err;
 
@@ -1146,10 +1146,6 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
 
        buff->ip_summed = skb->ip_summed;
 
-       /* Looks stupid, but our code really uses when of
-        * skbs, which it never sent before. --ANK
-        */
-       TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
        buff->tstamp = skb->tstamp;
        tcp_fragment_tstamp(skb, buff);
 
@@ -1874,8 +1870,8 @@ static int tcp_mtu_probe(struct sock *sk)
        tcp_init_tso_segs(sk, nskb, nskb->len);
 
        /* We're ready to send.  If this fails, the probe will
-        * be resegmented into mss-sized pieces by tcp_write_xmit(). */
-       TCP_SKB_CB(nskb)->when = tcp_time_stamp;
+        * be resegmented into mss-sized pieces by tcp_write_xmit().
+        */
        if (!tcp_transmit_skb(sk, nskb, 1, GFP_ATOMIC)) {
                /* Decrement cwnd here because we are sending
                 * effectively two packets. */
@@ -1935,8 +1931,8 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                BUG_ON(!tso_segs);
 
                if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) {
-                       /* "when" is used as a start point for the retransmit timer */
-                       TCP_SKB_CB(skb)->when = tcp_time_stamp;
+                       /* "skb_mstamp" is used as a start point for the retransmit timer */
+                       skb_mstamp_get(&skb->skb_mstamp);
                        goto repair; /* Skip network transmission */
                }
 
@@ -2000,8 +1996,6 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                    unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
                        break;
 
-               TCP_SKB_CB(skb)->when = tcp_time_stamp;
-
                if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
                        break;
 
@@ -2499,7 +2493,6 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        /* Make a copy, if the first transmission SKB clone we made
         * is still in somebody's hands, else make a clone.
         */
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
 
        /* make sure skb->data is aligned on arches that require it
         * and check if ack-trimming & collapsing extended the headroom
@@ -2544,7 +2537,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
 
                /* Save stamp of the first retransmit. */
                if (!tp->retrans_stamp)
-                       tp->retrans_stamp = TCP_SKB_CB(skb)->when;
+                       tp->retrans_stamp = tcp_skb_timestamp(skb);
 
                /* snd_nxt is stored to detect loss of retransmitted segment,
                 * see tcp_input.c tcp_sacktag_write_queue().
@@ -2752,7 +2745,6 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority)
        tcp_init_nondata_skb(skb, tcp_acceptable_seq(sk),
                             TCPHDR_ACK | TCPHDR_RST);
        /* Send it off. */
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
        if (tcp_transmit_skb(sk, skb, 0, priority))
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED);
 
@@ -2791,7 +2783,6 @@ int tcp_send_synack(struct sock *sk)
                TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ACK;
                TCP_ECN_send_synack(tcp_sk(sk), skb);
        }
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
        return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
 }
 
@@ -2835,10 +2826,10 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        memset(&opts, 0, sizeof(opts));
 #ifdef CONFIG_SYN_COOKIES
        if (unlikely(req->cookie_ts))
-               TCP_SKB_CB(skb)->when = cookie_init_timestamp(req);
+               skb->skb_mstamp.stamp_jiffies = cookie_init_timestamp(req);
        else
 #endif
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
+       skb_mstamp_get(&skb->skb_mstamp);
        tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, &md5,
                                             foc) + sizeof(*th);
 
@@ -3086,7 +3077,7 @@ int tcp_connect(struct sock *sk)
        skb_reserve(buff, MAX_TCP_HEADER);
 
        tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
-       tp->retrans_stamp = TCP_SKB_CB(buff)->when = tcp_time_stamp;
+       tp->retrans_stamp = tcp_time_stamp;
        tcp_connect_queue_skb(sk, buff);
        TCP_ECN_send_syn(sk, buff);
 
@@ -3194,7 +3185,7 @@ void tcp_send_ack(struct sock *sk)
        tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPHDR_ACK);
 
        /* Send it off, this clears delayed acks for us. */
-       TCP_SKB_CB(buff)->when = tcp_time_stamp;
+       skb_mstamp_get(&buff->skb_mstamp);
        tcp_transmit_skb(sk, buff, 0, sk_gfp_atomic(sk, GFP_ATOMIC));
 }
 
@@ -3226,7 +3217,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent)
         * send it.
         */
        tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPHDR_ACK);
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
+       skb_mstamp_get(&skb->skb_mstamp);
        return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC);
 }
 
@@ -3270,7 +3261,6 @@ int tcp_write_wakeup(struct sock *sk)
                        tcp_set_skb_tso_segs(sk, skb, mss);
 
                TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH;
-               TCP_SKB_CB(skb)->when = tcp_time_stamp;
                err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
                if (!err)
                        tcp_event_new_data_sent(sk, skb);
index 3b66610d41562035c541304924fc27a4eb416a6e..ebf5ff57526eab65018005c47a907545e61cacf6 100644 (file)
@@ -83,7 +83,6 @@ static struct {
        struct tcp_log  *log;
 } tcp_probe;
 
-
 static inline int tcp_probe_used(void)
 {
        return (tcp_probe.head - tcp_probe.tail) & (bufsize - 1);
@@ -101,7 +100,6 @@ static inline int tcp_probe_avail(void)
                si4.sin_addr.s_addr = inet->inet_##mem##addr;   \
        } while (0)                                             \
 
-
 /*
  * Hook inserted to be called before each receive packet.
  * Note: arguments must match tcp_rcv_established()!
@@ -194,8 +192,8 @@ static int tcpprobe_sprint(char *tbuf, int n)
 
        return scnprintf(tbuf, n,
                        "%lu.%09lu %pISpc %pISpc %d %#x %#x %u %u %u %u %u\n",
-                       (unsigned long) tv.tv_sec,
-                       (unsigned long) tv.tv_nsec,
+                       (unsigned long)tv.tv_sec,
+                       (unsigned long)tv.tv_nsec,
                        &p->src, &p->dst, p->length, p->snd_nxt, p->snd_una,
                        p->snd_cwnd, p->ssthresh, p->snd_wnd, p->srtt, p->rcv_wnd);
 }
index 8250949b88538db4e0f2d318050518855e74cf3d..6824afb65d9335532fe2bf61edce82cab8c3fd9c 100644 (file)
@@ -31,10 +31,10 @@ static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 static u32 tcp_scalable_ssthresh(struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
+
        return max(tp->snd_cwnd - (tp->snd_cwnd>>TCP_SCALABLE_MD_SCALE), 2U);
 }
 
-
 static struct tcp_congestion_ops tcp_scalable __read_mostly = {
        .ssthresh       = tcp_scalable_ssthresh,
        .cong_avoid     = tcp_scalable_cong_avoid,
index df90cd1ce37f71b145d3f5cde4bf1d9b4a4cfd22..a339e7ba05a434954744b6716a7d57be0400066c 100644 (file)
@@ -135,10 +135,9 @@ static bool retransmits_timed_out(struct sock *sk,
        if (!inet_csk(sk)->icsk_retransmits)
                return false;
 
-       if (unlikely(!tcp_sk(sk)->retrans_stamp))
-               start_ts = TCP_SKB_CB(tcp_write_queue_head(sk))->when;
-       else
-               start_ts = tcp_sk(sk)->retrans_stamp;
+       start_ts = tcp_sk(sk)->retrans_stamp;
+       if (unlikely(!start_ts))
+               start_ts = tcp_skb_timestamp(tcp_write_queue_head(sk));
 
        if (likely(timeout == 0)) {
                linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base);
index b40ad897f94509201988b6b9cc589e599d036851..a6afde666ab1284ea53c24ce80b2c287ff42073b 100644 (file)
@@ -51,7 +51,6 @@ MODULE_PARM_DESC(beta, "upper bound of packets in network");
 module_param(gamma, int, 0644);
 MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)");
 
-
 /* There are several situations when we must "re-start" Vegas:
  *
  *  o when a connection is established
@@ -133,7 +132,6 @@ EXPORT_SYMBOL_GPL(tcp_vegas_pkts_acked);
 
 void tcp_vegas_state(struct sock *sk, u8 ca_state)
 {
-
        if (ca_state == TCP_CA_Open)
                vegas_enable(sk);
        else
@@ -285,7 +283,6 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
        /* Use normal slow start */
        else if (tp->snd_cwnd <= tp->snd_ssthresh)
                tcp_slow_start(tp, acked);
-
 }
 
 /* Extract info for Tcp socket info provided via netlink. */
index 8276977d2c854729d9c7a0e3e501b2dee9db4c3d..a4d2d2d88dcae7c00cf4db83d8b13ce6b143b3b4 100644 (file)
@@ -175,7 +175,6 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                                } else
                                        tp->snd_cwnd_cnt++;
                        }
-
                }
                if (tp->snd_cwnd < 2)
                        tp->snd_cwnd = 2;
index b94a04ae2ed5672eca79a172c5c3467a677186a1..81911a92356c6a7a50b63800dc070d6943c280f3 100644 (file)
@@ -42,7 +42,6 @@ struct westwood {
        u8     reset_rtt_min;    /* Reset RTT min to next RTT sample*/
 };
 
-
 /* TCP Westwood functions and constants */
 #define TCP_WESTWOOD_RTT_MIN   (HZ/20) /* 50ms */
 #define TCP_WESTWOOD_INIT_RTT  (20*HZ) /* maybe too conservative?! */
@@ -153,7 +152,6 @@ static inline void update_rtt_min(struct westwood *w)
                w->rtt_min = min(w->rtt, w->rtt_min);
 }
 
-
 /*
  * @westwood_fast_bw
  * It is called when we are in fast path. In particular it is called when
@@ -208,7 +206,6 @@ static inline u32 westwood_acked_count(struct sock *sk)
        return w->cumul_ack;
 }
 
-
 /*
  * TCP Westwood
  * Here limit is evaluated as Bw estimation*RTTmin (for obtaining it
@@ -219,6 +216,7 @@ static u32 tcp_westwood_bw_rttmin(const struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
        const struct westwood *w = inet_csk_ca(sk);
+
        return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2);
 }
 
@@ -254,12 +252,12 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
        }
 }
 
-
 /* Extract info for Tcp socket info provided via netlink. */
 static void tcp_westwood_info(struct sock *sk, u32 ext,
                              struct sk_buff *skb)
 {
        const struct westwood *ca = inet_csk_ca(sk);
+
        if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
                struct tcpvegas_info info = {
                        .tcpv_enabled = 1,
@@ -271,7 +269,6 @@ static void tcp_westwood_info(struct sock *sk, u32 ext,
        }
 }
 
-
 static struct tcp_congestion_ops tcp_westwood __read_mostly = {
        .init           = tcp_westwood_init,
        .ssthresh       = tcp_reno_ssthresh,
index 599b79b8eac07298a34cff43ae87e546bdb36847..cd72732185989b41d1a3f9167eacbf44c235cc01 100644 (file)
@@ -54,10 +54,8 @@ static void tcp_yeah_init(struct sock *sk)
        /* Ensure the MD arithmetic works.  This is somewhat pedantic,
         * since I don't think we will see a cwnd this large. :) */
        tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
-
 }
 
-
 static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, s32 rtt_us)
 {
        const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -84,7 +82,7 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                /* Scalable */
 
                tp->snd_cwnd_cnt += yeah->pkts_acked;
-               if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){
+               if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)) {
                        if (tp->snd_cwnd < tp->snd_cwnd_clamp)
                                tp->snd_cwnd++;
                        tp->snd_cwnd_cnt = 0;
@@ -120,7 +118,6 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
         */
 
        if (after(ack, yeah->vegas.beg_snd_nxt)) {
-
                /* We do the Vegas calculations only if we got enough RTT
                 * samples that we can be reasonably sure that we got
                 * at least one RTT sample that wasn't from a delayed ACK.
@@ -189,7 +186,6 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                        }
 
                        yeah->lastQ = queue;
-
                }
 
                /* Save the extent of the current window so we can use this
@@ -205,7 +201,8 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
        }
 }
 
-static u32 tcp_yeah_ssthresh(struct sock *sk) {
+static u32 tcp_yeah_ssthresh(struct sock *sk)
+{
        const struct tcp_sock *tp = tcp_sk(sk);
        struct yeah *yeah = inet_csk_ca(sk);
        u32 reduction;
index f57c0e4c2326fd1a7d4b85cbdb4304657e5660f8..cd0db5471bb5eb6048208404aab71253867e1eec 100644 (file)
@@ -99,6 +99,7 @@
 #include <linux/slab.h>
 #include <net/tcp_states.h>
 #include <linux/skbuff.h>
+#include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <net/net_namespace.h>
@@ -224,7 +225,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
                remaining = (high - low) + 1;
 
                rand = prandom_u32();
-               first = (((u64)rand * remaining) >> 32) + low;
+               first = reciprocal_scale(rand, remaining) + low;
                /*
                 * force rand to be an odd multiple of UDP_HTABLE_SIZE
                 */
@@ -448,7 +449,7 @@ begin:
                        }
                } else if (score == badness && reuseport) {
                        matches++;
-                       if (((u64)hash * matches) >> 32 == 0)
+                       if (reciprocal_scale(hash, matches) == 0)
                                result = sk;
                        hash = next_pseudo_random32(hash);
                }
@@ -529,7 +530,7 @@ begin:
                        }
                } else if (score == badness && reuseport) {
                        matches++;
-                       if (((u64)hash * matches) >> 32 == 0)
+                       if (reciprocal_scale(hash, matches) == 0)
                                result = sk;
                        hash = next_pseudo_random32(hash);
                }
@@ -1787,6 +1788,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        if (sk != NULL) {
                int ret;
 
+               if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk))
+                       skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
+                                                inet_compute_pseudo);
+
                ret = udp_queue_rcv_skb(sk, skb);
                sock_put(sk);
 
@@ -1967,7 +1972,7 @@ void udp_v4_early_demux(struct sk_buff *skb)
                return;
 
        skb->sk = sk;
-       skb->destructor = sock_edemux;
+       skb->destructor = sock_efree;
        dst = sk->sk_rx_dst;
 
        if (dst)
index 59035bc3008d2bc45ec87e9eea4145120bf664be..84e0e05c9c0e97b584b4fe42fe22a65dcc071615 100644 (file)
@@ -228,30 +228,24 @@ unlock:
 }
 EXPORT_SYMBOL(udp_del_offload);
 
-static struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
+struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
+                                struct udphdr *uh)
 {
        struct udp_offload_priv *uo_priv;
        struct sk_buff *p, **pp = NULL;
-       struct udphdr *uh, *uh2;
-       unsigned int hlen, off;
+       struct udphdr *uh2;
+       unsigned int off = skb_gro_offset(skb);
        int flush = 1;
 
        if (NAPI_GRO_CB(skb)->udp_mark ||
-           (!skb->encapsulation && skb->ip_summed != CHECKSUM_COMPLETE))
+           (skb->ip_summed != CHECKSUM_PARTIAL &&
+            NAPI_GRO_CB(skb)->csum_cnt == 0 &&
+            !NAPI_GRO_CB(skb)->csum_valid))
                goto out;
 
        /* mark that this skb passed once through the udp gro layer */
        NAPI_GRO_CB(skb)->udp_mark = 1;
 
-       off  = skb_gro_offset(skb);
-       hlen = off + sizeof(*uh);
-       uh   = skb_gro_header_fast(skb, off);
-       if (skb_gro_header_hard(skb, hlen)) {
-               uh = skb_gro_header_slow(skb, hlen, off);
-               if (unlikely(!uh))
-                       goto out;
-       }
-
        rcu_read_lock();
        uo_priv = rcu_dereference(udp_offload_base);
        for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
@@ -269,7 +263,12 @@ unflush:
                        continue;
 
                uh2 = (struct udphdr   *)(p->data + off);
-               if ((*(u32 *)&uh->source != *(u32 *)&uh2->source)) {
+
+               /* Match ports and either checksums are either both zero
+                * or nonzero.
+                */
+               if ((*(u32 *)&uh->source != *(u32 *)&uh2->source) ||
+                   (!uh->check ^ !uh2->check)) {
                        NAPI_GRO_CB(p)->same_flow = 0;
                        continue;
                }
@@ -286,7 +285,33 @@ out:
        return pp;
 }
 
-static int udp_gro_complete(struct sk_buff *skb, int nhoff)
+static struct sk_buff **udp4_gro_receive(struct sk_buff **head,
+                                        struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_gro_udphdr(skb);
+
+       if (unlikely(!uh))
+               goto flush;
+
+       /* Don't bother verifying checksum if we're going to flush anyway. */
+       if (!NAPI_GRO_CB(skb)->flush)
+               goto skip;
+
+       if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
+                                                inet_gro_compute_pseudo))
+               goto flush;
+       else if (uh->check)
+               skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
+                                            inet_gro_compute_pseudo);
+skip:
+       return udp_gro_receive(head, skb, uh);
+
+flush:
+       NAPI_GRO_CB(skb)->flush = 1;
+       return NULL;
+}
+
+int udp_gro_complete(struct sk_buff *skb, int nhoff)
 {
        struct udp_offload_priv *uo_priv;
        __be16 newlen = htons(skb->len - nhoff);
@@ -311,12 +336,24 @@ static int udp_gro_complete(struct sk_buff *skb, int nhoff)
        return err;
 }
 
+int udp4_gro_complete(struct sk_buff *skb, int nhoff)
+{
+       const struct iphdr *iph = ip_hdr(skb);
+       struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
+
+       if (uh->check)
+               uh->check = ~udp_v4_check(skb->len - nhoff, iph->saddr,
+                                         iph->daddr, 0);
+
+       return udp_gro_complete(skb, nhoff);
+}
+
 static const struct net_offload udpv4_offload = {
        .callbacks = {
                .gso_send_check = udp4_ufo_send_check,
                .gso_segment = udp4_ufo_fragment,
-               .gro_receive  = udp_gro_receive,
-               .gro_complete = udp_gro_complete,
+               .gro_receive  = udp4_gro_receive,
+               .gro_complete = udp4_gro_complete,
        },
 };
 
index fc1fac2a052856e5c1b2476dc469d261a6558e5e..ad4598fcc416cde41211fd466b2b259d6cb98dc9 100644 (file)
@@ -180,7 +180,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .rtr_solicits           = MAX_RTR_SOLICITATIONS,
        .rtr_solicit_interval   = RTR_SOLICITATION_INTERVAL,
        .rtr_solicit_delay      = MAX_RTR_SOLICITATION_DELAY,
-       .use_tempaddr           = 0,
+       .use_tempaddr           = 0,
        .temp_valid_lft         = TEMP_VALID_LIFETIME,
        .temp_prefered_lft      = TEMP_PREFERRED_LIFETIME,
        .regen_max_retry        = REGEN_MAX_RETRY,
@@ -1105,8 +1105,8 @@ retry:
        spin_unlock_bh(&ifp->lock);
 
        regen_advance = idev->cnf.regen_max_retry *
-                       idev->cnf.dad_transmits *
-                       NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ;
+                       idev->cnf.dad_transmits *
+                       NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ;
        write_unlock_bh(&idev->lock);
 
        /* A temporary address is created only if this calculated Preferred
@@ -3030,7 +3030,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                struct hlist_head *h = &inet6_addr_lst[i];
 
                spin_lock_bh(&addrconf_hash_lock);
-       restart:
+restart:
                hlist_for_each_entry_rcu(ifa, h, addr_lst) {
                        if (ifa->idev == idev) {
                                hlist_del_init_rcu(&ifa->addr_lst);
@@ -3542,8 +3542,8 @@ static void __net_exit if6_proc_net_exit(struct net *net)
 }
 
 static struct pernet_operations if6_proc_net_ops = {
-       .init = if6_proc_net_init,
-       .exit = if6_proc_net_exit,
+       .init = if6_proc_net_init,
+       .exit = if6_proc_net_exit,
 };
 
 int __init if6_proc_init(void)
index 2daa3a133e498cdccfe5695ee62db7c72da8ce25..b9393e6a21fe0ae99cffad643cfe2a49e5472b35 100644 (file)
@@ -7,15 +7,15 @@
  *
  *     Adapted from linux/net/ipv4/af_inet.c
  *
- *     Fixes:
+ *     Fixes:
  *     piggy, Karl Knutson     :       Socket protocol table
- *     Hideaki YOSHIFUJI       :       sin6_scope_id support
- *     Arnaldo Melo            :       check proc_net_create return, cleanups
+ *     Hideaki YOSHIFUJI       :       sin6_scope_id support
+ *     Arnaldo Melo            :       check proc_net_create return, cleanups
  *
  *     This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
  */
 
 #define pr_fmt(fmt) "IPv6: " fmt
index 72a4930bdc0a0e0d43e1a6ad8670e6a1df1608f4..fcffd4e522c88276620cd52c56bbc574b159146f 100644 (file)
  * Authors
  *
  *     Mitsuru KANDA @USAGI       : IPv6 Support
- *     Kazunori MIYAZAWA @USAGI   :
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *     Kazunori MIYAZAWA @USAGI   :
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  *
- *     This file is derived from net/ipv4/ah.c.
+ *     This file is derived from net/ipv4/ah.c.
  */
 
 #define pr_fmt(fmt) "IPv6: " fmt
@@ -284,7 +284,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
                        ipv6_rearrange_rthdr(iph, exthdr.rth);
                        break;
 
-               default :
+               default:
                        return 0;
                }
 
@@ -478,7 +478,7 @@ static void ah6_input_done(struct crypto_async_request *base, int err)
        auth_data = ah_tmp_auth(work_iph, hdr_len);
        icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
 
-       err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
+       err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
        if (err)
                goto out;
 
@@ -622,7 +622,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
                goto out_free;
        }
 
-       err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
+       err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
        if (err)
                goto out_free;
 
@@ -647,8 +647,8 @@ static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                   u8 type, u8 code, int offset, __be32 info)
 {
        struct net *net = dev_net(skb->dev);
-       struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
-       struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset);
+       struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
+       struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+offset);
        struct xfrm_state *x;
 
        if (type != ICMPV6_PKT_TOOBIG &&
@@ -755,11 +755,10 @@ static int ah6_rcv_cb(struct sk_buff *skb, int err)
        return 0;
 }
 
-static const struct xfrm_type ah6_type =
-{
+static const struct xfrm_type ah6_type = {
        .description    = "AH6",
        .owner          = THIS_MODULE,
-       .proto          = IPPROTO_AH,
+       .proto          = IPPROTO_AH,
        .flags          = XFRM_TYPE_REPLAY_PROT,
        .init_state     = ah6_init_state,
        .destructor     = ah6_destroy,
index 2753319524f1acabb34a0520ea29ee361c1dfe9e..2cdc38338be3fda267d7137cb20fc8bbe72c4466 100644 (file)
@@ -43,13 +43,13 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a)
 int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
-       struct inet_sock        *inet = inet_sk(sk);
-       struct ipv6_pinfo       *np = inet6_sk(sk);
-       struct in6_addr         *daddr, *final_p, final;
+       struct inet_sock        *inet = inet_sk(sk);
+       struct ipv6_pinfo       *np = inet6_sk(sk);
+       struct in6_addr *daddr, *final_p, final;
        struct dst_entry        *dst;
        struct flowi6           fl6;
        struct ip6_flowlabel    *flowlabel = NULL;
-       struct ipv6_txoptions   *opt;
+       struct ipv6_txoptions   *opt;
        int                     addr_type;
        int                     err;
 
@@ -332,7 +332,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct sock_exterr_skb *serr;
-       struct sk_buff *skb, *skb2;
+       struct sk_buff *skb;
        DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name);
        struct {
                struct sock_extended_err ee;
@@ -342,7 +342,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        int copied;
 
        err = -EAGAIN;
-       skb = skb_dequeue(&sk->sk_error_queue);
+       skb = sock_dequeue_err_skb(sk);
        if (skb == NULL)
                goto out;
 
@@ -415,17 +415,6 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        msg->msg_flags |= MSG_ERRQUEUE;
        err = copied;
 
-       /* Reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
-               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else {
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-       }
-
 out_free_skb:
        kfree_skb(skb);
 out:
index d15da1377149d3a0fdf846a7a07364e6d1251845..83fc3a385a26782c316914c4f8aafab78fe1a5e2 100644 (file)
  * Authors
  *
  *     Mitsuru KANDA @USAGI       : IPv6 Support
- *     Kazunori MIYAZAWA @USAGI   :
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *     Kazunori MIYAZAWA @USAGI   :
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  *
- *     This file is derived from net/ipv4/esp.c
+ *     This file is derived from net/ipv4/esp.c
  */
 
 #define pr_fmt(fmt) "IPv6: " fmt
@@ -598,7 +598,7 @@ static int esp6_init_state(struct xfrm_state *x)
        case XFRM_MODE_BEET:
                if (x->sel.family != AF_INET6)
                        x->props.header_len += IPV4_BEET_PHMAXLEN +
-                                              (sizeof(struct ipv6hdr) - sizeof(struct iphdr));
+                                              (sizeof(struct ipv6hdr) - sizeof(struct iphdr));
                break;
        case XFRM_MODE_TRANSPORT:
                break;
@@ -621,11 +621,10 @@ static int esp6_rcv_cb(struct sk_buff *skb, int err)
        return 0;
 }
 
-static const struct xfrm_type esp6_type =
-{
+static const struct xfrm_type esp6_type = {
        .description    = "ESP6",
-       .owner          = THIS_MODULE,
-       .proto          = IPPROTO_ESP,
+       .owner          = THIS_MODULE,
+       .proto          = IPPROTO_ESP,
        .flags          = XFRM_TYPE_REPLAY_PROT,
        .init_state     = esp6_init_state,
        .destructor     = esp6_destroy,
index 8d67900aa0036139e934354f98aefab13ba51c7a..bfde361b613400df742c21225a1b4b44744ece65 100644 (file)
@@ -142,7 +142,7 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
                default: /* Other TLV code so scan list */
                        if (optlen > len)
                                goto bad;
-                       for (curr=procs; curr->type >= 0; curr++) {
+                       for (curr = procs; curr->type >= 0; curr++) {
                                if (curr->type == nh[off]) {
                                        /* type specific length/alignment
                                           checks will be performed in the
index 06ba3e58320ba45fc3856659e43afd952495db35..394bb824fe4bc9a31119b3e12f170800e5f375e5 100644 (file)
@@ -503,7 +503,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
        msg.type = type;
 
        len = skb->len - msg.offset;
-       len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr));
+       len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
        if (len < 0) {
                LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n");
                goto out_dst_release;
@@ -636,7 +636,7 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
                /* now skip over extension headers */
                inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
                                                &nexthdr, &frag_off);
-               if (inner_offset<0)
+               if (inner_offset < 0)
                        goto out;
        } else {
                inner_offset = sizeof(struct ipv6hdr);
@@ -808,7 +808,7 @@ void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
        memset(fl6, 0, sizeof(*fl6));
        fl6->saddr = *saddr;
        fl6->daddr = *daddr;
-       fl6->flowi6_proto       = IPPROTO_ICMPV6;
+       fl6->flowi6_proto       = IPPROTO_ICMPV6;
        fl6->fl6_icmp_type      = type;
        fl6->fl6_icmp_code      = 0;
        fl6->flowi6_oif         = oif;
@@ -875,8 +875,8 @@ static void __net_exit icmpv6_sk_exit(struct net *net)
 }
 
 static struct pernet_operations icmpv6_sk_ops = {
-       .init = icmpv6_sk_init,
-       .exit = icmpv6_sk_exit,
+       .init = icmpv6_sk_init,
+       .exit = icmpv6_sk_exit,
 };
 
 int __init icmpv6_init(void)
index a245e5ddffbd0450968c44de7d3fcd8a1dd055cf..29b32206e49488e1155900adfcd1707ea909855e 100644 (file)
@@ -63,7 +63,6 @@ int inet6_csk_bind_conflict(const struct sock *sk,
 
        return sk2 != NULL;
 }
-
 EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
 
 struct dst_entry *inet6_csk_route_req(struct sock *sk,
@@ -144,7 +143,6 @@ struct request_sock *inet6_csk_search_req(const struct sock *sk,
 
        return NULL;
 }
-
 EXPORT_SYMBOL_GPL(inet6_csk_search_req);
 
 void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
@@ -160,10 +158,9 @@ void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
        reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
        inet_csk_reqsk_queue_added(sk, timeout);
 }
-
 EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add);
 
-void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
+void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
 {
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
 
@@ -175,7 +172,6 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
        sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
                                                  sk->sk_bound_dev_if);
 }
-
 EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
 
 static inline
index 262e13c02ec27dea15154d9b4af5fd413dd1c504..051dffb49c90e979ca6cc58dd1c2cd2fe9b1cc4c 100644 (file)
@@ -6,7 +6,7 @@
  *             Generic INET6 transport hashtables
  *
  * Authors:    Lotsa people, from code originally in tcp, generalised here
- *             by Arnaldo Carvalho de Melo <acme@mandriva.com>
+ *             by Arnaldo Carvalho de Melo <acme@mandriva.com>
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -198,7 +198,7 @@ begin:
                        }
                } else if (score == hiscore && reuseport) {
                        matches++;
-                       if (((u64)phash * matches) >> 32 == 0)
+                       if (reciprocal_scale(phash, matches) == 0)
                                result = sk;
                        phash = next_pseudo_random32(phash);
                }
@@ -222,7 +222,6 @@ begin:
        rcu_read_unlock();
        return result;
 }
-
 EXPORT_SYMBOL_GPL(inet6_lookup_listener);
 
 struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
@@ -238,7 +237,6 @@ struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
 
        return sk;
 }
-
 EXPORT_SYMBOL_GPL(inet6_lookup);
 
 static int __inet6_check_established(struct inet_timewait_death_row *death_row,
@@ -324,5 +322,4 @@ int inet6_hash_connect(struct inet_timewait_death_row *death_row,
        return __inet_hash_connect(death_row, sk, inet6_sk_port_offset(sk),
                        __inet6_check_established, __inet6_hash);
 }
-
 EXPORT_SYMBOL_GPL(inet6_hash_connect);
index 4052694c6f2cb196b54ef7d5235d61d74e4ea69c..3dd7d4ebd7cd9dff75c7a89a3a872cf8a073543b 100644 (file)
@@ -136,7 +136,7 @@ static void ip6_fl_gc(unsigned long dummy)
 
        spin_lock(&ip6_fl_lock);
 
-       for (i=0; i<=FL_HASH_MASK; i++) {
+       for (i = 0; i <= FL_HASH_MASK; i++) {
                struct ip6_flowlabel *fl;
                struct ip6_flowlabel __rcu **flp;
 
@@ -239,7 +239,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net,
 
 /* Socket flowlabel lists */
 
-struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label)
+struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label)
 {
        struct ipv6_fl_socklist *sfl;
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -259,7 +259,6 @@ struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label)
        rcu_read_unlock_bh();
        return NULL;
 }
-
 EXPORT_SYMBOL_GPL(fl6_sock_lookup);
 
 void fl6_free_socklist(struct sock *sk)
@@ -293,11 +292,11 @@ void fl6_free_socklist(struct sock *sk)
    following rthdr.
  */
 
-struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
-                                        struct ip6_flowlabel * fl,
-                                        struct ipv6_txoptions * fopt)
+struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
+                                        struct ip6_flowlabel *fl,
+                                        struct ipv6_txoptions *fopt)
 {
-       struct ipv6_txoptions * fl_opt = fl->opt;
+       struct ipv6_txoptions *fl_opt = fl->opt;
 
        if (fopt == NULL || fopt->opt_flen == 0)
                return fl_opt;
@@ -388,7 +387,7 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
                        goto done;
 
                msg.msg_controllen = olen;
-               msg.msg_control = (void*)(fl->opt+1);
+               msg.msg_control = (void *)(fl->opt+1);
                memset(&flowi6, 0, sizeof(flowi6));
 
                err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt,
@@ -517,7 +516,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
        struct net *net = sock_net(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct in6_flowlabel_req freq;
-       struct ipv6_fl_socklist *sfl1=NULL;
+       struct ipv6_fl_socklist *sfl1 = NULL;
        struct ipv6_fl_socklist *sfl;
        struct ipv6_fl_socklist __rcu **sflp;
        struct ip6_flowlabel *fl, *fl1 = NULL;
@@ -542,7 +541,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
                }
                spin_lock_bh(&ip6_sk_fl_lock);
                for (sflp = &np->ipv6_fl_list;
-                    (sfl = rcu_dereference(*sflp))!=NULL;
+                    (sfl = rcu_dereference(*sflp)) != NULL;
                     sflp = &sfl->next) {
                        if (sfl->fl->label == freq.flr_label) {
                                if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK))
index 4578e23834f726ca254d577029c7ccf54ccbed7b..14dacc544c3efc06de8ac80f6bbf6a5ee6cf6b35 100644 (file)
@@ -13,7 +13,7 @@ static ip6_icmp_send_t __rcu *ip6_icmp_send;
 int inet6_register_icmp_sender(ip6_icmp_send_t *fn)
 {
        return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ?
-               0 : -EBUSY;
+               0 : -EBUSY;
 }
 EXPORT_SYMBOL(inet6_register_icmp_sender);
 
index 51d54dc376f3b1862040f38e6f58e2c75001049c..a3084ab5df6cd1b343af6d725975082f5c4b6eb6 100644 (file)
@@ -15,8 +15,8 @@
  */
 /* Changes
  *
- *     Mitsuru KANDA @USAGI and
- *     YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
+ *     Mitsuru KANDA @USAGI and
+ *     YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
  */
 
 #include <linux/errno.h>
@@ -65,7 +65,7 @@ int ip6_rcv_finish(struct sk_buff *skb)
 int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        const struct ipv6hdr *hdr;
-       u32             pkt_len;
+       u32 pkt_len;
        struct inet6_dev *idev;
        struct net *net = dev_net(skb->dev);
 
index 65eda2a8af48280e0c068f24d8ef7adc8c7d8c9e..5bcda338bcefbd1c9cb60e0e275df3aa41d2e35a 100644 (file)
@@ -244,7 +244,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
                        continue;
 
                iph2 = (struct ipv6hdr *)(p->data + off);
-               first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ;
+               first_word = *(__be32 *)iph ^ *(__be32 *)iph2;
 
                /* All fields must match except length and Traffic Class.
                 * XXX skbs on the gro_list have all been parsed and pulled
index 315a55d66079cb7129dbfe183e31bcceffd63f99..b7a3e7b3378e470edfc35e8b3235a529c174c3e5 100644 (file)
@@ -20,7 +20,7 @@
  *                             etc.
  *
  *      H. von Brand    :       Added missing #include <linux/string.h>
- *     Imran Patel     :       frag id should be in NBO
+ *     Imran Patel     :       frag id should be in NBO
  *      Kazunori MIYAZAWA @USAGI
  *                     :       add ip6_append_data and related functions
  *                             for datagram xmit
@@ -233,7 +233,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        kfree_skb(skb);
        return -EMSGSIZE;
 }
-
 EXPORT_SYMBOL(ip6_xmit);
 
 static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
@@ -555,14 +554,14 @@ static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
 int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
        struct sk_buff *frag;
-       struct rt6_info *rt = (struct rt6_info*)skb_dst(skb);
+       struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
        struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
        struct ipv6hdr *tmp_hdr;
        struct frag_hdr *fh;
        unsigned int mtu, hlen, left, len;
        int hroom, troom;
        __be32 frag_id = 0;
-       int ptr, offset = 0, err=0;
+       int ptr, offset = 0, err = 0;
        u8 *prevhdr, nexthdr = 0;
        struct net *net = dev_net(skb_dst(skb)->dev);
 
@@ -637,7 +636,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                }
 
                __skb_pull(skb, hlen);
-               fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr));
+               fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
                __skb_push(skb, hlen);
                skb_reset_network_header(skb);
                memcpy(skb_network_header(skb), tmp_hdr, hlen);
@@ -662,7 +661,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                        if (frag) {
                                frag->ip_summed = CHECKSUM_NONE;
                                skb_reset_transport_header(frag);
-                               fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr));
+                               fh = (struct frag_hdr *)__skb_push(frag, sizeof(struct frag_hdr));
                                __skb_push(frag, hlen);
                                skb_reset_network_header(frag);
                                memcpy(skb_network_header(frag), tmp_hdr,
@@ -681,7 +680,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                        }
 
                        err = output(skb);
-                       if(!err)
+                       if (!err)
                                IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
                                              IPSTATS_MIB_FRAGCREATES);
 
@@ -742,7 +741,7 @@ slow_path:
        /*
         *      Keep copying data until we run out.
         */
-       while(left > 0) {
+       while (left > 0)        {
                len = left;
                /* IF: it doesn't fit, use 'mtu' - the data space left */
                if (len > mtu)
@@ -865,7 +864,7 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
        /* Yes, checking route validity in not connected
         * case is not very simple. Take into account,
         * that we do not support routing by source, TOS,
-        * and MSG_DONTROUTE            --ANK (980726)
+        * and MSG_DONTROUTE            --ANK (980726)
         *
         * 1. ip6_rt_check(): If route was host route,
         *    check that cached destination is current.
@@ -1049,7 +1048,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                        int getfrag(void *from, char *to, int offset, int len,
                        int odd, struct sk_buff *skb),
                        void *from, int length, int hh_len, int fragheaderlen,
-                       int transhdrlen, int mtu,unsigned int flags,
+                       int transhdrlen, int mtu, unsigned int flags,
                        struct rt6_info *rt)
 
 {
@@ -1072,7 +1071,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                skb_reserve(skb, hh_len);
 
                /* create space for UDP/IP header */
-               skb_put(skb,fragheaderlen + transhdrlen);
+               skb_put(skb, fragheaderlen + transhdrlen);
 
                /* initialize network header pointer */
                skb_reset_network_header(skb);
index f9de5a69507252a12cbf1efffbf416721d9c871a..e01bd0399297a7d38917e55709a543b375077db9 100644 (file)
@@ -408,12 +408,12 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
 {
        const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
        __u8 nexthdr = ipv6h->nexthdr;
-       __u16 off = sizeof (*ipv6h);
+       __u16 off = sizeof(*ipv6h);
 
        while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
                __u16 optlen = 0;
                struct ipv6_opt_hdr *hdr;
-               if (raw + off + sizeof (*hdr) > skb->data &&
+               if (raw + off + sizeof(*hdr) > skb->data &&
                    !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
                        break;
 
@@ -530,7 +530,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
                        mtu = IPV6_MIN_MTU;
                t->dev->mtu = mtu;
 
-               if ((len = sizeof (*ipv6h) + ntohs(ipv6h->payload_len)) > mtu) {
+               if ((len = sizeof(*ipv6h) + ntohs(ipv6h->payload_len)) > mtu) {
                        rel_type = ICMPV6_PKT_TOOBIG;
                        rel_code = 0;
                        rel_info = mtu;
@@ -991,7 +991,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
                                     t->parms.name);
                goto tx_err_dst_release;
        }
-       mtu = dst_mtu(dst) - sizeof (*ipv6h);
+       mtu = dst_mtu(dst) - sizeof(*ipv6h);
        if (encap_limit >= 0) {
                max_headroom += 8;
                mtu -= 8;
@@ -1083,7 +1083,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
                encap_limit = t->parms.encap_limit;
 
-       memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6));
+       memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_IPIP;
 
        dsfield = ipv4_get_dsfield(iph);
@@ -1135,7 +1135,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
                encap_limit = t->parms.encap_limit;
 
-       memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6));
+       memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_IPV6;
 
        dsfield = ipv6_get_dsfield(ipv6h);
@@ -1229,11 +1229,11 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
 
                if (rt->dst.dev) {
                        dev->hard_header_len = rt->dst.dev->hard_header_len +
-                               sizeof (struct ipv6hdr);
+                               sizeof(struct ipv6hdr);
 
-                       dev->mtu = rt->dst.dev->mtu - sizeof (struct ipv6hdr);
+                       dev->mtu = rt->dst.dev->mtu - sizeof(struct ipv6hdr);
                        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
-                               dev->mtu-=8;
+                               dev->mtu -= 8;
 
                        if (dev->mtu < IPV6_MIN_MTU)
                                dev->mtu = IPV6_MIN_MTU;
@@ -1350,7 +1350,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        switch (cmd) {
        case SIOCGETTUNNEL:
                if (dev == ip6n->fb_tnl_dev) {
-                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
+                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
                                err = -EFAULT;
                                break;
                        }
@@ -1362,7 +1362,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        memset(&p, 0, sizeof(p));
                }
                ip6_tnl_parm_to_user(&p, &t->parms);
-               if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
+               if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) {
                        err = -EFAULT;
                }
                break;
@@ -1372,7 +1372,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        break;
                err = -EFAULT;
-               if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
+               if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
                        break;
                err = -EINVAL;
                if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
@@ -1407,7 +1407,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
                if (dev == ip6n->fb_tnl_dev) {
                        err = -EFAULT;
-                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
+                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
                                break;
                        err = -ENOENT;
                        ip6_tnl_parm_from_user(&p1, &p);
@@ -1482,11 +1482,11 @@ static void ip6_tnl_dev_setup(struct net_device *dev)
        dev->destructor = ip6_dev_free;
 
        dev->type = ARPHRD_TUNNEL6;
-       dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
-       dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
+       dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr);
+       dev->mtu = ETH_DATA_LEN - sizeof(struct ipv6hdr);
        t = netdev_priv(dev);
        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
-               dev->mtu-=8;
+               dev->mtu -= 8;
        dev->flags |= IFF_NOARP;
        dev->addr_len = sizeof(struct in6_addr);
        dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
index f9a3fd320d1df23ca1140e3d39e46b4d14a234be..0171f08325c3ff3991485297de4c532fe6992bf8 100644 (file)
@@ -845,7 +845,7 @@ static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c)
 
        atomic_dec(&mrt->cache_resolve_queue_len);
 
-       while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
+       while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
                if (ipv6_hdr(skb)->version == 0) {
                        struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
                        nlh->nlmsg_type = NLMSG_ERROR;
@@ -1103,7 +1103,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
         *      Play the pending entries through our router
         */
 
-       while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
+       while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
                if (ipv6_hdr(skb)->version == 0) {
                        struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
 
index d1c793cffcb5f44aba0f922f2ebdd3105d51b49f..1b9316e1386a96c899c67888fba4618d3004e69a 100644 (file)
@@ -181,8 +181,7 @@ static int ipcomp6_rcv_cb(struct sk_buff *skb, int err)
        return 0;
 }
 
-static const struct xfrm_type ipcomp6_type =
-{
+static const struct xfrm_type ipcomp6_type = {
        .description    = "IPCOMP6",
        .owner          = THIS_MODULE,
        .proto          = IPPROTO_COMP,
@@ -193,8 +192,7 @@ static const struct xfrm_type ipcomp6_type =
        .hdr_offset     = xfrm6_find_1stfragopt,
 };
 
-static struct xfrm6_protocol ipcomp6_protocol =
-{
+static struct xfrm6_protocol ipcomp6_protocol = {
        .handler        = xfrm6_rcv,
        .cb_handler     = ipcomp6_rcv_cb,
        .err_handler    = ipcomp6_err,
index 0c289982796dfb6e01a761ff4d49616700da3ba8..e1a9583bb4191f44b021e3d39483ed29d1f22fc4 100644 (file)
@@ -66,12 +66,12 @@ int ip6_ra_control(struct sock *sk, int sel)
        if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW)
                return -ENOPROTOOPT;
 
-       new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
+       new_ra = (sel >= 0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
 
        write_lock_bh(&ip6_ra_lock);
-       for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
+       for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
                if (ra->sk == sk) {
-                       if (sel>=0) {
+                       if (sel >= 0) {
                                write_unlock_bh(&ip6_ra_lock);
                                kfree(new_ra);
                                return -EADDRINUSE;
@@ -130,7 +130,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
        int retv = -ENOPROTOOPT;
 
        if (optval == NULL)
-               val=0;
+               val = 0;
        else {
                if (optlen >= sizeof(int)) {
                        if (get_user(val, (int __user *) optval))
@@ -139,7 +139,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                        val = 0;
        }
 
-       valbool = (val!=0);
+       valbool = (val != 0);
 
        if (ip6_mroute_opt(optname))
                return ip6_mroute_setsockopt(sk, optname, optval, optlen);
@@ -474,7 +474,7 @@ sticky_done:
                        goto done;
 
                msg.msg_controllen = optlen;
-               msg.msg_control = (void*)(opt+1);
+               msg.msg_control = (void *)(opt+1);
 
                retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk,
                                             &junk, &junk);
@@ -687,7 +687,7 @@ done:
                        retv = -ENOBUFS;
                        break;
                }
-               gsf = kmalloc(optlen,GFP_KERNEL);
+               gsf = kmalloc(optlen, GFP_KERNEL);
                if (!gsf) {
                        retv = -ENOBUFS;
                        break;
@@ -873,7 +873,6 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(ipv6_setsockopt);
 
 #ifdef CONFIG_COMPAT
@@ -909,7 +908,6 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(compat_ipv6_setsockopt);
 #endif
 
@@ -921,7 +919,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
        if (!opt)
                return 0;
 
-       switch(optname) {
+       switch (optname) {
        case IPV6_HOPOPTS:
                hdr = opt->hopopt;
                break;
@@ -1284,9 +1282,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                return -ENOPROTOOPT;
        }
        len = min_t(unsigned int, sizeof(int), len);
-       if(put_user(len, optlen))
+       if (put_user(len, optlen))
                return -EFAULT;
-       if(copy_to_user(optval,&val,len))
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
        return 0;
 }
@@ -1299,7 +1297,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
        if (level == SOL_IP && sk->sk_type != SOCK_RAW)
                return udp_prot.getsockopt(sk, level, optname, optval, optlen);
 
-       if(level != SOL_IPV6)
+       if (level != SOL_IPV6)
                return -ENOPROTOOPT;
 
        err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);
@@ -1321,7 +1319,6 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(ipv6_getsockopt);
 
 #ifdef CONFIG_COMPAT
@@ -1364,7 +1361,6 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(compat_ipv6_getsockopt);
 #endif
 
index a23b655a7627a69046d956139946c00dda8825f4..6833dd07b2c22f2f118feb09297f1f0d799634ee 100644 (file)
@@ -121,6 +121,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
 #define IPV6_MLD_MAX_MSF       64
 
 int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
+int sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT;
 
 /*
  *     socket join on multicast group
@@ -237,7 +238,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
        spin_lock(&ipv6_sk_mc_lock);
        for (lnk = &np->ipv6_mc_list;
             (mc_lst = rcu_dereference_protected(*lnk,
-                       lockdep_is_held(&ipv6_sk_mc_lock))) !=NULL ;
+                       lockdep_is_held(&ipv6_sk_mc_lock))) != NULL;
              lnk = &mc_lst->next) {
                if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&
                    ipv6_addr_equal(&mc_lst->addr, addr)) {
@@ -400,7 +401,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
                if (!psl)
                        goto done;      /* err = -EADDRNOTAVAIL */
                rv = !0;
-               for (i=0; i<psl->sl_count; i++) {
+               for (i = 0; i < psl->sl_count; i++) {
                        rv = !ipv6_addr_equal(&psl->sl_addr[i], source);
                        if (rv == 0)
                                break;
@@ -417,7 +418,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
                /* update the interface filter */
                ip6_mc_del_src(idev, group, omode, 1, source, 1);
 
-               for (j=i+1; j<psl->sl_count; j++)
+               for (j = i+1; j < psl->sl_count; j++)
                        psl->sl_addr[j-1] = psl->sl_addr[j];
                psl->sl_count--;
                err = 0;
@@ -443,19 +444,19 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
                newpsl->sl_max = count;
                newpsl->sl_count = count - IP6_SFBLOCK;
                if (psl) {
-                       for (i=0; i<psl->sl_count; i++)
+                       for (i = 0; i < psl->sl_count; i++)
                                newpsl->sl_addr[i] = psl->sl_addr[i];
                        sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
                }
                pmc->sflist = psl = newpsl;
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
-       for (i=0; i<psl->sl_count; i++) {
+       for (i = 0; i < psl->sl_count; i++) {
                rv = !ipv6_addr_equal(&psl->sl_addr[i], source);
                if (rv == 0) /* There is an error in the address. */
                        goto done;
        }
-       for (j=psl->sl_count-1; j>=i; j--)
+       for (j = psl->sl_count-1; j >= i; j--)
                psl->sl_addr[j+1] = psl->sl_addr[j];
        psl->sl_addr[i] = *source;
        psl->sl_count++;
@@ -524,7 +525,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
                        goto done;
                }
                newpsl->sl_max = newpsl->sl_count = gsf->gf_numsrc;
-               for (i=0; i<newpsl->sl_count; ++i) {
+               for (i = 0; i < newpsl->sl_count; ++i) {
                        struct sockaddr_in6 *psin6;
 
                        psin6 = (struct sockaddr_in6 *)&gsf->gf_slist[i];
@@ -616,7 +617,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
         * on ipv6_sk_mc_lock and a write lock on pmc->sflock. We
         * have the socket lock, so reading here is safe.
         */
-       for (i=0; i<copycount; i++) {
+       for (i = 0; i < copycount; i++) {
                struct sockaddr_in6 *psin6;
                struct sockaddr_storage ss;
 
@@ -658,7 +659,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
        } else {
                int i;
 
-               for (i=0; i<psl->sl_count; i++) {
+               for (i = 0; i < psl->sl_count; i++) {
                        if (ipv6_addr_equal(&psl->sl_addr[i], src_addr))
                                break;
                }
@@ -772,7 +773,7 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
                pmc->mca_tomb = im->mca_tomb;
                pmc->mca_sources = im->mca_sources;
                im->mca_tomb = im->mca_sources = NULL;
-               for (psf=pmc->mca_sources; psf; psf=psf->sf_next)
+               for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = pmc->mca_crcount;
        }
        spin_unlock_bh(&im->mca_lock);
@@ -790,7 +791,7 @@ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
 
        spin_lock_bh(&idev->mc_lock);
        pmc_prev = NULL;
-       for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_tomb; pmc; pmc = pmc->next) {
                if (ipv6_addr_equal(&pmc->mca_addr, pmca))
                        break;
                pmc_prev = pmc;
@@ -804,7 +805,7 @@ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
        spin_unlock_bh(&idev->mc_lock);
 
        if (pmc) {
-               for (psf=pmc->mca_tomb; psf; psf=psf_next) {
+               for (psf = pmc->mca_tomb; psf; psf = psf_next) {
                        psf_next = psf->sf_next;
                        kfree(psf);
                }
@@ -831,14 +832,14 @@ static void mld_clear_delrec(struct inet6_dev *idev)
 
        /* clear dead sources, too */
        read_lock_bh(&idev->lock);
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                struct ip6_sf_list *psf, *psf_next;
 
                spin_lock_bh(&pmc->mca_lock);
                psf = pmc->mca_tomb;
                pmc->mca_tomb = NULL;
                spin_unlock_bh(&pmc->mca_lock);
-               for (; psf; psf=psf_next) {
+               for (; psf; psf = psf_next) {
                        psf_next = psf->sf_next;
                        kfree(psf);
                }
@@ -931,7 +932,7 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
        ASSERT_RTNL();
 
        write_lock_bh(&idev->lock);
-       for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {
+       for (map = &idev->mc_list; (ma = *map) != NULL; map = &ma->next) {
                if (ipv6_addr_equal(&ma->mca_addr, addr)) {
                        if (--ma->mca_users == 0) {
                                *map = ma->next;
@@ -982,7 +983,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
        idev = __in6_dev_get(dev);
        if (idev) {
                read_lock_bh(&idev->lock);
-               for (mc = idev->mc_list; mc; mc=mc->next) {
+               for (mc = idev->mc_list; mc; mc = mc->next) {
                        if (ipv6_addr_equal(&mc->mca_addr, group))
                                break;
                }
@@ -991,7 +992,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
                                struct ip6_sf_list *psf;
 
                                spin_lock_bh(&mc->mca_lock);
-                               for (psf=mc->mca_sources;psf;psf=psf->sf_next) {
+                               for (psf = mc->mca_sources; psf; psf = psf->sf_next) {
                                        if (ipv6_addr_equal(&psf->sf_addr, src_addr))
                                                break;
                                }
@@ -1000,7 +1001,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
                                                psf->sf_count[MCAST_EXCLUDE] !=
                                                mc->mca_sfcount[MCAST_EXCLUDE];
                                else
-                                       rv = mc->mca_sfcount[MCAST_EXCLUDE] !=0;
+                                       rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0;
                                spin_unlock_bh(&mc->mca_lock);
                        } else
                                rv = true; /* don't filter unspecified source */
@@ -1091,10 +1092,10 @@ static bool mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
        int i, scount;
 
        scount = 0;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (scount == nsrcs)
                        break;
-               for (i=0; i<nsrcs; i++) {
+               for (i = 0; i < nsrcs; i++) {
                        /* skip inactive filters */
                        if (psf->sf_count[MCAST_INCLUDE] ||
                            pmc->mca_sfcount[MCAST_EXCLUDE] !=
@@ -1124,10 +1125,10 @@ static bool mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
        /* mark INCLUDE-mode sources */
 
        scount = 0;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (scount == nsrcs)
                        break;
-               for (i=0; i<nsrcs; i++) {
+               for (i = 0; i < nsrcs; i++) {
                        if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) {
                                psf->sf_gsresp = 1;
                                scount++;
@@ -1205,15 +1206,16 @@ static void mld_update_qrv(struct inet6_dev *idev,
         * and SHOULD NOT be one. Catch this here if we ever run
         * into such a case in future.
         */
+       const int min_qrv = min(MLD_QRV_DEFAULT, sysctl_mld_qrv);
        WARN_ON(idev->mc_qrv == 0);
 
        if (mlh2->mld2q_qrv > 0)
                idev->mc_qrv = mlh2->mld2q_qrv;
 
-       if (unlikely(idev->mc_qrv < 2)) {
+       if (unlikely(idev->mc_qrv < min_qrv)) {
                net_warn_ratelimited("IPv6: MLD: clamping QRV from %u to %u!\n",
-                                    idev->mc_qrv, MLD_QRV_DEFAULT);
-               idev->mc_qrv = MLD_QRV_DEFAULT;
+                                    idev->mc_qrv, min_qrv);
+               idev->mc_qrv = min_qrv;
        }
 }
 
@@ -1378,13 +1380,13 @@ int igmp6_event_query(struct sk_buff *skb)
 
        read_lock_bh(&idev->lock);
        if (group_type == IPV6_ADDR_ANY) {
-               for (ma = idev->mc_list; ma; ma=ma->next) {
+               for (ma = idev->mc_list; ma; ma = ma->next) {
                        spin_lock_bh(&ma->mca_lock);
                        igmp6_group_queried(ma, max_delay);
                        spin_unlock_bh(&ma->mca_lock);
                }
        } else {
-               for (ma = idev->mc_list; ma; ma=ma->next) {
+               for (ma = idev->mc_list; ma; ma = ma->next) {
                        if (!ipv6_addr_equal(group, &ma->mca_addr))
                                continue;
                        spin_lock_bh(&ma->mca_lock);
@@ -1448,7 +1450,7 @@ int igmp6_event_report(struct sk_buff *skb)
         */
 
        read_lock_bh(&idev->lock);
-       for (ma = idev->mc_list; ma; ma=ma->next) {
+       for (ma = idev->mc_list; ma; ma = ma->next) {
                if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) {
                        spin_lock(&ma->mca_lock);
                        if (del_timer(&ma->mca_timer))
@@ -1512,7 +1514,7 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted)
        struct ip6_sf_list *psf;
        int scount = 0;
 
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (!is_in(pmc, psf, type, gdeleted, sdeleted))
                        continue;
                scount++;
@@ -1726,7 +1728,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
        }
        first = 1;
        psf_prev = NULL;
-       for (psf=*psf_list; psf; psf=psf_next) {
+       for (psf = *psf_list; psf; psf = psf_next) {
                struct in6_addr *psrc;
 
                psf_next = psf->sf_next;
@@ -1805,7 +1807,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)
 
        read_lock_bh(&idev->lock);
        if (!pmc) {
-               for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+               for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                        if (pmc->mca_flags & MAF_NOREPORT)
                                continue;
                        spin_lock_bh(&pmc->mca_lock);
@@ -1838,7 +1840,7 @@ static void mld_clear_zeros(struct ip6_sf_list **ppsf)
        struct ip6_sf_list *psf_prev, *psf_next, *psf;
 
        psf_prev = NULL;
-       for (psf=*ppsf; psf; psf = psf_next) {
+       for (psf = *ppsf; psf; psf = psf_next) {
                psf_next = psf->sf_next;
                if (psf->sf_crcount == 0) {
                        if (psf_prev)
@@ -1862,7 +1864,7 @@ static void mld_send_cr(struct inet6_dev *idev)
 
        /* deleted MCA's */
        pmc_prev = NULL;
-       for (pmc=idev->mc_tomb; pmc; pmc=pmc_next) {
+       for (pmc = idev->mc_tomb; pmc; pmc = pmc_next) {
                pmc_next = pmc->next;
                if (pmc->mca_sfmode == MCAST_INCLUDE) {
                        type = MLD2_BLOCK_OLD_SOURCES;
@@ -1895,7 +1897,7 @@ static void mld_send_cr(struct inet6_dev *idev)
        spin_unlock(&idev->mc_lock);
 
        /* change recs */
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                spin_lock_bh(&pmc->mca_lock);
                if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
                        type = MLD2_BLOCK_OLD_SOURCES;
@@ -2032,7 +2034,7 @@ static void mld_send_initial_cr(struct inet6_dev *idev)
 
        skb = NULL;
        read_lock_bh(&idev->lock);
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                spin_lock_bh(&pmc->mca_lock);
                if (pmc->mca_sfcount[MCAST_EXCLUDE])
                        type = MLD2_CHANGE_TO_EXCLUDE;
@@ -2077,7 +2079,7 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
        int rv = 0;
 
        psf_prev = NULL;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (ipv6_addr_equal(&psf->sf_addr, psfsrc))
                        break;
                psf_prev = psf;
@@ -2118,7 +2120,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
        if (!idev)
                return -ENODEV;
        read_lock_bh(&idev->lock);
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                if (ipv6_addr_equal(pmca, &pmc->mca_addr))
                        break;
        }
@@ -2138,7 +2140,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
                pmc->mca_sfcount[sfmode]--;
        }
        err = 0;
-       for (i=0; i<sfcount; i++) {
+       for (i = 0; i < sfcount; i++) {
                int rv = ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
 
                changerec |= rv > 0;
@@ -2154,7 +2156,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
                pmc->mca_sfmode = MCAST_INCLUDE;
                pmc->mca_crcount = idev->mc_qrv;
                idev->mc_ifc_count = pmc->mca_crcount;
-               for (psf=pmc->mca_sources; psf; psf = psf->sf_next)
+               for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
                mld_ifc_event(pmc->idev);
        } else if (sf_setstate(pmc) || changerec)
@@ -2173,7 +2175,7 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
        struct ip6_sf_list *psf, *psf_prev;
 
        psf_prev = NULL;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (ipv6_addr_equal(&psf->sf_addr, psfsrc))
                        break;
                psf_prev = psf;
@@ -2198,7 +2200,7 @@ static void sf_markstate(struct ifmcaddr6 *pmc)
        struct ip6_sf_list *psf;
        int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];
 
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next)
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
                if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
                        psf->sf_oldin = mca_xcount ==
                                psf->sf_count[MCAST_EXCLUDE] &&
@@ -2215,7 +2217,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
        int new_in, rv;
 
        rv = 0;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
                        new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] &&
                                !psf->sf_count[MCAST_INCLUDE];
@@ -2225,8 +2227,8 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
                        if (!psf->sf_oldin) {
                                struct ip6_sf_list *prev = NULL;
 
-                               for (dpsf=pmc->mca_tomb; dpsf;
-                                    dpsf=dpsf->sf_next) {
+                               for (dpsf = pmc->mca_tomb; dpsf;
+                                    dpsf = dpsf->sf_next) {
                                        if (ipv6_addr_equal(&dpsf->sf_addr,
                                            &psf->sf_addr))
                                                break;
@@ -2248,7 +2250,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
                         * add or update "delete" records if an active filter
                         * is now inactive
                         */
-                       for (dpsf=pmc->mca_tomb; dpsf; dpsf=dpsf->sf_next)
+                       for (dpsf = pmc->mca_tomb; dpsf; dpsf = dpsf->sf_next)
                                if (ipv6_addr_equal(&dpsf->sf_addr,
                                    &psf->sf_addr))
                                        break;
@@ -2282,7 +2284,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
        if (!idev)
                return -ENODEV;
        read_lock_bh(&idev->lock);
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                if (ipv6_addr_equal(pmca, &pmc->mca_addr))
                        break;
        }
@@ -2298,7 +2300,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
        if (!delta)
                pmc->mca_sfcount[sfmode]++;
        err = 0;
-       for (i=0; i<sfcount; i++) {
+       for (i = 0; i < sfcount; i++) {
                err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i]);
                if (err)
                        break;
@@ -2308,7 +2310,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
 
                if (!delta)
                        pmc->mca_sfcount[sfmode]--;
-               for (j=0; j<i; j++)
+               for (j = 0; j < i; j++)
                        ip6_mc_del1_src(pmc, sfmode, &psfsrc[j]);
        } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
                struct ip6_sf_list *psf;
@@ -2322,7 +2324,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
 
                pmc->mca_crcount = idev->mc_qrv;
                idev->mc_ifc_count = pmc->mca_crcount;
-               for (psf=pmc->mca_sources; psf; psf = psf->sf_next)
+               for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
                mld_ifc_event(idev);
        } else if (sf_setstate(pmc))
@@ -2336,12 +2338,12 @@ static void ip6_mc_clear_src(struct ifmcaddr6 *pmc)
 {
        struct ip6_sf_list *psf, *nextpsf;
 
-       for (psf=pmc->mca_tomb; psf; psf=nextpsf) {
+       for (psf = pmc->mca_tomb; psf; psf = nextpsf) {
                nextpsf = psf->sf_next;
                kfree(psf);
        }
        pmc->mca_tomb = NULL;
-       for (psf=pmc->mca_sources; psf; psf=nextpsf) {
+       for (psf = pmc->mca_sources; psf; psf = nextpsf) {
                nextpsf = psf->sf_next;
                kfree(psf);
        }
@@ -2485,13 +2487,21 @@ void ipv6_mc_down(struct inet6_dev *idev)
        mld_gq_stop_timer(idev);
        mld_dad_stop_timer(idev);
 
-       for (i = idev->mc_list; i; i=i->next)
+       for (i = idev->mc_list; i; i = i->next)
                igmp6_group_dropped(i);
        read_unlock_bh(&idev->lock);
 
        mld_clear_delrec(idev);
 }
 
+static void ipv6_mc_reset(struct inet6_dev *idev)
+{
+       idev->mc_qrv = sysctl_mld_qrv;
+       idev->mc_qi = MLD_QI_DEFAULT;
+       idev->mc_qri = MLD_QRI_DEFAULT;
+       idev->mc_v1_seen = 0;
+       idev->mc_maxdelay = unsolicited_report_interval(idev);
+}
 
 /* Device going up */
 
@@ -2502,7 +2512,8 @@ void ipv6_mc_up(struct inet6_dev *idev)
        /* Install multicast list, except for all-nodes (already installed) */
 
        read_lock_bh(&idev->lock);
-       for (i = idev->mc_list; i; i=i->next)
+       ipv6_mc_reset(idev);
+       for (i = idev->mc_list; i; i = i->next)
                igmp6_group_added(i);
        read_unlock_bh(&idev->lock);
 }
@@ -2522,13 +2533,7 @@ void ipv6_mc_init_dev(struct inet6_dev *idev)
                        (unsigned long)idev);
        setup_timer(&idev->mc_dad_timer, mld_dad_timer_expire,
                    (unsigned long)idev);
-
-       idev->mc_qrv = MLD_QRV_DEFAULT;
-       idev->mc_qi = MLD_QI_DEFAULT;
-       idev->mc_qri = MLD_QRI_DEFAULT;
-
-       idev->mc_maxdelay = unsolicited_report_interval(idev);
-       idev->mc_v1_seen = 0;
+       ipv6_mc_reset(idev);
        write_unlock_bh(&idev->lock);
 }
 
index db9b6cbc9db3905695888343912be7dfd06af6f2..f61429d391d32693f3fb92fd75c630c01520f776 100644 (file)
@@ -336,11 +336,10 @@ static void mip6_destopt_destroy(struct xfrm_state *x)
 {
 }
 
-static const struct xfrm_type mip6_destopt_type =
-{
+static const struct xfrm_type mip6_destopt_type = {
        .description    = "MIP6DESTOPT",
        .owner          = THIS_MODULE,
-       .proto          = IPPROTO_DSTOPTS,
+       .proto          = IPPROTO_DSTOPTS,
        .flags          = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
        .init_state     = mip6_destopt_init_state,
        .destructor     = mip6_destopt_destroy,
@@ -469,11 +468,10 @@ static void mip6_rthdr_destroy(struct xfrm_state *x)
 {
 }
 
-static const struct xfrm_type mip6_rthdr_type =
-{
+static const struct xfrm_type mip6_rthdr_type = {
        .description    = "MIP6RT",
        .owner          = THIS_MODULE,
-       .proto          = IPPROTO_ROUTING,
+       .proto          = IPPROTO_ROUTING,
        .flags          = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
        .init_state     = mip6_rthdr_init_state,
        .destructor     = mip6_rthdr_destroy,
index 339078f95d1b6b955d29f094cf281f7835096f9c..4cb45c1079a29f4b7b59201e829905a5c65ac9fe 100644 (file)
@@ -175,7 +175,7 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
        type = cur->nd_opt_type;
        do {
                cur = ((void *)cur) + (cur->nd_opt_len << 3);
-       } while(cur < end && cur->nd_opt_type != type);
+       } while (cur < end && cur->nd_opt_type != type);
        return cur <= end && cur->nd_opt_type == type ? cur : NULL;
 }
 
@@ -192,7 +192,7 @@ static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
                return NULL;
        do {
                cur = ((void *)cur) + (cur->nd_opt_len << 3);
-       } while(cur < end && !ndisc_is_useropt(cur));
+       } while (cur < end && !ndisc_is_useropt(cur));
        return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
 }
 
@@ -284,7 +284,6 @@ int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev,
        }
        return -EINVAL;
 }
-
 EXPORT_SYMBOL(ndisc_mc_map);
 
 static u32 ndisc_hash(const void *pkey,
@@ -296,7 +295,7 @@ static u32 ndisc_hash(const void *pkey,
 
 static int ndisc_constructor(struct neighbour *neigh)
 {
-       struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
+       struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;
        struct net_device *dev = neigh->dev;
        struct inet6_dev *in6_dev;
        struct neigh_parms *parms;
@@ -344,7 +343,7 @@ static int ndisc_constructor(struct neighbour *neigh)
 
 static int pndisc_constructor(struct pneigh_entry *n)
 {
-       struct in6_addr *addr = (struct in6_addr*)&n->key;
+       struct in6_addr *addr = (struct in6_addr *)&n->key;
        struct in6_addr maddr;
        struct net_device *dev = n->dev;
 
@@ -357,7 +356,7 @@ static int pndisc_constructor(struct pneigh_entry *n)
 
 static void pndisc_destructor(struct pneigh_entry *n)
 {
-       struct in6_addr *addr = (struct in6_addr*)&n->key;
+       struct in6_addr *addr = (struct in6_addr *)&n->key;
        struct in6_addr maddr;
        struct net_device *dev = n->dev;
 
@@ -1065,7 +1064,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        int optlen;
        unsigned int pref = 0;
 
-       __u8 * opt = (__u8 *)(ra_msg + 1);
+       __u8 *opt = (__u8 *)(ra_msg + 1);
 
        optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
                sizeof(struct ra_msg);
@@ -1319,7 +1318,7 @@ skip_linkparms:
                                continue;
                        if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
                                continue;
-                       rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
+                       rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
                                      &ipv6_hdr(skb)->saddr);
                }
        }
@@ -1352,7 +1351,7 @@ skip_routeinfo:
                __be32 n;
                u32 mtu;
 
-               memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
+               memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
                mtu = ntohl(n);
 
                if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
index 5ec867e4a8b74fb23d8fdd2bcf9e0dce52f94455..fc24c390af0541050782c76434ccbbf9e00c24f0 100644 (file)
@@ -35,7 +35,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
                        if (found_rhdr)
                                return offset;
                        break;
-               default :
+               default:
                        return offset;
                }
 
index 2d6f860e5c1e77cb087b2220ba2db9592a770159..1752cd0b48820367ad64cd926d8ea16a6c69341a 100644 (file)
@@ -8,7 +8,7 @@
  *             except it reports the sockets in the INET6 address family.
  *
  * Authors:    David S. Miller (davem@caip.rutgers.edu)
- *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
index 39d44226e402473ed03058f6945111f02abeb146..896af8807979fad382ba65724ccad0bf040c992f 100644 (file)
@@ -889,7 +889,7 @@ back_from_confirm:
        else {
                lock_sock(sk);
                err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
-                       len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info*)dst,
+                       len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info *)dst,
                        msg->msg_flags, dontfrag);
 
                if (err)
@@ -902,7 +902,7 @@ done:
        dst_release(dst);
 out:
        fl6_sock_release(flowlabel);
-       return err<0?err:len;
+       return err < 0 ? err : len;
 do_confirm:
        dst_confirm(dst);
        if (!(msg->msg_flags & MSG_PROBE) || len)
@@ -1045,7 +1045,7 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
        struct raw6_sock *rp = raw6_sk(sk);
        int val, len;
 
-       if (get_user(len,optlen))
+       if (get_user(len, optlen))
                return -EFAULT;
 
        switch (optname) {
@@ -1069,7 +1069,7 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
 
        if (put_user(len, optlen))
                return -EFAULT;
-       if (copy_to_user(optval,&val,len))
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
        return 0;
 }
index c6557d9f7808c42e686582f31e8cc535a7067f3f..1a157ca2ebc18c5a12519adb9eacd30d508722eb 100644 (file)
 
 static const char ip6_frag_cache_name[] = "ip6-frags";
 
-struct ip6frag_skb_cb
-{
+struct ip6frag_skb_cb {
        struct inet6_skb_parm   h;
        int                     offset;
 };
 
-#define FRAG6_CB(skb)  ((struct ip6frag_skb_cb*)((skb)->cb))
+#define FRAG6_CB(skb)  ((struct ip6frag_skb_cb *)((skb)->cb))
 
 static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
 {
@@ -289,7 +288,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
                goto found;
        }
        prev = NULL;
-       for(next = fq->q.fragments; next != NULL; next = next->next) {
+       for (next = fq->q.fragments; next != NULL; next = next->next) {
                if (FRAG6_CB(next)->offset >= offset)
                        break;  /* bingo! */
                prev = next;
@@ -529,7 +528,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
        IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS);
 
        /* Jumbo payload inhibits frag. header */
-       if (hdr->payload_len==0)
+       if (hdr->payload_len == 0)
                goto fail_hdr;
 
        if (!pskb_may_pull(skb, (skb_transport_offset(skb) +
@@ -575,8 +574,7 @@ fail_hdr:
        return -1;
 }
 
-static const struct inet6_protocol frag_protocol =
-{
+static const struct inet6_protocol frag_protocol = {
        .handler        =       ipv6_frag_rcv,
        .flags          =       INET6_PROTO_NOPOLICY,
 };
index f23fbd28a501ed5c3438abb7f1cbbec85233688b..f74b0417bd60c4ada1d0e582dfbb1733fe750d8d 100644 (file)
@@ -813,7 +813,7 @@ out:
 
 }
 
-struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6,
+struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
                                    int flags)
 {
        return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
@@ -843,7 +843,6 @@ struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
 
        return NULL;
 }
-
 EXPORT_SYMBOL(rt6_lookup);
 
 /* ip6_ins_rt is called with FREE table->tb6_lock.
@@ -1024,7 +1023,7 @@ static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table
        return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
 }
 
-struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
+struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
                                    struct flowi6 *fl6)
 {
        int flags = 0;
@@ -1041,7 +1040,6 @@ struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
 
        return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
 }
-
 EXPORT_SYMBOL(ip6_route_output);
 
 struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
@@ -1149,7 +1147,7 @@ static void ip6_link_failure(struct sk_buff *skb)
 static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
                               struct sk_buff *skb, u32 mtu)
 {
-       struct rt6_info *rt6 = (struct rt6_info*)dst;
+       struct rt6_info *rt6 = (struct rt6_info *)dst;
 
        dst_confirm(dst);
        if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
@@ -1924,7 +1922,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net,
                return NULL;
 
        read_lock_bh(&table->tb6_lock);
-       fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
+       fn = fib6_locate(&table->tb6_root, prefixprefixlen, NULL, 0);
        if (!fn)
                goto out;
 
@@ -1983,7 +1981,7 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev
                return NULL;
 
        read_lock_bh(&table->tb6_lock);
-       for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
+       for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
                if (dev == rt->dst.dev &&
                    ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
                    ipv6_addr_equal(&rt->rt6i_gateway, addr))
@@ -2068,7 +2066,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        struct in6_rtmsg rtmsg;
        int err;
 
-       switch(cmd) {
+       switch (cmd) {
        case SIOCADDRT:         /* Add a route */
        case SIOCDELRT:         /* Delete a route */
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
@@ -2191,7 +2189,7 @@ int ip6_route_get_saddr(struct net *net,
                        unsigned int prefs,
                        struct in6_addr *saddr)
 {
-       struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
+       struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt);
        int err = 0;
        if (rt->rt6i_prefsrc.plen)
                *saddr = rt->rt6i_prefsrc.addr;
@@ -2486,7 +2484,7 @@ beginning:
        return last_err;
 }
 
-static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdrnlh)
+static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        struct fib6_config cfg;
        int err;
@@ -2501,7 +2499,7 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh)
                return ip6_route_del(&cfg);
 }
 
-static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdrnlh)
+static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        struct fib6_config cfg;
        int err;
@@ -2693,7 +2691,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
                     prefix, 0, NLM_F_MULTI);
 }
 
-static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdrnlh)
+static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
 {
        struct net *net = sock_net(in_skb->sk);
        struct nlattr *tb[RTA_MAX+1];
index 6163f851dc014ebd205211829214ce4d0bbc332b..86e3fa81f85eba7928a3c68d0c997e190c79543e 100644 (file)
@@ -812,9 +812,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
        const struct ipv6hdr *iph6 = ipv6_hdr(skb);
        u8     tos = tunnel->parms.iph.tos;
        __be16 df = tiph->frag_off;
-       struct rtable *rt;                      /* Route to the other host */
-       struct net_device *tdev;                /* Device to other host */
-       unsigned int max_headroom;              /* The extra header space needed */
+       struct rtable *rt;              /* Route to the other host */
+       struct net_device *tdev;        /* Device to other host */
+       unsigned int max_headroom;      /* The extra header space needed */
        __be32 dst = tiph->daddr;
        struct flowi4 fl4;
        int    mtu;
@@ -1123,7 +1123,7 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
 #endif
 
 static int
-ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
+ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        int err = 0;
        struct ip_tunnel_parm p;
@@ -1339,10 +1339,10 @@ static void ipip6_dev_free(struct net_device *dev)
 static void ipip6_tunnel_setup(struct net_device *dev)
 {
        dev->netdev_ops         = &ipip6_netdev_ops;
-       dev->destructor         = ipip6_dev_free;
+       dev->destructor         = ipip6_dev_free;
 
        dev->type               = ARPHRD_SIT;
-       dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
+       dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
        dev->mtu                = ETH_DATA_LEN - sizeof(struct iphdr);
        dev->flags              = IFF_NOARP;
        dev->priv_flags        &= ~IFF_XMIT_DST_RELEASE;
index 83cea1d39466affce703d7c1b737a386bf3faecf..c643dc907ce773badc1c8ec9029b20909c21698a 100644 (file)
@@ -24,7 +24,7 @@
 #define COOKIEBITS 24  /* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
-static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS];
+static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
 
 /* RFC 2460, Section 8.3:
  * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..]
index 0c56c93619e063710a8d32f3f9e15fd9cdb6453c..c5c10fafcfe2e068fe33adc8367206a16e40c7bf 100644 (file)
@@ -16,6 +16,8 @@
 #include <net/addrconf.h>
 #include <net/inet_frag.h>
 
+static int one = 1;
+
 static struct ctl_table ipv6_table_template[] = {
        {
                .procname       = "bindv6only",
@@ -63,6 +65,14 @@ static struct ctl_table ipv6_rotable[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "mld_qrv",
+               .data           = &sysctl_mld_qrv,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one
+       },
        { }
 };
 
index 29964c3d363c8a0e741b01b9df32fce3cdd7a1ba..5b3c70ff7a72a445e841c990e9af417f5caf479b 100644 (file)
@@ -738,7 +738,7 @@ static void tcp_v6_init_req(struct request_sock *req, struct sock *sk,
            ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
                ireq->ir_iif = inet6_iif(skb);
 
-       if (!TCP_SKB_CB(skb)->when &&
+       if (!TCP_SKB_CB(skb)->tcp_tw_isn &&
            (ipv6_opt_accepted(sk, skb) || np->rxopt.bits.rxinfo ||
             np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim ||
             np->rxopt.bits.rxohlim || np->repflow)) {
@@ -1412,7 +1412,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
        TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
                                    skb->len - th->doff*4);
        TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
-       TCP_SKB_CB(skb)->when = 0;
+       TCP_SKB_CB(skb)->tcp_tw_isn = 0;
        TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
        TCP_SKB_CB(skb)->sacked = 0;
 
index 01b0ff9a0c2c00d6734537254e2150edcbcb64d7..dbb3d9262bf66837a10e6ecc764dbcd0ea327264 100644 (file)
@@ -35,34 +35,14 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb)
 static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
                                         struct sk_buff *skb)
 {
-       const struct ipv6hdr *iph = skb_gro_network_header(skb);
-       __wsum wsum;
-
        /* Don't bother verifying checksum if we're going to flush anyway. */
-       if (NAPI_GRO_CB(skb)->flush)
-               goto skip_csum;
-
-       wsum = NAPI_GRO_CB(skb)->csum;
-
-       switch (skb->ip_summed) {
-       case CHECKSUM_NONE:
-               wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb),
-                                   wsum);
-
-               /* fall through */
-
-       case CHECKSUM_COMPLETE:
-               if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
-                                 wsum)) {
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       break;
-               }
-
+       if (!NAPI_GRO_CB(skb)->flush &&
+           skb_gro_checksum_validate(skb, IPPROTO_TCP,
+                                     ip6_gro_compute_pseudo)) {
                NAPI_GRO_CB(skb)->flush = 1;
                return NULL;
        }
 
-skip_csum:
        return tcp_gro_receive(head, skb);
 }
 
index 2c4e4c5c7614bf9ee864a99e095c7c17e46d9b57..3c758007b327decd0f1d950ae6cca928af052b05 100644 (file)
@@ -15,7 +15,7 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * Authors     Mitsuru KANDA  <mk@linux-ipv6.org>
- *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  */
 
 #define pr_fmt(fmt) "IPv6: " fmt
@@ -64,7 +64,6 @@ err:
 
        return ret;
 }
-
 EXPORT_SYMBOL(xfrm6_tunnel_register);
 
 int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
@@ -92,7 +91,6 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
 
        return ret;
 }
-
 EXPORT_SYMBOL(xfrm6_tunnel_deregister);
 
 #define for_each_tunnel_rcu(head, handler)             \
index 4836af8f582d32d881f8697c1c92b6909e37ab27..f6ba535b6febe40aad990e7f9541446fc573d511 100644 (file)
@@ -243,7 +243,7 @@ begin:
                                goto exact_match;
                } else if (score == badness && reuseport) {
                        matches++;
-                       if (((u64)hash * matches) >> 32 == 0)
+                       if (reciprocal_scale(hash, matches) == 0)
                                result = sk;
                        hash = next_pseudo_random32(hash);
                }
@@ -323,7 +323,7 @@ begin:
                        }
                } else if (score == badness && reuseport) {
                        matches++;
-                       if (((u64)hash * matches) >> 32 == 0)
+                       if (reciprocal_scale(hash, matches) == 0)
                                result = sk;
                        hash = next_pseudo_random32(hash);
                }
@@ -373,8 +373,8 @@ EXPORT_SYMBOL_GPL(udp6_lib_lookup);
 
 
 /*
- *     This should be easy, if there is something there we
- *     return it, otherwise we block.
+ *     This should be easy, if there is something there we
+ *     return it, otherwise we block.
  */
 
 int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
@@ -530,7 +530,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
        const struct in6_addr *saddr = &hdr->saddr;
        const struct in6_addr *daddr = &hdr->daddr;
-       struct udphdr *uh = (struct udphdr*)(skb->data+offset);
+       struct udphdr *uh = (struct udphdr *)(skb->data+offset);
        struct sock *sk;
        int err;
        struct net *net = dev_net(skb->dev);
@@ -596,7 +596,7 @@ static int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
 static __inline__ void udpv6_err(struct sk_buff *skb,
                                 struct inet6_skb_parm *opt, u8 type,
-                                u8 code, int offset, __be32 info     )
+                                u8 code, int offset, __be32 info)
 {
        __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table);
 }
@@ -891,6 +891,10 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                        goto csum_error;
                }
 
+               if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk))
+                       skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
+                                                ip6_compute_pseudo);
+
                ret = udpv6_queue_rcv_skb(sk, skb);
                sock_put(sk);
 
@@ -960,10 +964,10 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
 }
 
 /**
- *     udp6_hwcsum_outgoing  -  handle outgoing HW checksumming
- *     @sk:    socket we are sending on
- *     @skb:   sk_buff containing the filled-in UDP header
- *             (checksum field must be zeroed out)
+ *     udp6_hwcsum_outgoing  -  handle outgoing HW checksumming
+ *     @sk:    socket we are sending on
+ *     @skb:   sk_buff containing the filled-in UDP header
+ *             (checksum field must be zeroed out)
  */
 static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
                                 const struct in6_addr *saddr,
@@ -1294,7 +1298,7 @@ do_append_data:
        getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;
        err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen,
                sizeof(struct udphdr), hlimit, tclass, opt, &fl6,
-               (struct rt6_info*)dst,
+               (struct rt6_info *)dst,
                corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag);
        if (err)
                udp_v6_flush_pending_frames(sk);
index 0ae3d98f83e00533c14e6f8c23ab78a5a6a72625..89cb9a9b853789eab136cff742f36e3a4d5ee19d 100644 (file)
@@ -10,6 +10,7 @@
  *      UDPv6 GSO support
  */
 #include <linux/skbuff.h>
+#include <linux/netdevice.h>
 #include <net/protocol.h>
 #include <net/ipv6.h>
 #include <net/udp.h>
@@ -127,10 +128,52 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
 out:
        return segs;
 }
+
+static struct sk_buff **udp6_gro_receive(struct sk_buff **head,
+                                        struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_gro_udphdr(skb);
+
+       if (unlikely(!uh))
+               goto flush;
+
+       /* Don't bother verifying checksum if we're going to flush anyway. */
+       if (!NAPI_GRO_CB(skb)->flush)
+               goto skip;
+
+       if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
+                                                ip6_gro_compute_pseudo))
+               goto flush;
+       else if (uh->check)
+               skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
+                                            ip6_gro_compute_pseudo);
+
+skip:
+       return udp_gro_receive(head, skb, uh);
+
+flush:
+       NAPI_GRO_CB(skb)->flush = 1;
+       return NULL;
+}
+
+int udp6_gro_complete(struct sk_buff *skb, int nhoff)
+{
+       const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+       struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
+
+       if (uh->check)
+               uh->check = ~udp_v6_check(skb->len - nhoff, &ipv6h->saddr,
+                                         &ipv6h->daddr, 0);
+
+       return udp_gro_complete(skb, nhoff);
+}
+
 static const struct net_offload udpv6_offload = {
        .callbacks = {
                .gso_send_check =       udp6_ufo_send_check,
                .gso_segment    =       udp6_ufo_fragment,
+               .gro_receive    =       udp6_gro_receive,
+               .gro_complete   =       udp6_gro_complete,
        },
 };
 
index f8c3cf842f534e3e87c35a1213afcb320880998b..f48fbe4d16f5f433c40cba8077663db77d2984d4 100644 (file)
@@ -3,8 +3,8 @@
  *
  * Authors:
  *     Mitsuru KANDA @USAGI
- *     Kazunori MIYAZAWA @USAGI
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *     Kazunori MIYAZAWA @USAGI
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  *     YOSHIFUJI Hideaki @USAGI
  *             IPv6 support
  */
@@ -52,7 +52,6 @@ int xfrm6_rcv(struct sk_buff *skb)
        return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
                             0);
 }
-
 EXPORT_SYMBOL(xfrm6_rcv);
 
 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
@@ -142,5 +141,4 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 drop:
        return -1;
 }
-
 EXPORT_SYMBOL(xfrm6_input_addr);
index 433672d07d0b55e1e436be704780e8c6f5777447..ca3f29b98ae5d76b7e69c38f617362a90fd9fd04 100644 (file)
@@ -25,7 +25,6 @@ int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
 {
        return ip6_find_1stfragopt(skb, prevhdr);
 }
-
 EXPORT_SYMBOL(xfrm6_find_1stfragopt);
 
 static int xfrm6_local_dontfrag(struct sk_buff *skb)
index 2a0bbda2c76a99dfa687313d230595c251103b45..ac49f84fe2c34026b7af5392df06fc232ea3b9e1 100644 (file)
@@ -3,11 +3,11 @@
  *
  * Authors:
  *     Mitsuru KANDA @USAGI
- *     Kazunori MIYAZAWA @USAGI
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
- *             IPv6 support
- *     YOSHIFUJI Hideaki
- *             Split up af-specific portion
+ *     Kazunori MIYAZAWA @USAGI
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *             IPv6 support
+ *     YOSHIFUJI Hideaki
+ *             Split up af-specific portion
  *
  */
 
@@ -84,7 +84,7 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst,
                           int nfheader_len)
 {
        if (dst->ops->family == AF_INET6) {
-               struct rt6_info *rt = (struct rt6_info*)dst;
+               struct rt6_info *rt = (struct rt6_info *)dst;
                if (rt->rt6i_node)
                        path->path_cookie = rt->rt6i_node->fn_sernum;
        }
@@ -97,7 +97,7 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst,
 static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
                          const struct flowi *fl)
 {
-       struct rt6_info *rt = (struct rt6_info*)xdst->route;
+       struct rt6_info *rt = (struct rt6_info *)xdst->route;
 
        xdst->u.dst.dev = dev;
        dev_hold(dev);
@@ -296,7 +296,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
        .family =               AF_INET6,
        .dst_ops =              &xfrm6_dst_ops,
        .dst_lookup =           xfrm6_dst_lookup,
-       .get_saddr =            xfrm6_get_saddr,
+       .get_saddr =            xfrm6_get_saddr,
        .decode_session =       _decode_session6,
        .get_tos =              xfrm6_get_tos,
        .init_dst =             xfrm6_init_dst,
@@ -319,9 +319,9 @@ static void xfrm6_policy_fini(void)
 static struct ctl_table xfrm6_policy_table[] = {
        {
                .procname       = "xfrm6_gc_thresh",
-               .data           = &init_net.xfrm.xfrm6_dst_ops.gc_thresh,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
+               .data           = &init_net.xfrm.xfrm6_dst_ops.gc_thresh,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        { }
index 3fc970135fc66583e5842943246993da7e2b69b4..8a1f9c0d2a13b27ae0b67c9eacf802f30e656115 100644 (file)
@@ -3,11 +3,11 @@
  *
  * Authors:
  *     Mitsuru KANDA @USAGI
- *     Kazunori MIYAZAWA @USAGI
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
- *             IPv6 support
- *     YOSHIFUJI Hideaki @USAGI
- *             Split up af-specific portion
+ *     Kazunori MIYAZAWA @USAGI
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *             IPv6 support
+ *     YOSHIFUJI Hideaki @USAGI
+ *             Split up af-specific portion
  *
  */
 
@@ -45,10 +45,10 @@ xfrm6_init_temprop(struct xfrm_state *x, const struct xfrm_tmpl *tmpl,
                   const xfrm_address_t *daddr, const xfrm_address_t *saddr)
 {
        x->id = tmpl->id;
-       if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
+       if (ipv6_addr_any((struct in6_addr *)&x->id.daddr))
                memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
        memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
-       if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
+       if (ipv6_addr_any((struct in6_addr *)&x->props.saddr))
                memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
        x->props.mode = tmpl->mode;
        x->props.reqid = tmpl->reqid;
index 1c66465a42ddc09627dae47d4c6cbd40aa4fdc35..5743044cd660b8a8557d1a87c4ee35508ebff7e0 100644 (file)
@@ -15,7 +15,7 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * Authors     Mitsuru KANDA  <mk@linux-ipv6.org>
- *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  *
  * Based on net/ipv4/xfrm4_tunnel.c
  *
@@ -110,7 +110,6 @@ __be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr)
        rcu_read_unlock_bh();
        return htonl(spi);
 }
-
 EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
 
 static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi)
@@ -187,7 +186,6 @@ __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr)
 
        return htonl(spi);
 }
-
 EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
 
 static void x6spi_destroy_rcu(struct rcu_head *head)
index 1109d3bb8dac8d4142eb6bdd159915b2f978ea45..2aa2b6c15f2016d81d88976d46056e3a4fd34cb3 100644 (file)
@@ -148,7 +148,7 @@ do {                                                                        \
                 atomic_read(&_t->ref_count));                          \
        l2tp_tunnel_inc_refcount_1(_t);                                 \
 } while (0)
-#define l2tp_tunnel_dec_refcount(_t)
+#define l2tp_tunnel_dec_refcount(_t)                                   \
 do {                                                                   \
        pr_debug("l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n",        \
                 __func__, __LINE__, (_t)->name,                        \
@@ -1392,6 +1392,8 @@ static int l2tp_tunnel_sock_create(struct net *net,
                if (err < 0)
                        goto out;
 
+               udp_set_convert_csum(sock->sk, true);
+
                break;
 
        case L2TP_ENCAPTYPE_IP:
index de88c4ab5146a168bc0866f3fdc07098b5ebe543..5016a6929085ebdbf151a1f47582d36195885540 100644 (file)
@@ -142,7 +142,7 @@ static u32 hash_conntrack_raw(const struct nf_conntrack_tuple *tuple, u16 zone)
 
 static u32 __hash_bucket(u32 hash, unsigned int size)
 {
-       return ((u64)hash * size) >> 32;
+       return reciprocal_scale(hash, size);
 }
 
 static u32 hash_bucket(u32 hash, const struct net *net)
@@ -358,7 +358,7 @@ bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
 
        tstamp = nf_conn_tstamp_find(ct);
        if (tstamp && tstamp->stop == 0)
-               tstamp->stop = ktime_to_ns(ktime_get_real());
+               tstamp->stop = ktime_get_real_ns();
 
        if (nf_ct_is_dying(ct))
                goto delete;
index f87e8f68ad453e9baeec017cc74534e8ce85dfab..91a1837acd0e8fb981ccea73ae262197afecfb33 100644 (file)
@@ -83,7 +83,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple
        hash = jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
                      (((tuple->dst.protonum ^ tuple->src.l3num) << 16) |
                       (__force __u16)tuple->dst.u.all) ^ nf_conntrack_hash_rnd);
-       return ((u64)hash * nf_ct_expect_hsize) >> 32;
+
+       return reciprocal_scale(hash, nf_ct_expect_hsize);
 }
 
 struct nf_conntrack_expect *
index 355a5c4ef7635bb7aca1e1068ca269b891949550..1bd9ed9e62f642477e8a10d57cd73775cc1ebc14 100644 (file)
@@ -1737,7 +1737,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
        }
        tstamp = nf_conn_tstamp_find(ct);
        if (tstamp)
-               tstamp->start = ktime_to_ns(ktime_get_real());
+               tstamp->start = ktime_get_real_ns();
 
        err = nf_conntrack_hash_check_insert(ct);
        if (err < 0)
index f641751dba9dc467b4207716bdb0ac69208747f8..cf65a1e040dd8c8920dd8fc330c75c218ea7050b 100644 (file)
@@ -101,7 +101,7 @@ static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
 {
        struct ct_iter_state *st = seq->private;
 
-       st->time_now = ktime_to_ns(ktime_get_real());
+       st->time_now = ktime_get_real_ns();
        rcu_read_lock();
        return ct_get_idx(seq, *pos);
 }
index 552f97cd9fde5c510ac055642affb66adbda181d..4e0b47831d43a25f021a1eeb2c62c2307b8630e1 100644 (file)
@@ -126,7 +126,8 @@ hash_by_src(const struct net *net, u16 zone,
        /* Original src, to ensure we map it consistently if poss. */
        hash = jhash2((u32 *)&tuple->src, sizeof(tuple->src) / sizeof(u32),
                      tuple->dst.protonum ^ zone ^ nf_conntrack_hash_rnd);
-       return ((u64)hash * net->ct.nat_htable_size) >> 32;
+
+       return reciprocal_scale(hash, net->ct.nat_htable_size);
 }
 
 /* Is this tuple already taken? (not by us) */
@@ -274,7 +275,7 @@ find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
                }
 
                var_ipp->all[i] = (__force __u32)
-                       htonl(minip + (((u64)j * dist) >> 32));
+                       htonl(minip + reciprocal_scale(j, dist));
                if (var_ipp->all[i] != range->max_addr.all[i])
                        full_range = true;
 
index 73b73f687c580ccfe66648234caab5f0bdc543b9..02afaf48a7290b15e6f2d56b2ca2c5cb07455b4d 100644 (file)
@@ -126,7 +126,7 @@ hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info)
        hash = jhash_3words(src, dst, t->uports.v32, info->hashrnd);
        hash = hash ^ (t->proto & info->proto_mask);
 
-       return (((u64)hash * info->hmodulus) >> 32) + info->hoffset;
+       return reciprocal_scale(hash, info->hmodulus) + info->hoffset;
 }
 
 static void
index f4af1bfafb1c61642ddb56ac490f7e161df5d39d..96fa26b20b67dce9ed2d2abaaf6ce71dda363faf 100644 (file)
@@ -55,7 +55,8 @@ xt_cluster_hash(const struct nf_conn *ct,
                WARN_ON(1);
                break;
        }
-       return (((u64)hash * info->total_nodes) >> 32);
+
+       return reciprocal_scale(hash, info->total_nodes);
 }
 
 static inline bool
index 47dc6836830a9cfe1b329fbdddabfd1d80c4d100..52eb3e03458d95a3f65b8e8cfd39f4b847cc39c0 100644 (file)
@@ -135,7 +135,7 @@ hash_dst(const struct xt_hashlimit_htable *ht, const struct dsthash_dst *dst)
         * give results between [0 and cfg.size-1] and same hash distribution,
         * but using a multiply, less expensive than a divide
         */
-       return ((u64)hash * ht->cfg.size) >> 32;
+       return reciprocal_scale(hash, ht->cfg.size);
 }
 
 static struct dsthash_ent *
index d07ab538fc9d37b78082e88906fe41c433467166..7064da92f42037124576069e8ae10eb77203d73b 100644 (file)
@@ -89,7 +89,7 @@ void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
                         * allocated stats as we have already locked them.
                         */
                        if (likely(flow->stats_last_writer != NUMA_NO_NODE)
-                           && likely(!rcu_dereference(flow->stats[node]))) {
+                           && likely(!rcu_access_pointer(flow->stats[node]))) {
                                /* Try to allocate node-specific stats. */
                                struct flow_stats *new_stats;
 
index 93896d2092f67dc60a17c6a7c6b4abbb689b6cd9..87d20f48ff06195766e8ecd20a3fcfae5ccae690 100644 (file)
@@ -240,11 +240,9 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po);
 static int packet_direct_xmit(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
-       const struct net_device_ops *ops = dev->netdev_ops;
        netdev_features_t features;
        struct netdev_queue *txq;
        int ret = NETDEV_TX_BUSY;
-       u16 queue_map;
 
        if (unlikely(!netif_running(dev) ||
                     !netif_carrier_ok(dev)))
@@ -255,17 +253,13 @@ static int packet_direct_xmit(struct sk_buff *skb)
            __skb_linearize(skb))
                goto drop;
 
-       queue_map = skb_get_queue_mapping(skb);
-       txq = netdev_get_tx_queue(dev, queue_map);
+       txq = skb_get_tx_queue(dev, skb);
 
        local_bh_disable();
 
        HARD_TX_LOCK(dev, txq, smp_processor_id());
-       if (!netif_xmit_frozen_or_drv_stopped(txq)) {
-               ret = ops->ndo_start_xmit(skb, dev);
-               if (ret == NETDEV_TX_OK)
-                       txq_trans_update(txq);
-       }
+       if (!netif_xmit_frozen_or_drv_stopped(txq))
+               ret = netdev_start_xmit(skb, dev, txq, false);
        HARD_TX_UNLOCK(dev, txq);
 
        local_bh_enable();
index bc5514211b0cfb4b3d4d42a12eeb03de8e90a2b4..e873d7d9f8571c4d5db2efd70dcdd0c5da792e1c 100644 (file)
@@ -160,7 +160,8 @@ void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigne
                break;
 
        case ROSE_DIAGNOSTIC:
-               printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
+               pr_warn("ROSE: received diagnostic #%d - %3ph\n", skb->data[3],
+                       skb->data + 4);
                break;
 
        default:
index db57458c824c87b463ceff200be22c07df936b73..74c0fcd36838dfc7326eeddb7726483576da0413 100644 (file)
@@ -37,7 +37,7 @@ void rxrpc_UDP_error_report(struct sock *sk)
 
        _enter("%p{%d}", sk, local->debug_id);
 
-       skb = skb_dequeue(&sk->sk_error_queue);
+       skb = sock_dequeue_err_skb(sk);
        if (!skb) {
                _leave("UDP socket errqueue empty");
                return;
@@ -111,18 +111,6 @@ void rxrpc_UDP_error_report(struct sock *sk)
        skb_queue_tail(&trans->error_queue, skb);
        rxrpc_queue_work(&trans->error_handler);
 
-       /* reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       skb = skb_peek(&sk->sk_error_queue);
-       if (skb) {
-               sk->sk_err = SKB_EXT_ERR(skb)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else {
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-       }
-
        _leave("");
 }
 
index 63b21e580de95d21c60bfeeffac7d2b0aaefaf42..481f89f93789a147fd5979e894e62145f4d9d767 100644 (file)
@@ -45,7 +45,7 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb,
        struct rxrpc_skb_priv *sp;
        struct rxrpc_sock *rx = call->socket;
        struct sock *sk;
-       int skb_len, ret;
+       int ret;
 
        _enter(",,%d,%d", force, terminal);
 
@@ -101,13 +101,6 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb,
                        rx->interceptor(sk, call->user_call_ID, skb);
                        spin_unlock_bh(&sk->sk_receive_queue.lock);
                } else {
-
-                       /* Cache the SKB length before we tack it onto the
-                        * receive queue.  Once it is added it no longer
-                        * belongs to us and may be freed by other threads of
-                        * control pulling packets from the queue */
-                       skb_len = skb->len;
-
                        _net("post skb %p", skb);
                        __skb_queue_tail(&sk->sk_receive_queue, skb);
                        spin_unlock_bh(&sk->sk_receive_queue.lock);
index 0566e4606a4ac86710ebbc04a80c9ad1729849cd..f32bcb0949154c5992eeb93e3e6b8ff576812060 100644 (file)
@@ -231,7 +231,7 @@ override:
        if (ret != ACT_P_CREATED)
                return ret;
 
-       police->tcfp_t_c = ktime_to_ns(ktime_get());
+       police->tcfp_t_c = ktime_get_ns();
        police->tcf_index = parm->index ? parm->index :
                tcf_hash_new_index(hinfo);
        h = tcf_hash(police->tcf_index, POL_TAB_MASK);
@@ -279,7 +279,7 @@ static int tcf_act_police(struct sk_buff *skb, const struct tc_action *a,
                        return police->tcfp_result;
                }
 
-               now = ktime_to_ns(ktime_get());
+               now = ktime_get_ns();
                toks = min_t(s64, now - police->tcfp_t_c,
                             police->tcfp_burst);
                if (police->peak_present) {
index ba32c2b005d0821788f656e8ae05d4d47a862351..e12f997e1b4ca9862f408f6751713c793d747606 100644 (file)
@@ -416,7 +416,7 @@ static void fq_check_throttled(struct fq_sched_data *q, u64 now)
 static struct sk_buff *fq_dequeue(struct Qdisc *sch)
 {
        struct fq_sched_data *q = qdisc_priv(sch);
-       u64 now = ktime_to_ns(ktime_get());
+       u64 now = ktime_get_ns();
        struct fq_flow_head *head;
        struct sk_buff *skb;
        struct fq_flow *f;
@@ -787,7 +787,7 @@ nla_put_failure:
 static int fq_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
 {
        struct fq_sched_data *q = qdisc_priv(sch);
-       u64 now = ktime_to_ns(ktime_get());
+       u64 now = ktime_get_ns();
        struct tc_fq_qd_stats st = {
                .gc_flows               = q->stat_gc_flows,
                .highprio_packets       = q->stat_internal_packets,
index 063b726bf1f8636e3529a2e61d1b43fced918d9c..cc56c8bb9bed7c3487ffd39c7bbed5c445ef144b 100644 (file)
@@ -77,7 +77,8 @@ static unsigned int fq_codel_hash(const struct fq_codel_sched_data *q,
        hash = jhash_3words((__force u32)keys.dst,
                            (__force u32)keys.src ^ keys.ip_proto,
                            (__force u32)keys.ports, q->perturbation);
-       return ((u64)hash * q->flows_cnt) >> 32;
+
+       return reciprocal_scale(hash, q->flows_cnt);
 }
 
 static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch,
index fc04fe93c2da2fa8b43b4be97ccd28dba8ca9e3c..19696ebe9ebc897379b6b9826e339f8ab10ddbc8 100644 (file)
@@ -63,15 +63,18 @@ static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
 
        if (unlikely(skb)) {
                /* check the reason of requeuing without tx lock first */
-               txq = netdev_get_tx_queue(txq->dev, skb_get_queue_mapping(skb));
+               txq = skb_get_tx_queue(txq->dev, skb);
                if (!netif_xmit_frozen_or_stopped(txq)) {
                        q->gso_skb = NULL;
                        q->q.qlen--;
                } else
                        skb = NULL;
        } 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));
+               }
        }
 
        return skb;
@@ -90,7 +93,7 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb,
                 * detect it by checking xmit owner and drop the packet when
                 * deadloop is detected. Return OK to try the next skb.
                 */
-               kfree_skb(skb);
+               kfree_skb_list(skb);
                net_warn_ratelimited("Dead loop on netdevice %s, fix it urgently!\n",
                                     dev_queue->dev->name);
                ret = qdisc_qlen(q);
@@ -107,9 +110,9 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb,
 }
 
 /*
- * Transmit one skb, and handle the return status as required. Holding the
- * __QDISC___STATE_RUNNING bit guarantees that only one CPU can execute this
- * function.
+ * Transmit possibly several skbs, and handle the return status as
+ * required. Holding the __QDISC___STATE_RUNNING bit guarantees that
+ * only one CPU can execute this function.
  *
  * Returns to the caller:
  *                             0  - queue is empty or throttled.
@@ -126,7 +129,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
 
        HARD_TX_LOCK(dev, txq, smp_processor_id());
        if (!netif_xmit_frozen_or_stopped(txq))
-               ret = dev_hard_start_xmit(skb, dev, txq);
+               skb = dev_hard_start_xmit(skb, dev, txq, &ret);
 
        HARD_TX_UNLOCK(dev, txq);
 
@@ -183,10 +186,12 @@ static inline int qdisc_restart(struct Qdisc *q)
        skb = dequeue_skb(q);
        if (unlikely(!skb))
                return 0;
+
        WARN_ON_ONCE(skb_dst_is_noref(skb));
+
        root_lock = qdisc_lock(q);
        dev = qdisc_dev(q);
-       txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
+       txq = skb_get_tx_queue(dev, skb);
 
        return sch_direct_xmit(skb, q, dev, txq, root_lock);
 }
@@ -616,7 +621,7 @@ void qdisc_reset(struct Qdisc *qdisc)
                ops->reset(qdisc);
 
        if (qdisc->gso_skb) {
-               kfree_skb(qdisc->gso_skb);
+               kfree_skb_list(qdisc->gso_skb);
                qdisc->gso_skb = NULL;
                qdisc->q.qlen = 0;
        }
@@ -652,7 +657,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
        module_put(ops->owner);
        dev_put(qdisc_dev(qdisc));
 
-       kfree_skb(qdisc->gso_skb);
+       kfree_skb_list(qdisc->gso_skb);
        /*
         * gen_estimator est_timer() might access qdisc->q.lock,
         * wait a RCU grace period before freeing qdisc.
index 9f949abcacef1680dcdc15579c7fe56611f21852..aea942ce6008c542982ab503555b925733ede962 100644 (file)
@@ -895,7 +895,7 @@ ok:
 
        if (!sch->q.qlen)
                goto fin;
-       q->now = ktime_to_ns(ktime_get());
+       q->now = ktime_get_ns();
        start_at = jiffies;
 
        next_event = q->now + 5LLU * NSEC_PER_SEC;
@@ -1225,7 +1225,7 @@ static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl,
        parent->un.leaf.q = new_q ? new_q : &noop_qdisc;
        parent->tokens = parent->buffer;
        parent->ctokens = parent->cbuffer;
-       parent->t_c = ktime_to_ns(ktime_get());
+       parent->t_c = ktime_get_ns();
        parent->cmode = HTB_CAN_SEND;
 }
 
@@ -1455,7 +1455,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                cl->tokens = PSCHED_TICKS2NS(hopt->buffer);
                cl->ctokens = PSCHED_TICKS2NS(hopt->cbuffer);
                cl->mbuffer = 60ULL * NSEC_PER_SEC;     /* 1min */
-               cl->t_c = ktime_to_ns(ktime_get());
+               cl->t_c = ktime_get_ns();
                cl->cmode = HTB_CAN_SEND;
 
                /* attach to the hash list and parent's family */
index 18ff634337092d5f8e7cba8fe817542f1455738f..0c39b754083b2028438289ddd8a5a292a1cbf938 100644 (file)
@@ -239,7 +239,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc *sch)
                s64 ptoks = 0;
                unsigned int len = qdisc_pkt_len(skb);
 
-               now = ktime_to_ns(ktime_get());
+               now = ktime_get_ns();
                toks = min_t(s64, now - q->t_c, q->buffer);
 
                if (tbf_peak_present(q)) {
@@ -292,7 +292,7 @@ static void tbf_reset(struct Qdisc *sch)
 
        qdisc_reset(q->qdisc);
        sch->q.qlen = 0;
-       q->t_c = ktime_to_ns(ktime_get());
+       q->t_c = ktime_get_ns();
        q->tokens = q->buffer;
        q->ptokens = q->mtu;
        qdisc_watchdog_cancel(&q->watchdog);
@@ -431,7 +431,7 @@ static int tbf_init(struct Qdisc *sch, struct nlattr *opt)
        if (opt == NULL)
                return -EINVAL;
 
-       q->t_c = ktime_to_ns(ktime_get());
+       q->t_c = ktime_get_ns();
        qdisc_watchdog_init(&q->watchdog, sch);
        q->qdisc = &noop_qdisc;
 
index bd33793b527e176b07f7bacb77143ed38e32d31c..aaa8d03ed054789f36e184b314d75ba1fd27c6c7 100644 (file)
@@ -301,7 +301,6 @@ restart:
        do {
                struct net_device *slave = qdisc_dev(q);
                struct netdev_queue *slave_txq = netdev_get_tx_queue(slave, 0);
-               const struct net_device_ops *slave_ops = slave->netdev_ops;
 
                if (slave_txq->qdisc_sleeping != q)
                        continue;
@@ -317,8 +316,8 @@ restart:
                                unsigned int length = qdisc_pkt_len(skb);
 
                                if (!netif_xmit_frozen_or_stopped(slave_txq) &&
-                                   slave_ops->ndo_start_xmit(skb, slave) == NETDEV_TX_OK) {
-                                       txq_trans_update(slave_txq);
+                                   netdev_start_xmit(skb, slave, slave_txq, false) ==
+                                   NETDEV_TX_OK) {
                                        __netif_tx_unlock(slave_txq);
                                        master->slaves = NEXT_SLAVE(q);
                                        netif_wake_queue(dev);
index c1b991294516fd1ef29de13cf24f06c1d63c8be2..b6493b3f11a97f359d0ec70cde2812082f65910f 100644 (file)
@@ -133,9 +133,13 @@ int sctp_rcv(struct sk_buff *skb)
        __skb_pull(skb, skb_transport_offset(skb));
        if (skb->len < sizeof(struct sctphdr))
                goto discard_it;
-       if (!sctp_checksum_disable && !skb_csum_unnecessary(skb) &&
-                 sctp_rcv_checksum(net, skb) < 0)
+
+       skb->csum_valid = 0; /* Previous value not applicable */
+       if (skb_csum_unnecessary(skb))
+               __skb_decr_checksum_unnecessary(skb);
+       else if (!sctp_checksum_disable && sctp_rcv_checksum(net, skb) < 0)
                goto discard_it;
+       skb->csum_valid = 1;
 
        skb_pull(skb, sizeof(struct sctphdr));
 
index a080c66d819a032233a963512d849f757cc979e2..b8a13caad59a518dddd2a8a50ad3a9a04f363cae 100644 (file)
@@ -7,7 +7,7 @@ obj-$(CONFIG_TIPC) := tipc.o
 tipc-y += addr.o bcast.o bearer.o config.o \
           core.o link.o discover.o msg.o  \
           name_distr.o  subscr.o name_table.o net.o  \
-          netlink.o node.o node_subscr.o port.o ref.o  \
+          netlink.o node.o node_subscr.o \
           socket.o log.o eth_media.o server.o
 
 tipc-$(CONFIG_TIPC_MEDIA_IB)   += ib_media.o
index dd13bfa09333246fb6ba54171fd11ad0cc4fe63f..b2bbe69b25543c5a355286ebb75750c6b5726e1c 100644 (file)
@@ -37,7 +37,6 @@
 
 #include "core.h"
 #include "link.h"
-#include "port.h"
 #include "socket.h"
 #include "msg.h"
 #include "bcast.h"
@@ -300,8 +299,8 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
                tipc_link_push_queue(bcl);
                bclink_set_last_sent();
        }
-       if (unlikely(released && !list_empty(&bcl->waiting_ports)))
-               tipc_link_wakeup_ports(bcl, 0);
+       if (unlikely(released && !skb_queue_empty(&bcl->waiting_sks)))
+               bclink->node.action_flags |= TIPC_WAKEUP_USERS;
 exit:
        tipc_bclink_unlock();
 }
@@ -840,9 +839,10 @@ int tipc_bclink_init(void)
        sprintf(bcbearer->media.name, "tipc-broadcast");
 
        spin_lock_init(&bclink->lock);
-       INIT_LIST_HEAD(&bcl->waiting_ports);
+       __skb_queue_head_init(&bcl->waiting_sks);
        bcl->next_out_no = 1;
        spin_lock_init(&bclink->node.lock);
+       __skb_queue_head_init(&bclink->node.waiting_sks);
        bcl->owner = &bclink->node;
        bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
        tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
index 2b42403ad33a690221456ff25fb4be50a2235255..876f4c6a2631b35eba2b9927430b30c34d125c87 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #include "core.h"
-#include "port.h"
+#include "socket.h"
 #include "name_table.h"
 #include "config.h"
 #include "server.h"
@@ -266,7 +266,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
                rep_tlv_buf = tipc_media_get_names();
                break;
        case TIPC_CMD_SHOW_PORTS:
-               rep_tlv_buf = tipc_port_get_ports();
+               rep_tlv_buf = tipc_sk_socks_show();
                break;
        case TIPC_CMD_SHOW_STATS:
                rep_tlv_buf = tipc_show_stats();
index 676d18015dd82efa0346f6bed2bf0d7f5489f1f6..a5737b8407ddbf63f9ecfb024bde3b079f979098 100644 (file)
  */
 
 #include "core.h"
-#include "ref.h"
 #include "name_table.h"
 #include "subscr.h"
 #include "config.h"
-#include "port.h"
+#include "socket.h"
 
 #include <linux/module.h>
 
@@ -85,7 +84,7 @@ static void tipc_core_stop(void)
        tipc_netlink_stop();
        tipc_subscr_stop();
        tipc_nametbl_stop();
-       tipc_ref_table_stop();
+       tipc_sk_ref_table_stop();
        tipc_socket_stop();
        tipc_unregister_sysctl();
 }
@@ -99,7 +98,7 @@ static int tipc_core_start(void)
 
        get_random_bytes(&tipc_random, sizeof(tipc_random));
 
-       err = tipc_ref_table_init(tipc_max_ports, tipc_random);
+       err = tipc_sk_ref_table_init(tipc_max_ports, tipc_random);
        if (err)
                goto out_reftbl;
 
@@ -139,7 +138,7 @@ out_socket:
 out_netlink:
        tipc_nametbl_stop();
 out_nametbl:
-       tipc_ref_table_stop();
+       tipc_sk_ref_table_stop();
 out_reftbl:
        return err;
 }
index bb26ed1ee966c84c66fc7322877d80f763047e5a..f773b148722f7e51195d525a55e2ae18577c3c3e 100644 (file)
@@ -81,6 +81,7 @@ extern u32 tipc_own_addr __read_mostly;
 extern int tipc_max_ports __read_mostly;
 extern int tipc_net_id __read_mostly;
 extern int sysctl_tipc_rmem[3] __read_mostly;
+extern int sysctl_tipc_named_timeout __read_mostly;
 
 /*
  * Other global variables
@@ -187,8 +188,11 @@ static inline void k_term_timer(struct timer_list *timer)
 
 struct tipc_skb_cb {
        void *handle;
-       bool deferred;
        struct sk_buff *tail;
+       bool deferred;
+       bool wakeup_pending;
+       u16 chain_sz;
+       u16 chain_imp;
 };
 
 #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
index fb1485dc6736ec84719c262334ead93d659bb7c4..65410e18b8a6e90f52554276db9bdd927d2a63ba 100644 (file)
@@ -36,7 +36,6 @@
 
 #include "core.h"
 #include "link.h"
-#include "port.h"
 #include "socket.h"
 #include "name_distr.h"
 #include "discover.h"
@@ -275,7 +274,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
        link_init_max_pkt(l_ptr);
 
        l_ptr->next_out_no = 1;
-       INIT_LIST_HEAD(&l_ptr->waiting_ports);
+       __skb_queue_head_init(&l_ptr->waiting_sks);
 
        link_reset_statistics(l_ptr);
 
@@ -322,66 +321,47 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down)
 }
 
 /**
- * link_schedule_port - schedule port for deferred sending
- * @l_ptr: pointer to link
- * @origport: reference to sending port
- * @sz: amount of data to be sent
- *
- * Schedules port for renewed sending of messages after link congestion
- * has abated.
+ * link_schedule_user - schedule user for wakeup after congestion
+ * @link: congested link
+ * @oport: sending port
+ * @chain_sz: size of buffer chain that was attempted sent
+ * @imp: importance of message attempted sent
+ * Create pseudo msg to send back to user when congestion abates
  */
-static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz)
+static bool link_schedule_user(struct tipc_link *link, u32 oport,
+                              uint chain_sz, uint imp)
 {
-       struct tipc_port *p_ptr;
-       struct tipc_sock *tsk;
+       struct sk_buff *buf;
 
-       spin_lock_bh(&tipc_port_list_lock);
-       p_ptr = tipc_port_lock(origport);
-       if (p_ptr) {
-               if (!list_empty(&p_ptr->wait_list))
-                       goto exit;
-               tsk = tipc_port_to_sock(p_ptr);
-               tsk->link_cong = 1;
-               p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt);
-               list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports);
-               l_ptr->stats.link_congs++;
-exit:
-               tipc_port_unlock(p_ptr);
-       }
-       spin_unlock_bh(&tipc_port_list_lock);
-       return -ELINKCONG;
+       buf = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, tipc_own_addr,
+                             tipc_own_addr, oport, 0, 0);
+       if (!buf)
+               return false;
+       TIPC_SKB_CB(buf)->chain_sz = chain_sz;
+       TIPC_SKB_CB(buf)->chain_imp = imp;
+       __skb_queue_tail(&link->waiting_sks, buf);
+       link->stats.link_congs++;
+       return true;
 }
 
-void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all)
+/**
+ * link_prepare_wakeup - prepare users for wakeup after congestion
+ * @link: congested link
+ * Move a number of waiting users, as permitted by available space in
+ * the send queue, from link wait queue to node wait queue for wakeup
+ */
+static void link_prepare_wakeup(struct tipc_link *link)
 {
-       struct tipc_port *p_ptr;
-       struct tipc_sock *tsk;
-       struct tipc_port *temp_p_ptr;
-       int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size;
-
-       if (all)
-               win = 100000;
-       if (win <= 0)
-               return;
-       if (!spin_trylock_bh(&tipc_port_list_lock))
-               return;
-       if (link_congested(l_ptr))
-               goto exit;
-       list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports,
-                                wait_list) {
-               if (win <= 0)
+       struct sk_buff_head *wq = &link->waiting_sks;
+       struct sk_buff *buf;
+       uint pend_qsz = link->out_queue_size;
+
+       for (buf = skb_peek(wq); buf; buf = skb_peek(wq)) {
+               if (pend_qsz >= link->queue_limit[TIPC_SKB_CB(buf)->chain_imp])
                        break;
-               tsk = tipc_port_to_sock(p_ptr);
-               list_del_init(&p_ptr->wait_list);
-               spin_lock_bh(p_ptr->lock);
-               tsk->link_cong = 0;
-               tipc_sock_wakeup(tsk);
-               win -= p_ptr->waiting_pkts;
-               spin_unlock_bh(p_ptr->lock);
+               pend_qsz += TIPC_SKB_CB(buf)->chain_sz;
+               __skb_queue_tail(&link->owner->waiting_sks, __skb_dequeue(wq));
        }
-
-exit:
-       spin_unlock_bh(&tipc_port_list_lock);
 }
 
 /**
@@ -423,6 +403,7 @@ void tipc_link_reset(struct tipc_link *l_ptr)
        u32 prev_state = l_ptr->state;
        u32 checkpoint = l_ptr->next_in_no;
        int was_active_link = tipc_link_is_active(l_ptr);
+       struct tipc_node *owner = l_ptr->owner;
 
        msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff));
 
@@ -450,9 +431,10 @@ void tipc_link_reset(struct tipc_link *l_ptr)
        kfree_skb(l_ptr->proto_msg_queue);
        l_ptr->proto_msg_queue = NULL;
        kfree_skb_list(l_ptr->oldest_deferred_in);
-       if (!list_empty(&l_ptr->waiting_ports))
-               tipc_link_wakeup_ports(l_ptr, 1);
-
+       if (!skb_queue_empty(&l_ptr->waiting_sks)) {
+               skb_queue_splice_init(&l_ptr->waiting_sks, &owner->waiting_sks);
+               owner->action_flags |= TIPC_WAKEUP_USERS;
+       }
        l_ptr->retransm_queue_head = 0;
        l_ptr->retransm_queue_size = 0;
        l_ptr->last_out = NULL;
@@ -688,19 +670,23 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
 static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
-       uint psz = msg_size(msg);
        uint imp = tipc_msg_tot_importance(msg);
        u32 oport = msg_tot_origport(msg);
 
-       if (likely(imp <= TIPC_CRITICAL_IMPORTANCE)) {
-               if (!msg_errcode(msg) && !msg_reroute_cnt(msg)) {
-                       link_schedule_port(link, oport, psz);
-                       return -ELINKCONG;
-               }
-       } else {
+       if (unlikely(imp > TIPC_CRITICAL_IMPORTANCE)) {
                pr_warn("%s<%s>, send queue full", link_rst_msg, link->name);
                tipc_link_reset(link);
+               goto drop;
        }
+       if (unlikely(msg_errcode(msg)))
+               goto drop;
+       if (unlikely(msg_reroute_cnt(msg)))
+               goto drop;
+       if (TIPC_SKB_CB(buf)->wakeup_pending)
+               return -ELINKCONG;
+       if (link_schedule_user(link, oport, TIPC_SKB_CB(buf)->chain_sz, imp))
+               return -ELINKCONG;
+drop:
        kfree_skb_list(buf);
        return -EHOSTUNREACH;
 }
@@ -1202,8 +1188,10 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
                if (unlikely(l_ptr->next_out))
                        tipc_link_push_queue(l_ptr);
 
-               if (unlikely(!list_empty(&l_ptr->waiting_ports)))
-                       tipc_link_wakeup_ports(l_ptr, 0);
+               if (released && !skb_queue_empty(&l_ptr->waiting_sks)) {
+                       link_prepare_wakeup(l_ptr);
+                       l_ptr->owner->action_flags |= TIPC_WAKEUP_USERS;
+               }
 
                /* Process the incoming packet */
                if (unlikely(!link_working_working(l_ptr))) {
index 782983ccd323a8f4df659765f76888ec3faebc7a..b567a3427fda46e05a692b606f424da1a60eaa93 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/link.h: Include file for TIPC link code
  *
- * Copyright (c) 1995-2006, 2013, Ericsson AB
+ * Copyright (c) 1995-2006, 2013-2014, Ericsson AB
  * Copyright (c) 2004-2005, 2010-2011, Wind River Systems
  * All rights reserved.
  *
@@ -133,7 +133,7 @@ struct tipc_stats {
  * @retransm_queue_size: number of messages to retransmit
  * @retransm_queue_head: sequence number of first message to retransmit
  * @next_out: ptr to first unsent outbound message in queue
- * @waiting_ports: linked list of ports waiting for link congestion to abate
+ * @waiting_sks: linked list of sockets waiting for link congestion to abate
  * @long_msg_seq_no: next identifier to use for outbound fragmented messages
  * @reasm_buf: head of partially reassembled inbound message fragments
  * @stats: collects statistics regarding link activity
@@ -194,7 +194,7 @@ struct tipc_link {
        u32 retransm_queue_size;
        u32 retransm_queue_head;
        struct sk_buff *next_out;
-       struct list_head waiting_ports;
+       struct sk_buff_head waiting_sks;
 
        /* Fragmentation/reassembly */
        u32 long_msg_seq_no;
@@ -235,7 +235,6 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob,
 void tipc_link_push_queue(struct tipc_link *l_ptr);
 u32 tipc_link_defer_pkt(struct sk_buff **head, struct sk_buff **tail,
                        struct sk_buff *buf);
-void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all);
 void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window);
 void tipc_link_retransmit(struct tipc_link *l_ptr,
                          struct sk_buff *start, u32 retransmits);
index 9680be6d388a2b77a80e930f1092d6f6c3df13f3..74745a47d72ae1c0ce84c6ff5b096682410a0789 100644 (file)
@@ -56,8 +56,35 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
        msg_set_size(m, hsize);
        msg_set_prevnode(m, tipc_own_addr);
        msg_set_type(m, type);
-       msg_set_orignode(m, tipc_own_addr);
-       msg_set_destnode(m, destnode);
+       if (hsize > SHORT_H_SIZE) {
+               msg_set_orignode(m, tipc_own_addr);
+               msg_set_destnode(m, destnode);
+       }
+}
+
+struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
+                               uint data_sz, u32 dnode, u32 onode,
+                               u32 dport, u32 oport, int errcode)
+{
+       struct tipc_msg *msg;
+       struct sk_buff *buf;
+
+       buf = tipc_buf_acquire(hdr_sz + data_sz);
+       if (unlikely(!buf))
+               return NULL;
+
+       msg = buf_msg(buf);
+       tipc_msg_init(msg, user, type, hdr_sz, dnode);
+       msg_set_size(msg, hdr_sz + data_sz);
+       msg_set_prevnode(msg, onode);
+       msg_set_origport(msg, oport);
+       msg_set_destport(msg, dport);
+       msg_set_errcode(msg, errcode);
+       if (hdr_sz > SHORT_H_SIZE) {
+               msg_set_orignode(msg, onode);
+               msg_set_destnode(msg, dnode);
+       }
+       return buf;
 }
 
 /* tipc_buf_append(): Append a buffer to the fragment list of another buffer
@@ -155,7 +182,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
        struct sk_buff *buf, *prev;
        char *pktpos;
        int rc;
-
+       uint chain_sz = 0;
        msg_set_size(mhdr, msz);
 
        /* No fragmentation needed? */
@@ -166,6 +193,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
                        return -ENOMEM;
                skb_copy_to_linear_data(buf, mhdr, mhsz);
                pktpos = buf->data + mhsz;
+               TIPC_SKB_CB(buf)->chain_sz = 1;
                if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz))
                        return dsz;
                rc = -EFAULT;
@@ -182,6 +210,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
        *chain = buf = tipc_buf_acquire(pktmax);
        if (!buf)
                return -ENOMEM;
+       chain_sz = 1;
        pktpos = buf->data;
        skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE);
        pktpos += INT_H_SIZE;
@@ -215,6 +244,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
                        rc = -ENOMEM;
                        goto error;
                }
+               chain_sz++;
                prev->next = buf;
                msg_set_type(&pkthdr, FRAGMENT);
                msg_set_size(&pkthdr, pktsz);
@@ -224,7 +254,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
                pktrem = pktsz - INT_H_SIZE;
 
        } while (1);
-
+       TIPC_SKB_CB(*chain)->chain_sz = chain_sz;
        msg_set_type(buf_msg(buf), LAST_FRAGMENT);
        return dsz;
 error:
index 462fa194a6afe5e2f6f759d4a04846d6e26ef32e..0ea7b695ac4d891a7556ae2f08110d11306369f9 100644 (file)
@@ -442,6 +442,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
 #define  NAME_DISTRIBUTOR     11
 #define  MSG_FRAGMENTER       12
 #define  LINK_CONFIG          13
+#define  SOCK_WAKEUP          14       /* pseudo user */
 
 /*
  *  Connection management protocol message types
@@ -732,6 +733,10 @@ int tipc_msg_eval(struct sk_buff *buf, u32 *dnode);
 void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
                   u32 destnode);
 
+struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
+                               uint data_sz, u32 dnode, u32 onode,
+                               u32 dport, u32 oport, int errcode);
+
 int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf);
 
 bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu);
index dcc15bcd569279a96b74cc052ee140e6f8e1bf3b..780ef710a849b0e4c58c5733b6f552c4e6552ae8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/name_distr.c: TIPC name distribution code
  *
- * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2000-2006, 2014, Ericsson AB
  * Copyright (c) 2005, 2010-2011, Wind River Systems
  * All rights reserved.
  *
@@ -71,6 +71,21 @@ static struct publ_list *publ_lists[] = {
 };
 
 
+int sysctl_tipc_named_timeout __read_mostly = 2000;
+
+/**
+ * struct tipc_dist_queue - queue holding deferred name table updates
+ */
+static struct list_head tipc_dist_queue = LIST_HEAD_INIT(tipc_dist_queue);
+
+struct distr_queue_item {
+       struct distr_item i;
+       u32 dtype;
+       u32 node;
+       unsigned long expires;
+       struct list_head next;
+};
+
 /**
  * publ_to_item - add publication info to a publication message
  */
@@ -262,55 +277,105 @@ static void named_purge_publ(struct publication *publ)
        kfree(p);
 }
 
+/**
+ * tipc_update_nametbl - try to process a nametable update and notify
+ *                      subscribers
+ *
+ * tipc_nametbl_lock must be held.
+ * Returns the publication item if successful, otherwise NULL.
+ */
+struct publication *tipc_update_nametbl(struct distr_item *i, u32 node,
+                                       u32 dtype)
+{
+       struct publication *publ = NULL;
+
+       if (dtype == PUBLICATION) {
+               publ = tipc_nametbl_insert_publ(ntohl(i->type), ntohl(i->lower),
+                                               ntohl(i->upper),
+                                               TIPC_CLUSTER_SCOPE, node,
+                                               ntohl(i->ref), ntohl(i->key));
+               if (publ) {
+                       tipc_nodesub_subscribe(&publ->subscr, node, publ,
+                                              (net_ev_handler)
+                                              named_purge_publ);
+               }
+       } else if (dtype == WITHDRAWAL) {
+               publ = tipc_nametbl_remove_publ(ntohl(i->type), ntohl(i->lower),
+                                               node, ntohl(i->ref),
+                                               ntohl(i->key));
+               if (publ) {
+                       tipc_nodesub_unsubscribe(&publ->subscr);
+                       kfree(publ);
+               }
+       } else {
+               pr_warn("Unrecognized name table message received\n");
+       }
+       return publ;
+}
+
+/**
+ * tipc_named_add_backlog - add a failed name table update to the backlog
+ *
+ */
+static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
+{
+       struct distr_queue_item *e;
+       unsigned long now = get_jiffies_64();
+
+       e = kzalloc(sizeof(*e), GFP_ATOMIC);
+       if (!e)
+               return;
+       e->dtype = type;
+       e->node = node;
+       e->expires = now + msecs_to_jiffies(sysctl_tipc_named_timeout);
+       memcpy(e, i, sizeof(*i));
+       list_add_tail(&e->next, &tipc_dist_queue);
+}
+
+/**
+ * tipc_named_process_backlog - try to process any pending name table updates
+ * from the network.
+ */
+void tipc_named_process_backlog(void)
+{
+       struct distr_queue_item *e, *tmp;
+       char addr[16];
+       unsigned long now = get_jiffies_64();
+
+       list_for_each_entry_safe(e, tmp, &tipc_dist_queue, next) {
+               if (time_after(e->expires, now)) {
+                       if (!tipc_update_nametbl(&e->i, e->node, e->dtype))
+                               continue;
+               } else {
+                       tipc_addr_string_fill(addr, e->node);
+                       pr_warn_ratelimited("Dropping name table update (%d) of {%u, %u, %u} from %s key=%u\n",
+                                           e->dtype, ntohl(e->i.type),
+                                           ntohl(e->i.lower),
+                                           ntohl(e->i.upper),
+                                           addr, ntohl(e->i.key));
+               }
+               list_del(&e->next);
+               kfree(e);
+       }
+}
+
 /**
  * tipc_named_rcv - process name table update message sent by another node
  */
 void tipc_named_rcv(struct sk_buff *buf)
 {
-       struct publication *publ;
        struct tipc_msg *msg = buf_msg(buf);
        struct distr_item *item = (struct distr_item *)msg_data(msg);
        u32 count = msg_data_sz(msg) / ITEM_SIZE;
+       u32 node = msg_orignode(msg);
 
        write_lock_bh(&tipc_nametbl_lock);
        while (count--) {
-               if (msg_type(msg) == PUBLICATION) {
-                       publ = tipc_nametbl_insert_publ(ntohl(item->type),
-                                                       ntohl(item->lower),
-                                                       ntohl(item->upper),
-                                                       TIPC_CLUSTER_SCOPE,
-                                                       msg_orignode(msg),
-                                                       ntohl(item->ref),
-                                                       ntohl(item->key));
-                       if (publ) {
-                               tipc_nodesub_subscribe(&publ->subscr,
-                                                      msg_orignode(msg),
-                                                      publ,
-                                                      (net_ev_handler)
-                                                      named_purge_publ);
-                       }
-               } else if (msg_type(msg) == WITHDRAWAL) {
-                       publ = tipc_nametbl_remove_publ(ntohl(item->type),
-                                                       ntohl(item->lower),
-                                                       msg_orignode(msg),
-                                                       ntohl(item->ref),
-                                                       ntohl(item->key));
-
-                       if (publ) {
-                               tipc_nodesub_unsubscribe(&publ->subscr);
-                               kfree(publ);
-                       } else {
-                               pr_err("Unable to remove publication by node 0x%x\n"
-                                      " (type=%u, lower=%u, ref=%u, key=%u)\n",
-                                      msg_orignode(msg), ntohl(item->type),
-                                      ntohl(item->lower), ntohl(item->ref),
-                                      ntohl(item->key));
-                       }
-               } else {
-                       pr_warn("Unrecognized name table message received\n");
-               }
+               if (!tipc_update_nametbl(item, node, msg_type(msg)))
+                       tipc_named_add_backlog(item, msg_type(msg), node);
                item++;
        }
+       tipc_named_process_backlog();
        write_unlock_bh(&tipc_nametbl_lock);
        kfree_skb(buf);
 }
index 8afe32b7fc9a0b6a2b9f78657fd13756eae0b465..b9e75feb3434e76fc96a5e71a07e94fbcc709888 100644 (file)
@@ -73,5 +73,6 @@ void named_cluster_distribute(struct sk_buff *buf);
 void tipc_named_node_up(u32 dnode);
 void tipc_named_rcv(struct sk_buff *buf);
 void tipc_named_reinit(void);
+void tipc_named_process_backlog(void);
 
 #endif
index 9d7d37d95187c77d9d7490ce7aec4de147a9f2fd..3a6a0a7c0759f01ad06b7c8d9b08a6c8d98e4ca9 100644 (file)
@@ -39,7 +39,6 @@
 #include "name_table.h"
 #include "name_distr.h"
 #include "subscr.h"
-#include "port.h"
 
 #define TIPC_NAMETBL_SIZE 1024         /* must be a power of 2 */
 
@@ -262,8 +261,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
 
                /* Lower end overlaps existing entry => need an exact match */
                if ((sseq->lower != lower) || (sseq->upper != upper)) {
-                       pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
-                               type, lower, upper);
                        return NULL;
                }
 
@@ -285,8 +282,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
                /* Fail if upper end overlaps into an existing entry */
                if ((inspos < nseq->first_free) &&
                    (upper >= nseq->sseqs[inspos].lower)) {
-                       pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
-                               type, lower, upper);
                        return NULL;
                }
 
@@ -678,6 +673,8 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
        if (likely(publ)) {
                table.local_publ_count++;
                buf = tipc_named_publish(publ);
+               /* Any pending external events? */
+               tipc_named_process_backlog();
        }
        write_unlock_bh(&tipc_nametbl_lock);
 
@@ -699,6 +696,8 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
        if (likely(publ)) {
                table.local_publ_count--;
                buf = tipc_named_withdraw(publ);
+               /* Any pending external events? */
+               tipc_named_process_backlog();
                write_unlock_bh(&tipc_nametbl_lock);
                list_del_init(&publ->pport_list);
                kfree(publ);
index 7fcc94998feae6eb1427dd25ac965fece340227a..93b9944a6a8bb1e94c332b8bd5e5f641d90899d8 100644 (file)
@@ -38,7 +38,6 @@
 #include "net.h"
 #include "name_distr.h"
 #include "subscr.h"
-#include "port.h"
 #include "socket.h"
 #include "node.h"
 #include "config.h"
@@ -111,7 +110,7 @@ int tipc_net_start(u32 addr)
 
        tipc_own_addr = addr;
        tipc_named_reinit();
-       tipc_port_reinit();
+       tipc_sk_reinit();
        res = tipc_bclink_init();
        if (res)
                return res;
index f7069299943f847f7853a3bb9e5cf781e6caf9b8..17e6378c4dfe479790d085916cb5bfe40b445ae9 100644 (file)
@@ -38,6 +38,7 @@
 #include "config.h"
 #include "node.h"
 #include "name_distr.h"
+#include "socket.h"
 
 #define NODE_HTABLE_SIZE 512
 
@@ -50,6 +51,13 @@ static u32 tipc_num_nodes;
 static u32 tipc_num_links;
 static DEFINE_SPINLOCK(node_list_lock);
 
+struct tipc_sock_conn {
+       u32 port;
+       u32 peer_port;
+       u32 peer_node;
+       struct list_head list;
+};
+
 /*
  * A trivial power-of-two bitmask technique is used for speed, since this
  * operation is done for every incoming TIPC packet. The number of hash table
@@ -100,6 +108,8 @@ struct tipc_node *tipc_node_create(u32 addr)
        INIT_HLIST_NODE(&n_ptr->hash);
        INIT_LIST_HEAD(&n_ptr->list);
        INIT_LIST_HEAD(&n_ptr->nsub);
+       INIT_LIST_HEAD(&n_ptr->conn_sks);
+       __skb_queue_head_init(&n_ptr->waiting_sks);
 
        hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]);
 
@@ -136,6 +146,71 @@ void tipc_node_stop(void)
        spin_unlock_bh(&node_list_lock);
 }
 
+int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port)
+{
+       struct tipc_node *node;
+       struct tipc_sock_conn *conn;
+
+       if (in_own_node(dnode))
+               return 0;
+
+       node = tipc_node_find(dnode);
+       if (!node) {
+               pr_warn("Connecting sock to node 0x%x failed\n", dnode);
+               return -EHOSTUNREACH;
+       }
+       conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
+       if (!conn)
+               return -EHOSTUNREACH;
+       conn->peer_node = dnode;
+       conn->port = port;
+       conn->peer_port = peer_port;
+
+       tipc_node_lock(node);
+       list_add_tail(&conn->list, &node->conn_sks);
+       tipc_node_unlock(node);
+       return 0;
+}
+
+void tipc_node_remove_conn(u32 dnode, u32 port)
+{
+       struct tipc_node *node;
+       struct tipc_sock_conn *conn, *safe;
+
+       if (in_own_node(dnode))
+               return;
+
+       node = tipc_node_find(dnode);
+       if (!node)
+               return;
+
+       tipc_node_lock(node);
+       list_for_each_entry_safe(conn, safe, &node->conn_sks, list) {
+               if (port != conn->port)
+                       continue;
+               list_del(&conn->list);
+               kfree(conn);
+       }
+       tipc_node_unlock(node);
+}
+
+void tipc_node_abort_sock_conns(struct list_head *conns)
+{
+       struct tipc_sock_conn *conn, *safe;
+       struct sk_buff *buf;
+
+       list_for_each_entry_safe(conn, safe, conns, list) {
+               buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
+                                     SHORT_H_SIZE, 0, tipc_own_addr,
+                                     conn->peer_node, conn->port,
+                                     conn->peer_port, TIPC_ERR_NO_NODE);
+               if (likely(buf))
+                       tipc_sk_rcv(buf);
+               list_del(&conn->list);
+               kfree(conn);
+       }
+}
+
 /**
  * tipc_node_link_up - handle addition of link
  *
@@ -474,6 +549,8 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len)
 void tipc_node_unlock(struct tipc_node *node)
 {
        LIST_HEAD(nsub_list);
+       LIST_HEAD(conn_sks);
+       struct sk_buff_head waiting_sks;
        u32 addr = 0;
 
        if (likely(!node->action_flags)) {
@@ -481,8 +558,14 @@ void tipc_node_unlock(struct tipc_node *node)
                return;
        }
 
+       __skb_queue_head_init(&waiting_sks);
+       if (node->action_flags & TIPC_WAKEUP_USERS) {
+               skb_queue_splice_init(&node->waiting_sks, &waiting_sks);
+               node->action_flags &= ~TIPC_WAKEUP_USERS;
+       }
        if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) {
                list_replace_init(&node->nsub, &nsub_list);
+               list_replace_init(&node->conn_sks, &conn_sks);
                node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN;
        }
        if (node->action_flags & TIPC_NOTIFY_NODE_UP) {
@@ -491,8 +574,15 @@ void tipc_node_unlock(struct tipc_node *node)
        }
        spin_unlock_bh(&node->lock);
 
+       while (!skb_queue_empty(&waiting_sks))
+               tipc_sk_rcv(__skb_dequeue(&waiting_sks));
+
+       if (!list_empty(&conn_sks))
+               tipc_node_abort_sock_conns(&conn_sks);
+
        if (!list_empty(&nsub_list))
                tipc_nodesub_notify(&nsub_list);
+
        if (addr)
                tipc_named_node_up(addr);
 }
index b61716a8218e583b6a01f711cfb3a7de950d3569..522d6f3157b32cb9aa2d28086700728216e17e81 100644 (file)
@@ -58,7 +58,8 @@ enum {
        TIPC_WAIT_PEER_LINKS_DOWN       = (1 << 1),
        TIPC_WAIT_OWN_LINKS_DOWN        = (1 << 2),
        TIPC_NOTIFY_NODE_DOWN           = (1 << 3),
-       TIPC_NOTIFY_NODE_UP             = (1 << 4)
+       TIPC_NOTIFY_NODE_UP             = (1 << 4),
+       TIPC_WAKEUP_USERS               = (1 << 5)
 };
 
 /**
@@ -115,6 +116,8 @@ struct tipc_node {
        int working_links;
        u32 signature;
        struct list_head nsub;
+       struct sk_buff_head waiting_sks;
+       struct list_head conn_sks;
        struct rcu_head rcu;
 };
 
@@ -133,6 +136,8 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
 struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space);
 int tipc_node_get_linkname(u32 bearer_id, u32 node, char *linkname, size_t len);
 void tipc_node_unlock(struct tipc_node *node);
+int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port);
+void tipc_node_remove_conn(u32 dnode, u32 port);
 
 static inline void tipc_node_lock(struct tipc_node *node)
 {
diff --git a/net/tipc/port.c b/net/tipc/port.c
deleted file mode 100644 (file)
index 7e096a5..0000000
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * net/tipc/port.c: TIPC port code
- *
- * Copyright (c) 1992-2007, 2014, Ericsson AB
- * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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, WHETHER IN
- * 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.
- */
-
-#include "core.h"
-#include "config.h"
-#include "port.h"
-#include "name_table.h"
-#include "socket.h"
-
-/* Connection management: */
-#define PROBING_INTERVAL 3600000       /* [ms] => 1 h */
-
-#define MAX_REJECT_SIZE 1024
-
-DEFINE_SPINLOCK(tipc_port_list_lock);
-
-static LIST_HEAD(ports);
-static void port_handle_node_down(unsigned long ref);
-static struct sk_buff *port_build_self_abort_msg(struct tipc_port *, u32 err);
-static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);
-static void port_timeout(unsigned long ref);
-
-/**
- * tipc_port_peer_msg - verify message was sent by connected port's peer
- *
- * Handles cases where the node's network address has changed from
- * the default of <0.0.0> to its configured setting.
- */
-int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
-{
-       u32 peernode;
-       u32 orignode;
-
-       if (msg_origport(msg) != tipc_port_peerport(p_ptr))
-               return 0;
-
-       orignode = msg_orignode(msg);
-       peernode = tipc_port_peernode(p_ptr);
-       return (orignode == peernode) ||
-               (!orignode && (peernode == tipc_own_addr)) ||
-               (!peernode && (orignode == tipc_own_addr));
-}
-
-/* tipc_port_init - intiate TIPC port and lock it
- *
- * Returns obtained reference if initialization is successful, zero otherwise
- */
-u32 tipc_port_init(struct tipc_port *p_ptr,
-                  const unsigned int importance)
-{
-       struct tipc_msg *msg;
-       u32 ref;
-
-       ref = tipc_ref_acquire(p_ptr, &p_ptr->lock);
-       if (!ref) {
-               pr_warn("Port registration failed, ref. table exhausted\n");
-               return 0;
-       }
-
-       p_ptr->max_pkt = MAX_PKT_DEFAULT;
-       p_ptr->ref = ref;
-       INIT_LIST_HEAD(&p_ptr->wait_list);
-       INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
-       k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
-       INIT_LIST_HEAD(&p_ptr->publications);
-       INIT_LIST_HEAD(&p_ptr->port_list);
-
-       /*
-        * Must hold port list lock while initializing message header template
-        * to ensure a change to node's own network address doesn't result
-        * in template containing out-dated network address information
-        */
-       spin_lock_bh(&tipc_port_list_lock);
-       msg = &p_ptr->phdr;
-       tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0);
-       msg_set_origport(msg, ref);
-       list_add_tail(&p_ptr->port_list, &ports);
-       spin_unlock_bh(&tipc_port_list_lock);
-       return ref;
-}
-
-void tipc_port_destroy(struct tipc_port *p_ptr)
-{
-       struct sk_buff *buf = NULL;
-       struct tipc_msg *msg = NULL;
-       u32 peer;
-
-       tipc_withdraw(p_ptr, 0, NULL);
-
-       spin_lock_bh(p_ptr->lock);
-       tipc_ref_discard(p_ptr->ref);
-       spin_unlock_bh(p_ptr->lock);
-
-       k_cancel_timer(&p_ptr->timer);
-       if (p_ptr->connected) {
-               buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
-               tipc_nodesub_unsubscribe(&p_ptr->subscription);
-               msg = buf_msg(buf);
-               peer = msg_destnode(msg);
-               tipc_link_xmit(buf, peer, msg_link_selector(msg));
-       }
-       spin_lock_bh(&tipc_port_list_lock);
-       list_del(&p_ptr->port_list);
-       list_del(&p_ptr->wait_list);
-       spin_unlock_bh(&tipc_port_list_lock);
-       k_term_timer(&p_ptr->timer);
-}
-
-/*
- * port_build_proto_msg(): create connection protocol message for port
- *
- * On entry the port must be locked and connected.
- */
-static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr,
-                                           u32 type, u32 ack)
-{
-       struct sk_buff *buf;
-       struct tipc_msg *msg;
-
-       buf = tipc_buf_acquire(INT_H_SIZE);
-       if (buf) {
-               msg = buf_msg(buf);
-               tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE,
-                             tipc_port_peernode(p_ptr));
-               msg_set_destport(msg, tipc_port_peerport(p_ptr));
-               msg_set_origport(msg, p_ptr->ref);
-               msg_set_msgcnt(msg, ack);
-               buf->next = NULL;
-       }
-       return buf;
-}
-
-static void port_timeout(unsigned long ref)
-{
-       struct tipc_port *p_ptr = tipc_port_lock(ref);
-       struct sk_buff *buf = NULL;
-       struct tipc_msg *msg = NULL;
-
-       if (!p_ptr)
-               return;
-
-       if (!p_ptr->connected) {
-               tipc_port_unlock(p_ptr);
-               return;
-       }
-
-       /* Last probe answered ? */
-       if (p_ptr->probing_state == TIPC_CONN_PROBING) {
-               buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
-       } else {
-               buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0);
-               p_ptr->probing_state = TIPC_CONN_PROBING;
-               k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
-       }
-       tipc_port_unlock(p_ptr);
-       msg = buf_msg(buf);
-       tipc_link_xmit(buf, msg_destnode(msg),  msg_link_selector(msg));
-}
-
-
-static void port_handle_node_down(unsigned long ref)
-{
-       struct tipc_port *p_ptr = tipc_port_lock(ref);
-       struct sk_buff *buf = NULL;
-       struct tipc_msg *msg = NULL;
-
-       if (!p_ptr)
-               return;
-       buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
-       tipc_port_unlock(p_ptr);
-       msg = buf_msg(buf);
-       tipc_link_xmit(buf, msg_destnode(msg),  msg_link_selector(msg));
-}
-
-
-static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err)
-{
-       struct sk_buff *buf = port_build_peer_abort_msg(p_ptr, err);
-
-       if (buf) {
-               struct tipc_msg *msg = buf_msg(buf);
-               msg_swap_words(msg, 4, 5);
-               msg_swap_words(msg, 6, 7);
-               buf->next = NULL;
-       }
-       return buf;
-}
-
-
-static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err)
-{
-       struct sk_buff *buf;
-       struct tipc_msg *msg;
-       u32 imp;
-
-       if (!p_ptr->connected)
-               return NULL;
-
-       buf = tipc_buf_acquire(BASIC_H_SIZE);
-       if (buf) {
-               msg = buf_msg(buf);
-               memcpy(msg, &p_ptr->phdr, BASIC_H_SIZE);
-               msg_set_hdr_sz(msg, BASIC_H_SIZE);
-               msg_set_size(msg, BASIC_H_SIZE);
-               imp = msg_importance(msg);
-               if (imp < TIPC_CRITICAL_IMPORTANCE)
-                       msg_set_importance(msg, ++imp);
-               msg_set_errcode(msg, err);
-               buf->next = NULL;
-       }
-       return buf;
-}
-
-static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id)
-{
-       struct publication *publ;
-       int ret;
-
-       if (full_id)
-               ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
-                                   tipc_zone(tipc_own_addr),
-                                   tipc_cluster(tipc_own_addr),
-                                   tipc_node(tipc_own_addr), p_ptr->ref);
-       else
-               ret = tipc_snprintf(buf, len, "%-10u:", p_ptr->ref);
-
-       if (p_ptr->connected) {
-               u32 dport = tipc_port_peerport(p_ptr);
-               u32 destnode = tipc_port_peernode(p_ptr);
-
-               ret += tipc_snprintf(buf + ret, len - ret,
-                                    " connected to <%u.%u.%u:%u>",
-                                    tipc_zone(destnode),
-                                    tipc_cluster(destnode),
-                                    tipc_node(destnode), dport);
-               if (p_ptr->conn_type != 0)
-                       ret += tipc_snprintf(buf + ret, len - ret,
-                                            " via {%u,%u}", p_ptr->conn_type,
-                                            p_ptr->conn_instance);
-       } else if (p_ptr->published) {
-               ret += tipc_snprintf(buf + ret, len - ret, " bound to");
-               list_for_each_entry(publ, &p_ptr->publications, pport_list) {
-                       if (publ->lower == publ->upper)
-                               ret += tipc_snprintf(buf + ret, len - ret,
-                                                    " {%u,%u}", publ->type,
-                                                    publ->lower);
-                       else
-                               ret += tipc_snprintf(buf + ret, len - ret,
-                                                    " {%u,%u,%u}", publ->type,
-                                                    publ->lower, publ->upper);
-               }
-       }
-       ret += tipc_snprintf(buf + ret, len - ret, "\n");
-       return ret;
-}
-
-struct sk_buff *tipc_port_get_ports(void)
-{
-       struct sk_buff *buf;
-       struct tlv_desc *rep_tlv;
-       char *pb;
-       int pb_len;
-       struct tipc_port *p_ptr;
-       int str_len = 0;
-
-       buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
-       if (!buf)
-               return NULL;
-       rep_tlv = (struct tlv_desc *)buf->data;
-       pb = TLV_DATA(rep_tlv);
-       pb_len = ULTRA_STRING_MAX_LEN;
-
-       spin_lock_bh(&tipc_port_list_lock);
-       list_for_each_entry(p_ptr, &ports, port_list) {
-               spin_lock_bh(p_ptr->lock);
-               str_len += port_print(p_ptr, pb, pb_len, 0);
-               spin_unlock_bh(p_ptr->lock);
-       }
-       spin_unlock_bh(&tipc_port_list_lock);
-       str_len += 1;   /* for "\0" */
-       skb_put(buf, TLV_SPACE(str_len));
-       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
-
-       return buf;
-}
-
-void tipc_port_reinit(void)
-{
-       struct tipc_port *p_ptr;
-       struct tipc_msg *msg;
-
-       spin_lock_bh(&tipc_port_list_lock);
-       list_for_each_entry(p_ptr, &ports, port_list) {
-               msg = &p_ptr->phdr;
-               msg_set_prevnode(msg, tipc_own_addr);
-               msg_set_orignode(msg, tipc_own_addr);
-       }
-       spin_unlock_bh(&tipc_port_list_lock);
-}
-
-void tipc_acknowledge(u32 ref, u32 ack)
-{
-       struct tipc_port *p_ptr;
-       struct sk_buff *buf = NULL;
-       struct tipc_msg *msg;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return;
-       if (p_ptr->connected)
-               buf = port_build_proto_msg(p_ptr, CONN_ACK, ack);
-
-       tipc_port_unlock(p_ptr);
-       if (!buf)
-               return;
-       msg = buf_msg(buf);
-       tipc_link_xmit(buf, msg_destnode(msg),  msg_link_selector(msg));
-}
-
-int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
-                struct tipc_name_seq const *seq)
-{
-       struct publication *publ;
-       u32 key;
-
-       if (p_ptr->connected)
-               return -EINVAL;
-       key = p_ptr->ref + p_ptr->pub_count + 1;
-       if (key == p_ptr->ref)
-               return -EADDRINUSE;
-
-       publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
-                                   scope, p_ptr->ref, key);
-       if (publ) {
-               list_add(&publ->pport_list, &p_ptr->publications);
-               p_ptr->pub_count++;
-               p_ptr->published = 1;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope,
-                 struct tipc_name_seq const *seq)
-{
-       struct publication *publ;
-       struct publication *tpubl;
-       int res = -EINVAL;
-
-       if (!seq) {
-               list_for_each_entry_safe(publ, tpubl,
-                                        &p_ptr->publications, pport_list) {
-                       tipc_nametbl_withdraw(publ->type, publ->lower,
-                                             publ->ref, publ->key);
-               }
-               res = 0;
-       } else {
-               list_for_each_entry_safe(publ, tpubl,
-                                        &p_ptr->publications, pport_list) {
-                       if (publ->scope != scope)
-                               continue;
-                       if (publ->type != seq->type)
-                               continue;
-                       if (publ->lower != seq->lower)
-                               continue;
-                       if (publ->upper != seq->upper)
-                               break;
-                       tipc_nametbl_withdraw(publ->type, publ->lower,
-                                             publ->ref, publ->key);
-                       res = 0;
-                       break;
-               }
-       }
-       if (list_empty(&p_ptr->publications))
-               p_ptr->published = 0;
-       return res;
-}
-
-int tipc_port_connect(u32 ref, struct tipc_portid const *peer)
-{
-       struct tipc_port *p_ptr;
-       int res;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       res = __tipc_port_connect(ref, p_ptr, peer);
-       tipc_port_unlock(p_ptr);
-       return res;
-}
-
-/*
- * __tipc_port_connect - connect to a remote peer
- *
- * Port must be locked.
- */
-int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr,
-                       struct tipc_portid const *peer)
-{
-       struct tipc_msg *msg;
-       int res = -EINVAL;
-
-       if (p_ptr->published || p_ptr->connected)
-               goto exit;
-       if (!peer->ref)
-               goto exit;
-
-       msg = &p_ptr->phdr;
-       msg_set_destnode(msg, peer->node);
-       msg_set_destport(msg, peer->ref);
-       msg_set_type(msg, TIPC_CONN_MSG);
-       msg_set_lookup_scope(msg, 0);
-       msg_set_hdr_sz(msg, SHORT_H_SIZE);
-
-       p_ptr->probing_interval = PROBING_INTERVAL;
-       p_ptr->probing_state = TIPC_CONN_OK;
-       p_ptr->connected = 1;
-       k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
-
-       tipc_nodesub_subscribe(&p_ptr->subscription, peer->node,
-                         (void *)(unsigned long)ref,
-                         (net_ev_handler)port_handle_node_down);
-       res = 0;
-exit:
-       p_ptr->max_pkt = tipc_node_get_mtu(peer->node, ref);
-       return res;
-}
-
-/*
- * __tipc_disconnect - disconnect port from peer
- *
- * Port must be locked.
- */
-int __tipc_port_disconnect(struct tipc_port *tp_ptr)
-{
-       if (tp_ptr->connected) {
-               tp_ptr->connected = 0;
-               /* let timer expire on it's own to avoid deadlock! */
-               tipc_nodesub_unsubscribe(&tp_ptr->subscription);
-               return 0;
-       }
-
-       return -ENOTCONN;
-}
-
-/*
- * tipc_port_disconnect(): Disconnect port form peer.
- *                    This is a node local operation.
- */
-int tipc_port_disconnect(u32 ref)
-{
-       struct tipc_port *p_ptr;
-       int res;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       res = __tipc_port_disconnect(p_ptr);
-       tipc_port_unlock(p_ptr);
-       return res;
-}
-
-/*
- * tipc_port_shutdown(): Send a SHUTDOWN msg to peer and disconnect
- */
-int tipc_port_shutdown(u32 ref)
-{
-       struct tipc_msg *msg;
-       struct tipc_port *p_ptr;
-       struct sk_buff *buf = NULL;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-
-       buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN);
-       tipc_port_unlock(p_ptr);
-       msg = buf_msg(buf);
-       tipc_link_xmit(buf, msg_destnode(msg),  msg_link_selector(msg));
-       return tipc_port_disconnect(ref);
-}
diff --git a/net/tipc/port.h b/net/tipc/port.h
deleted file mode 100644 (file)
index 3087da3..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * net/tipc/port.h: Include file for TIPC port code
- *
- * Copyright (c) 1994-2007, 2014, Ericsson AB
- * Copyright (c) 2004-2007, 2010-2013, Wind River Systems
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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, WHETHER IN
- * 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.
- */
-
-#ifndef _TIPC_PORT_H
-#define _TIPC_PORT_H
-
-#include "ref.h"
-#include "net.h"
-#include "msg.h"
-#include "node_subscr.h"
-
-#define TIPC_CONNACK_INTV         256
-#define TIPC_FLOWCTRL_WIN        (TIPC_CONNACK_INTV * 2)
-#define TIPC_CONN_OVERLOAD_LIMIT ((TIPC_FLOWCTRL_WIN * 2 + 1) * \
-                                 SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
-
-/**
- * struct tipc_port - TIPC port structure
- * @lock: pointer to spinlock for controlling access to port
- * @connected: non-zero if port is currently connected to a peer port
- * @conn_type: TIPC type used when connection was established
- * @conn_instance: TIPC instance used when connection was established
- * @published: non-zero if port has one or more associated names
- * @max_pkt: maximum packet size "hint" used when building messages sent by port
- * @ref: unique reference to port in TIPC object registry
- * @phdr: preformatted message header used when sending messages
- * @port_list: adjacent ports in TIPC's global list of ports
- * @wait_list: adjacent ports in list of ports waiting on link congestion
- * @waiting_pkts:
- * @publications: list of publications for port
- * @pub_count: total # of publications port has made during its lifetime
- * @probing_state:
- * @probing_interval:
- * @timer_ref:
- * @subscription: "node down" subscription used to terminate failed connections
- */
-struct tipc_port {
-       spinlock_t *lock;
-       int connected;
-       u32 conn_type;
-       u32 conn_instance;
-       int published;
-       u32 max_pkt;
-       u32 ref;
-       struct tipc_msg phdr;
-       struct list_head port_list;
-       struct list_head wait_list;
-       u32 waiting_pkts;
-       struct list_head publications;
-       u32 pub_count;
-       u32 probing_state;
-       u32 probing_interval;
-       struct timer_list timer;
-       struct tipc_node_subscr subscription;
-};
-
-extern spinlock_t tipc_port_list_lock;
-struct tipc_port_list;
-
-/*
- * TIPC port manipulation routines
- */
-u32 tipc_port_init(struct tipc_port *p_ptr,
-                  const unsigned int importance);
-
-void tipc_acknowledge(u32 port_ref, u32 ack);
-
-void tipc_port_destroy(struct tipc_port *p_ptr);
-
-int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
-                struct tipc_name_seq const *name_seq);
-
-int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope,
-                 struct tipc_name_seq const *name_seq);
-
-int tipc_port_connect(u32 portref, struct tipc_portid const *port);
-
-int tipc_port_disconnect(u32 portref);
-
-int tipc_port_shutdown(u32 ref);
-
-/*
- * The following routines require that the port be locked on entry
- */
-int __tipc_port_disconnect(struct tipc_port *tp_ptr);
-int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr,
-                  struct tipc_portid const *peer);
-int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg);
-
-struct sk_buff *tipc_port_get_ports(void);
-void tipc_port_reinit(void);
-
-/**
- * tipc_port_lock - lock port instance referred to and return its pointer
- */
-static inline struct tipc_port *tipc_port_lock(u32 ref)
-{
-       return (struct tipc_port *)tipc_ref_lock(ref);
-}
-
-/**
- * tipc_port_unlock - unlock a port instance
- *
- * Can use pointer instead of tipc_ref_unlock() since port is already locked.
- */
-static inline void tipc_port_unlock(struct tipc_port *p_ptr)
-{
-       spin_unlock_bh(p_ptr->lock);
-}
-
-static inline u32 tipc_port_peernode(struct tipc_port *p_ptr)
-{
-       return msg_destnode(&p_ptr->phdr);
-}
-
-static inline u32 tipc_port_peerport(struct tipc_port *p_ptr)
-{
-       return msg_destport(&p_ptr->phdr);
-}
-
-static inline  bool tipc_port_unreliable(struct tipc_port *port)
-{
-       return msg_src_droppable(&port->phdr) != 0;
-}
-
-static inline void tipc_port_set_unreliable(struct tipc_port *port,
-                                           bool unreliable)
-{
-       msg_set_src_droppable(&port->phdr, unreliable ? 1 : 0);
-}
-
-static inline bool tipc_port_unreturnable(struct tipc_port *port)
-{
-       return msg_dest_droppable(&port->phdr) != 0;
-}
-
-static inline void tipc_port_set_unreturnable(struct tipc_port *port,
-                                            bool unreturnable)
-{
-       msg_set_dest_droppable(&port->phdr, unreturnable ? 1 : 0);
-}
-
-
-static inline int tipc_port_importance(struct tipc_port *port)
-{
-       return msg_importance(&port->phdr);
-}
-
-static inline int tipc_port_set_importance(struct tipc_port *port, int imp)
-{
-       if (imp > TIPC_CRITICAL_IMPORTANCE)
-               return -EINVAL;
-       msg_set_importance(&port->phdr, (u32)imp);
-       return 0;
-}
-
-#endif
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
deleted file mode 100644 (file)
index 3d4ecd7..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * net/tipc/ref.c: TIPC object registry code
- *
- * Copyright (c) 1991-2006, Ericsson AB
- * Copyright (c) 2004-2007, Wind River Systems
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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, WHETHER IN
- * 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.
- */
-
-#include "core.h"
-#include "ref.h"
-
-/**
- * struct reference - TIPC object reference entry
- * @object: pointer to object associated with reference entry
- * @lock: spinlock controlling access to object
- * @ref: reference value for object (combines instance & array index info)
- */
-struct reference {
-       void *object;
-       spinlock_t lock;
-       u32 ref;
-};
-
-/**
- * struct tipc_ref_table - table of TIPC object reference entries
- * @entries: pointer to array of reference entries
- * @capacity: array index of first unusable entry
- * @init_point: array index of first uninitialized entry
- * @first_free: array index of first unused object reference entry
- * @last_free: array index of last unused object reference entry
- * @index_mask: bitmask for array index portion of reference values
- * @start_mask: initial value for instance value portion of reference values
- */
-struct ref_table {
-       struct reference *entries;
-       u32 capacity;
-       u32 init_point;
-       u32 first_free;
-       u32 last_free;
-       u32 index_mask;
-       u32 start_mask;
-};
-
-/*
- * Object reference table consists of 2**N entries.
- *
- * State       Object ptr      Reference
- * -----        ----------      ---------
- * In use        non-NULL       XXXX|own index
- *                             (XXXX changes each time entry is acquired)
- * Free            NULL         YYYY|next free index
- *                             (YYYY is one more than last used XXXX)
- * Uninitialized   NULL         0
- *
- * Entry 0 is not used; this allows index 0 to denote the end of the free list.
- *
- * Note that a reference value of 0 does not necessarily indicate that an
- * entry is uninitialized, since the last entry in the free list could also
- * have a reference value of 0 (although this is unlikely).
- */
-
-static struct ref_table tipc_ref_table;
-
-static DEFINE_SPINLOCK(ref_table_lock);
-
-/**
- * tipc_ref_table_init - create reference table for objects
- */
-int tipc_ref_table_init(u32 requested_size, u32 start)
-{
-       struct reference *table;
-       u32 actual_size;
-
-       /* account for unused entry, then round up size to a power of 2 */
-
-       requested_size++;
-       for (actual_size = 16; actual_size < requested_size; actual_size <<= 1)
-               /* do nothing */ ;
-
-       /* allocate table & mark all entries as uninitialized */
-       table = vzalloc(actual_size * sizeof(struct reference));
-       if (table == NULL)
-               return -ENOMEM;
-
-       tipc_ref_table.entries = table;
-       tipc_ref_table.capacity = requested_size;
-       tipc_ref_table.init_point = 1;
-       tipc_ref_table.first_free = 0;
-       tipc_ref_table.last_free = 0;
-       tipc_ref_table.index_mask = actual_size - 1;
-       tipc_ref_table.start_mask = start & ~tipc_ref_table.index_mask;
-
-       return 0;
-}
-
-/**
- * tipc_ref_table_stop - destroy reference table for objects
- */
-void tipc_ref_table_stop(void)
-{
-       vfree(tipc_ref_table.entries);
-       tipc_ref_table.entries = NULL;
-}
-
-/**
- * tipc_ref_acquire - create reference to an object
- *
- * Register an object pointer in reference table and lock the object.
- * Returns a unique reference value that is used from then on to retrieve the
- * object pointer, or to determine that the object has been deregistered.
- *
- * Note: The object is returned in the locked state so that the caller can
- * register a partially initialized object, without running the risk that
- * the object will be accessed before initialization is complete.
- */
-u32 tipc_ref_acquire(void *object, spinlock_t **lock)
-{
-       u32 index;
-       u32 index_mask;
-       u32 next_plus_upper;
-       u32 ref;
-       struct reference *entry = NULL;
-
-       if (!object) {
-               pr_err("Attempt to acquire ref. to non-existent obj\n");
-               return 0;
-       }
-       if (!tipc_ref_table.entries) {
-               pr_err("Ref. table not found in acquisition attempt\n");
-               return 0;
-       }
-
-       /* take a free entry, if available; otherwise initialize a new entry */
-       spin_lock_bh(&ref_table_lock);
-       if (tipc_ref_table.first_free) {
-               index = tipc_ref_table.first_free;
-               entry = &(tipc_ref_table.entries[index]);
-               index_mask = tipc_ref_table.index_mask;
-               next_plus_upper = entry->ref;
-               tipc_ref_table.first_free = next_plus_upper & index_mask;
-               ref = (next_plus_upper & ~index_mask) + index;
-       } else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
-               index = tipc_ref_table.init_point++;
-               entry = &(tipc_ref_table.entries[index]);
-               spin_lock_init(&entry->lock);
-               ref = tipc_ref_table.start_mask + index;
-       } else {
-               ref = 0;
-       }
-       spin_unlock_bh(&ref_table_lock);
-
-       /*
-        * Grab the lock so no one else can modify this entry
-        * While we assign its ref value & object pointer
-        */
-       if (entry) {
-               spin_lock_bh(&entry->lock);
-               entry->ref = ref;
-               entry->object = object;
-               *lock = &entry->lock;
-               /*
-                * keep it locked, the caller is responsible
-                * for unlocking this when they're done with it
-                */
-       }
-
-       return ref;
-}
-
-/**
- * tipc_ref_discard - invalidate references to an object
- *
- * Disallow future references to an object and free up the entry for re-use.
- * Note: The entry's spin_lock may still be busy after discard
- */
-void tipc_ref_discard(u32 ref)
-{
-       struct reference *entry;
-       u32 index;
-       u32 index_mask;
-
-       if (!tipc_ref_table.entries) {
-               pr_err("Ref. table not found during discard attempt\n");
-               return;
-       }
-
-       index_mask = tipc_ref_table.index_mask;
-       index = ref & index_mask;
-       entry = &(tipc_ref_table.entries[index]);
-
-       spin_lock_bh(&ref_table_lock);
-
-       if (!entry->object) {
-               pr_err("Attempt to discard ref. to non-existent obj\n");
-               goto exit;
-       }
-       if (entry->ref != ref) {
-               pr_err("Attempt to discard non-existent reference\n");
-               goto exit;
-       }
-
-       /*
-        * mark entry as unused; increment instance part of entry's reference
-        * to invalidate any subsequent references
-        */
-       entry->object = NULL;
-       entry->ref = (ref & ~index_mask) + (index_mask + 1);
-
-       /* append entry to free entry list */
-       if (tipc_ref_table.first_free == 0)
-               tipc_ref_table.first_free = index;
-       else
-               tipc_ref_table.entries[tipc_ref_table.last_free].ref |= index;
-       tipc_ref_table.last_free = index;
-
-exit:
-       spin_unlock_bh(&ref_table_lock);
-}
-
-/**
- * tipc_ref_lock - lock referenced object and return pointer to it
- */
-void *tipc_ref_lock(u32 ref)
-{
-       if (likely(tipc_ref_table.entries)) {
-               struct reference *entry;
-
-               entry = &tipc_ref_table.entries[ref &
-                                               tipc_ref_table.index_mask];
-               if (likely(entry->ref != 0)) {
-                       spin_lock_bh(&entry->lock);
-                       if (likely((entry->ref == ref) && (entry->object)))
-                               return entry->object;
-                       spin_unlock_bh(&entry->lock);
-               }
-       }
-       return NULL;
-}
diff --git a/net/tipc/ref.h b/net/tipc/ref.h
deleted file mode 100644 (file)
index d01aa1d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * net/tipc/ref.h: Include file for TIPC object registry code
- *
- * Copyright (c) 1991-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the names of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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, WHETHER IN
- * 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.
- */
-
-#ifndef _TIPC_REF_H
-#define _TIPC_REF_H
-
-int tipc_ref_table_init(u32 requested_size, u32 start);
-void tipc_ref_table_stop(void);
-
-u32 tipc_ref_acquire(void *object, spinlock_t **lock);
-void tipc_ref_discard(u32 ref);
-
-void *tipc_ref_lock(u32 ref);
-
-#endif
index ff8c8118d56e216a62172f0d60e92bf892660ee3..75275c5cf9291a0afe0818b6ef99ccfc14db8822 100644 (file)
  */
 
 #include "core.h"
-#include "port.h"
 #include "name_table.h"
 #include "node.h"
 #include "link.h"
 #include <linux/export.h>
+#include "config.h"
+#include "socket.h"
 
 #define SS_LISTENING   -1      /* socket is listening */
 #define SS_READY       -2      /* socket is connectionless */
 
-#define CONN_TIMEOUT_DEFAULT   8000    /* default connect timeout = 8s */
-#define TIPC_FWD_MSG           1
+#define CONN_TIMEOUT_DEFAULT  8000     /* default connect timeout = 8s */
+#define CONN_PROBING_INTERVAL 3600000  /* [ms] => 1 h */
+#define TIPC_FWD_MSG         1
+#define TIPC_CONN_OK          0
+#define TIPC_CONN_PROBING     1
+
+/**
+ * struct tipc_sock - TIPC socket structure
+ * @sk: socket - interacts with 'port' and with user via the socket API
+ * @connected: non-zero if port is currently connected to a peer port
+ * @conn_type: TIPC type used when connection was established
+ * @conn_instance: TIPC instance used when connection was established
+ * @published: non-zero if port has one or more associated names
+ * @max_pkt: maximum packet size "hint" used when building messages sent by port
+ * @ref: unique reference to port in TIPC object registry
+ * @phdr: preformatted message header used when sending messages
+ * @port_list: adjacent ports in TIPC's global list of ports
+ * @publications: list of publications for port
+ * @pub_count: total # of publications port has made during its lifetime
+ * @probing_state:
+ * @probing_interval:
+ * @timer:
+ * @port: port - interacts with 'sk' and with the rest of the TIPC stack
+ * @peer_name: the peer of the connection, if any
+ * @conn_timeout: the time we can wait for an unresponded setup request
+ * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue
+ * @link_cong: non-zero if owner must sleep because of link congestion
+ * @sent_unacked: # messages sent by socket, and not yet acked by peer
+ * @rcv_unacked: # messages read by user, but not yet acked back to peer
+ */
+struct tipc_sock {
+       struct sock sk;
+       int connected;
+       u32 conn_type;
+       u32 conn_instance;
+       int published;
+       u32 max_pkt;
+       u32 ref;
+       struct tipc_msg phdr;
+       struct list_head sock_list;
+       struct list_head publications;
+       u32 pub_count;
+       u32 probing_state;
+       u32 probing_interval;
+       struct timer_list timer;
+       uint conn_timeout;
+       atomic_t dupl_rcvcnt;
+       bool link_cong;
+       uint sent_unacked;
+       uint rcv_unacked;
+};
 
 static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 static void tipc_data_ready(struct sock *sk);
@@ -53,6 +103,16 @@ static void tipc_write_space(struct sock *sk);
 static int tipc_release(struct socket *sock);
 static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);
 static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p);
+static void tipc_sk_timeout(unsigned long ref);
+static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
+                          struct tipc_name_seq const *seq);
+static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
+                           struct tipc_name_seq const *seq);
+static u32 tipc_sk_ref_acquire(struct tipc_sock *tsk);
+static void tipc_sk_ref_discard(u32 ref);
+static struct tipc_sock *tipc_sk_get(u32 ref);
+static struct tipc_sock *tipc_sk_get_next(u32 *ref);
+static void tipc_sk_put(struct tipc_sock *tsk);
 
 static const struct proto_ops packet_ops;
 static const struct proto_ops stream_ops;
@@ -106,24 +166,75 @@ static struct proto tipc_proto_kern;
  *   - port reference
  */
 
-#include "socket.h"
+static u32 tsk_peer_node(struct tipc_sock *tsk)
+{
+       return msg_destnode(&tsk->phdr);
+}
+
+static u32 tsk_peer_port(struct tipc_sock *tsk)
+{
+       return msg_destport(&tsk->phdr);
+}
+
+static  bool tsk_unreliable(struct tipc_sock *tsk)
+{
+       return msg_src_droppable(&tsk->phdr) != 0;
+}
+
+static void tsk_set_unreliable(struct tipc_sock *tsk, bool unreliable)
+{
+       msg_set_src_droppable(&tsk->phdr, unreliable ? 1 : 0);
+}
+
+static bool tsk_unreturnable(struct tipc_sock *tsk)
+{
+       return msg_dest_droppable(&tsk->phdr) != 0;
+}
+
+static void tsk_set_unreturnable(struct tipc_sock *tsk, bool unreturnable)
+{
+       msg_set_dest_droppable(&tsk->phdr, unreturnable ? 1 : 0);
+}
+
+static int tsk_importance(struct tipc_sock *tsk)
+{
+       return msg_importance(&tsk->phdr);
+}
+
+static int tsk_set_importance(struct tipc_sock *tsk, int imp)
+{
+       if (imp > TIPC_CRITICAL_IMPORTANCE)
+               return -EINVAL;
+       msg_set_importance(&tsk->phdr, (u32)imp);
+       return 0;
+}
+
+static struct tipc_sock *tipc_sk(const struct sock *sk)
+{
+       return container_of(sk, struct tipc_sock, sk);
+}
+
+static int tsk_conn_cong(struct tipc_sock *tsk)
+{
+       return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN;
+}
 
 /**
- * advance_rx_queue - discard first buffer in socket receive queue
+ * tsk_advance_rx_queue - discard first buffer in socket receive queue
  *
  * Caller must hold socket lock
  */
-static void advance_rx_queue(struct sock *sk)
+static void tsk_advance_rx_queue(struct sock *sk)
 {
        kfree_skb(__skb_dequeue(&sk->sk_receive_queue));
 }
 
 /**
- * reject_rx_queue - reject all buffers in socket receive queue
+ * tsk_rej_rx_queue - reject all buffers in socket receive queue
  *
  * Caller must hold socket lock
  */
-static void reject_rx_queue(struct sock *sk)
+static void tsk_rej_rx_queue(struct sock *sk)
 {
        struct sk_buff *buf;
        u32 dnode;
@@ -134,6 +245,38 @@ static void reject_rx_queue(struct sock *sk)
        }
 }
 
+/* tsk_peer_msg - verify if message was sent by connected port's peer
+ *
+ * Handles cases where the node's network address has changed from
+ * the default of <0.0.0> to its configured setting.
+ */
+static bool tsk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg)
+{
+       u32 peer_port = tsk_peer_port(tsk);
+       u32 orig_node;
+       u32 peer_node;
+
+       if (unlikely(!tsk->connected))
+               return false;
+
+       if (unlikely(msg_origport(msg) != peer_port))
+               return false;
+
+       orig_node = msg_orignode(msg);
+       peer_node = tsk_peer_node(tsk);
+
+       if (likely(orig_node == peer_node))
+               return true;
+
+       if (!orig_node && (peer_node == tipc_own_addr))
+               return true;
+
+       if (!peer_node && (orig_node == tipc_own_addr))
+               return true;
+
+       return false;
+}
+
 /**
  * tipc_sk_create - create a TIPC socket
  * @net: network namespace (must be default network)
@@ -153,7 +296,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        socket_state state;
        struct sock *sk;
        struct tipc_sock *tsk;
-       struct tipc_port *port;
+       struct tipc_msg *msg;
        u32 ref;
 
        /* Validate arguments */
@@ -188,20 +331,24 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
                return -ENOMEM;
 
        tsk = tipc_sk(sk);
-       port = &tsk->port;
-
-       ref = tipc_port_init(port, TIPC_LOW_IMPORTANCE);
+       ref = tipc_sk_ref_acquire(tsk);
        if (!ref) {
-               pr_warn("Socket registration failed, ref. table exhausted\n");
-               sk_free(sk);
+               pr_warn("Socket create failed; reference table exhausted\n");
                return -ENOMEM;
        }
+       tsk->max_pkt = MAX_PKT_DEFAULT;
+       tsk->ref = ref;
+       INIT_LIST_HEAD(&tsk->publications);
+       msg = &tsk->phdr;
+       tipc_msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG,
+                     NAMED_H_SIZE, 0);
+       msg_set_origport(msg, ref);
 
        /* Finish initializing socket data structures */
        sock->ops = ops;
        sock->state = state;
-
        sock_init_data(sock, sk);
+       k_init_timer(&tsk->timer, (Handler)tipc_sk_timeout, ref);
        sk->sk_backlog_rcv = tipc_backlog_rcv;
        sk->sk_rcvbuf = sysctl_tipc_rmem[1];
        sk->sk_data_ready = tipc_data_ready;
@@ -209,12 +356,11 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        tsk->conn_timeout = CONN_TIMEOUT_DEFAULT;
        tsk->sent_unacked = 0;
        atomic_set(&tsk->dupl_rcvcnt, 0);
-       tipc_port_unlock(port);
 
        if (sock->state == SS_READY) {
-               tipc_port_set_unreturnable(port, true);
+               tsk_set_unreturnable(tsk, true);
                if (sock->type == SOCK_DGRAM)
-                       tipc_port_set_unreliable(port, true);
+                       tsk_set_unreliable(tsk, true);
        }
        return 0;
 }
@@ -308,7 +454,6 @@ static int tipc_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk;
-       struct tipc_port *port;
        struct sk_buff *buf;
        u32 dnode;
 
@@ -320,13 +465,13 @@ static int tipc_release(struct socket *sock)
                return 0;
 
        tsk = tipc_sk(sk);
-       port = &tsk->port;
        lock_sock(sk);
 
        /*
         * Reject all unreceived messages, except on an active connection
         * (which disconnects locally & sends a 'FIN+' to peer)
         */
+       dnode = tsk_peer_node(tsk);
        while (sock->state != SS_DISCONNECTING) {
                buf = __skb_dequeue(&sk->sk_receive_queue);
                if (buf == NULL)
@@ -337,17 +482,27 @@ static int tipc_release(struct socket *sock)
                        if ((sock->state == SS_CONNECTING) ||
                            (sock->state == SS_CONNECTED)) {
                                sock->state = SS_DISCONNECTING;
-                               tipc_port_disconnect(port->ref);
+                               tsk->connected = 0;
+                               tipc_node_remove_conn(dnode, tsk->ref);
                        }
                        if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT))
                                tipc_link_xmit(buf, dnode, 0);
                }
        }
 
-       /* Destroy TIPC port; also disconnects an active connection and
-        * sends a 'FIN-' to peer.
-        */
-       tipc_port_destroy(port);
+       tipc_sk_withdraw(tsk, 0, NULL);
+       tipc_sk_ref_discard(tsk->ref);
+       k_cancel_timer(&tsk->timer);
+       if (tsk->connected) {
+               buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
+                                     SHORT_H_SIZE, 0, dnode, tipc_own_addr,
+                                     tsk_peer_port(tsk),
+                                     tsk->ref, TIPC_ERR_NO_PORT);
+               if (buf)
+                       tipc_link_xmit(buf, dnode, tsk->ref);
+               tipc_node_remove_conn(dnode, tsk->ref);
+       }
+       k_term_timer(&tsk->timer);
 
        /* Discard any remaining (connection-based) messages in receive queue */
        __skb_queue_purge(&sk->sk_receive_queue);
@@ -355,7 +510,6 @@ static int tipc_release(struct socket *sock)
        /* Reject any messages that accumulated in backlog queue */
        sock->state = SS_DISCONNECTING;
        release_sock(sk);
-
        sock_put(sk);
        sock->sk = NULL;
 
@@ -387,7 +541,7 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
 
        lock_sock(sk);
        if (unlikely(!uaddr_len)) {
-               res = tipc_withdraw(&tsk->port, 0, NULL);
+               res = tipc_sk_withdraw(tsk, 0, NULL);
                goto exit;
        }
 
@@ -415,8 +569,8 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
        }
 
        res = (addr->scope > 0) ?
-               tipc_publish(&tsk->port, addr->scope, &addr->addr.nameseq) :
-               tipc_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq);
+               tipc_sk_publish(tsk, addr->scope, &addr->addr.nameseq) :
+               tipc_sk_withdraw(tsk, -addr->scope, &addr->addr.nameseq);
 exit:
        release_sock(sk);
        return res;
@@ -446,10 +600,10 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,
                if ((sock->state != SS_CONNECTED) &&
                        ((peer != 2) || (sock->state != SS_DISCONNECTING)))
                        return -ENOTCONN;
-               addr->addr.id.ref = tipc_port_peerport(&tsk->port);
-               addr->addr.id.node = tipc_port_peernode(&tsk->port);
+               addr->addr.id.ref = tsk_peer_port(tsk);
+               addr->addr.id.node = tsk_peer_node(tsk);
        } else {
-               addr->addr.id.ref = tsk->port.ref;
+               addr->addr.id.ref = tsk->ref;
                addr->addr.id.node = tipc_own_addr;
        }
 
@@ -518,7 +672,7 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
                break;
        case SS_READY:
        case SS_CONNECTED:
-               if (!tsk->link_cong && !tipc_sk_conn_cong(tsk))
+               if (!tsk->link_cong && !tsk_conn_cong(tsk))
                        mask |= POLLOUT;
                /* fall thru' */
        case SS_CONNECTING:
@@ -549,7 +703,7 @@ static int tipc_sendmcast(struct  socket *sock, struct tipc_name_seq *seq,
                          struct iovec *iov, size_t dsz, long timeo)
 {
        struct sock *sk = sock->sk;
-       struct tipc_msg *mhdr = &tipc_sk(sk)->port.phdr;
+       struct tipc_msg *mhdr = &tipc_sk(sk)->phdr;
        struct sk_buff *buf;
        uint mtu;
        int rc;
@@ -579,6 +733,7 @@ new_mtu:
                        goto new_mtu;
                if (rc != -ELINKCONG)
                        break;
+               tipc_sk(sk)->link_cong = 1;
                rc = tipc_wait_for_sndmsg(sock, &timeo);
                if (rc)
                        kfree_skb_list(buf);
@@ -638,20 +793,19 @@ static int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode,
                             struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
-       struct tipc_port *port = &tsk->port;
        int conn_cong;
 
        /* Ignore if connection cannot be validated: */
-       if (!port->connected || !tipc_port_peer_msg(port, msg))
+       if (!tsk_peer_msg(tsk, msg))
                goto exit;
 
-       port->probing_state = TIPC_CONN_OK;
+       tsk->probing_state = TIPC_CONN_OK;
 
        if (msg_type(msg) == CONN_ACK) {
-               conn_cong = tipc_sk_conn_cong(tsk);
+               conn_cong = tsk_conn_cong(tsk);
                tsk->sent_unacked -= msg_msgcnt(msg);
                if (conn_cong)
-                       tipc_sock_wakeup(tsk);
+                       tsk->sk.sk_write_space(&tsk->sk);
        } else if (msg_type(msg) == CONN_PROBE) {
                if (!tipc_msg_reverse(buf, dnode, TIPC_OK))
                        return TIPC_OK;
@@ -742,8 +896,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
-       struct tipc_msg *mhdr = &port->phdr;
+       struct tipc_msg *mhdr = &tsk->phdr;
        struct iovec *iov = m->msg_iov;
        u32 dnode, dport;
        struct sk_buff *buf;
@@ -774,13 +927,13 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
                        rc = -EISCONN;
                        goto exit;
                }
-               if (tsk->port.published) {
+               if (tsk->published) {
                        rc = -EOPNOTSUPP;
                        goto exit;
                }
                if (dest->addrtype == TIPC_ADDR_NAME) {
-                       tsk->port.conn_type = dest->addr.name.name.type;
-                       tsk->port.conn_instance = dest->addr.name.name.instance;
+                       tsk->conn_type = dest->addr.name.name.type;
+                       tsk->conn_instance = dest->addr.name.name.instance;
                }
        }
        rc = dest_name_check(dest, m);
@@ -820,13 +973,14 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
        }
 
 new_mtu:
-       mtu = tipc_node_get_mtu(dnode, tsk->port.ref);
+       mtu = tipc_node_get_mtu(dnode, tsk->ref);
        rc = tipc_msg_build(mhdr, iov, 0, dsz, mtu, &buf);
        if (rc < 0)
                goto exit;
 
        do {
-               rc = tipc_link_xmit(buf, dnode, tsk->port.ref);
+               TIPC_SKB_CB(buf)->wakeup_pending = tsk->link_cong;
+               rc = tipc_link_xmit(buf, dnode, tsk->ref);
                if (likely(rc >= 0)) {
                        if (sock->state != SS_READY)
                                sock->state = SS_CONNECTING;
@@ -835,10 +989,9 @@ new_mtu:
                }
                if (rc == -EMSGSIZE)
                        goto new_mtu;
-
                if (rc != -ELINKCONG)
                        break;
-
+               tsk->link_cong = 1;
                rc = tipc_wait_for_sndmsg(sock, &timeo);
                if (rc)
                        kfree_skb_list(buf);
@@ -873,8 +1026,8 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p)
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                done = sk_wait_event(sk, timeo_p,
                                     (!tsk->link_cong &&
-                                     !tipc_sk_conn_cong(tsk)) ||
-                                    !tsk->port.connected);
+                                     !tsk_conn_cong(tsk)) ||
+                                    !tsk->connected);
                finish_wait(sk_sleep(sk), &wait);
        } while (!done);
        return 0;
@@ -897,11 +1050,10 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
-       struct tipc_msg *mhdr = &port->phdr;
+       struct tipc_msg *mhdr = &tsk->phdr;
        struct sk_buff *buf;
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
-       u32 ref = port->ref;
+       u32 ref = tsk->ref;
        int rc = -EINVAL;
        long timeo;
        u32 dnode;
@@ -929,16 +1081,16 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
        }
 
        timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
-       dnode = tipc_port_peernode(port);
+       dnode = tsk_peer_node(tsk);
 
 next:
-       mtu = port->max_pkt;
+       mtu = tsk->max_pkt;
        send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE);
        rc = tipc_msg_build(mhdr, m->msg_iov, sent, send, mtu, &buf);
        if (unlikely(rc < 0))
                goto exit;
        do {
-               if (likely(!tipc_sk_conn_cong(tsk))) {
+               if (likely(!tsk_conn_cong(tsk))) {
                        rc = tipc_link_xmit(buf, dnode, ref);
                        if (likely(!rc)) {
                                tsk->sent_unacked++;
@@ -948,11 +1100,12 @@ next:
                                goto next;
                        }
                        if (rc == -EMSGSIZE) {
-                               port->max_pkt = tipc_node_get_mtu(dnode, ref);
+                               tsk->max_pkt = tipc_node_get_mtu(dnode, ref);
                                goto next;
                        }
                        if (rc != -ELINKCONG)
                                break;
+                       tsk->link_cong = 1;
                }
                rc = tipc_wait_for_sndpkt(sock, &timeo);
                if (rc)
@@ -984,29 +1137,25 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock,
        return tipc_send_stream(iocb, sock, m, dsz);
 }
 
-/**
- * auto_connect - complete connection setup to a remote port
- * @tsk: tipc socket structure
- * @msg: peer's response message
- *
- * Returns 0 on success, errno otherwise
+/* tipc_sk_finish_conn - complete the setup of a connection
  */
-static int auto_connect(struct tipc_sock *tsk, struct tipc_msg *msg)
+static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,
+                               u32 peer_node)
 {
-       struct tipc_port *port = &tsk->port;
-       struct socket *sock = tsk->sk.sk_socket;
-       struct tipc_portid peer;
-
-       peer.ref = msg_origport(msg);
-       peer.node = msg_orignode(msg);
-
-       __tipc_port_connect(port->ref, port, &peer);
-
-       if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)
-               return -EINVAL;
-       msg_set_importance(&port->phdr, (u32)msg_importance(msg));
-       sock->state = SS_CONNECTED;
-       return 0;
+       struct tipc_msg *msg = &tsk->phdr;
+
+       msg_set_destnode(msg, peer_node);
+       msg_set_destport(msg, peer_port);
+       msg_set_type(msg, TIPC_CONN_MSG);
+       msg_set_lookup_scope(msg, 0);
+       msg_set_hdr_sz(msg, SHORT_H_SIZE);
+
+       tsk->probing_interval = CONN_PROBING_INTERVAL;
+       tsk->probing_state = TIPC_CONN_OK;
+       tsk->connected = 1;
+       k_start_timer(&tsk->timer, tsk->probing_interval);
+       tipc_node_add_conn(peer_node, tsk->ref, peer_port);
+       tsk->max_pkt = tipc_node_get_mtu(peer_node, tsk->ref);
 }
 
 /**
@@ -1033,17 +1182,17 @@ static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
 }
 
 /**
- * anc_data_recv - optionally capture ancillary data for received message
+ * tipc_sk_anc_data_recv - optionally capture ancillary data for received message
  * @m: descriptor for message info
  * @msg: received message header
- * @tport: TIPC port associated with message
+ * @tsk: TIPC port associated with message
  *
  * Note: Ancillary data is not captured if not requested by receiver.
  *
  * Returns 0 if successful, otherwise errno
  */
-static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
-                        struct tipc_port *tport)
+static int tipc_sk_anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
+                                struct tipc_sock *tsk)
 {
        u32 anc_data[3];
        u32 err;
@@ -1086,10 +1235,10 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
                anc_data[2] = msg_nameupper(msg);
                break;
        case TIPC_CONN_MSG:
-               has_name = (tport->conn_type != 0);
-               anc_data[0] = tport->conn_type;
-               anc_data[1] = tport->conn_instance;
-               anc_data[2] = tport->conn_instance;
+               has_name = (tsk->conn_type != 0);
+               anc_data[0] = tsk->conn_type;
+               anc_data[1] = tsk->conn_instance;
+               anc_data[2] = tsk->conn_instance;
                break;
        default:
                has_name = 0;
@@ -1103,6 +1252,24 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
        return 0;
 }
 
+static void tipc_sk_send_ack(struct tipc_sock *tsk, uint ack)
+{
+       struct sk_buff *buf = NULL;
+       struct tipc_msg *msg;
+       u32 peer_port = tsk_peer_port(tsk);
+       u32 dnode = tsk_peer_node(tsk);
+
+       if (!tsk->connected)
+               return;
+       buf = tipc_msg_create(CONN_MANAGER, CONN_ACK, INT_H_SIZE, 0, dnode,
+                             tipc_own_addr, peer_port, tsk->ref, TIPC_OK);
+       if (!buf)
+               return;
+       msg = buf_msg(buf);
+       msg_set_msgcnt(msg, ack);
+       tipc_link_xmit(buf, dnode, msg_link_selector(msg));
+}
+
 static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
 {
        struct sock *sk = sock->sk;
@@ -1153,7 +1320,6 @@ static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        struct tipc_msg *msg;
        long timeo;
@@ -1188,7 +1354,7 @@ restart:
 
        /* Discard an empty non-errored message & try again */
        if ((!sz) && (!err)) {
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
                goto restart;
        }
 
@@ -1196,7 +1362,7 @@ restart:
        set_orig_addr(m, msg);
 
        /* Capture ancillary data (optional) */
-       res = anc_data_recv(m, msg, port);
+       res = tipc_sk_anc_data_recv(m, msg, tsk);
        if (res)
                goto exit;
 
@@ -1223,10 +1389,10 @@ restart:
        if (likely(!(flags & MSG_PEEK))) {
                if ((sock->state != SS_READY) &&
                    (++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) {
-                       tipc_acknowledge(port->ref, tsk->rcv_unacked);
+                       tipc_sk_send_ack(tsk, tsk->rcv_unacked);
                        tsk->rcv_unacked = 0;
                }
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
        }
 exit:
        release_sock(sk);
@@ -1250,7 +1416,6 @@ static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        struct tipc_msg *msg;
        long timeo;
@@ -1288,14 +1453,14 @@ restart:
 
        /* Discard an empty non-errored message & try again */
        if ((!sz) && (!err)) {
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
                goto restart;
        }
 
        /* Optionally capture sender's address & ancillary data of first msg */
        if (sz_copied == 0) {
                set_orig_addr(m, msg);
-               res = anc_data_recv(m, msg, port);
+               res = tipc_sk_anc_data_recv(m, msg, tsk);
                if (res)
                        goto exit;
        }
@@ -1334,10 +1499,10 @@ restart:
        /* Consume received message (optional) */
        if (likely(!(flags & MSG_PEEK))) {
                if (unlikely(++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) {
-                       tipc_acknowledge(port->ref, tsk->rcv_unacked);
+                       tipc_sk_send_ack(tsk, tsk->rcv_unacked);
                        tsk->rcv_unacked = 0;
                }
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
        }
 
        /* Loop around if more data is required */
@@ -1396,12 +1561,9 @@ static void tipc_data_ready(struct sock *sk)
 static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
 {
        struct sock *sk = &tsk->sk;
-       struct tipc_port *port = &tsk->port;
        struct socket *sock = sk->sk_socket;
        struct tipc_msg *msg = buf_msg(*buf);
-
        int retval = -TIPC_ERR_NO_PORT;
-       int res;
 
        if (msg_mcast(msg))
                return retval;
@@ -1409,16 +1571,23 @@ static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
        switch ((int)sock->state) {
        case SS_CONNECTED:
                /* Accept only connection-based messages sent by peer */
-               if (msg_connected(msg) && tipc_port_peer_msg(port, msg)) {
+               if (tsk_peer_msg(tsk, msg)) {
                        if (unlikely(msg_errcode(msg))) {
                                sock->state = SS_DISCONNECTING;
-                               __tipc_port_disconnect(port);
+                               tsk->connected = 0;
+                               /* let timer expire on it's own */
+                               tipc_node_remove_conn(tsk_peer_node(tsk),
+                                                     tsk->ref);
                        }
                        retval = TIPC_OK;
                }
                break;
        case SS_CONNECTING:
                /* Accept only ACK or NACK message */
+
+               if (unlikely(!msg_connected(msg)))
+                       break;
+
                if (unlikely(msg_errcode(msg))) {
                        sock->state = SS_DISCONNECTING;
                        sk->sk_err = ECONNREFUSED;
@@ -1426,17 +1595,17 @@ static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
                        break;
                }
 
-               if (unlikely(!msg_connected(msg)))
-                       break;
-
-               res = auto_connect(tsk, msg);
-               if (res) {
+               if (unlikely(msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)) {
                        sock->state = SS_DISCONNECTING;
-                       sk->sk_err = -res;
+                       sk->sk_err = EINVAL;
                        retval = TIPC_OK;
                        break;
                }
 
+               tipc_sk_finish_conn(tsk, msg_origport(msg), msg_orignode(msg));
+               msg_set_importance(&tsk->phdr, msg_importance(msg));
+               sock->state = SS_CONNECTED;
+
                /* If an incoming message is an 'ACK-', it should be
                 * discarded here because it doesn't contain useful
                 * data. In addition, we should try to wake up
@@ -1518,6 +1687,13 @@ static int filter_rcv(struct sock *sk, struct sk_buff *buf)
        if (unlikely(msg_user(msg) == CONN_MANAGER))
                return tipc_sk_proto_rcv(tsk, &onode, buf);
 
+       if (unlikely(msg_user(msg) == SOCK_WAKEUP)) {
+               kfree_skb(buf);
+               tsk->link_cong = 0;
+               sk->sk_write_space(sk);
+               return TIPC_OK;
+       }
+
        /* Reject message if it is wrong sort of message for socket */
        if (msg_type(msg) > TIPC_DIRECT_MSG)
                return -TIPC_ERR_NO_PORT;
@@ -1585,7 +1761,6 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf)
 int tipc_sk_rcv(struct sk_buff *buf)
 {
        struct tipc_sock *tsk;
-       struct tipc_port *port;
        struct sock *sk;
        u32 dport = msg_destport(buf_msg(buf));
        int rc = TIPC_OK;
@@ -1593,13 +1768,11 @@ int tipc_sk_rcv(struct sk_buff *buf)
        u32 dnode;
 
        /* Validate destination and message */
-       port = tipc_port_lock(dport);
-       if (unlikely(!port)) {
+       tsk = tipc_sk_get(dport);
+       if (unlikely(!tsk)) {
                rc = tipc_msg_eval(buf, &dnode);
                goto exit;
        }
-
-       tsk = tipc_port_to_sock(port);
        sk = &tsk->sk;
 
        /* Queue message */
@@ -1615,8 +1788,7 @@ int tipc_sk_rcv(struct sk_buff *buf)
                        rc = -TIPC_ERR_OVERLOAD;
        }
        bh_unlock_sock(sk);
-       tipc_port_unlock(port);
-
+       tipc_sk_put(tsk);
        if (likely(!rc))
                return 0;
 exit:
@@ -1803,10 +1975,8 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
 {
        struct sock *new_sk, *sk = sock->sk;
        struct sk_buff *buf;
-       struct tipc_port *new_port;
+       struct tipc_sock *new_tsock;
        struct tipc_msg *msg;
-       struct tipc_portid peer;
-       u32 new_ref;
        long timeo;
        int res;
 
@@ -1828,8 +1998,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
                goto exit;
 
        new_sk = new_sock->sk;
-       new_port = &tipc_sk(new_sk)->port;
-       new_ref = new_port->ref;
+       new_tsock = tipc_sk(new_sk);
        msg = buf_msg(buf);
 
        /* we lock on new_sk; but lockdep sees the lock on sk */
@@ -1839,18 +2008,16 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
         * Reject any stray messages received by new socket
         * before the socket lock was taken (very, very unlikely)
         */
-       reject_rx_queue(new_sk);
+       tsk_rej_rx_queue(new_sk);
 
        /* Connect new socket to it's peer */
-       peer.ref = msg_origport(msg);
-       peer.node = msg_orignode(msg);
-       tipc_port_connect(new_ref, &peer);
+       tipc_sk_finish_conn(new_tsock, msg_origport(msg), msg_orignode(msg));
        new_sock->state = SS_CONNECTED;
 
-       tipc_port_set_importance(new_port, msg_importance(msg));
+       tsk_set_importance(new_tsock, msg_importance(msg));
        if (msg_named(msg)) {
-               new_port->conn_type = msg_nametype(msg);
-               new_port->conn_instance = msg_nameinst(msg);
+               new_tsock->conn_type = msg_nametype(msg);
+               new_tsock->conn_instance = msg_nameinst(msg);
        }
 
        /*
@@ -1860,7 +2027,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
        if (!msg_data_sz(msg)) {
                struct msghdr m = {NULL,};
 
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
                tipc_send_packet(NULL, new_sock, &m, 0);
        } else {
                __skb_dequeue(&sk->sk_receive_queue);
@@ -1886,9 +2053,8 @@ static int tipc_shutdown(struct socket *sock, int how)
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
-       u32 peer;
+       u32 dnode;
        int res;
 
        if (how != SHUT_RDWR)
@@ -1908,15 +2074,21 @@ restart:
                                kfree_skb(buf);
                                goto restart;
                        }
-                       tipc_port_disconnect(port->ref);
-                       if (tipc_msg_reverse(buf, &peer, TIPC_CONN_SHUTDOWN))
-                               tipc_link_xmit(buf, peer, 0);
+                       if (tipc_msg_reverse(buf, &dnode, TIPC_CONN_SHUTDOWN))
+                               tipc_link_xmit(buf, dnode, tsk->ref);
+                       tipc_node_remove_conn(dnode, tsk->ref);
                } else {
-                       tipc_port_shutdown(port->ref);
+                       dnode = tsk_peer_node(tsk);
+                       buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
+                                             TIPC_CONN_MSG, SHORT_H_SIZE,
+                                             0, dnode, tipc_own_addr,
+                                             tsk_peer_port(tsk),
+                                             tsk->ref, TIPC_CONN_SHUTDOWN);
+                       tipc_link_xmit(buf, dnode, tsk->ref);
                }
-
+               tsk->connected = 0;
                sock->state = SS_DISCONNECTING;
-
+               tipc_node_remove_conn(dnode, tsk->ref);
                /* fall through */
 
        case SS_DISCONNECTING:
@@ -1937,6 +2109,432 @@ restart:
        return res;
 }
 
+static void tipc_sk_timeout(unsigned long ref)
+{
+       struct tipc_sock *tsk;
+       struct sock *sk;
+       struct sk_buff *buf = NULL;
+       u32 peer_port, peer_node;
+
+       tsk = tipc_sk_get(ref);
+       if (!tsk)
+               return;
+
+       sk = &tsk->sk;
+       bh_lock_sock(sk);
+       if (!tsk->connected) {
+               bh_unlock_sock(sk);
+               goto exit;
+       }
+       peer_port = tsk_peer_port(tsk);
+       peer_node = tsk_peer_node(tsk);
+
+       if (tsk->probing_state == TIPC_CONN_PROBING) {
+               /* Previous probe not answered -> self abort */
+               buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
+                                     SHORT_H_SIZE, 0, tipc_own_addr,
+                                     peer_node, ref, peer_port,
+                                     TIPC_ERR_NO_PORT);
+       } else {
+               buf = tipc_msg_create(CONN_MANAGER, CONN_PROBE, INT_H_SIZE,
+                                     0, peer_node, tipc_own_addr,
+                                     peer_port, ref, TIPC_OK);
+               tsk->probing_state = TIPC_CONN_PROBING;
+               k_start_timer(&tsk->timer, tsk->probing_interval);
+       }
+       bh_unlock_sock(sk);
+       if (buf)
+               tipc_link_xmit(buf, peer_node, ref);
+exit:
+       tipc_sk_put(tsk);
+}
+
+static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
+                          struct tipc_name_seq const *seq)
+{
+       struct publication *publ;
+       u32 key;
+
+       if (tsk->connected)
+               return -EINVAL;
+       key = tsk->ref + tsk->pub_count + 1;
+       if (key == tsk->ref)
+               return -EADDRINUSE;
+
+       publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
+                                   scope, tsk->ref, key);
+       if (unlikely(!publ))
+               return -EINVAL;
+
+       list_add(&publ->pport_list, &tsk->publications);
+       tsk->pub_count++;
+       tsk->published = 1;
+       return 0;
+}
+
+static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
+                           struct tipc_name_seq const *seq)
+{
+       struct publication *publ;
+       struct publication *safe;
+       int rc = -EINVAL;
+
+       list_for_each_entry_safe(publ, safe, &tsk->publications, pport_list) {
+               if (seq) {
+                       if (publ->scope != scope)
+                               continue;
+                       if (publ->type != seq->type)
+                               continue;
+                       if (publ->lower != seq->lower)
+                               continue;
+                       if (publ->upper != seq->upper)
+                               break;
+                       tipc_nametbl_withdraw(publ->type, publ->lower,
+                                             publ->ref, publ->key);
+                       rc = 0;
+                       break;
+               }
+               tipc_nametbl_withdraw(publ->type, publ->lower,
+                                     publ->ref, publ->key);
+               rc = 0;
+       }
+       if (list_empty(&tsk->publications))
+               tsk->published = 0;
+       return rc;
+}
+
+static int tipc_sk_show(struct tipc_sock *tsk, char *buf,
+                       int len, int full_id)
+{
+       struct publication *publ;
+       int ret;
+
+       if (full_id)
+               ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
+                                   tipc_zone(tipc_own_addr),
+                                   tipc_cluster(tipc_own_addr),
+                                   tipc_node(tipc_own_addr), tsk->ref);
+       else
+               ret = tipc_snprintf(buf, len, "%-10u:", tsk->ref);
+
+       if (tsk->connected) {
+               u32 dport = tsk_peer_port(tsk);
+               u32 destnode = tsk_peer_node(tsk);
+
+               ret += tipc_snprintf(buf + ret, len - ret,
+                                    " connected to <%u.%u.%u:%u>",
+                                    tipc_zone(destnode),
+                                    tipc_cluster(destnode),
+                                    tipc_node(destnode), dport);
+               if (tsk->conn_type != 0)
+                       ret += tipc_snprintf(buf + ret, len - ret,
+                                            " via {%u,%u}", tsk->conn_type,
+                                            tsk->conn_instance);
+       } else if (tsk->published) {
+               ret += tipc_snprintf(buf + ret, len - ret, " bound to");
+               list_for_each_entry(publ, &tsk->publications, pport_list) {
+                       if (publ->lower == publ->upper)
+                               ret += tipc_snprintf(buf + ret, len - ret,
+                                                    " {%u,%u}", publ->type,
+                                                    publ->lower);
+                       else
+                               ret += tipc_snprintf(buf + ret, len - ret,
+                                                    " {%u,%u,%u}", publ->type,
+                                                    publ->lower, publ->upper);
+               }
+       }
+       ret += tipc_snprintf(buf + ret, len - ret, "\n");
+       return ret;
+}
+
+struct sk_buff *tipc_sk_socks_show(void)
+{
+       struct sk_buff *buf;
+       struct tlv_desc *rep_tlv;
+       char *pb;
+       int pb_len;
+       struct tipc_sock *tsk;
+       int str_len = 0;
+       u32 ref = 0;
+
+       buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
+       if (!buf)
+               return NULL;
+       rep_tlv = (struct tlv_desc *)buf->data;
+       pb = TLV_DATA(rep_tlv);
+       pb_len = ULTRA_STRING_MAX_LEN;
+
+       tsk = tipc_sk_get_next(&ref);
+       for (; tsk; tsk = tipc_sk_get_next(&ref)) {
+               lock_sock(&tsk->sk);
+               str_len += tipc_sk_show(tsk, pb + str_len,
+                                       pb_len - str_len, 0);
+               release_sock(&tsk->sk);
+               tipc_sk_put(tsk);
+       }
+       str_len += 1;   /* for "\0" */
+       skb_put(buf, TLV_SPACE(str_len));
+       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+       return buf;
+}
+
+/* tipc_sk_reinit: set non-zero address in all existing sockets
+ *                 when we go from standalone to network mode.
+ */
+void tipc_sk_reinit(void)
+{
+       struct tipc_msg *msg;
+       u32 ref = 0;
+       struct tipc_sock *tsk = tipc_sk_get_next(&ref);
+
+       for (; tsk; tsk = tipc_sk_get_next(&ref)) {
+               lock_sock(&tsk->sk);
+               msg = &tsk->phdr;
+               msg_set_prevnode(msg, tipc_own_addr);
+               msg_set_orignode(msg, tipc_own_addr);
+               release_sock(&tsk->sk);
+               tipc_sk_put(tsk);
+       }
+}
+
+/**
+ * struct reference - TIPC socket reference entry
+ * @tsk: pointer to socket associated with reference entry
+ * @ref: reference value for socket (combines instance & array index info)
+ */
+struct reference {
+       struct tipc_sock *tsk;
+       u32 ref;
+};
+
+/**
+ * struct tipc_ref_table - table of TIPC socket reference entries
+ * @entries: pointer to array of reference entries
+ * @capacity: array index of first unusable entry
+ * @init_point: array index of first uninitialized entry
+ * @first_free: array index of first unused socket reference entry
+ * @last_free: array index of last unused socket reference entry
+ * @index_mask: bitmask for array index portion of reference values
+ * @start_mask: initial value for instance value portion of reference values
+ */
+struct ref_table {
+       struct reference *entries;
+       u32 capacity;
+       u32 init_point;
+       u32 first_free;
+       u32 last_free;
+       u32 index_mask;
+       u32 start_mask;
+};
+
+/* Socket reference table consists of 2**N entries.
+ *
+ * State       Socket ptr      Reference
+ * -----        ----------      ---------
+ * In use        non-NULL       XXXX|own index
+ *                             (XXXX changes each time entry is acquired)
+ * Free            NULL         YYYY|next free index
+ *                             (YYYY is one more than last used XXXX)
+ * Uninitialized   NULL         0
+ *
+ * Entry 0 is not used; this allows index 0 to denote the end of the free list.
+ *
+ * Note that a reference value of 0 does not necessarily indicate that an
+ * entry is uninitialized, since the last entry in the free list could also
+ * have a reference value of 0 (although this is unlikely).
+ */
+
+static struct ref_table tipc_ref_table;
+
+static DEFINE_RWLOCK(ref_table_lock);
+
+/**
+ * tipc_ref_table_init - create reference table for sockets
+ */
+int tipc_sk_ref_table_init(u32 req_sz, u32 start)
+{
+       struct reference *table;
+       u32 actual_sz;
+
+       /* account for unused entry, then round up size to a power of 2 */
+
+       req_sz++;
+       for (actual_sz = 16; actual_sz < req_sz; actual_sz <<= 1) {
+               /* do nothing */
+       };
+
+       /* allocate table & mark all entries as uninitialized */
+       table = vzalloc(actual_sz * sizeof(struct reference));
+       if (table == NULL)
+               return -ENOMEM;
+
+       tipc_ref_table.entries = table;
+       tipc_ref_table.capacity = req_sz;
+       tipc_ref_table.init_point = 1;
+       tipc_ref_table.first_free = 0;
+       tipc_ref_table.last_free = 0;
+       tipc_ref_table.index_mask = actual_sz - 1;
+       tipc_ref_table.start_mask = start & ~tipc_ref_table.index_mask;
+
+       return 0;
+}
+
+/**
+ * tipc_ref_table_stop - destroy reference table for sockets
+ */
+void tipc_sk_ref_table_stop(void)
+{
+       if (!tipc_ref_table.entries)
+               return;
+       vfree(tipc_ref_table.entries);
+       tipc_ref_table.entries = NULL;
+}
+
+/* tipc_ref_acquire - create reference to a socket
+ *
+ * Register an socket pointer in the reference table.
+ * Returns a unique reference value that is used from then on to retrieve the
+ * socket pointer, or to determine if the socket has been deregistered.
+ */
+u32 tipc_sk_ref_acquire(struct tipc_sock *tsk)
+{
+       u32 index;
+       u32 index_mask;
+       u32 next_plus_upper;
+       u32 ref = 0;
+       struct reference *entry;
+
+       if (unlikely(!tsk)) {
+               pr_err("Attempt to acquire ref. to non-existent obj\n");
+               return 0;
+       }
+       if (unlikely(!tipc_ref_table.entries)) {
+               pr_err("Ref. table not found in acquisition attempt\n");
+               return 0;
+       }
+
+       /* Take a free entry, if available; otherwise initialize a new one */
+       write_lock_bh(&ref_table_lock);
+       index = tipc_ref_table.first_free;
+       entry = &tipc_ref_table.entries[index];
+
+       if (likely(index)) {
+               index = tipc_ref_table.first_free;
+               entry = &tipc_ref_table.entries[index];
+               index_mask = tipc_ref_table.index_mask;
+               next_plus_upper = entry->ref;
+               tipc_ref_table.first_free = next_plus_upper & index_mask;
+               ref = (next_plus_upper & ~index_mask) + index;
+               entry->tsk = tsk;
+       } else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
+               index = tipc_ref_table.init_point++;
+               entry = &tipc_ref_table.entries[index];
+               ref = tipc_ref_table.start_mask + index;
+       }
+
+       if (ref) {
+               entry->ref = ref;
+               entry->tsk = tsk;
+       }
+       write_unlock_bh(&ref_table_lock);
+       return ref;
+}
+
+/* tipc_sk_ref_discard - invalidate reference to an socket
+ *
+ * Disallow future references to an socket and free up the entry for re-use.
+ */
+void tipc_sk_ref_discard(u32 ref)
+{
+       struct reference *entry;
+       u32 index;
+       u32 index_mask;
+
+       if (unlikely(!tipc_ref_table.entries)) {
+               pr_err("Ref. table not found during discard attempt\n");
+               return;
+       }
+
+       index_mask = tipc_ref_table.index_mask;
+       index = ref & index_mask;
+       entry = &tipc_ref_table.entries[index];
+
+       write_lock_bh(&ref_table_lock);
+
+       if (unlikely(!entry->tsk)) {
+               pr_err("Attempt to discard ref. to non-existent socket\n");
+               goto exit;
+       }
+       if (unlikely(entry->ref != ref)) {
+               pr_err("Attempt to discard non-existent reference\n");
+               goto exit;
+       }
+
+       /* Mark entry as unused; increment instance part of entry's
+        *   reference to invalidate any subsequent references
+        */
+
+       entry->tsk = NULL;
+       entry->ref = (ref & ~index_mask) + (index_mask + 1);
+
+       /* Append entry to free entry list */
+       if (unlikely(tipc_ref_table.first_free == 0))
+               tipc_ref_table.first_free = index;
+       else
+               tipc_ref_table.entries[tipc_ref_table.last_free].ref |= index;
+       tipc_ref_table.last_free = index;
+exit:
+       write_unlock_bh(&ref_table_lock);
+}
+
+/* tipc_sk_get - find referenced socket and return pointer to it
+ */
+struct tipc_sock *tipc_sk_get(u32 ref)
+{
+       struct reference *entry;
+       struct tipc_sock *tsk;
+
+       if (unlikely(!tipc_ref_table.entries))
+               return NULL;
+       read_lock_bh(&ref_table_lock);
+       entry = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask];
+       tsk = entry->tsk;
+       if (likely(tsk && (entry->ref == ref)))
+               sock_hold(&tsk->sk);
+       else
+               tsk = NULL;
+       read_unlock_bh(&ref_table_lock);
+       return tsk;
+}
+
+/* tipc_sk_get_next - lock & return next socket after referenced one
+*/
+struct tipc_sock *tipc_sk_get_next(u32 *ref)
+{
+       struct reference *entry;
+       struct tipc_sock *tsk = NULL;
+       uint index = *ref & tipc_ref_table.index_mask;
+
+       read_lock_bh(&ref_table_lock);
+       while (++index < tipc_ref_table.capacity) {
+               entry = &tipc_ref_table.entries[index];
+               if (!entry->tsk)
+                       continue;
+               tsk = entry->tsk;
+               sock_hold(&tsk->sk);
+               *ref = entry->ref;
+               break;
+       }
+       read_unlock_bh(&ref_table_lock);
+       return tsk;
+}
+
+static void tipc_sk_put(struct tipc_sock *tsk)
+{
+       sock_put(&tsk->sk);
+}
+
 /**
  * tipc_setsockopt - set socket option
  * @sock: socket structure
@@ -1955,7 +2553,6 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        u32 value;
        int res;
 
@@ -1973,16 +2570,16 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
 
        switch (opt) {
        case TIPC_IMPORTANCE:
-               res = tipc_port_set_importance(port, value);
+               res = tsk_set_importance(tsk, value);
                break;
        case TIPC_SRC_DROPPABLE:
                if (sock->type != SOCK_STREAM)
-                       tipc_port_set_unreliable(port, value);
+                       tsk_set_unreliable(tsk, value);
                else
                        res = -ENOPROTOOPT;
                break;
        case TIPC_DEST_DROPPABLE:
-               tipc_port_set_unreturnable(port, value);
+               tsk_set_unreturnable(tsk, value);
                break;
        case TIPC_CONN_TIMEOUT:
                tipc_sk(sk)->conn_timeout = value;
@@ -2015,7 +2612,6 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        int len;
        u32 value;
        int res;
@@ -2032,16 +2628,16 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt,
 
        switch (opt) {
        case TIPC_IMPORTANCE:
-               value = tipc_port_importance(port);
+               value = tsk_importance(tsk);
                break;
        case TIPC_SRC_DROPPABLE:
-               value = tipc_port_unreliable(port);
+               value = tsk_unreliable(tsk);
                break;
        case TIPC_DEST_DROPPABLE:
-               value = tipc_port_unreturnable(port);
+               value = tsk_unreturnable(tsk);
                break;
        case TIPC_CONN_TIMEOUT:
-               value = tipc_sk(sk)->conn_timeout;
+               value = tsk->conn_timeout;
                /* no need to set "res", since already 0 at this point */
                break;
        case TIPC_NODE_RECVQ_DEPTH:
index 43b75b3cecedb9b3bee4fd6a9a42a8f5a4cbcf0b..baa43d03901e5b093238bf4a92b01135c109d5a2 100644 (file)
 #ifndef _TIPC_SOCK_H
 #define _TIPC_SOCK_H
 
-#include "port.h"
 #include <net/sock.h>
 
-#define TIPC_CONN_OK      0
-#define TIPC_CONN_PROBING 1
-
-/**
- * struct tipc_sock - TIPC socket structure
- * @sk: socket - interacts with 'port' and with user via the socket API
- * @port: port - interacts with 'sk' and with the rest of the TIPC stack
- * @peer_name: the peer of the connection, if any
- * @conn_timeout: the time we can wait for an unresponded setup request
- * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue
- * @link_cong: non-zero if owner must sleep because of link congestion
- * @sent_unacked: # messages sent by socket, and not yet acked by peer
- * @rcv_unacked: # messages read by user, but not yet acked back to peer
- */
-
-struct tipc_sock {
-       struct sock sk;
-       struct tipc_port port;
-       unsigned int conn_timeout;
-       atomic_t dupl_rcvcnt;
-       int link_cong;
-       uint sent_unacked;
-       uint rcv_unacked;
-};
-
-static inline struct tipc_sock *tipc_sk(const struct sock *sk)
-{
-       return container_of(sk, struct tipc_sock, sk);
-}
-
-static inline struct tipc_sock *tipc_port_to_sock(const struct tipc_port *port)
-{
-       return container_of(port, struct tipc_sock, port);
-}
-
-static inline void tipc_sock_wakeup(struct tipc_sock *tsk)
-{
-       tsk->sk.sk_write_space(&tsk->sk);
-}
-
-static inline int tipc_sk_conn_cong(struct tipc_sock *tsk)
-{
-       return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN;
-}
-
+#define TIPC_CONNACK_INTV         256
+#define TIPC_FLOWCTRL_WIN        (TIPC_CONNACK_INTV * 2)
+#define TIPC_CONN_OVERLOAD_LIMIT ((TIPC_FLOWCTRL_WIN * 2 + 1) * \
+                                 SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
 int tipc_sk_rcv(struct sk_buff *buf);
-
+struct sk_buff *tipc_sk_socks_show(void);
 void tipc_sk_mcast_rcv(struct sk_buff *buf);
+void tipc_sk_reinit(void);
+int tipc_sk_ref_table_init(u32 requested_size, u32 start);
+void tipc_sk_ref_table_stop(void);
 
 #endif
index 642437231ad5d2da2e7c9de5bd4494b082f3472e..31b5cb232a4371e3728ed9e7b934c3560f9ed92c 100644 (file)
@@ -36,7 +36,6 @@
 
 #include "core.h"
 #include "name_table.h"
-#include "port.h"
 #include "subscr.h"
 
 /**
index f3fef93325a8977c0e22ffe8cb0fd9a2302cff0e..1a779b1e85100b501c1f0cde29cbfaa0d98fb4eb 100644 (file)
@@ -47,6 +47,13 @@ static struct ctl_table tipc_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
+       {
+               .procname       = "named_timeout",
+               .data           = &sysctl_tipc_named_timeout,
+               .maxlen         = sizeof(sysctl_tipc_named_timeout),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
        {}
 };