Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
diff --git a/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt b/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
new file mode 100644
index 0000000..ab0bb42
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
@@ -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
index 0000000..30d4875
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/broadcom-sf2.txt
@@ -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
index 0000000..9e33177
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/m_can.txt
@@ -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
index 0000000..002d844
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/rcar_can.txt
@@ -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";
+};
diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt
index 49f4f7a..a62c889 100644
--- a/Documentation/devicetree/bindings/net/dsa/dsa.txt
+++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt
@@ -39,6 +39,22 @@
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 @@
port@0 {
reg = <0>;
label = "lan1";
+ phy-handle = <&phy0>;
};
port@1 {
diff --git a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt
index 2a60cd3..3a9d679 100644
--- a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt
+++ b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt
@@ -12,6 +12,10 @@
- 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 {
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 29a9351..db2383c 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -65,6 +65,12 @@
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 @@
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 @@
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
diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt
index 897f942..412f45c 100644
--- a/Documentation/networking/timestamping.txt
+++ b/Documentation/networking/timestamping.txt
@@ -1,102 +1,307 @@
-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.
+
+
+1.3.1 Timestamp Generation
+
+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.
+
+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. 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:
+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 systime if available
-SOF_TIMESTAMPING_SYS_HARDWARE: report hwtimetrans if available (deprecated)
-SOF_TIMESTAMPING_RAW_HARDWARE: report hwtimeraw if available
+SOF_TIMESTAMPING_SOFTWARE:
+ Report any software timestamps when available.
-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.
+SOF_TIMESTAMPING_SYS_HARDWARE:
+ This option is deprecated and ignored.
-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_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.
+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].
-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.
+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.
-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.
+2.1.1 Transmit timestamps with MSG_ERRQUEUE
-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.
+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.
-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.
+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.
-SIOCSHWTSTAMP, SIOCGHWTSTAMP:
+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 @@
*/
};
-
-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
diff --git a/Documentation/networking/timestamping/Makefile b/Documentation/networking/timestamping/Makefile
index d934afc..95e239c 100644
--- a/Documentation/networking/timestamping/Makefile
+++ b/Documentation/networking/timestamping/Makefile
@@ -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
index 0000000..b32fc2a
--- /dev/null
+++ b/Documentation/networking/timestamping/txtimestamp.c
@@ -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;
+}
diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
index 9a0319a..04892b8 100644
--- a/Documentation/sysctl/net.txt
+++ b/Documentation/sysctl/net.txt
@@ -241,6 +241,9 @@
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 @@
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.
diff --git a/MAINTAINERS b/MAINTAINERS
index 5e7866a..fd86604 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7378,7 +7378,7 @@
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/
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index a37b989..a76623b 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -930,5 +930,6 @@
{
if (fp->jited)
module_free(NULL, fp->bpf_func);
- kfree(fp);
+
+ bpf_prog_unlock_free(fp);
}
diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c
index 05a5661..cfa83cf 100644
--- a/arch/mips/net/bpf_jit.c
+++ b/arch/mips/net/bpf_jit.c
@@ -1427,5 +1427,6 @@
{
if (fp->jited)
module_free(NULL, fp->bpf_func);
- kfree(fp);
+
+ bpf_prog_unlock_free(fp);
}
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index 3afa6f4..40c53ff 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -697,5 +697,6 @@
{
if (fp->jited)
module_free(NULL, fp->bpf_func);
- kfree(fp);
+
+ bpf_prog_unlock_free(fp);
}
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 61e45b7..f2833c5 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -887,5 +887,5 @@
module_free(NULL, header);
free_filter:
- kfree(fp);
+ bpf_prog_unlock_free(fp);
}
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c
index 1f76c22..f7a736b 100644
--- a/arch/sparc/net/bpf_jit_comp.c
+++ b/arch/sparc/net/bpf_jit_comp.c
@@ -812,5 +812,6 @@
{
if (fp->jited)
module_free(NULL, fp->bpf_func);
- kfree(fp);
+
+ bpf_prog_unlock_free(fp);
}
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 5c8cb80..39ccfbb 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -515,6 +515,48 @@
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 @@
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);
}
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index b7ae0a0..aecec6d 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -2365,7 +2365,7 @@
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);
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index d0a41cb..00d4077 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -751,7 +751,7 @@
/* 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);
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index a4f05c5..87f7dff 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -1454,66 +1454,63 @@
#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;
}
- dsp->tx_R = t;
- goto send_packet;
+ 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;
+ }
}
-#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) {
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 95dd1f5..73c21e2 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1388,7 +1388,7 @@
}
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);
}
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index d163e11..e1489d9 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -96,6 +96,10 @@
[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 @@
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 @@
.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,
};
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index dc73463..d8dc17f 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -625,6 +625,8 @@
out:
if (ret)
bond_opt_error_interpret(bond, opt, ret, val);
+ else
+ call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev);
return ret;
}
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 4168822..e78d6b3 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -143,6 +143,8 @@
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"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 1697f22..fc93041 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -17,6 +17,7 @@
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_RCAR) += rcar_can.o
obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/c_can/Makefile b/drivers/net/can/c_can/Makefile
index ad1cc84..9fdc678 100644
--- a/drivers/net/can/c_can/Makefile
+++ b/drivers/net/can/c_can/Makefile
@@ -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
diff --git a/drivers/net/can/cc770/Makefile b/drivers/net/can/cc770/Makefile
index 9fb8321..8657f87 100644
--- a/drivers/net/can/cc770/Makefile
+++ b/drivers/net/can/cc770/Makefile
@@ -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
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index 9f91fcb..02492d2 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -103,11 +103,11 @@
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 @@
}
best_tseg = tseg / 2;
best_brp = brp;
- best_rate = rate;
if (error == 0)
break;
}
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 944aa5d..2700865 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -92,6 +92,27 @@
#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)
@@ -150,18 +171,20 @@
* 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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
flexcan_write(0x0, ®s->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(®s->crl2);
+ reg_crl2 |= FLEXCAN_CRL2_ECRWRE;
+ flexcan_write(reg_crl2, ®s->crl2);
+
+ reg_mecr = flexcan_read(®s->mecr);
+ reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
+ flexcan_write(reg_mecr, ®s->mecr);
+ reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK |
+ FLEXCAN_MECR_FANCEI_MSK);
+ flexcan_write(reg_mecr, ®s->mecr);
+ }
+
err = flexcan_transceiver_enable(priv);
if (err)
goto out_chip_disable;
@@ -1089,6 +1173,7 @@
{ .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
index 0000000..fca5482
--- /dev/null
+++ b/drivers/net/can/m_can/Kconfig
@@ -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
index 0000000..8bbd7f2
--- /dev/null
+++ b/drivers/net/can/m_can/Makefile
@@ -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
index 0000000..10d571e
--- /dev/null
+++ b/drivers/net/can/m_can/m_can.c
@@ -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");
diff --git a/drivers/net/can/mscan/Makefile b/drivers/net/can/mscan/Makefile
index c9fab17..58903b4 100644
--- a/drivers/net/can/mscan/Makefile
+++ b/drivers/net/can/mscan/Makefile
@@ -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
diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c
index 5268d21..1abe133 100644
--- a/drivers/net/can/rcar_can.c
+++ b/drivers/net/can/rcar_can.c
@@ -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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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,
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index 531d5fc..be11ddd 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -12,5 +12,3 @@
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
diff --git a/drivers/net/can/softing/Makefile b/drivers/net/can/softing/Makefile
index c5e5016..a23da49 100644
--- a/drivers/net/can/softing/Makefile
+++ b/drivers/net/can/softing/Makefile
@@ -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
diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
index 90bcacf..0e86040 100644
--- a/drivers/net/can/spi/Makefile
+++ b/drivers/net/can/spi/Makefile
@@ -4,5 +4,3 @@
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index 5df239e..c66d699 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1107,10 +1107,10 @@
* 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 @@
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 @@
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))
diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
index 7b9a393..a64cf98 100644
--- a/drivers/net/can/usb/Makefile
+++ b/drivers/net/can/usb/Makefile
@@ -8,5 +8,3 @@
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
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index b8fe808..c6ee07c 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -36,4 +36,15 @@
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
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index f3bda05..dd3cd3b 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -7,3 +7,4 @@
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
index 0000000..bb7cb8e
--- /dev/null
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -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
index 0000000..260bab3
--- /dev/null
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -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
index 0000000..885c231
--- /dev/null
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -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 */
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
index cc25a3a..caade30 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -271,7 +271,6 @@
#define DMA_PBL_X8_DISABLE 0x00
#define DMA_PBL_X8_ENABLE 0x01
-
/* MAC register offsets */
#define MAC_TCR 0x0000
#define MAC_RCR 0x0004
@@ -792,7 +791,6 @@
#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
@@ -815,7 +813,6 @@
#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.
@@ -825,7 +822,6 @@
*/
#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
@@ -929,7 +925,6 @@
#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 @@
((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 @@
_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 @@
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 @@
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 @@
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 @@
#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
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c b/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
index 7d6a49b..8a50b01 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
@@ -120,7 +120,6 @@
#include "xgbe.h"
#include "xgbe-common.h"
-
static int xgbe_dcb_ieee_getets(struct net_device *netdev,
struct ieee_ets *ets)
{
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
index a3c1135..76479d0 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
@@ -121,7 +121,6 @@
#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)
{
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
index 1c5d62e..6fc5da0 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
@@ -117,7 +117,6 @@
#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 @@
/* 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)) {
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index ea27383..9da3a03 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -122,7 +122,6 @@
#include "xgbe.h"
#include "xgbe-common.h"
-
static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata,
unsigned int usec)
{
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index b26d758..2955499 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -126,7 +126,6 @@
#include "xgbe.h"
#include "xgbe-common.h"
-
static int xgbe_poll(struct napi_struct *, int);
static void xgbe_set_rx_mode(struct net_device *);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
index 46f6130..49508ec 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
@@ -121,7 +121,6 @@
#include "xgbe.h"
#include "xgbe-common.h"
-
struct xgbe_stats {
char stat_string[ETH_GSTRING_LEN];
int stat_size;
@@ -173,6 +172,7 @@
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)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index bdf9cfa..f5a8fa0 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -128,7 +128,6 @@
#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);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
index 6d2221e..363b210 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -123,7 +123,6 @@
#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;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
index 37e64cf..a1bf9d1c 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
@@ -122,7 +122,6 @@
#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,
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index e9fe6e6..789957d 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -128,7 +128,6 @@
#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"
@@ -199,7 +198,6 @@
((_ring)->rdata + \
((_idx) & ((_ring)->rdesc_count - 1)))
-
/* Default coalescing parameters */
#define XGMAC_INIT_DMA_TX_USECS 50
#define XGMAC_INIT_DMA_TX_FRAMES 25
diff --git a/drivers/net/ethernet/arc/Kconfig b/drivers/net/ethernet/arc/Kconfig
index 514c57f..89e04fd 100644
--- a/drivers/net/ethernet/arc/Kconfig
+++ b/drivers/net/ethernet/arc/Kconfig
@@ -17,10 +17,14 @@
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---
diff --git a/drivers/net/ethernet/arc/Makefile b/drivers/net/ethernet/arc/Makefile
index 00c8657..241bb80 100644
--- a/drivers/net/ethernet/arc/Makefile
+++ b/drivers/net/ethernet/arc/Makefile
@@ -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
diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
index 36cc9bd..eb2ba67 100644
--- a/drivers/net/ethernet/arc/emac.h
+++ b/drivers/net/ethernet/arc/emac.h
@@ -124,6 +124,8 @@
*/
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 @@
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
index 0000000..f9cb99b
--- /dev/null
+++ b/drivers/net/ethernet/arc/emac_arc.c
@@ -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");
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index fe5cfea..a777392 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -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 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 @@
#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 @@
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 @@
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 @@
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_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 @@
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");
diff --git a/drivers/net/ethernet/arc/emac_mdio.c b/drivers/net/ethernet/arc/emac_mdio.c
index 26ba242..d5ee986 100644
--- a/drivers/net/ethernet/arc/emac_mdio.c
+++ b/drivers/net/ethernet/arc/emac_mdio.c
@@ -100,7 +100,6 @@
/**
* 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 @@
*
* 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 @@
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);
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index d8d07a8..c3e260c 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -122,6 +122,7 @@
config BNX2X
tristate "Broadcom NetXtremeII 10Gb support"
depends on PCI
+ select PTP_1588_CLOCK
select FW_LOADER
select ZLIB_INFLATE
select LIBCRC32C
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 6f4e186..662cf22 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -139,6 +139,15 @@
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 @@
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,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index d777fae..86e9451 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -20,13 +20,17 @@
#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 @@
#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 @@
#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 @@
#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 @@
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 @@
#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 */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 4ccc806..6dc32ae 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -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 @@
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 @@
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 @@
__set_bit(BNX2X_RSS_IPV4_UDP, ¶ms.rss_flags);
if (rss_obj->udp_rss_v6)
__set_bit(BNX2X_RSS_IPV6_UDP, ¶ms.rss_flags);
+
+ if (!CHIP_IS_E1x(bp))
+ /* valid only for TUNN_MODE_GRE tunnel mode */
+ __set_bit(BNX2X_RSS_GRE_INNER_HDRS, ¶ms.rss_flags);
} else {
__set_bit(BNX2X_RSS_MODE_DISABLED, ¶ms.rss_flags);
}
@@ -2800,7 +2810,11 @@
/* 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 @@
}
#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(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 @@
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 @@
(__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 @@
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 @@
*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 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 @@
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 @@
/* 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 @@
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 @@
&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 @@
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 @@
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 @@
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;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 571427c..ac63e16 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -932,8 +932,9 @@
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);
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index fb26bc4..6e4294e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -2092,7 +2092,6 @@
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 @@
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;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
index 12eb4ba..741aa13 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
@@ -40,7 +40,7 @@
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 @@
{ 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 @@
{ 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 @@
{ 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 @@
{ 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 @@
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,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index 92fee84..0b173ed2 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -3481,6 +3481,46 @@
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 @@
.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 = {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
index 95dc365..7636e3c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
@@ -10,170 +10,170 @@
#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))
-#define CSTORM_STATUS_BLOCK_DATA_STATE_OFFSET(sbId) \
- (IRO[134].base + ((sbId) * IRO[134].m1))
-#define CSTORM_STATUS_BLOCK_DATA_TIMEOUT_OFFSET(sbId, hcIndex) \
- (IRO[135].base + ((sbId) * IRO[135].m1) + ((hcIndex) * IRO[135].m2))
-#define CSTORM_STATUS_BLOCK_OFFSET(sbId) \
- (IRO[132].base + ((sbId) * IRO[132].m1))
-#define CSTORM_STATUS_BLOCK_SIZE (IRO[132].size)
-#define CSTORM_SYNC_BLOCK_OFFSET(sbId) \
(IRO[137].base + ((sbId) * IRO[137].m1))
-#define CSTORM_SYNC_BLOCK_SIZE (IRO[137].size)
+#define CSTORM_STATUS_BLOCK_DATA_STATE_OFFSET(sbId) \
+ (IRO[138].base + ((sbId) * IRO[138].m1))
+#define CSTORM_STATUS_BLOCK_DATA_TIMEOUT_OFFSET(sbId, hcIndex) \
+ (IRO[139].base + ((sbId) * IRO[139].m1) + ((hcIndex) * IRO[139].m2))
+#define CSTORM_STATUS_BLOCK_OFFSET(sbId) \
+ (IRO[136].base + ((sbId) * IRO[136].m1))
+#define CSTORM_STATUS_BLOCK_SIZE (IRO[136].size)
+#define CSTORM_SYNC_BLOCK_OFFSET(sbId) \
+ (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))
-#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \
- (IRO[273].base + ((pfId) * IRO[273].m1))
-#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \
- (IRO[274].base + ((pfId) * IRO[274].m1))
-#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \
- (IRO[275].base + ((pfId) * IRO[275].m1))
-#define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
- (IRO[271].base + ((pfId) * IRO[271].m1))
-#define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
- (IRO[270].base + ((pfId) * IRO[270].m1))
-#define TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
- (IRO[269].base + ((pfId) * IRO[269].m1))
-#define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
- (IRO[268].base + ((pfId) * IRO[268].m1))
-#define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \
(IRO[278].base + ((pfId) * IRO[278].m1))
-#define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
- (IRO[264].base + ((pfId) * IRO[264].m1))
-#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
- (IRO[265].base + ((pfId) * IRO[265].m1))
-#define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \
- (IRO[266].base + ((pfId) * IRO[266].m1))
-#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
- (IRO[267].base + ((pfId) * IRO[267].m1))
-#define TSTORM_MAC_FILTER_CONFIG_OFFSET(pfId) \
- (IRO[202].base + ((pfId) * IRO[202].m1))
-#define TSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
- (IRO[105].base + ((funcId) * IRO[105].m1))
-#define TSTORM_TCP_MAX_CWND_OFFSET(pfId) \
- (IRO[217].base + ((pfId) * IRO[217].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)
-#define USTORM_ASSERT_LIST_OFFSET(assertListEntry) \
- (IRO[176].base + ((assertListEntry) * IRO[176].m1))
-#define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \
- (IRO[183].base + ((portId) * IRO[183].m1))
-#define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \
- (IRO[319].base + ((pfId) * IRO[319].m1))
-#define USTORM_FUNC_EN_OFFSET(funcId) \
- (IRO[178].base + ((funcId) * IRO[178].m1))
-#define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
- (IRO[283].base + ((pfId) * IRO[283].m1))
-#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
- (IRO[284].base + ((pfId) * IRO[284].m1))
-#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
- (IRO[288].base + ((pfId) * IRO[288].m1))
-#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \
- (IRO[285].base + ((pfId) * IRO[285].m1))
-#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
- (IRO[281].base + ((pfId) * IRO[281].m1))
-#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
- (IRO[280].base + ((pfId) * IRO[280].m1))
-#define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
+#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \
(IRO[279].base + ((pfId) * IRO[279].m1))
-#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
- (IRO[282].base + ((pfId) * IRO[282].m1))
-#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \
- (IRO[286].base + ((pfId) * IRO[286].m1))
-#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
+#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \
+ (IRO[280].base + ((pfId) * IRO[280].m1))
+#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \
+ (IRO[281].base + ((pfId) * IRO[281].m1))
+#define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
+ (IRO[277].base + ((pfId) * IRO[277].m1))
+#define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
+ (IRO[276].base + ((pfId) * IRO[276].m1))
+#define TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
+ (IRO[275].base + ((pfId) * IRO[275].m1))
+#define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
+ (IRO[274].base + ((pfId) * IRO[274].m1))
+#define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \
+ (IRO[284].base + ((pfId) * IRO[284].m1))
+#define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
+ (IRO[270].base + ((pfId) * IRO[270].m1))
+#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
+ (IRO[271].base + ((pfId) * IRO[271].m1))
+#define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \
+ (IRO[272].base + ((pfId) * IRO[272].m1))
+#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
+ (IRO[273].base + ((pfId) * IRO[273].m1))
+#define TSTORM_MAC_FILTER_CONFIG_OFFSET(pfId) \
+ (IRO[206].base + ((pfId) * IRO[206].m1))
+#define TSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
+ (IRO[109].base + ((funcId) * IRO[109].m1))
+#define TSTORM_TCP_MAX_CWND_OFFSET(pfId) \
+ (IRO[223].base + ((pfId) * IRO[223].m1))
+#define TSTORM_VF_TO_PF_OFFSET(funcId) \
+ (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[180].base + ((assertListEntry) * IRO[180].m1))
+#define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \
+ (IRO[187].base + ((portId) * IRO[187].m1))
+#define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \
+ (IRO[325].base + ((pfId) * IRO[325].m1))
+#define USTORM_FUNC_EN_OFFSET(funcId) \
+ (IRO[182].base + ((funcId) * IRO[182].m1))
+#define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
+ (IRO[289].base + ((pfId) * IRO[289].m1))
+#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
+ (IRO[290].base + ((pfId) * IRO[290].m1))
+#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
+ (IRO[294].base + ((pfId) * IRO[294].m1))
+#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \
+ (IRO[291].base + ((pfId) * IRO[291].m1))
+#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
(IRO[287].base + ((pfId) * IRO[287].m1))
+#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
+ (IRO[286].base + ((pfId) * IRO[286].m1))
+#define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
+ (IRO[285].base + ((pfId) * IRO[285].m1))
+#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
+ (IRO[288].base + ((pfId) * IRO[288].m1))
+#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \
+ (IRO[292].base + ((pfId) * IRO[292].m1))
+#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
+ (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)
@@ -186,39 +186,39 @@
#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))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \
- (IRO[299].base + ((pfId) * IRO[299].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \
- (IRO[300].base + ((pfId) * IRO[300].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \
- (IRO[301].base + ((pfId) * IRO[301].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \
(IRO[302].base + ((pfId) * IRO[302].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \
- (IRO[303].base + ((pfId) * IRO[303].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \
- (IRO[304].base + ((pfId) * IRO[304].m1))
-#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \
(IRO[305].base + ((pfId) * IRO[305].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \
+ (IRO[306].base + ((pfId) * IRO[306].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \
+ (IRO[307].base + ((pfId) * IRO[307].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \
+ (IRO[308].base + ((pfId) * IRO[308].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \
+ (IRO[309].base + ((pfId) * IRO[309].m1))
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \
+ (IRO[310].base + ((pfId) * IRO[310].m1))
+#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \
+ (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) \
@@ -231,16 +231,19 @@
#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
@@ -356,6 +359,7 @@
#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 ****/
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index c4daa06..3e0621a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -2881,8 +2881,8 @@
};
#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 @@
CLASSIFY_RULE_OPCODE_MAC,
CLASSIFY_RULE_OPCODE_VLAN,
CLASSIFY_RULE_OPCODE_PAIR,
+ CLASSIFY_RULE_OPCODE_VXLAN,
MAX_CLASSIFY_RULE
};
@@ -3480,7 +3481,8 @@
u8 func_id;
u8 cos;
u8 traffic_type;
- u32 reserved0;
+ u8 fp_hsi_ver;
+ u8 reserved0[3];
};
@@ -3550,7 +3552,9 @@
__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 @@
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 @@
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 @@
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
@@ -3724,12 +3735,25 @@
};
/*
+ * 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
*/
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 @@
#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_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 @@
/* 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 @@
*/
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 @@
/* 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 @@
__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 @@
__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 @@
#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 @@
#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 @@
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 @@
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 @@
#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 @@
* 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 @@
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 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];
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index d1c093d..32e2444 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -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 @@
* 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 @@
* 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 @@
}
unlock:
+
spin_unlock_bh(&bp->dmae_lock);
+
return rc;
}
@@ -646,119 +651,98 @@
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;
+ 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"
+ };
- /* 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);
+ 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++) {
+ /* 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);
- 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;
+ /* 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;
+ }
}
}
- /* 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;
- }
- }
-
- /* 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;
- }
- }
-
- /* 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 @@
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 @@
/* 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 @@
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 @@
/* 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 @@
else
value = 0;
- DP(NETIF_MSG_LINK, "pin %d value 0x%x\n", gpio_num, value);
-
return value;
}
@@ -4678,7 +4689,7 @@
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 @@
_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 @@
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 @@
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 @@
}
/* 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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
bp->dump_preset_idx = 1;
+ if (CHIP_IS_E3B0(bp))
+ bp->flags |= PTP_SUPPORTED;
+
return rc;
}
@@ -12308,13 +12383,17 @@
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 @@
}
}
+/* 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 @@
"Unknown",
dev->base_addr, bp->pdev->irq, dev->dev_addr);
+ bnx2x_register_phc(bp);
+
return 0;
init_one_exit:
@@ -13155,6 +13421,11 @@
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 @@
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");
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
index 2beb543..b0779d7 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
@@ -2182,6 +2182,45 @@
#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 */
@@ -2194,6 +2233,17 @@
* 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
@@ -2300,7 +2350,46 @@
* 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
@@ -2342,6 +2431,17 @@
* 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
@@ -2361,6 +2461,78 @@
#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
@@ -2513,6 +2685,10 @@
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 */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index b193604..19d0c11 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -4019,6 +4019,7 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
data->tx_switching_change_flg =
test_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
¶ms->update_flags);
+
+ /* PTP */
+ data->handle_ptp_pkts_flg =
+ test_bit(BNX2X_Q_UPDATE_PTP_PKTS, ¶ms->update_flags);
+ data->handle_ptp_pkts_change_flg =
+ test_bit(BNX2X_Q_UPDATE_PTP_PKTS_CHNG, ¶ms->update_flags);
}
static inline int bnx2x_q_send_update(struct bnx2x *bp,
@@ -5376,6 +5385,10 @@
(!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 @@
(!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 @@
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 @@
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 @@
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 =
+ ¶ms->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 @@
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;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index 718ecd2..21c8f6f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
@@ -711,6 +711,7 @@
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 @@
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 @@
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 @@
#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 @@
};
/********************** 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 @@
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 @@
/* 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 @@
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 @@
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_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;
};
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 662310c..c88b20a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -1125,7 +1125,7 @@
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 @@
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 @@
}
/* 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 @@
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 @@
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 @@
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 @@
/* 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 @@
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_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 @@
}
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;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index ca1055f..01bafa4 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -299,7 +299,8 @@
#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 */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index ca47665..d160829 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -137,7 +137,7 @@
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 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 @@
cnt--;
usleep_range(1000, 2000);
}
- return 1;
}
/*
@@ -1630,6 +1629,11 @@
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;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
index 54e0427..b1d9c44 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -583,7 +583,6 @@
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 @@
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)
{
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index a6a9f28..23f23c9 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -383,7 +383,7 @@
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 @@
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 @@
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);
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index 962510f..5ba5ad0 100644
--- a/drivers/net/ethernet/cisco/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h
@@ -186,6 +186,7 @@
____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)
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
index 523c9ce..85173d6 100644
--- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -379,6 +379,43 @@
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 @@
.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)
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index c8832bc..929bfe7 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
dev_err(dev, "Cannot register net device, aborting\n");
goto err_out_dev_deinit;
}
+ enic->rx_copybreak = RX_COPYBREAK_DEFAULT;
return 0;
diff --git a/drivers/net/ethernet/dec/tulip/dmfe.c b/drivers/net/ethernet/dec/tulip/dmfe.c
index 322213d..c820560 100644
--- a/drivers/net/ethernet/dec/tulip/dmfe.c
+++ b/drivers/net/ethernet/dec/tulip/dmfe.c
@@ -328,10 +328,10 @@
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 @@
/* 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 @@
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 @@
*/
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
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 @@
/* 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 @@
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 @@
* 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 @@
/* 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 @@
* 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 @@
/* 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 @@
* 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 @@
* 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 @@
/* 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 @@
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 @@
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 @@
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 @@
/* 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 */
diff --git a/drivers/net/ethernet/ec_bhf.c b/drivers/net/ethernet/ec_bhf.c
index 056b44b..d101750 100644
--- a/drivers/net/ethernet/ec_bhf.c
+++ b/drivers/net/ethernet/ec_bhf.c
@@ -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 ec_bhf_priv {
struct net_device *net_dev;
-
struct pci_dev *dev;
void __iomem *io;
@@ -162,32 +160,6 @@
#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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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;
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 43e08d0..a9f239a 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -86,6 +86,8 @@
#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 @@
#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 @@
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 @@
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_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 @@
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 @@
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)
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 4370ec1..5be100d 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -1681,17 +1681,17 @@
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 @@
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 @@
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 @@
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 @@
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);
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 5284b82..0e11868 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -2101,7 +2101,7 @@
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,
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 0cd3311..2fd3826 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -78,6 +78,11 @@
* 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 @@
* 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_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 */
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index 8840c64..295ee08 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -315,6 +315,18 @@
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
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 93ff8ef..5b26c4c 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -738,38 +738,37 @@
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 @@
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 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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
*/
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 @@
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 @@
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 @@
{
#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 @@
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 @@
&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 @@
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 @@
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;
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index cca5bca..9b50272 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -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 @@
#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 @@
"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 @@
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 @@
}
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 @@
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 @@
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 @@
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 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 @@
* 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 @@
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 @@
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 @@
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 @@
/* Test each interrupt */
for (; i < 10; i++) {
-
/* Interrupt to test */
mask = 1 << i;
@@ -1149,8 +1145,7 @@
*/
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 @@
*/
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 @@
/* 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 @@
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 @@
* attempt this 10 times.
*/
while (e1000_nonintegrated_phy_loopback(adapter) &&
- count++ < 10);
+ count++ < 10);
if (count < 11)
return 0;
}
@@ -1348,8 +1342,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
*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 @@
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 @@
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_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 @@
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 @@
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++) {
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 801da39..f1e33f8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -144,6 +144,8 @@
__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 @@
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 @@
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 @@
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,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
index b29c157..72f5d25 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
@@ -840,7 +840,8 @@
/* 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_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 @@
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
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index df43e7c..30056b2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -75,13 +75,15 @@
* @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 @@
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 @@
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;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index 5a0cabe..7067f4b 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -1356,6 +1356,9 @@
"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 =
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index e8ba747..1dda467 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -145,6 +145,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 +
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index eddec6b..ed5f1c1 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -37,9 +37,9 @@
#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 @@
* 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 @@
/* 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 @@
{
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 @@
}
}
- 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 @@
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 @@
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 @@
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 @@
{
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 @@
}
}
+#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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
.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 @@
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 @@
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);
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index 949a9a0..0988b5c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -52,10 +52,8 @@
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);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 369848e..be039dd 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -224,15 +224,19 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 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 @@
* 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 @@
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 @@
}
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->csum_level = ipv4_tunnel || ipv6_tunnel;
return;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 73f4fa4..d7a625a 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -121,6 +121,7 @@
/* 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)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index 3ac6a0d..4eeed26 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -73,7 +73,7 @@
{
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
*
* 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;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
index 63e7e0d..0adc61e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -122,7 +122,7 @@
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);
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c
index 0030060..f206be9 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c
@@ -788,7 +788,8 @@
/* 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_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 @@
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
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c
index 4ea90bf..9525605 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c
@@ -75,13 +75,15 @@
* @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 @@
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) {
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
index 849edcc..9173834 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
@@ -53,10 +53,8 @@
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);
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
index 95a3ec2..04c7c15 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -163,11 +163,13 @@
* 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 @@
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 @@
}
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->csum_level = ipv4_tunnel || ipv6_tunnel;
return;
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
index 8bc6858..f6dcf9d 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
@@ -121,6 +121,7 @@
/* 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)
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index 38429fa..c51bc7a 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -36,7 +36,7 @@
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.";
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index 236a618..051ea94 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -2548,11 +2548,13 @@
/**
* 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 @@
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 @@
/**
* 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 @@
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);
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index b407c55..2154aea 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -263,8 +263,8 @@
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
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index c737d1f..02cfd3b 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2675,6 +2675,7 @@
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 @@
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 @@
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 @@
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;
}
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index cb14bbd..6cf0c17 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2012,10 +2012,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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:
@@ -6768,113 +6769,6 @@
}
/**
- * 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
* @rx_desc: pointer to the EOP Rx descriptor
@@ -6918,7 +6812,7 @@
/* 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)));
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index 2d9451e..ae36fd6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -1086,6 +1086,11 @@
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 @@
/* 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;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 87bd53f..166dc00 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1521,120 +1521,6 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
{
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",
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index c14d4d8..706fc69 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -250,13 +250,15 @@
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;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index e6b07c2..dfd55d8 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -2194,6 +2194,8 @@
#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 @@
#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,
diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c
index 4d44d64..9cddd56 100644
--- a/drivers/net/ethernet/intel/ixgbevf/vf.c
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.c
@@ -434,6 +434,21 @@
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;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 9c909d2..14686b6f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -588,6 +588,8 @@
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 @@
}
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 @@
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 @@
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,
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index dae3da6..bc8f51c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -319,7 +319,7 @@
}
}
}
- dev_kfree_skb_any(skb);
+ dev_consume_skb_any(skb);
return tx_info->nr_txbb;
}
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 925b296..f39cae6 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -1481,7 +1481,7 @@
}
/* 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));
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index b84f5ea..e56c1bb 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -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 @@
u8 lb_mode;
u16 vxlan_port;
struct device *hwmon_dev;
+ u32 post_mode;
+ bool run_post;
};
struct qlcnic_adapter_stats {
@@ -2283,6 +2285,7 @@
#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 @@
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;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 476e499..840bf36 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -35,6 +35,35 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index 2bf101a..f3346a3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -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 @@
#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)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index 86783e1..9a2cfe4 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -2075,6 +2075,121 @@
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 @@
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 @@
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 @@
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);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 851cb4a8..8102673 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -341,7 +341,7 @@
}
return -EIO;
}
- msleep(1);
+ usleep_range(1000, 1500);
}
if (id_reg)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index c4262c2..be41e4c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -537,7 +537,7 @@
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 @@
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 @@
rc = qlcnic_validate_firmware(adapter);
if (rc != 0) {
release_firmware(adapter->fw);
- msleep(1);
+ usleep_range(1000, 1500);
goto next;
}
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index e45bf09..18e5de7 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -1753,7 +1753,7 @@
if (qlcnic_encap_length(sts_data[1]) &&
skb->ip_summed == CHECKSUM_UNNECESSARY) {
- skb->encapsulation = 1;
+ skb->csum_level = 1;
adapter->stats.encap_rx_csummed++;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index cf08b2d..f5e29f7 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -52,7 +52,7 @@
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 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),
@@ -228,6 +229,11 @@
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,
0x203,
@@ -1131,6 +1137,7 @@
*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 @@
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;
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 91652e7..02dd92a 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -52,6 +52,10 @@
#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 @@
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 @@
[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 @@
#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 @@
#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 @@
#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 @@
/* 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_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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
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_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 @@
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);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index ec632e6..ddc6115 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -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>
@@ -30,6 +31,12 @@
#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 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 @@
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 @@
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 @@
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 @@
.setup = socfpga_dwmac_probe,
.init = socfpga_dwmac_init,
.exit = socfpga_dwmac_exit,
+ .fix_mac_speed = socfpga_dwmac_fix_mac_speed,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index cf4f38d..3a08a1f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -261,11 +261,11 @@
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 @@
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;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 6e6ee22..9dbb02d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -834,7 +834,7 @@
/* 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);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index a5b1e1b..8dd0408 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -253,7 +253,7 @@
}
/*
- * 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.
*/
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index f7415b6..fef5dec 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -115,7 +115,7 @@
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 @@
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 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 @@
/* 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 @@
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 @@
/* 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 @@
/* 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
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 999fb72..03b4099 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -2232,18 +2232,24 @@
}
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;
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index d5e07de..2f48f79 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -591,7 +591,7 @@
#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 @@
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;
};
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 66979cf..977984bc 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -42,6 +42,12 @@
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 @@
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 @@
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 @@
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 @@
vmbus_close(device->channel);
cleanup:
- kfree(net_device);
+ free_netvsc_device(net_device);
return ret;
}
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 65de0ca..14afa4f2 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -159,8 +159,6 @@
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 @@
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
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 7dc3d5b..eb3b18b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -34,3 +34,4 @@
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
diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c
index f3230ee..c456559 100644
--- a/drivers/net/phy/amd-xgbe-phy.c
+++ b/drivers/net/phy/amd-xgbe-phy.c
@@ -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 @@
#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 @@
#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 @@
#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 @@
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 @@
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 @@
/* 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 @@
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 @@
amd_xgbe_phy_serdes_complete_ratechange(phydev);
- priv->mode = AMD_XGBE_MODE_KR;
-
return 0;
}
@@ -518,8 +523,6 @@
amd_xgbe_phy_serdes_complete_ratechange(phydev);
- priv->mode = AMD_XGBE_MODE_KX;
-
return 0;
}
@@ -568,18 +571,43 @@
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 @@
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 @@
*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_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 @@
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 @@
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 @@
/* 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 @@
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_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 @@
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 @@
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 @@
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 @@
{
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 @@
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 @@
{
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 @@
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 @@
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);
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index fdce1ea..09dd6e1 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -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 @@
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 @@
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 @@
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 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, },
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 34088d6..854f2c9 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -25,132 +25,10 @@
#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)
{
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index c301e4c..87648b3 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -721,7 +721,7 @@
}
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 @@
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 @@
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 @@
}
}
- return parsed * sizeof(u16);
+ return parsed;
}
static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
@@ -905,9 +912,9 @@
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 @@
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 @@
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 @@
case HWTSTAMP_TX_OFF:
default:
- skb_complete_tx_timestamp(skb, NULL);
+ kfree_skb(skb);
break;
}
}
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index d60d875..5b19fbb 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -124,6 +124,17 @@
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
index 0000000..5b643e5
--- /dev/null
+++ b/drivers/net/phy/mdio-bcm-unimac.c
@@ -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");
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 4eaadcf..50051f2 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -553,8 +553,14 @@
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);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index a854d38..1dfffdc 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -955,7 +955,7 @@
* 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 @@
}
return value;
}
+EXPORT_SYMBOL(phy_read_mmd_indirect);
/**
* phy_write_mmd_indirect - writes data to the MMD registers
@@ -988,7 +989,7 @@
* 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 @@
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 @@
{
/* 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;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ca5ec3e..3fc91e8 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -230,13 +230,13 @@
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;
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index ae7cd7f..92578d72 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -47,22 +47,22 @@
{ 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 @@
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 @@
{
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 @@
{
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 @@
{
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 @@
{
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 @@
{
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 @@
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_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 @@
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 @@
* 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_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 @@
/* 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 @@
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 @@
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 @@
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 @@
}
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 @@
{
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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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++)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index ef10302..2277c36 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1003,7 +1003,6 @@
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 @@
return 0;
err_port_enter:
- port->dev->priv_flags &= ~IFF_TEAM_PORT;
dev_put(team->dev);
return err;
@@ -1026,7 +1024,6 @@
{
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 @@
}
#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 @@
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 @@
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 @@
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 @@
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);
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 87f7104..f95e678 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -424,7 +424,7 @@
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 @@
* 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 @@
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 @@
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 @@
}
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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
}
}
-/*
- * 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 @@
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 @@
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 @@
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 @@
/* 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 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 @@
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 @@
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 @@
{
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 @@
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 @@
} 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 @@
{
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));
}
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 59caa06..9359a13d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -934,7 +934,6 @@
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 @@
}
}
+ if (__netif_subqueue_stopped(dev, qnum) || !skb->xmit_more)
+ virtqueue_kick(sq->vq);
+
return NETDEV_TX_OK;
}
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index beb377b..53c3ec1 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1158,8 +1158,6 @@
if (!vs)
goto drop;
- skb_pop_rcv_encapsulation(skb);
-
vs->rcv(vs, skb, vxh->vx_vni);
return 0;
@@ -2372,6 +2370,8 @@
/* Disable multicast loopback */
inet_sk(sock->sk)->mc_loop = 0;
+ udp_set_convert_csum(sock->sk, true);
+
return sock;
}
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 43c9960..ae6ecf4 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -192,8 +192,10 @@
{
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;
}
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index bcdc882..146f48c 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1101,7 +1101,15 @@
/* 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;
}
}
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index 61219b9..5bd35cc 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -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
@@ -92,4 +94,130 @@
#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
index 362bf19..0000000
--- a/include/linux/cycx_x25.h
+++ /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 */
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 9c5529d..733980f 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -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;
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index e658229..c1a2d60 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -257,6 +257,10 @@
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 *);
};
diff --git a/include/linux/filter.h b/include/linux/filter.h
index a5227ab..c789945 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -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_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 @@
#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 @@
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_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
index afac5c7..0000000
--- a/include/linux/i82593.h
+++ /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 */
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index f47550d..2c677af 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -39,6 +39,7 @@
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;
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 511c6e0..1befd8d 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -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 @@
/* 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 */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c8e388e..ba72f6b 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1747,6 +1747,12 @@
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 @@
#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 @@
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 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 @@
#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_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_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 @@
#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
index 4269de9..0000000
--- a/include/linux/phonedev.h
+++ /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
diff --git a/include/linux/phy.h b/include/linux/phy.h
index ed39956..d090cfc 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -598,6 +598,19 @@
}
/**
+ * 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
* @regnum: register number to read
@@ -668,6 +681,20 @@
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);
diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h
index ae612ac..9411386 100644
--- a/include/linux/phy_fixed.h
+++ b/include/linux/phy_fixed.h
@@ -18,6 +18,9 @@
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 @@
{
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 */
diff --git a/include/linux/random.h b/include/linux/random.h
index 57fbbff..b05856e 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -26,7 +26,7 @@
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 @@
};
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)
diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h
index 36826c0..fb298e9d 100644
--- a/include/linux/rhashtable.h
+++ b/include/linux/rhashtable.h
@@ -44,6 +44,7 @@
* @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 @@
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,
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index abde271..07c9fdd 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -47,11 +47,29 @@
*
* 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:
*
@@ -112,6 +130,9 @@
#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 @@
* @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 @@
__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 @@
__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 @@
__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 @@
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 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 @@
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 @@
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 @@
{
if (skb_csum_unnecessary(skb) || (zero_okay && !check)) {
skb->csum_valid = 1;
+ __skb_decr_checksum_unnecessary(skb);
return false;
}
@@ -2826,6 +2884,9 @@
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 @@
#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 @@
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
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index fa5258f..e567f0d 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -276,7 +276,7 @@
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 */
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 247cfdc..ee32775 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -49,7 +49,11 @@
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 @@
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)
diff --git a/include/net/codel.h b/include/net/codel.h
index fe0eab3..aeee280 100644
--- a/include/net/codel.h
+++ b/include/net/codel.h
@@ -66,7 +66,7 @@
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;
}
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6efce38..9771292 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -15,6 +15,14 @@
#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 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 @@
* 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_chip_data *chip;
};
+struct dsa_device_ops;
+
struct dsa_switch_tree {
/*
* Configuration data for the platform device that owns
@@ -71,6 +88,7 @@
* protocol to use.
*/
struct net_device *master_netdev;
+ const struct dsa_device_ops *ops;
__be16 tag_protocol;
/*
@@ -119,6 +137,7 @@
*/
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];
};
@@ -170,6 +189,14 @@
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.
*/
void (*get_strings)(struct dsa_switch *ds, int port, uint8_t *data);
@@ -186,21 +213,9 @@
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)
+static inline bool dsa_uses_tagged_protocol(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)
-{
- return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
+ return dst->tag_protocol != 0;
}
#endif
diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h
index 6667a05..7ee2df0 100644
--- a/include/net/flow_keys.h
+++ b/include/net/flow_keys.h
@@ -27,7 +27,19 @@
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
diff --git a/include/net/ip.h b/include/net/ip.h
index db4a771..c8fd611 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -364,6 +364,14 @@
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.
*/
diff --git a/include/net/ip6_checksum.h b/include/net/ip6_checksum.h
index 55236cb..1a49b73 100644
--- a/include/net/ip6_checksum.h
+++ b/include/net/ip6_checksum.h
@@ -48,6 +48,14 @@
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,
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 9922093..dc9d2a2 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -65,7 +65,8 @@
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 @@
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;
};
/*
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index a2db816..7e247e9 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -121,6 +121,7 @@
/* sysctls */
extern int sysctl_mld_max_msf;
+extern int sysctl_mld_qrv;
#define _DEVINC(net, statname, modifier, idev, field) \
({ \
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index ec030cd..8bbe626 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -50,7 +50,7 @@
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
diff --git a/include/net/sock.h b/include/net/sock.h
index b9a5bd0..049ab1b 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1574,7 +1574,12 @@
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 @@
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
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 590e01a..a4201ef 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -672,6 +672,12 @@
*/
#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 @@
} 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. */
diff --git a/include/net/udp.h b/include/net/udp.h
index 70f9413..16f4e80 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -158,6 +158,24 @@
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
index 30d48f6..0000000
--- a/include/rxrpc/types.h
+++ /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 */
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index e3c7a71..7a364f2 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -209,6 +209,32 @@
__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 @@
#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
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index 0f8210b..aa63ed0 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -128,6 +128,7 @@
#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.
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 7f0dbcb..b54bb2c 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -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 @@
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 @@
/* 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);
diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
index c766ee5..b64e238 100644
--- a/kernel/crash_dump.c
+++ b/kernel/crash_dump.c
@@ -18,6 +18,7 @@
* 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
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 44eb005..84922be 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -395,16 +395,15 @@
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 @@
return filter;
free_filter_prog:
- kfree(filter->prog);
+ __bpf_prog_free(filter->prog);
free_filter:
kfree(filter);
free_prog:
diff --git a/lib/random32.c b/lib/random32.c
index c9b6bf3..0bee183 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -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 @@
* 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;
+ u8 *ptr = buf;
- for (i = 0; i < round_down(bytes, sizeof(u32)); i += sizeof(u32)) {
- u32 random = prandom_u32_state(state);
- int j;
-
- 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 @@
* @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 @@
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 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 @@
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);
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index a2c7881..8dfec3f 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -298,7 +298,7 @@
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 @@
}
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 @@
(!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)
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index 89e0345..9a67456 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -1342,6 +1342,44 @@
{ { 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 = {
BPF_ALU64_REG(BPF_MOV, R6, R1),
@@ -1798,7 +1836,7 @@
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;
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index e8e0e7a..0e98222 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -599,7 +599,7 @@
}
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)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 7751c92..648d79c 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1822,7 +1822,7 @@
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);
}
diff --git a/net/core/dev.c b/net/core/dev.c
index ab9a165..3c6a967 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2485,52 +2485,6 @@
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 @@
}
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;
- int rc = NETDEV_TX_OK;
- unsigned int skb_len;
+ unsigned int len;
+ int rc;
- if (likely(!skb->next)) {
- netdev_features_t features;
+ if (!list_empty(&ptype_all))
+ dev_queue_xmit_nit(skb, dev);
- /*
- * 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);
+ 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);
- features = netif_skb_features(skb);
-
- 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;
-
- skb->vlan_tci = 0;
- }
-
- /* 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;
-
- 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 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 (!list_empty(&ptype_all))
- dev_queue_xmit_nit(skb, dev);
-
- 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;
- }
-
-gso:
- do {
- struct sk_buff *nskb = skb->next;
-
- skb->next = nskb->next;
- nskb->next = NULL;
-
- 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;
- }
- 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;
- }
-out_kfree_skb:
- kfree_skb(skb);
-out:
return rc;
}
-EXPORT_SYMBOL_GPL(dev_hard_start_xmit);
+
+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;
+
+ while (skb) {
+ struct sk_buff *next = skb->next;
+
+ skb->next = NULL;
+ rc = xmit_one(skb, dev, txq, next != NULL);
+ if (unlikely(!dev_xmit_complete(rc))) {
+ skb->next = next;
+ goto out;
+ }
+
+ skb = next;
+ if (netif_xmit_stopped(txq) && skb) {
+ rc = NETDEV_TX_BUSY;
+ break;
+ }
+ }
+
+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;
+}
+
+struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
+{
+ netdev_features_t features;
+
+ if (skb->next)
+ return 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);
+
+ features = netif_skb_features(skb);
+ skb = validate_xmit_vlan(skb, features);
+ if (unlikely(!skb))
+ goto out_null;
+
+ /* 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;
+
+ if (netif_needs_gso(skb, features)) {
+ struct sk_buff *segs;
+
+ 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 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;
+ }
+ }
+
+ return skb;
+
+out_kfree_skb:
+ kfree_skb(skb);
+out_null:
+ return NULL;
+}
static void qdisc_pkt_len_init(struct sk_buff *skb)
{
@@ -2785,7 +2745,8 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
}
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.
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index cf999e0..72e899a 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -365,11 +365,8 @@
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);
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 17cb912..27e61b8 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -1621,6 +1621,80 @@
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 @@
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 @@
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;
}
diff --git a/net/core/filter.c b/net/core/filter.c
index d814b8a..fa5b7d0 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -113,7 +113,7 @@
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 @@
/* 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 @@
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 @@
if (fprog->filter == NULL)
return -EINVAL;
- prog = kmalloc(bpf_fsize, GFP_KERNEL);
+ prog = bpf_prog_alloc(bpf_fsize, 0);
if (!prog)
return -ENOMEM;
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 5f362c1..8560dea 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -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 @@
}
/**
- * 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 @@
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 @@
__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 @@
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 @@
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 @@
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 @@
return false;
}
}
+ case htons(ETH_P_FCOE):
+ flow->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
+ /* fall through */
default:
return false;
}
@@ -151,7 +187,7 @@
__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 @@
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 @@
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 @@
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;
+ u32 poff = keys->thoff;
- if (!skb_flow_dissect(skb, &keys))
- return 0;
-
- 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 @@
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 @@
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;
}
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 907fb5e..e6645b4 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -72,7 +72,6 @@
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 @@
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 @@
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());
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 8b849dd..21cb483 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -202,6 +202,7 @@
#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 @@
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 @@
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 @@
"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 @@
pgh->pgh_magic = htonl(PKTGEN_MAGIC);
pgh->seq_num = htonl(pkt_dev->seq_num);
- do_gettimeofday(×tamp);
- 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(×tamp);
+ 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_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 @@
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 @@
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++;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index f0493e3..a688268 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1481,9 +1481,12 @@
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 @@
put_net(net);
if (err)
goto errout;
- modified = 1;
+ status |= DO_SETLINK_MODIFIED;
}
if (tb[IFLA_MAP]) {
@@ -1531,7 +1534,7 @@
if (err < 0)
goto errout;
- modified = 1;
+ status |= DO_SETLINK_NOTIFY;
}
if (tb[IFLA_ADDRESS]) {
@@ -1551,19 +1554,19 @@
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 @@
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 @@
nla_len(tb[IFLA_IFALIAS]));
if (err < 0)
goto errout;
- modified = 1;
+ status |= DO_SETLINK_NOTIFY;
}
if (tb[IFLA_BROADCAST]) {
@@ -1601,25 +1604,35 @@
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 @@
err = do_setvfinfo(dev, attr);
if (err < 0)
goto errout;
- modified = 1;
+ status |= DO_SETLINK_NOTIFY;
}
}
err = 0;
@@ -1664,7 +1677,7 @@
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 @@
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 @@
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 @@
}
if (dev) {
- int modified = 0;
+ int status = 0;
if (nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
@@ -2004,7 +2022,7 @@
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 @@
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)) {
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
index ba71212..51dd319 100644
--- a/net/core/secure_seq.c
+++ b/net/core/secure_seq.c
@@ -35,7 +35,7 @@
* 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 @@
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 @@
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;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index da1378a..a18dfb0 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3491,32 +3491,53 @@
}
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 @@
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,
diff --git a/net/core/sock.c b/net/core/sock.c
index d372b4b..6f436b5 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -437,7 +437,6 @@
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 @@
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 @@
}
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 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 @@
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:
diff --git a/net/core/timestamping.c b/net/core/timestamping.c
index a877039..43d3dd6 100644
--- a/net/core/timestamping.c
+++ b/net/core/timestamping.c
@@ -36,10 +36,9 @@
{
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 @@
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;
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index ae011b4..25733d5 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -127,6 +127,7 @@
#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 @@
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;
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 3b726f3..4400da7 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -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 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... */
diff --git a/net/decnet/dn_timer.c b/net/decnet/dn_timer.c
index d9c150c..1d330fd 100644
--- a/net/decnet/dn_timer.c
+++ b/net/decnet/dn_timer.c
@@ -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 @@
* 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);
}
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index f5eede1..a585fd6 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -12,6 +12,9 @@
if NET_DSA
# tagging formats
+config NET_DSA_TAG_BRCM
+ bool
+
config NET_DSA_TAG_DSA
bool
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 7b9fcbb..da06ed1 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -3,6 +3,7 @@
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
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 0a49632..61f145c 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -144,6 +144,11 @@
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 @@
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 @@
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 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 @@
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);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index d4cf5cc..98afed4 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -33,6 +33,10 @@
* 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 @@
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
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 45a1e34..7333a4a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -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 @@
{
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 @@
{
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 @@
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 @@
.get_sset_count = dsa_slave_get_sset_count,
};
-#ifdef CONFIG_NET_DSA_TAG_DSA
-static const struct net_device_ops dsa_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 = dsa_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_EDSA
-static const struct net_device_ops edsa_netdev_ops = {
- .ndo_init = dsa_slave_init,
- .ndo_open = dsa_slave_open,
- .ndo_stop = dsa_slave_close,
- .ndo_start_xmit = edsa_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
-#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,
-};
-#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 @@
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 = ¬ag_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
index 0000000..e0b759e
--- /dev/null
+++ b/net/dsa/tag_brcm.c
@@ -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,
+};
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index cacce1e..d7dbc5b 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -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 @@
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,
};
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index e70c43c..6b30abe 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -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 @@
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,
};
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index 94bc260..5fe9444 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -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 @@
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,
};
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index f405e05..33a140e 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -146,6 +146,33 @@
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
* @dev: receiving network device
@@ -181,11 +208,8 @@
* 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;
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 255aa99..23104a3 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -243,7 +243,7 @@
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 @@
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 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;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index b10cd43a..5b6efb3 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -157,9 +157,12 @@
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 @@
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);
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c
index 0485bf7..7e0756d 100644
--- a/net/ipv4/gre_demux.c
+++ b/net/ipv4/gre_demux.c
@@ -125,6 +125,10 @@
*csum_err = true;
return -EINVAL;
}
+
+ skb_checksum_try_convert(skb, IPPROTO_GRE, 0,
+ null_compute_pseudo);
+
options++;
}
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
index 6556263..d3fe2ac 100644
--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -119,28 +119,6 @@
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 @@
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) {
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index f10eab4..4146153 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -117,7 +117,7 @@
#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 @@
{
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 @@
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 @@
}
/* 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 @@
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 @@
(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 @@
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 @@
*/
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 @@
#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 @@
/* 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 @@
#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 @@
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);
}
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 43116e8..9111a4e 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -229,7 +229,7 @@
}
} 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);
}
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 5cb830c..455e75b 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -405,7 +405,7 @@
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 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 @@
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:
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 5bbef4f..648fa14 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -262,7 +262,8 @@
/* 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)
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 2510c02..e90f83a 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -285,7 +285,7 @@
}
/* 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
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index eaa4b00..234a43e 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -596,12 +596,12 @@
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 @@
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 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;
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index c0c7568..0431a8f 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -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)
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 79a007c..45d156d 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -450,6 +450,16 @@
.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,
diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c
index d5de69b..bb395d4 100644
--- a/net/ipv4/tcp_bic.c
+++ b/net/ipv4/tcp_bic.c
@@ -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_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 @@
/* 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 @@
bictcp_update(ca, tp->snd_cwnd);
tcp_cong_avoid_ai(tp, ca->cnt);
}
-
}
/*
@@ -177,7 +174,6 @@
ca->loss_cwnd = tp->snd_cwnd;
-
if (tp->snd_cwnd <= low_window)
return max(tp->snd_cwnd >> 1U, 2U);
else
@@ -188,6 +184,7 @@
{
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 @@
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,
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 7b09d8b..80248f5 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -142,7 +142,6 @@
}
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 @@
offs += snprintf(buf + offs, maxlen - offs,
"%s%s",
offs == 0 ? "" : " ", ca->name);
-
}
rcu_read_unlock();
}
@@ -186,7 +184,6 @@
offs += snprintf(buf + offs, maxlen - offs,
"%s%s",
offs == 0 ? "" : " ", ca->name);
-
}
rcu_read_unlock();
}
@@ -230,7 +227,6 @@
return ret;
}
-
/* Change congestion control for socket */
int tcp_set_congestion_control(struct sock *sk, const char *name)
{
@@ -337,6 +333,7 @@
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);
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index a9bd8a4..20de011 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -82,12 +82,13 @@
/* 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 @@
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 @@
/* 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 @@
/* 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 @@
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 @@
* 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 */
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index ed3f2ad..0d73f9d 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -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_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);
}
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
index 1c49082..882c08a 100644
--- a/net/ipv4/tcp_highspeed.c
+++ b/net/ipv4/tcp_highspeed.c
@@ -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 @@
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)
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
index 0313613..58469ff 100644
--- a/net/ipv4/tcp_htcp.c
+++ b/net/ipv4/tcp_htcp.c
@@ -98,7 +98,8 @@
}
}
-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 @@
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 @@
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;
diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c
index d8f8f05..f963b27 100644
--- a/net/ipv4/tcp_hybla.c
+++ b/net/ipv4/tcp_hybla.c
@@ -29,7 +29,6 @@
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)
{
diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c
index 5999b39..1d5a30a 100644
--- a/net/ipv4/tcp_illinois.c
+++ b/net/ipv4/tcp_illinois.c
@@ -284,7 +284,7 @@
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 @@
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)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index a906e02..f97003a 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1888,23 +1888,23 @@
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;
-}
-
-void tcp_clear_retrans(struct tcp_sock *tp)
-{
- tcp_clear_retrans_partial(tp);
-
tp->fackets_out = 0;
tp->sacked_out = 0;
}
+static inline void tcp_init_undo(struct tcp_sock *tp)
+{
+ 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
* and reset tags completely, otherwise preserve SACKs. If receiver
* dropped its ofo queue, we will know this due to reneging detection.
@@ -1925,18 +1925,18 @@
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 @@
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 @@
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 @@
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 @@
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 };
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index cd17f00..3f9bc3f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -90,7 +90,6 @@
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 @@
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 @@
.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 @@
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 @@
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);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 1649988..a058f41 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -232,7 +232,7 @@
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;
}
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index bc1b83c..7291253 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -288,35 +288,14 @@
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);
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 5a7c41f..7f1280d 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -550,7 +550,7 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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);
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 3b66610..ebf5ff57 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -83,7 +83,6 @@
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 @@
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 @@
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);
}
diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c
index 8250949..6824afb 100644
--- a/net/ipv4/tcp_scalable.c
+++ b/net/ipv4/tcp_scalable.c
@@ -31,10 +31,10 @@
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,
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index df90cd1..a339e7b 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -135,10 +135,9 @@
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);
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
index b40ad89..a6afde6 100644
--- a/net/ipv4/tcp_vegas.c
+++ b/net/ipv4/tcp_vegas.c
@@ -51,7 +51,6 @@
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 @@
void tcp_vegas_state(struct sock *sk, u8 ca_state)
{
-
if (ca_state == TCP_CA_Open)
vegas_enable(sk);
else
@@ -285,7 +283,6 @@
/* 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. */
diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c
index 8276977..a4d2d2d 100644
--- a/net/ipv4/tcp_veno.c
+++ b/net/ipv4/tcp_veno.c
@@ -175,7 +175,6 @@
} else
tp->snd_cwnd_cnt++;
}
-
}
if (tp->snd_cwnd < 2)
tp->snd_cwnd = 2;
diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c
index b94a04a..81911a9 100644
--- a/net/ipv4/tcp_westwood.c
+++ b/net/ipv4/tcp_westwood.c
@@ -42,7 +42,6 @@
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 @@
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 @@
return w->cumul_ack;
}
-
/*
* TCP Westwood
* Here limit is evaluated as Bw estimation*RTTmin (for obtaining it
@@ -219,6 +216,7 @@
{
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 @@
}
}
-
/* 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 struct tcp_congestion_ops tcp_westwood __read_mostly = {
.init = tcp_westwood_init,
.ssthresh = tcp_reno_ssthresh,
diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c
index 599b79b..cd72732 100644
--- a/net/ipv4/tcp_yeah.c
+++ b/net/ipv4/tcp_yeah.c
@@ -54,10 +54,8 @@
/* 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 @@
/* 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 @@
*/
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 @@
}
yeah->lastQ = queue;
-
}
/* Save the extent of the current window so we can use this
@@ -205,7 +201,8 @@
}
}
-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;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index f57c0e4..cd0db54 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -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 @@
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 @@
}
} 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 @@
}
} 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 @@
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 @@
return;
skb->sk = sk;
- skb->destructor = sock_edemux;
+ skb->destructor = sock_efree;
dst = sk->sk_rx_dst;
if (dst)
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 59035bc..84e0e05 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -228,30 +228,24 @@
}
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 @@
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 @@
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 @@
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,
},
};
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index fc1fac2..ad4598f 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -180,7 +180,7 @@
.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 @@
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 @@
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 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)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 2daa3a1..b9393e6 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -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
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 72a4930..fcffd4e 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -17,10 +17,10 @@
* 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 @@
ipv6_rearrange_rthdr(iph, exthdr.rth);
break;
- default :
+ default:
return 0;
}
@@ -478,7 +478,7 @@
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 @@
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 @@
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 @@
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,
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 2753319..2cdc383 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -43,13 +43,13 @@
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 @@
{
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 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 @@
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:
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index d15da13..83fc3a3 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -17,10 +17,10 @@
* 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 @@
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 @@
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,
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 8d67900..bfde361 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -142,7 +142,7 @@
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
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 06ba3e5..394bb82 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -503,7 +503,7 @@
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 @@
/* 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 @@
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 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)
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index a245e5d..29b3220 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -63,7 +63,6 @@
return sk2 != NULL;
}
-
EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
struct dst_entry *inet6_csk_route_req(struct sock *sk,
@@ -144,7 +143,6 @@
return NULL;
}
-
EXPORT_SYMBOL_GPL(inet6_csk_search_req);
void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
@@ -160,10 +158,9 @@
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 @@
sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
sk->sk_bound_dev_if);
}
-
EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
static inline
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 262e13c..051dffb 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -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 @@
}
} 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 @@
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 @@
return sk;
}
-
EXPORT_SYMBOL_GPL(inet6_lookup);
static int __inet6_check_established(struct inet_timewait_death_row *death_row,
@@ -324,5 +322,4 @@
return __inet_hash_connect(death_row, sk, inet6_sk_port_offset(sk),
__inet6_check_established, __inet6_hash);
}
-
EXPORT_SYMBOL_GPL(inet6_hash_connect);
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 4052694..3dd7d4e 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -136,7 +136,7 @@
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 @@
/* 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 @@
rcu_read_unlock_bh();
return NULL;
}
-
EXPORT_SYMBOL_GPL(fl6_sock_lookup);
void fl6_free_socklist(struct sock *sk)
@@ -293,11 +292,11 @@
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 @@
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 @@
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 @@
}
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))
diff --git a/net/ipv6/ip6_icmp.c b/net/ipv6/ip6_icmp.c
index 4578e23..14dacc5 100644
--- a/net/ipv6/ip6_icmp.c
+++ b/net/ipv6/ip6_icmp.c
@@ -13,7 +13,7 @@
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);
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 51d54dc..a3084ab 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -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 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);
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index 65eda2a..5bcda33 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -244,7 +244,7 @@
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
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 315a55d..b7a3e7b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -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 @@
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 @@
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 @@
}
__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 @@
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 @@
}
err = output(skb);
- if(!err)
+ if (!err)
IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
IPSTATS_MIB_FRAGCREATES);
@@ -742,7 +741,7 @@
/*
* 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 @@
/* 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 @@
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 @@
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);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index f9de5a6..e01bd03 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -408,12 +408,12 @@
{
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 @@
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 @@
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 @@
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 @@
} 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index f9a3fd3..0171f08 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -845,7 +845,7 @@
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 @@
* 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));
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index d1c793c..1b9316e 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -181,8 +181,7 @@
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 @@
.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,
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 0c28998..e1a9583 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -66,12 +66,12 @@
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 @@
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 @@
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 @@
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 @@
retv = -ENOBUFS;
break;
}
- gsf = kmalloc(optlen,GFP_KERNEL);
+ gsf = kmalloc(optlen, GFP_KERNEL);
if (!gsf) {
retv = -ENOBUFS;
break;
@@ -873,7 +873,6 @@
#endif
return err;
}
-
EXPORT_SYMBOL(ipv6_setsockopt);
#ifdef CONFIG_COMPAT
@@ -909,7 +908,6 @@
#endif
return err;
}
-
EXPORT_SYMBOL(compat_ipv6_setsockopt);
#endif
@@ -921,7 +919,7 @@
if (!opt)
return 0;
- switch(optname) {
+ switch (optname) {
case IPV6_HOPOPTS:
hdr = opt->hopopt;
break;
@@ -1284,9 +1282,9 @@
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 @@
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 @@
#endif
return err;
}
-
EXPORT_SYMBOL(ipv6_getsockopt);
#ifdef CONFIG_COMPAT
@@ -1364,7 +1361,6 @@
#endif
return err;
}
-
EXPORT_SYMBOL(compat_ipv6_getsockopt);
#endif
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index a23b655..6833dd0 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -121,6 +121,7 @@
#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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
* 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 @@
} 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 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
* 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 @@
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 @@
*/
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 @@
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 @@
}
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
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 @@
/* 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 @@
(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);
}
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index db9b6cb..f61429d 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -336,11 +336,10 @@
{
}
-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 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,
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 339078f..4cb45c1 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -175,7 +175,7 @@
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 @@
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 @@
}
return -EINVAL;
}
-
EXPORT_SYMBOL(ndisc_mc_map);
static u32 ndisc_hash(const void *pkey,
@@ -296,7 +295,7 @@
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 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 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 @@
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 @@
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 @@
__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) {
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index 5ec867e..fc24c39 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -35,7 +35,7 @@
if (found_rhdr)
return offset;
break;
- default :
+ default:
return offset;
}
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 2d6f860..1752cd0 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -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
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 39d4422..896af88 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -889,7 +889,7 @@
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 @@
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 @@
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 @@
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;
}
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index c6557d9..1a157ca2 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -62,13 +62,12 @@
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 @@
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 @@
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 @@
return -1;
}
-static const struct inet6_protocol frag_protocol =
-{
+static const struct inet6_protocol frag_protocol = {
.handler = ipv6_frag_rcv,
.flags = INET6_PROTO_NOPOLICY,
};
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f23fbd2..f74b041 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -813,7 +813,7 @@
}
-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 @@
return NULL;
}
-
EXPORT_SYMBOL(rt6_lookup);
/* ip6_ins_rt is called with FREE table->tb6_lock.
@@ -1024,7 +1023,7 @@
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 @@
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_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 @@
return NULL;
read_lock_bh(&table->tb6_lock);
- fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
+ fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0);
if (!fn)
goto out;
@@ -1983,7 +1981,7 @@
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 @@
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 @@
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 @@
return last_err;
}
-static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh)
+static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct fib6_config cfg;
int err;
@@ -2501,7 +2499,7 @@
return ip6_route_del(&cfg);
}
-static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh)
+static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct fib6_config cfg;
int err;
@@ -2693,7 +2691,7 @@
prefix, 0, NLM_F_MULTI);
}
-static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh)
+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];
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 6163f85..86e3fa8 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -812,9 +812,9 @@
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 @@
#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_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;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 83cea1d..c643dc907 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -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 [..]
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 0c56c93..c5c10fa 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -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 @@
.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
+ },
{ }
};
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 29964c3..5b3c70f 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -738,7 +738,7 @@
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 @@
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;
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c
index 01b0ff9..dbb3d92 100644
--- a/net/ipv6/tcpv6_offload.c
+++ b/net/ipv6/tcpv6_offload.c
@@ -35,34 +35,14 @@
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);
}
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c
index 2c4e4c5..3c75800 100644
--- a/net/ipv6/tunnel6.c
+++ b/net/ipv6/tunnel6.c
@@ -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 @@
return ret;
}
-
EXPORT_SYMBOL(xfrm6_tunnel_register);
int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
@@ -92,7 +91,6 @@
return ret;
}
-
EXPORT_SYMBOL(xfrm6_tunnel_deregister);
#define for_each_tunnel_rcu(head, handler) \
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 4836af8..f6ba535 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -243,7 +243,7 @@
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 @@
}
} 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 @@
/*
- * 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 @@
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 __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 @@
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 @@
}
/**
- * 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 @@
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);
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 0ae3d98..89cb9a9b 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -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 @@
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,
},
};
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index f8c3cf84..f48fbe4 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -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 @@
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 @@
drop:
return -1;
}
-
EXPORT_SYMBOL(xfrm6_input_addr);
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 433672d..ca3f29b 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -25,7 +25,6 @@
{
return ip6_find_1stfragopt(skb, prevhdr);
}
-
EXPORT_SYMBOL(xfrm6_find_1stfragopt);
static int xfrm6_local_dontfrag(struct sk_buff *skb)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 2a0bbda..ac49f84 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -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 @@
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_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 @@
.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 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,
},
{ }
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index 3fc9701..8a1f9c0 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -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 @@
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;
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 1c66465..5743044 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -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 @@
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 @@
return htonl(spi);
}
-
EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
static void x6spi_destroy_rcu(struct rcu_head *head)
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 1109d3b..2aa2b6c 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -148,7 +148,7 @@
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 @@
if (err < 0)
goto out;
+ udp_set_convert_csum(sock->sk, true);
+
break;
case L2TP_ENCAPTYPE_IP:
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index de88c4a..5016a69 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -142,7 +142,7 @@
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 @@
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;
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index f87e8f6..91a1837a 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -83,7 +83,8 @@
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 *
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 355a5c4..1bd9ed9 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1737,7 +1737,7 @@
}
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)
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index f641751..cf65a1e 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -101,7 +101,7 @@
{
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);
}
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 552f97c..4e0b478 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -126,7 +126,8 @@
/* 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 @@
}
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;
diff --git a/net/netfilter/xt_HMARK.c b/net/netfilter/xt_HMARK.c
index 73b73f6..02afaf4 100644
--- a/net/netfilter/xt_HMARK.c
+++ b/net/netfilter/xt_HMARK.c
@@ -126,7 +126,7 @@
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
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c
index f4af1bf..96fa26b 100644
--- a/net/netfilter/xt_cluster.c
+++ b/net/netfilter/xt_cluster.c
@@ -55,7 +55,8 @@
WARN_ON(1);
break;
}
- return (((u64)hash * info->total_nodes) >> 32);
+
+ return reciprocal_scale(hash, info->total_nodes);
}
static inline bool
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 47dc683..52eb3e0 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -135,7 +135,7 @@
* 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 *
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index d07ab538..7064da9 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -89,7 +89,7 @@
* 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;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 93896d2..87d20f4 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -240,11 +240,9 @@
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 @@
__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();
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
index bc55142..e873d7d 100644
--- a/net/rose/rose_link.c
+++ b/net/rose/rose_link.c
@@ -160,7 +160,8 @@
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:
diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c
index db57458..74c0fcd 100644
--- a/net/rxrpc/ar-error.c
+++ b/net/rxrpc/ar-error.c
@@ -37,7 +37,7 @@
_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 @@
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("");
}
diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c
index 63b21e5..481f89f 100644
--- a/net/rxrpc/ar-input.c
+++ b/net/rxrpc/ar-input.c
@@ -45,7 +45,7 @@
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 @@
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);
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 0566e46..f32bcb0 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -231,7 +231,7 @@
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 @@
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) {
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index ba32c2b..e12f997 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -416,7 +416,7 @@
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 @@
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,
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 063b726..cc56c8b 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -77,7 +77,8 @@
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,
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index fc04fe9..19696eb 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -63,15 +63,18 @@
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 @@
* 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 @@
}
/*
- * 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 @@
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 @@
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 @@
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 @@
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.
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 9f949ab..aea942c 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -895,7 +895,7 @@
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 @@
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 @@
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 */
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 18ff634..0c39b75 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -239,7 +239,7 @@
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 @@
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 @@
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;
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index bd33793..aaa8d03 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -301,7 +301,6 @@
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 @@
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);
diff --git a/net/sctp/input.c b/net/sctp/input.c
index c1b9912..b6493b3 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -133,9 +133,13 @@
__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));
diff --git a/net/tipc/Makefile b/net/tipc/Makefile
index a080c66..b8a13ca 100644
--- a/net/tipc/Makefile
+++ b/net/tipc/Makefile
@@ -7,7 +7,7 @@
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
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index dd13bfa0..b2bbe69 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -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 @@
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 @@
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);
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 2b42403..876f4c6 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -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 @@
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();
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 676d180..a5737b8 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -35,11 +35,10 @@
*/
#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 @@
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 @@
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_netlink:
tipc_nametbl_stop();
out_nametbl:
- tipc_ref_table_stop();
+ tipc_sk_ref_table_stop();
out_reftbl:
return err;
}
diff --git a/net/tipc/core.h b/net/tipc/core.h
index bb26ed1..f773b14 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -81,6 +81,7 @@
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 @@
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]))
diff --git a/net/tipc/link.c b/net/tipc/link.c
index fb1485d..65410e1 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -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 @@
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 @@
}
/**
- * 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;
+ struct sk_buff_head *wq = &link->waiting_sks;
+ struct sk_buff *buf;
+ uint pend_qsz = link->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)
+ 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 @@
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 @@
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 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 @@
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))) {
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 782983c..b567a34 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -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 @@
* @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 @@
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_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);
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 9680be6..74745a4 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -56,8 +56,35 @@
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 @@
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 @@
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 @@
*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 @@
rc = -ENOMEM;
goto error;
}
+ chain_sz++;
prev->next = buf;
msg_set_type(&pkthdr, FRAGMENT);
msg_set_size(&pkthdr, pktsz);
@@ -224,7 +254,7 @@
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:
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index 462fa19..0ea7b69 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -442,6 +442,7 @@
#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 @@
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);
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index dcc15bc..780ef71 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -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 @@
};
+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
*/
@@ -263,54 +278,104 @@
}
/**
+ * 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);
}
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
index 8afe32b..b9e75fe 100644
--- a/net/tipc/name_distr.h
+++ b/net/tipc/name_distr.h
@@ -73,5 +73,6 @@
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
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 9d7d37d..3a6a0a7 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -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 @@
/* 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 @@
/* 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 @@
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 @@
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);
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 7fcc949..93b9944 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -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 @@
tipc_own_addr = addr;
tipc_named_reinit();
- tipc_port_reinit();
+ tipc_sk_reinit();
res = tipc_bclink_init();
if (res)
return res;
diff --git a/net/tipc/node.c b/net/tipc/node.c
index f706929..17e6378 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -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_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 @@
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 @@
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 @@
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 @@
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 @@
}
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);
}
diff --git a/net/tipc/node.h b/net/tipc/node.h
index b61716a..522d6f3 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -58,7 +58,8 @@
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 @@
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_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
index 7e096a5..0000000
--- a/net/tipc/port.c
+++ /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
index 3087da3..0000000
--- a/net/tipc/port.h
+++ /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
index 3d4ecd7..0000000
--- a/net/tipc/ref.c
+++ /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
index d01aa1d..0000000
--- a/net/tipc/ref.h
+++ /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
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index ff8c811..75275c5 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -35,17 +35,67 @@
*/
#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 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 @@
* - 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 @@
}
}
+/* 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 @@
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 @@
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 @@
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 @@
{
struct sock *sk = sock->sk;
struct tipc_sock *tsk;
- struct tipc_port *port;
struct sk_buff *buf;
u32 dnode;
@@ -320,13 +465,13 @@
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 @@
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 @@
/* 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
{
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 @@
}
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 @@
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 @@
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;
+ struct tipc_msg *msg = &tsk->phdr;
- peer.ref = msg_origport(msg);
- peer.node = msg_orignode(msg);
+ 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);
- __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;
+ 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 @@
}
/**
- * 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 @@
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 @@
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 @@
{
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 @@
/* 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 @@
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 @@
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 @@
{
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 @@
/* 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 @@
/* 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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
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 @@
* 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 @@
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 @@
{
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 @@
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 @@
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 @@
{
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 @@
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 @@
{
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 @@
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:
diff --git a/net/tipc/socket.h b/net/tipc/socket.h
index 43b75b3..baa43d0 100644
--- a/net/tipc/socket.h
+++ b/net/tipc/socket.h
@@ -35,56 +35,17 @@
#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
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 6424372..31b5cb2 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -36,7 +36,6 @@
#include "core.h"
#include "name_table.h"
-#include "port.h"
#include "subscr.h"
/**
diff --git a/net/tipc/sysctl.c b/net/tipc/sysctl.c
index f3fef93..1a779b1 100644
--- a/net/tipc/sysctl.c
+++ b/net/tipc/sysctl.c
@@ -47,6 +47,13 @@
.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,
+ },
{}
};