Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next

Pull networking updates from David Miller:

 1) Unified UDP encapsulation offload methods for drivers, from
    Alexander Duyck.

 2) Make DSA binding more sane, from Andrew Lunn.

 3) Support QCA9888 chips in ath10k, from Anilkumar Kolli.

 4) Several workqueue usage cleanups, from Bhaktipriya Shridhar.

 5) Add XDP (eXpress Data Path), essentially running BPF programs on RX
    packets as soon as the device sees them, with the option to mirror
    the packet on TX via the same interface.  From Brenden Blanco and
    others.

 6) Allow qdisc/class stats dumps to run lockless, from Eric Dumazet.

 7) Add VLAN support to b53 and bcm_sf2, from Florian Fainelli.

 8) Simplify netlink conntrack entry layout, from Florian Westphal.

 9) Add ipv4 forwarding support to mlxsw spectrum driver, from Ido
    Schimmel, Yotam Gigi, and Jiri Pirko.

10) Add SKB array infrastructure and convert tun and macvtap over to it.
    From Michael S Tsirkin and Jason Wang.

11) Support qdisc packet injection in pktgen, from John Fastabend.

12) Add neighbour monitoring framework to TIPC, from Jon Paul Maloy.

13) Add NV congestion control support to TCP, from Lawrence Brakmo.

14) Add GSO support to SCTP, from Marcelo Ricardo Leitner.

15) Allow GRO and RPS to function on macsec devices, from Paolo Abeni.

16) Support MPLS over IPV4, from Simon Horman.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1622 commits)
  xgene: Fix build warning with ACPI disabled.
  be2net: perform temperature query in adapter regardless of its interface state
  l2tp: Correctly return -EBADF from pppol2tp_getname.
  net/mlx5_core/health: Remove deprecated create_singlethread_workqueue
  net: ipmr/ip6mr: update lastuse on entry change
  macsec: ensure rx_sa is set when validation is disabled
  tipc: dump monitor attributes
  tipc: add a function to get the bearer name
  tipc: get monitor threshold for the cluster
  tipc: make cluster size threshold for monitoring configurable
  tipc: introduce constants for tipc address validation
  net: neigh: disallow transition to NUD_STALE if lladdr is unchanged in neigh_update()
  MAINTAINERS: xgene: Add driver and documentation path
  Documentation: dtb: xgene: Add MDIO node
  dtb: xgene: Add MDIO node
  drivers: net: xgene: ethtool: Use phy_ethtool_gset and sset
  drivers: net: xgene: Use exported functions
  drivers: net: xgene: Enable MDIO driver
  drivers: net: xgene: Add backward compatibility
  drivers: net: phy: xgene: Add MDIO driver
  ...
This commit is contained in:
Linus Torvalds 2016-07-27 12:03:20 -07:00
commit 468fc7ed55
1390 changed files with 96178 additions and 37208 deletions

View File

@ -1,19 +1,10 @@
What: /sys/class/net/<iface>/batman-adv/throughput_override
Date: Feb 2014
Contact: Antonio Quartulli <antonio@meshcoding.com>
description:
Defines the throughput value to be used by B.A.T.M.A.N. V
when estimating the link throughput using this interface.
If the value is set to 0 then batman-adv will try to
estimate the throughput by itself.
What: /sys/class/net/<iface>/batman-adv/elp_interval
Date: Feb 2014
Contact: Linus Lüssing <linus.luessing@web.de>
Description:
Defines the interval in milliseconds in which batman
sends its probing packets for link quality measurements.
emits probing packets for neighbor sensing (ELP).
What: /sys/class/net/<iface>/batman-adv/iface_status
Date: May 2010
@ -28,3 +19,12 @@ Description:
The /sys/class/net/<iface>/batman-adv/mesh_iface file
displays the batman mesh interface this <iface>
currently is associated with.
What: /sys/class/net/<iface>/batman-adv/throughput_override
Date: Feb 2014
Contact: Antonio Quartulli <a@unstable.cc>
description:
Defines the throughput value to be used by B.A.T.M.A.N. V
when estimating the link throughput using this interface.
If the value is set to 0 then batman-adv will try to
estimate the throughput by itself.

View File

@ -136,6 +136,7 @@
!Finclude/net/cfg80211.h cfg80211_ibss_joined
!Finclude/net/cfg80211.h cfg80211_connect_result
!Finclude/net/cfg80211.h cfg80211_connect_bss
!Finclude/net/cfg80211.h cfg80211_connect_timeout
!Finclude/net/cfg80211.h cfg80211_roamed
!Finclude/net/cfg80211.h cfg80211_disconnected
!Finclude/net/cfg80211.h cfg80211_ready_on_channel

View File

@ -0,0 +1,37 @@
APM X-Gene SoC MDIO node
MDIO node is defined to describe on-chip MDIO controller.
Required properties:
- compatible: Must be "apm,xgene-mdio-rgmii" or "apm,xgene-mdio-xfi"
- #address-cells: Must be <1>.
- #size-cells: Must be <0>.
- reg: Address and length of the register set
- clocks: Reference to the clock entry
For the phys on the mdio bus, there must be a node with the following fields:
- compatible: PHY identifier. Please refer ./phy.txt for the format.
- reg: The ID number for the phy.
Example:
mdio: mdio@17020000 {
compatible = "apm,xgene-mdio-rgmii";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x17020000 0x0 0xd100>;
clocks = <&menetclk 0>;
};
/* Board-specific peripheral configurations */
&mdio {
menetphy: phy@3 {
reg = <0x3>;
};
sgenet0phy: phy@4 {
reg = <0x4>;
};
sgenet1phy: phy@5 {
reg = <0x5>;
};
};

View File

@ -0,0 +1,59 @@
Properties for an MDIO bus multiplexer found in Broadcom iProc based SoCs.
This MDIO bus multiplexer defines buses that could be internal as well as
external to SoCs and could accept MDIO transaction compatible to C-22 or
C-45 Clause. When child bus is selected, one needs to select these two
properties as well to generate desired MDIO transaction on appropriate bus.
Required properties in addition to the generic multiplexer properties:
MDIO multiplexer node:
- compatible: brcm,mdio-mux-iproc.
Every non-ethernet PHY requires a compatible so that it could be probed based
on this compatible string.
Additional information regarding generic multiplexer properties can be found
at- Documentation/devicetree/bindings/net/mdio-mux.txt
for example:
mdio_mux_iproc: mdio-mux@6602023c {
compatible = "brcm,mdio-mux-iproc";
reg = <0x6602023c 0x14>;
#address-cells = <1>;
#size-cells = <0>;
mdio@0 {
reg = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
pci_phy0: pci-phy@0 {
compatible = "brcm,ns2-pcie-phy";
reg = <0x0>;
#phy-cells = <0>;
};
};
mdio@7 {
reg = <0x7>;
#address-cells = <1>;
#size-cells = <0>;
pci_phy1: pci-phy@0 {
compatible = "brcm,ns2-pcie-phy";
reg = <0x0>;
#phy-cells = <0>;
};
};
mdio@10 {
reg = <0x10>;
#address-cells = <1>;
#size-cells = <0>;
gphy0: eth-phy@10 {
reg = <0x10>;
};
};
};

View File

@ -0,0 +1,96 @@
Renesas R-Car CAN FD controller Device Tree Bindings
----------------------------------------------------
Required properties:
- compatible: Must contain one or more of the following:
- "renesas,rcar-gen3-canfd" for R-Car Gen3 compatible controller.
- "renesas,r8a7795-canfd" for R8A7795 (R-Car H3) compatible controller.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first, followed by the
family-specific and/or generic versions.
- reg: physical base address and size of the R-Car CAN FD register map.
- interrupts: interrupt specifier for the Global & Channel interrupts
- clocks: phandles and clock specifiers for 3 clock inputs.
- clock-names: 3 clock input name strings: "fck", "canfd", "can_clk".
- pinctrl-0: pin control group to be used for this controller.
- pinctrl-names: must be "default".
Required child nodes:
The controller supports two channels and each is represented as a child node.
The name of the child nodes are "channel0" and "channel1" respectively. Each
child node supports the "status" property only, which is used to
enable/disable the respective channel.
Required properties for "renesas,r8a7795-canfd" compatible:
In R8A7795 SoC, canfd clock is a div6 clock and can be used by both CAN
and CAN FD controller at the same time. It needs to be scaled to maximum
frequency if any of these controllers use it. This is done using the
below properties.
- assigned-clocks: phandle of canfd clock.
- assigned-clock-rates: maximum frequency of this clock.
Optional property:
The controller can operate in either CAN FD only mode (default) or
Classical CAN only mode. The mode is global to both the channels. In order to
enable the later, define the following optional property.
- renesas,no-can-fd: puts the controller in Classical CAN only mode.
Example
-------
SoC common .dtsi file:
canfd: can@e66c0000 {
compatible = "renesas,r8a7795-canfd",
"renesas,rcar-gen3-canfd";
reg = <0 0xe66c0000 0 0x8000>;
interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 914>,
<&cpg CPG_CORE R8A7795_CLK_CANFD>,
<&can_clk>;
clock-names = "fck", "canfd", "can_clk";
assigned-clocks = <&cpg CPG_CORE R8A7795_CLK_CANFD>;
assigned-clock-rates = <40000000>;
power-domains = <&cpg>;
status = "disabled";
channel0 {
status = "disabled";
};
channel1 {
status = "disabled";
};
};
Board specific .dts file:
E.g. below enables Channel 1 alone in the board in Classical CAN only mode.
&canfd {
pinctrl-0 = <&canfd1_pins>;
pinctrl-names = "default";
renesas,no-can-fd;
status = "okay";
channel1 {
status = "okay";
};
};
E.g. below enables Channel 0 alone in the board using External clock
as fCAN clock.
&canfd {
pinctrl-0 = <&canfd0_pins &can_clk_pins>;
pinctrl-names = "default";
status = "okay";
channel0 {
status = "okay";
};
};

View File

@ -0,0 +1,13 @@
* Cirrus Logic CS8900/CS8920 Network Controller
Required properties:
- compatible : Should be "cirrus,cs8900" or "cirrus,cs8920".
- reg : Address and length of the IO space.
- interrupts : Should contain the controller interrupt line.
Examples:
eth0: eth@10000000 {
compatible = "cirrus,cs8900";
reg = <0x10000000 0x400>;
interrupts = <10>;
};

View File

@ -15,7 +15,6 @@ Required properties:
- cpdma_channels : Specifies number of channels in CPDMA
- ale_entries : Specifies No of entries ALE can hold
- bd_ram_size : Specifies internal descriptor RAM size
- rx_descs : Specifies number of Rx descriptors
- mac_control : Specifies Default MAC control register content
for the specific platform
- slaves : Specifies number for slaves

View File

@ -2,7 +2,10 @@ TI SoC Davinci/Keystone2 MDIO Controller Device Tree Bindings
---------------------------------------------------
Required properties:
- compatible : Should be "ti,davinci_mdio" or "ti,keystone_mdio"
- compatible : Should be "ti,davinci_mdio"
and "ti,keystone_mdio" for Keystone 2 SoCs
and "ti,cpsw-mdio" for am335x, am472x, am57xx/dra7, dm814x SoCs
and "ti,am4372-mdio" for am472x SoC
- reg : physical base address and size of the davinci mdio
registers map
- bus_freq : Mdio Bus frequency

View File

@ -0,0 +1,97 @@
Broadcom BCM53xx Ethernet switches
==================================
Required properties:
- compatible: For external switch chips, compatible string must be exactly one
of: "brcm,bcm5325"
"brcm,bcm53115"
"brcm,bcm53125"
"brcm,bcm53128"
"brcm,bcm5365"
"brcm,bcm5395"
"brcm,bcm5397"
"brcm,bcm5398"
For the BCM5310x SoCs with an integrated switch, must be one of:
"brcm,bcm53010-srab"
"brcm,bcm53011-srab"
"brcm,bcm53012-srab"
"brcm,bcm53018-srab"
"brcm,bcm53019-srab" and the mandatory "brcm,bcm5301x-srab" string
For the BCM585xx/586XX/88312 SoCs with an integrated switch, must be one of:
"brcm,bcm58522-srab"
"brcm,bcm58523-srab"
"brcm,bcm58525-srab"
"brcm,bcm58622-srab"
"brcm,bcm58623-srab"
"brcm,bcm58625-srab"
"brcm,bcm88312-srab" and the mandatory "brcm,nsp-srab string
For the BCM63xx/33xx SoCs with an integrated switch, must be one of:
"brcm,bcm3384-switch"
"brcm,bcm6328-switch"
"brcm,bcm6368-switch" and the mandatory "brcm,bcm63xx-switch"
See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional
required and optional properties.
Examples:
Ethernet switch connected via MDIO to the host, CPU port wired to eth0:
eth0: ethernet@10001000 {
compatible = "brcm,unimac";
reg = <0x10001000 0x1000>;
fixed-link {
speed = <1000>;
duplex-full;
};
};
mdio0: mdio@10000000 {
compatible = "brcm,unimac-mdio";
#address-cells = <1>;
#size-cells = <0>;
switch0: ethernet-switch@30 {
compatible = "brcm,bcm53125";
#address-cells = <1>;
#size-cells = <0>;
ports {
port0@0 {
reg = <0>;
label = "lan1";
};
port1@1 {
reg = <1>;
label = "lan2";
};
port5@5 {
reg = <5>;
label = "cable-modem";
fixed-link {
speed = <1000>;
duplex-full;
};
phy-mode = "rgmii-txid";
};
port8@8 {
reg = <8>;
label = "cpu";
fixed-link {
speed = <1000>;
duplex-full;
};
phy-mode = "rgmii-txid";
ethernet = <&eth0>;
};
};
};
};

View File

@ -1,5 +1,279 @@
Marvell Distributed Switch Architecture Device Tree Bindings
------------------------------------------------------------
Distributed Switch Architecture Device Tree Bindings
----------------------------------------------------
Two bindings exist, one of which has been deprecated due to
limitations.
Current Binding
---------------
Switches are true Linux devices and can be probes by any means. Once
probed, they register to the DSA framework, passing a node
pointer. This node is expected to fulfil the following binding, and
may contain additional properties as required by the device it is
embedded within.
Required properties:
- ports : A container for child nodes representing switch ports.
Optional properties:
- dsa,member : A two element list indicates which DSA cluster, and position
within the cluster a switch takes. <0 0> is cluster 0,
switch 0. <0 1> is cluster 0, switch 1. <1 0> is cluster 1,
switch 0. A switch not part of any cluster (single device
hanging off a CPU port) must not specify this property
The ports container has the following properties
Required properties:
- #address-cells : Must be 1
- #size-cells : Must be 0
Each port children node must have the following mandatory properties:
- reg : Describes the port address in the switch
- label : Describes the label associated with this port, which
will become the netdev name. Special labels are
"cpu" to indicate a CPU port and "dsa" to
indicate an uplink/downlink port between switches in
the cluster.
A port labelled "dsa" has the following mandatory property:
- link : Should be a list of phandles to other switch's DSA
port. This port is used as the outgoing port
towards the phandle ports. The full routing
information must be given, not just the one hop
routes to neighbouring switches.
A port labelled "cpu" has the following mandatory property:
- ethernet : Should be a phandle to a valid Ethernet device node.
This host device is what the switch port is
connected to.
Port child nodes may also contain the following optional standardised
properties, described in binding documents:
- phy-handle : Phandle to a PHY on an MDIO bus. See
Documentation/devicetree/bindings/net/ethernet.txt
for details.
- phy-mode : See
Documentation/devicetree/bindings/net/ethernet.txt
for details.
- 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
The following example shows three switches on three MDIO busses,
linked into one DSA cluster.
&mdio1 {
#address-cells = <1>;
#size-cells = <0>;
switch0: switch0@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan0";
};
port@1 {
reg = <1>;
label = "lan1";
};
port@2 {
reg = <2>;
label = "lan2";
};
switch0port5: port@5 {
reg = <5>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port6
&switch2port9>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&fec1>;
fixed-link {
speed = <100>;
full-duplex;
};
};
};
};
};
&mdio2 {
#address-cells = <1>;
#size-cells = <0>;
switch1: switch1@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan3";
phy-handle = <&switch1phy0>;
};
port@1 {
reg = <1>;
label = "lan4";
phy-handle = <&switch1phy1>;
};
port@2 {
reg = <2>;
label = "lan5";
phy-handle = <&switch1phy2>;
};
switch1port5: port@5 {
reg = <5>;
label = "dsa";
link = <&switch2port9>;
phy-mode = "rgmii-txid";
fixed-link {
speed = <1000>;
full-duplex;
};
};
switch1port6: port@6 {
reg = <6>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
switch1phy0: switch1phy0@0 {
reg = <0>;
};
switch1phy1: switch1phy0@1 {
reg = <1>;
};
switch1phy2: switch1phy0@2 {
reg = <2>;
};
};
};
};
&mdio4 {
#address-cells = <1>;
#size-cells = <0>;
switch2: switch2@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 2>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan6";
};
port@1 {
reg = <1>;
label = "lan7";
};
port@2 {
reg = <2>;
label = "lan8";
};
port@3 {
reg = <3>;
label = "optical3";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 2
GPIO_ACTIVE_HIGH>;
};
};
port@4 {
reg = <4>;
label = "optical4";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 3
GPIO_ACTIVE_HIGH>;
};
};
switch2port9: port@9 {
reg = <9>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port5
&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
};
Deprecated Binding
------------------
The deprecated binding makes use of a platform device to represent the
switches. The switches themselves are not Linux devices, and make use
of an MDIO bus for management.
Required properties:
- compatible : Should be "marvell,dsa"

View File

@ -0,0 +1,22 @@
Hisilicon Fast Ethernet MDIO Controller interface
Required properties:
- compatible: should be "hisilicon,hisi-femac-mdio".
- reg: address and length of the register set for the device.
- clocks: A phandle to the reference clock for this device.
- PHY subnode: inherits from phy binding [1]
[1] Documentation/devicetree/bindings/net/phy.txt
Example:
mdio: mdio@10091100 {
compatible = "hisilicon,hisi-femac-mdio";
reg = <0x10091100 0x10>;
clocks = <&crg HI3516CV300_MDIO_CLK>;
#address-cells = <1>;
#size-cells = <0>;
phy0: phy@1 {
reg = <1>;
};
};

View File

@ -0,0 +1,39 @@
Hisilicon Fast Ethernet MAC controller
Required properties:
- compatible: should contain one of the following version strings:
* "hisilicon,hisi-femac-v1"
* "hisilicon,hisi-femac-v2"
and the soc string "hisilicon,hi3516cv300-femac".
- reg: specifies base physical address(s) and size of the device registers.
The first region is the MAC core register base and size.
The second region is the global MAC control register.
- interrupts: should contain the MAC interrupt.
- clocks: A phandle to the MAC main clock.
- resets: should contain the phandle to the MAC reset signal(required) and
the PHY reset signal(optional).
- reset-names: should contain the reset signal name "mac"(required)
and "phy"(optional).
- mac-address: see ethernet.txt [1].
- phy-mode: see ethernet.txt [1].
- phy-handle: see ethernet.txt [1].
- hisilicon,phy-reset-delays-us: triplet of delays if PHY reset signal given.
The 1st cell is reset pre-delay in micro seconds.
The 2nd cell is reset pulse in micro seconds.
The 3rd cell is reset post-delay in micro seconds.
[1] Documentation/devicetree/bindings/net/ethernet.txt
Example:
hisi_femac: ethernet@10090000 {
compatible = "hisilicon,hi3516cv300-femac","hisilicon,hisi-femac-v2";
reg = <0x10090000 0x1000>,<0x10091300 0x200>;
interrupts = <12>;
clocks = <&crg HI3518EV200_ETH_CLK>;
resets = <&crg 0xec 0>,<&crg 0xec 3>;
reset-names = "mac","phy";
mac-address = [00 00 00 00 00 00];
phy-mode = "mii";
phy-handle = <&phy0>;
hisilicon,phy-reset-delays-us = <10000 20000 20000>;
};

View File

@ -2,7 +2,7 @@ This document describes the device tree bindings associated with the
keystone network coprocessor(NetCP) driver support.
The network coprocessor (NetCP) is a hardware accelerator that processes
Ethernet packets. NetCP has a gigabit Ethernet (GbE) subsytem with a ethernet
Ethernet packets. NetCP has a gigabit Ethernet (GbE) subsystem with a ethernet
switch sub-module to send and receive packets. NetCP also includes a packet
accelerator (PA) module to perform packet classification operations such as
header matching, and packet modification operations such as checksum

View File

@ -5,11 +5,12 @@ numbered uniquely in a device dependent manner. The nodes for an MDIO
bus multiplexer/switch will have one child node for each child bus.
Required properties:
- mdio-parent-bus : phandle to the parent MDIO bus.
- #address-cells = <1>;
- #size-cells = <0>;
Optional properties:
- mdio-parent-bus : phandle to the parent MDIO bus.
- Other properties specific to the multiplexer/switch hardware.
Required properties for child nodes:

View File

@ -35,3 +35,13 @@ Optional properties:
supported clocks:
- KSZ8021, KSZ8031, KSZ8081, KSZ8091: "rmii-ref": The RMII reference
input clock. Used to determine the XI input clock.
- micrel,fiber-mode: If present the PHY is configured to operate in fiber mode
Some PHYs, such as the KSZ8041FTL variant, support fiber mode, enabled
by the FXEN boot strapping pin. It can't be determined from the PHY
registers whether the PHY is in fiber mode, so this boolean device tree
property can be used to describe it.
In fiber mode, auto-negotiation is disabled and the PHY can only work in
100base-fx (full and half duplex) modes.

View File

@ -3,7 +3,8 @@ Rockchip SoC RK3288 10/100/1000 Ethernet driver(GMAC)
The device node has following properties.
Required properties:
- compatible: Can be one of "rockchip,rk3288-gmac", "rockchip,rk3368-gmac"
- compatible: Can be one of "rockchip,rk3228-gmac", "rockchip,rk3288-gmac",
"rockchip,rk3368-gmac"
- reg: addresses and length of the register sets for the device.
- interrupts: Should contain the GMAC interrupts.
- interrupt-names: Should contain the interrupt names "macirq".

View File

@ -17,9 +17,26 @@ Required properties:
Optional properties:
altr,emac-splitter: Should be the phandle to the emac splitter soft IP node if
DWMAC controller is connected emac splitter.
phy-mode: The phy mode the ethernet operates in
altr,sgmii-to-sgmii-converter: phandle to the TSE SGMII converter
This device node has additional phandle dependency, the sgmii converter:
Required properties:
- compatible : Should be altr,gmii-to-sgmii-2.0
- reg-names : Should be "eth_tse_control_port"
Example:
gmii_to_sgmii_converter: phy@0x100000240 {
compatible = "altr,gmii-to-sgmii-2.0";
reg = <0x00000001 0x00000240 0x00000008>,
<0x00000001 0x00000200 0x00000040>;
reg-names = "eth_tse_control_port";
clocks = <&sgmii_1_clk_0 &emac1 1 &sgmii_clk_125 &sgmii_clk_125>;
clock-names = "tse_pcs_ref_clk_clock_connection", "tse_rx_cdr_refclk";
};
gmac0: ethernet@ff700000 {
compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac";
altr,sysmgr-syscon = <&sysmgr 0x60 0>;
@ -30,4 +47,6 @@ gmac0: ethernet@ff700000 {
mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */
clocks = <&emac_0_clk>;
clock-names = "stmmaceth";
phy-mode = "sgmii";
altr,gmii-to-sgmii-converter = <&gmii_to_sgmii_converter>;
};

View File

@ -47,6 +47,9 @@ Optional properties:
supported by this device instance
- snps,perfect-filter-entries: Number of perfect filter entries supported
by this device instance
- snps,ps-speed: port selection speed that can be passed to the core when
PCS is supported. For example, this is used in case of SGMII
and MAC2MAC connection.
- AXI BUS Mode parameters: below the list of all the parameters to program the
AXI register inside the DMA module:
- snps,lpi_en: enable Low Power Interface

View File

@ -1,19 +1,30 @@
* Texas Instruments wl1271 wireless lan controller
* Texas Instruments wl12xx/wl18xx wireless lan controller
The wl1271 chip can be connected via SPI or via SDIO. This
The wl12xx/wl18xx chips can be connected via SPI or via SDIO. This
document describes the binding for the SPI connected chip.
Required properties:
- compatible : Should be "ti,wl1271"
- compatible : Should be one of the following:
* "ti,wl1271"
* "ti,wl1273"
* "ti,wl1281"
* "ti,wl1283"
* "ti,wl1801"
* "ti,wl1805"
* "ti,wl1807"
* "ti,wl1831"
* "ti,wl1835"
* "ti,wl1837"
- reg : Chip select address of device
- spi-max-frequency : Maximum SPI clocking speed of device in Hz
- ref-clock-frequency : Reference clock frequency
- interrupt-parent, interrupts :
Should contain parameters for 1 interrupt line.
Interrupt parameters: parent, line number, type.
- vwlan-supply : Point the node of the regulator that powers/enable the wl1271 chip
- vwlan-supply : Point the node of the regulator that powers/enable the
wl12xx/wl18xx chip
Optional properties:
- ref-clock-frequency : Reference clock frequency (should be set for wl12xx)
- clock-xtal : boolean, clock is generated from XTAL
- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
@ -21,16 +32,28 @@ Optional properties:
Examples:
For wl12xx family:
&spi1 {
wl1271@1 {
wlcore: wlcore@1 {
compatible = "ti,wl1271";
reg = <1>;
spi-max-frequency = <48000000>;
clock-xtal;
ref-clock-frequency = <38400000>;
interrupt-parent = <&gpio3>;
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
vwlan-supply = <&vwlan_fixed>;
clock-xtal;
ref-clock-frequency = <38400000>;
};
};
For wl18xx family:
&spi0 {
wlcore: wlcore@0 {
compatible = "ti,wl1835";
reg = <0>;
spi-max-frequency = <48000000>;
interrupt-parent = <&gpio0>;
interrupts = <27 IRQ_TYPE_EDGE_RISING>;
vwlan-supply = <&vwlan_fixed>;
};
};

View File

@ -0,0 +1,27 @@
* Broadcom NS2 PCIe PHY binding document
Required bus properties:
- reg: MDIO Bus number for the MDIO interface
- #address-cells: must be 1
- #size-cells: must be 0
Required PHY properties:
- compatible: should be "brcm,ns2-pcie-phy"
- reg: MDIO Phy ID for the MDIO interface
- #phy-cells: must be 0
This is a child bus node of "brcm,mdio-mux-iproc" node.
Example:
mdio@0 {
reg = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
pci_phy0: pci-phy@0 {
compatible = "brcm,ns2-pcie-phy";
reg = <0x0>;
#phy-cells = <0>;
};
};

View File

@ -31,6 +31,7 @@ This file contains
4.2.4 Broadcast Manager message sequence transmission
4.2.5 Broadcast Manager receive filter timers
4.2.6 Broadcast Manager multiplex message receive filter
4.2.7 Broadcast Manager CAN FD support
4.3 connected transport protocols (SOCK_SEQPACKET)
4.4 unconnected transport protocols (SOCK_DGRAM)
@ -799,7 +800,7 @@ solution for a couple of reasons:
} mytxmsg;
(..)
mytxmsg.nframes = 4;
mytxmsg.msg_head.nframes = 4;
(..)
write(s, &mytxmsg, sizeof(mytxmsg));
@ -852,6 +853,28 @@ solution for a couple of reasons:
write(s, &msg, sizeof(msg));
4.2.7 Broadcast Manager CAN FD support
The programming API of the CAN_BCM depends on struct can_frame which is
given as array directly behind the bcm_msg_head structure. To follow this
schema for the CAN FD frames a new flag 'CAN_FD_FRAME' in the bcm_msg_head
flags indicates that the concatenated CAN frame structures behind the
bcm_msg_head are defined as struct canfd_frame.
struct {
struct bcm_msg_head msg_head;
struct canfd_frame frame[5];
} msg;
msg.msg_head.opcode = RX_SETUP;
msg.msg_head.can_id = 0x42;
msg.msg_head.flags = CAN_FD_FRAME;
msg.msg_head.nframes = 5;
(..)
When using CAN FD frames for multiplex filtering the MUX mask is still
expected in the first 64 bit of the struct canfd_frame data section.
4.3 connected transport protocols (SOCK_SEQPACKET)
4.4 unconnected transport protocols (SOCK_DGRAM)

View File

@ -21,7 +21,7 @@ struct mystruct {
...
};
Update statistics:
Update statistics, in dequeue() methods only, (while owning qdisc->running)
mystruct->tstats.packet++;
mystruct->qstats.backlog += skb->pkt_len;

View File

@ -7,12 +7,13 @@ nf_conntrack_acct - BOOLEAN
Enable connection tracking flow accounting. 64-bit byte and packet
counters per flow are added.
nf_conntrack_buckets - INTEGER (read-only)
nf_conntrack_buckets - INTEGER
Size of hash table. If not specified as parameter during module
loading, the default size is calculated by dividing total memory
by 16384 to determine the number of buckets but the hash table will
never have fewer than 32 and limited to 16384 buckets. For systems
with more than 4GB of memory it will be 65536 buckets.
This sysctl is only writeable in the initial net namespace.
nf_conntrack_checksum - BOOLEAN
0 - disabled

View File

@ -85,7 +85,8 @@ Socket Interface
bind(fd, &sockaddr_in, ...)
This binds the socket to a local IP address and port, and a
transport.
transport, if one has not already been selected via the
SO_RDS_TRANSPORT socket option
sendmsg(fd, ...)
Sends a message to the indicated recipient. The kernel will
@ -146,6 +147,20 @@ Socket Interface
operation. In this case, it would use RDS_CANCEL_SENT_TO to
nuke any pending messages.
setsockopt(fd, SOL_RDS, SO_RDS_TRANSPORT, (int *)&transport ..)
getsockopt(fd, SOL_RDS, SO_RDS_TRANSPORT, (int *)&transport ..)
Set or read an integer defining the underlying
encapsulating transport to be used for RDS packets on the
socket. When setting the option, integer argument may be
one of RDS_TRANS_TCP or RDS_TRANS_IB. When retrieving the
value, RDS_TRANS_NONE will be returned on an unbound socket.
This socket option may only be set exactly once on the socket,
prior to binding it via the bind(2) system call. Attempts to
set SO_RDS_TRANSPORT on a socket for which the transport has
been previously attached explicitly (by SO_RDS_TRANSPORT) or
implicitly (via bind(2)) will return an error of EOPNOTSUPP.
An attempt to set SO_RDS_TRANSPPORT to RDS_TRANS_NONE will
always return EINVAL.
RDMA for RDS
============
@ -350,4 +365,59 @@ The recv path
handle CMSGs
return to application
Multipath RDS (mprds)
=====================
Mprds is multipathed-RDS, primarily intended for RDS-over-TCP
(though the concept can be extended to other transports). The classical
implementation of RDS-over-TCP is implemented by demultiplexing multiple
PF_RDS sockets between any 2 endpoints (where endpoint == [IP address,
port]) over a single TCP socket between the 2 IP addresses involved. This
has the limitation that it ends up funneling multiple RDS flows over a
single TCP flow, thus it is
(a) upper-bounded to the single-flow bandwidth,
(b) suffers from head-of-line blocking for all the RDS sockets.
Better throughput (for a fixed small packet size, MTU) can be achieved
by having multiple TCP/IP flows per rds/tcp connection, i.e., multipathed
RDS (mprds). Each such TCP/IP flow constitutes a path for the rds/tcp
connection. RDS sockets will be attached to a path based on some hash
(e.g., of local address and RDS port number) and packets for that RDS
socket will be sent over the attached path using TCP to segment/reassemble
RDS datagrams on that path.
Multipathed RDS is implemented by splitting the struct rds_connection into
a common (to all paths) part, and a per-path struct rds_conn_path. All
I/O workqs and reconnect threads are driven from the rds_conn_path.
Transports such as TCP that are multipath capable may then set up a
TPC socket per rds_conn_path, and this is managed by the transport via
the transport privatee cp_transport_data pointer.
Transports announce themselves as multipath capable by setting the
t_mp_capable bit during registration with the rds core module. When the
transport is multipath-capable, rds_sendmsg() hashes outgoing traffic
across multiple paths. The outgoing hash is computed based on the
local address and port that the PF_RDS socket is bound to.
Additionally, even if the transport is MP capable, we may be
peering with some node that does not support mprds, or supports
a different number of paths. As a result, the peering nodes need
to agree on the number of paths to be used for the connection.
This is done by sending out a control packet exchange before the
first data packet. The control packet exchange must have completed
prior to outgoing hash completion in rds_sendmsg() when the transport
is mutlipath capable.
The control packet is an RDS ping packet (i.e., packet to rds dest
port 0) with the ping packet having a rds extension header option of
type RDS_EXTHDR_NPATHS, length 2 bytes, and the value is the
number of paths supported by the sender. The "probe" ping packet will
get sent from some reserved port, RDS_FLAG_PROBE_PORT (in <linux/rds.h>)
The receiver of a ping from RDS_FLAG_PROBE_PORT will thus immediately
be able to compute the min(sender_paths, rcvr_paths). The pong
sent in response to a probe-ping should contain the rcvr's npaths
when the rcvr is mprds-capable.
If the rcvr is not mprds-capable, the exthdr in the ping will be
ignored. In this case the pong will not have any exthdrs, so the sender
of the probe-ping can default to single-path mprds.

View File

@ -285,6 +285,7 @@ Please see the following document:
o mmc_core.c/mmc.h: Management MAC Counters;
o stmmac_hwtstamp.c: HW timestamp support for PTP;
o stmmac_ptp.c: PTP 1588 clock;
o stmmac_pcs.h: Physical Coding Sublayer common implementation;
o dwmac-<XXX>.c: these are for the platform glue-logic file; e.g. dwmac-sti.c
for STMicroelectronics SoCs.

View File

@ -15,9 +15,9 @@ the use of higher priority ip rules (Policy Based Routing, PBR) to take
precedence over the VRF device rules directing specific traffic as desired.
In addition, VRF devices allow VRFs to be nested within namespaces. For
example network namespaces provide separation of network interfaces at L1
(Layer 1 separation), VLANs on the interfaces within a namespace provide
L2 separation and then VRF devices provide L3 separation.
example network namespaces provide separation of network interfaces at the
device layer, VLANs on the interfaces within a namespace provide L2 separation
and then VRF devices provide L3 separation.
Design
------
@ -37,21 +37,22 @@ are then enslaved to a VRF device:
+------+ +------+
Packets received on an enslaved device and are switched to the VRF device
using an rx_handler which gives the impression that packets flow through
the VRF device. Similarly on egress routing rules are used to send packets
to the VRF device driver before getting sent out the actual interface. This
allows tcpdump on a VRF device to capture all packets into and out of the
VRF as a whole.[1] Similarly, netfilter [2] and tc rules can be applied
using the VRF device to specify rules that apply to the VRF domain as a whole.
in the IPv4 and IPv6 processing stacks giving the impression that packets
flow through the VRF device. Similarly on egress routing rules are used to
send packets to the VRF device driver before getting sent out the actual
interface. This allows tcpdump on a VRF device to capture all packets into
and out of the VRF as a whole.[1] Similarly, netfilter[2] and tc rules can be
applied using the VRF device to specify rules that apply to the VRF domain
as a whole.
[1] Packets in the forwarded state do not flow through the device, so those
packets are not seen by tcpdump. Will revisit this limitation in a
future release.
[2] Iptables on ingress is limited to NF_INET_PRE_ROUTING only with skb->dev
set to real ingress device and egress is limited to NF_INET_POST_ROUTING.
Will revisit this limitation in a future release.
[2] Iptables on ingress supports PREROUTING with skb->dev set to the real
ingress device and both INPUT and PREROUTING rules with skb->dev set to
the VRF device. For egress POSTROUTING and OUTPUT rules can be written
using either the VRF device or real egress device.
Setup
-----
@ -59,23 +60,33 @@ Setup
e.g, ip link add vrf-blue type vrf table 10
ip link set dev vrf-blue up
2. Rules are added that send lookups to the associated FIB table when the
iif or oif is the VRF device. e.g.,
2. An l3mdev FIB rule directs lookups to the table associated with the device.
A single l3mdev rule is sufficient for all VRFs. The VRF device adds the
l3mdev rule for IPv4 and IPv6 when the first device is created with a
default preference of 1000. Users may delete the rule if desired and add
with a different priority or install per-VRF rules.
Prior to the v4.8 kernel iif and oif rules are needed for each VRF device:
ip ru add oif vrf-blue table 10
ip ru add iif vrf-blue table 10
Set the default route for the table (and hence default route for the VRF).
e.g, ip route add table 10 prohibit default
3. Set the default route for the table (and hence default route for the VRF).
ip route add table 10 unreachable default
3. Enslave L3 interfaces to a VRF device.
e.g, ip link set dev eth1 master vrf-blue
4. Enslave L3 interfaces to a VRF device.
ip link set dev eth1 master vrf-blue
Local and connected routes for enslaved devices are automatically moved to
the table associated with VRF device. Any additional routes depending on
the enslaved device will need to be reinserted following the enslavement.
the enslaved device are dropped and will need to be reinserted to the VRF
FIB table following the enslavement.
4. Additional VRF routes are added to associated table.
e.g., ip route add table 10 ...
The IPv6 sysctl option keep_addr_on_down can be enabled to keep IPv6 global
addresses as VRF enslavement changes.
sysctl -w net.ipv6.conf.all.keep_addr_on_down=1
5. Additional VRF routes are added to associated table.
ip route add table 10 ...
Applications
@ -87,39 +98,34 @@ VRF device:
or to specify the output device using cmsg and IP_PKTINFO.
TCP services running in the default VRF context (ie., not bound to any VRF
device) can work across all VRF domains by enabling the tcp_l3mdev_accept
sysctl option:
sysctl -w net.ipv4.tcp_l3mdev_accept=1
Limitations
-----------
Index of original ingress interface is not available via cmsg. Will address
soon.
netfilter rules on the VRF device can be used to limit access to services
running in the default VRF context as well.
The default VRF does not have limited scope with respect to port bindings.
That is, if a process does a wildcard bind to a port in the default VRF it
owns the port across all VRF domains within the network namespace.
################################################################################
Using iproute2 for VRFs
=======================
VRF devices do *not* have to start with 'vrf-'. That is a convention used here
for emphasis of the device type, similar to use of 'br' in bridge names.
iproute2 supports the vrf keyword as of v4.7. For backwards compatibility this
section lists both commands where appropriate -- with the vrf keyword and the
older form without it.
1. Create a VRF
To instantiate a VRF device and associate it with a table:
$ ip link add dev NAME type vrf table ID
Remember to add the ip rules as well:
$ ip ru add oif NAME table 10
$ ip ru add iif NAME table 10
$ ip -6 ru add oif NAME table 10
$ ip -6 ru add iif NAME table 10
Without the rules route lookups are not directed to the table.
For example:
$ ip link add dev vrf-blue type vrf table 10
$ ip ru add pref 200 oif vrf-blue table 10
$ ip ru add pref 200 iif vrf-blue table 10
$ ip -6 ru add pref 200 oif vrf-blue table 10
$ ip -6 ru add pref 200 iif vrf-blue table 10
As of v4.8 the kernel supports the l3mdev FIB rule where a single rule
covers all VRFs. The l3mdev rule is created for IPv4 and IPv6 on first
device create.
2. List VRFs
@ -129,16 +135,16 @@ for emphasis of the device type, similar to use of 'br' in bridge names.
For example:
$ ip -d link show type vrf
11: vrf-mgmt: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
11: mgmt: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 72:b3:ba:91:e2:24 brd ff:ff:ff:ff:ff:ff promiscuity 0
vrf table 1 addrgenmode eui64
12: vrf-red: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
12: red: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether b6:6f:6e:f6:da:73 brd ff:ff:ff:ff:ff:ff promiscuity 0
vrf table 10 addrgenmode eui64
13: vrf-blue: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
13: blue: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 36:62:e8:7d:bb:8c brd ff:ff:ff:ff:ff:ff promiscuity 0
vrf table 66 addrgenmode eui64
14: vrf-green: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
14: green: <NOARP,MASTER,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether e6:28:b8:63:70:bb brd ff:ff:ff:ff:ff:ff promiscuity 0
vrf table 81 addrgenmode eui64
@ -146,43 +152,44 @@ for emphasis of the device type, similar to use of 'br' in bridge names.
Or in brief output:
$ ip -br link show type vrf
vrf-mgmt UP 72:b3:ba:91:e2:24 <NOARP,MASTER,UP,LOWER_UP>
vrf-red UP b6:6f:6e:f6:da:73 <NOARP,MASTER,UP,LOWER_UP>
vrf-blue UP 36:62:e8:7d:bb:8c <NOARP,MASTER,UP,LOWER_UP>
vrf-green UP e6:28:b8:63:70:bb <NOARP,MASTER,UP,LOWER_UP>
mgmt UP 72:b3:ba:91:e2:24 <NOARP,MASTER,UP,LOWER_UP>
red UP b6:6f:6e:f6:da:73 <NOARP,MASTER,UP,LOWER_UP>
blue UP 36:62:e8:7d:bb:8c <NOARP,MASTER,UP,LOWER_UP>
green UP e6:28:b8:63:70:bb <NOARP,MASTER,UP,LOWER_UP>
3. Assign a Network Interface to a VRF
Network interfaces are assigned to a VRF by enslaving the netdevice to a
VRF device:
$ ip link set dev NAME master VRF-NAME
$ ip link set dev NAME master NAME
On enslavement connected and local routes are automatically moved to the
table associated with the VRF device.
For example:
$ ip link set dev eth0 master vrf-mgmt
$ ip link set dev eth0 master mgmt
4. Show Devices Assigned to a VRF
To show devices that have been assigned to a specific VRF add the master
option to the ip command:
$ ip link show master VRF-NAME
$ ip link show vrf NAME
$ ip link show master NAME
For example:
$ ip link show master vrf-red
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP mode DEFAULT group default qlen 1000
$ ip link show vrf red
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP mode DEFAULT group default qlen 1000
link/ether 02:00:00:00:02:02 brd ff:ff:ff:ff:ff:ff
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP mode DEFAULT group default qlen 1000
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP mode DEFAULT group default qlen 1000
link/ether 02:00:00:00:02:03 brd ff:ff:ff:ff:ff:ff
7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master vrf-red state DOWN mode DEFAULT group default qlen 1000
7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master red state DOWN mode DEFAULT group default qlen 1000
link/ether 02:00:00:00:02:06 brd ff:ff:ff:ff:ff:ff
Or using the brief output:
$ ip -br link show master vrf-red
$ ip -br link show vrf red
eth1 UP 02:00:00:00:02:02 <BROADCAST,MULTICAST,UP,LOWER_UP>
eth2 UP 02:00:00:00:02:03 <BROADCAST,MULTICAST,UP,LOWER_UP>
eth5 DOWN 02:00:00:00:02:06 <BROADCAST,MULTICAST>
@ -192,26 +199,28 @@ for emphasis of the device type, similar to use of 'br' in bridge names.
To list neighbor entries associated with devices enslaved to a VRF device
add the master option to the ip command:
$ ip [-6] neigh show master VRF-NAME
$ ip [-6] neigh show vrf NAME
$ ip [-6] neigh show master NAME
For example:
$ ip neigh show master vrf-red
$ ip neigh show vrf red
10.2.1.254 dev eth1 lladdr a6:d9:c7:4f:06:23 REACHABLE
10.2.2.254 dev eth2 lladdr 5e:54:01:6a:ee:80 REACHABLE
$ ip -6 neigh show master vrf-red
2002:1::64 dev eth1 lladdr a6:d9:c7:4f:06:23 REACHABLE
$ ip -6 neigh show vrf red
2002:1::64 dev eth1 lladdr a6:d9:c7:4f:06:23 REACHABLE
6. Show Addresses for a VRF
To show addresses for interfaces associated with a VRF add the master
option to the ip command:
$ ip addr show master VRF-NAME
$ ip addr show vrf NAME
$ ip addr show master NAME
For example:
$ ip addr show master vrf-red
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP group default qlen 1000
$ ip addr show vrf red
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP group default qlen 1000
link/ether 02:00:00:00:02:02 brd ff:ff:ff:ff:ff:ff
inet 10.2.1.2/24 brd 10.2.1.255 scope global eth1
valid_lft forever preferred_lft forever
@ -219,7 +228,7 @@ for emphasis of the device type, similar to use of 'br' in bridge names.
valid_lft forever preferred_lft forever
inet6 fe80::ff:fe00:202/64 scope link
valid_lft forever preferred_lft forever
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vrf-red state UP group default qlen 1000
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP group default qlen 1000
link/ether 02:00:00:00:02:03 brd ff:ff:ff:ff:ff:ff
inet 10.2.2.2/24 brd 10.2.2.255 scope global eth2
valid_lft forever preferred_lft forever
@ -227,11 +236,11 @@ for emphasis of the device type, similar to use of 'br' in bridge names.
valid_lft forever preferred_lft forever
inet6 fe80::ff:fe00:203/64 scope link
valid_lft forever preferred_lft forever
7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master vrf-red state DOWN group default qlen 1000
7: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master red state DOWN group default qlen 1000
link/ether 02:00:00:00:02:06 brd ff:ff:ff:ff:ff:ff
Or in brief format:
$ ip -br addr show master vrf-red
$ ip -br addr show vrf red
eth1 UP 10.2.1.2/24 2002:1::2/120 fe80::ff:fe00:202/64
eth2 UP 10.2.2.2/24 2002:2::2/120 fe80::ff:fe00:203/64
eth5 DOWN
@ -241,10 +250,11 @@ for emphasis of the device type, similar to use of 'br' in bridge names.
To show routes for a VRF use the ip command to display the table associated
with the VRF device:
$ ip [-6] route show vrf NAME
$ ip [-6] route show table ID
For example:
$ ip route show table vrf-red
$ ip route show vrf red
prohibit default
broadcast 10.2.1.0 dev eth1 proto kernel scope link src 10.2.1.2
10.2.1.0/24 dev eth1 proto kernel scope link src 10.2.1.2
@ -255,7 +265,7 @@ for emphasis of the device type, similar to use of 'br' in bridge names.
local 10.2.2.2 dev eth2 proto kernel scope host src 10.2.2.2
broadcast 10.2.2.255 dev eth2 proto kernel scope link src 10.2.2.2
$ ip -6 route show table vrf-red
$ ip -6 route show vrf red
local 2002:1:: dev lo proto none metric 0 pref medium
local 2002:1::2 dev lo proto none metric 0 pref medium
2002:1::/120 dev eth1 proto kernel metric 256 pref medium
@ -268,23 +278,24 @@ for emphasis of the device type, similar to use of 'br' in bridge names.
local fe80::ff:fe00:203 dev lo proto none metric 0 pref medium
fe80::/64 dev eth1 proto kernel metric 256 pref medium
fe80::/64 dev eth2 proto kernel metric 256 pref medium
ff00::/8 dev vrf-red metric 256 pref medium
ff00::/8 dev red metric 256 pref medium
ff00::/8 dev eth1 metric 256 pref medium
ff00::/8 dev eth2 metric 256 pref medium
8. Route Lookup for a VRF
A test route lookup can be done for a VRF by adding the oif option to ip:
$ ip [-6] route get oif VRF-NAME ADDRESS
A test route lookup can be done for a VRF:
$ ip [-6] route get vrf NAME ADDRESS
$ ip [-6] route get oif NAME ADDRESS
For example:
$ ip route get 10.2.1.40 oif vrf-red
10.2.1.40 dev eth1 table vrf-red src 10.2.1.2
$ ip route get 10.2.1.40 vrf red
10.2.1.40 dev eth1 table red src 10.2.1.2
cache
$ ip -6 route get 2002:1::32 oif vrf-red
2002:1::32 from :: dev eth1 table vrf-red proto kernel src 2002:1::2 metric 256 pref medium
$ ip -6 route get 2002:1::32 vrf red
2002:1::32 from :: dev eth1 table red proto kernel src 2002:1::2 metric 256 pref medium
9. Removing Network Interface from a VRF
@ -303,46 +314,40 @@ for emphasis of the device type, similar to use of 'br' in bridge names.
Commands used in this example:
cat >> /etc/iproute2/rt_tables <<EOF
1 vrf-mgmt
10 vrf-red
66 vrf-blue
81 vrf-green
cat >> /etc/iproute2/rt_tables.d/vrf.conf <<EOF
1 mgmt
10 red
66 blue
81 green
EOF
function vrf_create
{
VRF=$1
TBID=$2
# create VRF device
ip link add vrf-${VRF} type vrf table ${TBID}
# add rules that direct lookups to vrf table
ip ru add pref 200 oif vrf-${VRF} table ${TBID}
ip ru add pref 200 iif vrf-${VRF} table ${TBID}
ip -6 ru add pref 200 oif vrf-${VRF} table ${TBID}
ip -6 ru add pref 200 iif vrf-${VRF} table ${TBID}
# create VRF device
ip link add ${VRF} type vrf table ${TBID}
if [ "${VRF}" != "mgmt" ]; then
ip route add table ${TBID} prohibit default
ip route add table ${TBID} unreachable default
fi
ip link set dev vrf-${VRF} up
ip link set dev vrf-${VRF} state up
ip link set dev ${VRF} up
}
vrf_create mgmt 1
ip link set dev eth0 master vrf-mgmt
ip link set dev eth0 master mgmt
vrf_create red 10
ip link set dev eth1 master vrf-red
ip link set dev eth2 master vrf-red
ip link set dev eth5 master vrf-red
ip link set dev eth1 master red
ip link set dev eth2 master red
ip link set dev eth5 master red
vrf_create blue 66
ip link set dev eth3 master vrf-blue
ip link set dev eth3 master blue
vrf_create green 81
ip link set dev eth4 master vrf-green
ip link set dev eth4 master green
Interface addresses from /etc/network/interfaces:

View File

@ -840,7 +840,9 @@ M: Iyappan Subramanian <isubramanian@apm.com>
M: Keyur Chudgar <kchudgar@apm.com>
S: Supported
F: drivers/net/ethernet/apm/xgene/
F: drivers/net/phy/mdio-xgene.c
F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt
F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt
APTINA CAMERA SENSOR PLL
M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
@ -2303,6 +2305,7 @@ S: Maintained
F: Documentation/ABI/testing/sysfs-class-net-batman-adv
F: Documentation/ABI/testing/sysfs-class-net-mesh
F: Documentation/networking/batman-adv.txt
F: include/uapi/linux/batman_adv.h
F: net/batman-adv/
BAYCOM/HDLCDRV DRIVERS FOR AX.25
@ -2466,6 +2469,14 @@ L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/broadcom/b44.*
BROADCOM B53 ETHERNET SWITCH DRIVER
M: Florian Fainelli <f.fainelli@gmail.com>
L: netdev@vger.kernel.org
L: openwrt-devel@lists.openwrt.org (subscribers-only)
S: Supported
F: drivers/net/dsa/b53/*
F: include/linux/platform_data/b53.h
BROADCOM GENET ETHERNET DRIVER
M: Florian Fainelli <f.fainelli@gmail.com>
L: netdev@vger.kernel.org
@ -2582,12 +2593,11 @@ S: Supported
F: drivers/net/ethernet/broadcom/tg3.*
BROADCOM BRCM80211 IEEE802.11n WIRELESS DRIVER
M: Brett Rudley <brudley@broadcom.com>
M: Arend van Spriel <arend@broadcom.com>
M: Franky (Zhenhui) Lin <frankyl@broadcom.com>
M: Hante Meuleman <meuleman@broadcom.com>
M: Arend van Spriel <arend.vanspriel@broadcom.com>
M: Franky Lin <franky.lin@broadcom.com>
M: Hante Meuleman <hante.meuleman@broadcom.com>
L: linux-wireless@vger.kernel.org
L: brcm80211-dev-list@broadcom.com
L: brcm80211-dev-list.pdl@broadcom.com
S: Supported
F: drivers/net/wireless/broadcom/brcm80211/
@ -2819,6 +2829,7 @@ W: https://github.com/linux-can
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
S: Maintained
F: Documentation/devicetree/bindings/net/can/
F: drivers/net/can/
F: include/linux/can/dev.h
F: include/linux/can/platform/
@ -4910,6 +4921,13 @@ F: drivers/net/ethernet/freescale/gianfar*
X: drivers/net/ethernet/freescale/gianfar_ptp.c
F: Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
FREESCALE QUICC ENGINE UCC HDLC DRIVER
M: Zhao Qiang <qiang.zhao@nxp.com>
L: netdev@vger.kernel.org
L: linuxppc-dev@lists.ozlabs.org
S: Maintained
F: drivers/net/wan/fsl_ucc_hdlc*
FREESCALE QUICC ENGINE UCC UART DRIVER
M: Timur Tabi <timur@tabi.org>
L: linuxppc-dev@lists.ozlabs.org
@ -5453,6 +5471,15 @@ F: include/uapi/linux/if_hippi.h
F: net/802/hippi.c
F: drivers/net/hippi/
HISILICON NETWORK SUBSYSTEM DRIVER
M: Yisen Zhuang <yisen.zhuang@huawei.com>
M: Salil Mehta <salil.mehta@huawei.com>
L: netdev@vger.kernel.org
W: http://www.hisilicon.com
S: Maintained
F: drivers/net/ethernet/hisilicon/
F: Documentation/devicetree/bindings/net/hisilicon*.txt
HISILICON SAS Controller
M: John Garry <john.garry@huawei.com>
W: http://www.hisilicon.com
@ -7226,6 +7253,12 @@ W: http://www.kernel.org/doc/man-pages
L: linux-man@vger.kernel.org
S: Maintained
MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER
M: Andrew Lunn <andrew@lunn.ch>
M: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
S: Maintained
F: drivers/net/dsa/mv88e6xxx/
MARVELL ARMADA DRM SUPPORT
M: Russell King <rmk+kernel@armlinux.org.uk>
S: Maintained
@ -7233,11 +7266,6 @@ F: drivers/gpu/drm/armada/
F: include/uapi/drm/armada_drm.h
F: Documentation/devicetree/bindings/display/armada/
MARVELL 88E6352 DSA support
M: Guenter Roeck <linux@roeck-us.net>
S: Maintained
F: drivers/net/dsa/mv88e6352.c
MARVELL CRYPTO DRIVER
M: Boris Brezillon <boris.brezillon@free-electrons.com>
M: Arnaud Ebalard <arno@natisbad.org>
@ -9626,7 +9654,7 @@ M: Florian Fainelli <florian@openwrt.org>
S: Maintained
RDC R6040 FAST ETHERNET DRIVER
M: Florian Fainelli <florian@openwrt.org>
M: Florian Fainelli <f.fainelli@gmail.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/rdc/r6040.c
@ -9778,7 +9806,6 @@ F: Documentation/ABI/*/sysfs-driver-hid-roccat*
ROCKER DRIVER
M: Jiri Pirko <jiri@resnulli.us>
M: Scott Feldman <sfeldma@gmail.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/rocker/
@ -10376,10 +10403,9 @@ W: http://www.avagotech.com
S: Supported
F: drivers/scsi/be2iscsi/
Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER
Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER (be2net)
M: Sathya Perla <sathya.perla@broadcom.com>
M: Ajit Khaparde <ajit.khaparde@broadcom.com>
M: Padmanabh Ratnakar <padmanabh.ratnakar@broadcom.com>
M: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
M: Somnath Kotur <somnath.kotur@broadcom.com>
L: netdev@vger.kernel.org

View File

@ -766,7 +766,6 @@
ale_entries = <1024>;
bd_ram_size = <0x2000>;
no_bd_ram = <0>;
rx_descs = <64>;
mac_control = <0x20>;
slaves = <2>;
active_slave = <0>;
@ -789,7 +788,7 @@
status = "disabled";
davinci_mdio: mdio@4a101000 {
compatible = "ti,davinci_mdio";
compatible = "ti,cpsw-mdio","ti,davinci_mdio";
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "davinci_mdio";

View File

@ -626,7 +626,6 @@
ale_entries = <1024>;
bd_ram_size = <0x2000>;
no_bd_ram = <0>;
rx_descs = <64>;
mac_control = <0x20>;
slaves = <2>;
active_slave = <0>;
@ -636,7 +635,7 @@
syscon = <&scm_conf>;
davinci_mdio: mdio@4a101000 {
compatible = "ti,am4372-mdio","ti,davinci_mdio";
compatible = "ti,am4372-mdio","ti,cpsw-mdio","ti,davinci_mdio";
reg = <0x4a101000 0x100>;
#address-cells = <1>;
#size-cells = <0>;

View File

@ -509,7 +509,6 @@
ale_entries = <1024>;
bd_ram_size = <0x2000>;
no_bd_ram = <0>;
rx_descs = <64>;
mac_control = <0x20>;
slaves = <2>;
active_slave = <0>;

View File

@ -1628,7 +1628,6 @@
ale_entries = <1024>;
bd_ram_size = <0x2000>;
no_bd_ram = <0>;
rx_descs = <64>;
mac_control = <0x20>;
slaves = <2>;
active_slave = <0>;
@ -1663,7 +1662,7 @@
status = "disabled";
davinci_mdio: mdio@48485000 {
compatible = "ti,davinci_mdio";
compatible = "ti,cpsw-mdio","ti,davinci_mdio";
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "davinci_mdio";

View File

@ -539,8 +539,9 @@
gmac: ethernet@ff290000 {
compatible = "rockchip,rk3288-gmac";
reg = <0xff290000 0x10000>;
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq", "eth_wake_irq";
rockchip,grf = <&grf>;
clocks = <&cru SCLK_MAC>,
<&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,

View File

@ -85,18 +85,193 @@
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
switch0: switch0@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan0";
};
port@1 {
reg = <1>;
label = "lan1";
};
port@2 {
reg = <2>;
label = "lan2";
};
switch0port5: port@5 {
reg = <5>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port6
&switch2port9>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&fec1>;
fixed-link {
speed = <100>;
full-duplex;
};
};
};
};
};
mdio_mux_2: mdio@2 {
reg = <2>;
#address-cells = <1>;
#size-cells = <0>;
switch1: switch1@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan3";
phy-handle = <&switch1phy0>;
};
port@1 {
reg = <1>;
label = "lan4";
phy-handle = <&switch1phy1>;
};
port@2 {
reg = <2>;
label = "lan5";
phy-handle = <&switch1phy2>;
};
switch1port5: port@5 {
reg = <5>;
label = "dsa";
link = <&switch2port9>;
phy-mode = "rgmii-txid";
fixed-link {
speed = <1000>;
full-duplex;
};
};
switch1port6: port@6 {
reg = <6>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
mdio {
#address-cells = <1>;
#size-cells = <0>;
switch1phy0: switch1phy0@0 {
reg = <0>;
};
switch1phy1: switch1phy0@1 {
reg = <1>;
};
switch1phy2: switch1phy0@2 {
reg = <2>;
};
};
};
};
mdio_mux_4: mdio@4 {
reg = <4>;
#address-cells = <1>;
#size-cells = <0>;
reg = <4>;
switch2: switch2@0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
dsa,member = <0 2>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan6";
};
port@1 {
reg = <1>;
label = "lan7";
};
port@2 {
reg = <2>;
label = "lan8";
};
port@3 {
reg = <3>;
label = "optical3";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 2
GPIO_ACTIVE_HIGH>;
};
};
port@4 {
reg = <4>;
label = "optical4";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 3
GPIO_ACTIVE_HIGH>;
};
};
switch2port9: port@9 {
reg = <9>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port5
&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
};
mdio_mux_8: mdio@8 {
@ -106,169 +281,6 @@
};
};
dsa {
compatible = "marvell,dsa";
#address-cells = <2>;
#size-cells = <0>;
dsa,ethernet = <&fec1>;
dsa,mii-bus = <&mdio_mux_1>;
/* 6352 - Primary - 7 ports */
switch0: switch@0-0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x00 0>;
eeprom-length = <512>;
port@0 {
reg = <0>;
label = "lan0";
};
port@1 {
reg = <1>;
label = "lan1";
};
port@2 {
reg = <2>;
label = "lan2";
};
switch0port5: port@5 {
reg = <5>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port6
&switch2port9>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
port@6 {
reg = <6>;
label = "cpu";
fixed-link {
speed = <100>;
full-duplex;
};
};
};
/* 6352 - Secondary - 7 ports */
switch1: switch@0-1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x00 1>;
eeprom-length = <512>;
mii-bus = <&mdio_mux_2>;
port@0 {
reg = <0>;
label = "lan3";
};
port@1 {
reg = <1>;
label = "lan4";
};
port@2 {
reg = <2>;
label = "lan5";
};
switch1port5: port@5 {
reg = <5>;
label = "dsa";
link = <&switch2port9>;
phy-mode = "rgmii-txid";
fixed-link {
speed = <1000>;
full-duplex;
};
};
switch1port6: port@6 {
reg = <6>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
/* 6185 - 10 ports */
switch2: switch@0-2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x00 2>;
mii-bus = <&mdio_mux_4>;
port@0 {
reg = <0>;
label = "lan6";
};
port@1 {
reg = <1>;
label = "lan7";
};
port@2 {
reg = <2>;
label = "lan8";
};
port@3 {
reg = <3>;
label = "optical3";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 2
GPIO_ACTIVE_HIGH>;
};
};
port@4 {
reg = <4>;
label = "optical4";
fixed-link {
speed = <1000>;
full-duplex;
link-gpios = <&gpio6 3
GPIO_ACTIVE_HIGH>;
};
};
switch2port9: port@9 {
reg = <9>;
label = "dsa";
phy-mode = "rgmii-txid";
link = <&switch1port5
&switch0port5>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};
reg_vcc_3v3_mcu: regulator-vcc-3v3-mcu {
compatible = "regulator-fixed";
regulator-name = "vcc_3v3_mcu";

View File

@ -83,3 +83,9 @@
status = "ok";
};
};
&mdio {
sgenet0phy: phy@0 {
reg = <0x0>;
};
};

View File

@ -79,3 +79,15 @@
&mmc0 {
status = "ok";
};
&mdio {
menet0phy: phy@3 {
reg = <0x3>;
};
sgenet0phy: phy@4 {
reg = <0x4>;
};
sgenet1phy: phy@5 {
reg = <0x5>;
};
};

View File

@ -625,10 +625,18 @@
apm,irq-start = <8>;
};
mdio: mdio@1f610000 {
compatible = "apm,xgene-mdio-xfi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x1f610000 0x0 0xd100>;
clocks = <&xge0clk 0>;
};
sgenet0: ethernet@1f610000 {
compatible = "apm,xgene2-sgenet";
status = "disabled";
reg = <0x0 0x1f610000 0x0 0x10000>,
reg = <0x0 0x1f610000 0x0 0xd100>,
<0x0 0x1f600000 0x0 0Xd100>,
<0x0 0x20000000 0x0 0X20000>;
interrupts = <0 96 4>,
@ -637,6 +645,7 @@
clocks = <&xge0clk 0>;
local-mac-address = [00 01 73 00 00 01];
phy-connection-type = "sgmii";
phy-handle = <&sgenet0phy>;
};
xgenet1: ethernet@1f620000 {

View File

@ -237,20 +237,11 @@
clocks = <&socplldiv2 0>;
reg = <0x0 0x1f21c000 0x0 0x1000>;
reg-names = "csr-reg";
csr-mask = <0x3>;
csr-mask = <0xa>;
enable-mask = <0xf>;
clock-output-names = "sge0clk";
};
sge1clk: sge1clk@1f21c000 {
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
clocks = <&socplldiv2 0>;
reg = <0x0 0x1f21c000 0x0 0x1000>;
reg-names = "csr-reg";
csr-mask = <0xc>;
clock-output-names = "sge1clk";
};
xge0clk: xge0clk@1f61c000 {
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
@ -921,6 +912,14 @@
clocks = <&rtcclk 0>;
};
mdio: mdio@17020000 {
compatible = "apm,xgene-mdio-rgmii";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x17020000 0x0 0xd100>;
clocks = <&menetclk 0>;
};
menet: ethernet@17020000 {
compatible = "apm,xgene-enet";
status = "disabled";
@ -934,7 +933,7 @@
/* mac address will be overwritten by the bootloader */
local-mac-address = [00 00 00 00 00 00];
phy-connection-type = "rgmii";
phy-handle = <&menetphy>;
phy-handle = <&menet0phy>,<&menetphy>;
mdio {
compatible = "apm,xgene-mdio";
#address-cells = <1>;
@ -960,6 +959,7 @@
clocks = <&sge0clk 0>;
local-mac-address = [00 00 00 00 00 00];
phy-connection-type = "sgmii";
phy-handle = <&sgenet0phy>;
};
sgenet1: ethernet@1f210030 {
@ -973,9 +973,9 @@
<0x0 0xAD 0x4>;
port-id = <1>;
dma-coherent;
clocks = <&sge1clk 0>;
local-mac-address = [00 00 00 00 00 00];
phy-connection-type = "sgmii";
phy-handle = <&sgenet1phy>;
};
xgenet: ethernet@1f610000 {

View File

@ -52,6 +52,14 @@
};
};
&pci_phy0 {
status = "ok";
};
&pci_phy1 {
status = "ok";
};
&pcie0 {
status = "ok";
};
@ -132,3 +140,11 @@
#size-cells = <1>;
};
};
&mdio_mux_iproc {
mdio@10 {
gphy0: eth-phy@10 {
reg = <0x10>;
};
};
};

View File

@ -263,6 +263,45 @@
IRQ_TYPE_LEVEL_HIGH)>;
};
mdio_mux_iproc: mdio-mux@6602023c {
compatible = "brcm,mdio-mux-iproc";
reg = <0x6602023c 0x14>;
#address-cells = <1>;
#size-cells = <0>;
mdio@0 {
reg = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
pci_phy0: pci-phy@0 {
compatible = "brcm,ns2-pcie-phy";
reg = <0x0>;
#phy-cells = <0>;
status = "disabled";
};
};
mdio@7 {
reg = <0x7>;
#address-cells = <1>;
#size-cells = <0>;
pci_phy1: pci-phy@0 {
compatible = "brcm,ns2-pcie-phy";
reg = <0x0>;
#phy-cells = <0>;
status = "disabled";
};
};
mdio@10 {
reg = <0x10>;
#address-cells = <1>;
#size-cells = <0>;
};
};
timer0: timer@66030000 {
compatible = "arm,sp804", "arm,primecell";
reg = <0x66030000 0x1000>;

View File

@ -1,7 +1,7 @@
/*
* BPF JIT compiler for ARM64
*
* Copyright (C) 2014-2015 Zi Shen Lim <zlim.lnx@gmail.com>
* Copyright (C) 2014-2016 Zi Shen Lim <zlim.lnx@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -55,6 +55,7 @@
#define A64_BL(imm26) A64_BRANCH((imm26) << 2, LINK)
/* Unconditional branch (register) */
#define A64_BR(Rn) aarch64_insn_gen_branch_reg(Rn, AARCH64_INSN_BRANCH_NOLINK)
#define A64_BLR(Rn) aarch64_insn_gen_branch_reg(Rn, AARCH64_INSN_BRANCH_LINK)
#define A64_RET(Rn) aarch64_insn_gen_branch_reg(Rn, AARCH64_INSN_BRANCH_RETURN)

View File

@ -18,6 +18,7 @@
#define pr_fmt(fmt) "bpf_jit: " fmt
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/printk.h>
#include <linux/skbuff.h>
@ -33,6 +34,7 @@ int bpf_jit_enable __read_mostly;
#define TMP_REG_1 (MAX_BPF_JIT_REG + 0)
#define TMP_REG_2 (MAX_BPF_JIT_REG + 1)
#define TCALL_CNT (MAX_BPF_JIT_REG + 2)
/* Map BPF registers to A64 registers */
static const int bpf2a64[] = {
@ -54,6 +56,8 @@ static const int bpf2a64[] = {
/* temporary registers for internal BPF JIT */
[TMP_REG_1] = A64_R(10),
[TMP_REG_2] = A64_R(11),
/* tail_call_cnt */
[TCALL_CNT] = A64_R(26),
/* temporary register for blinding constants */
[BPF_REG_AX] = A64_R(9),
};
@ -146,13 +150,18 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
#define STACK_SIZE STACK_ALIGN(_STACK_SIZE)
static void build_prologue(struct jit_ctx *ctx)
#define PROLOGUE_OFFSET 8
static int build_prologue(struct jit_ctx *ctx)
{
const u8 r6 = bpf2a64[BPF_REG_6];
const u8 r7 = bpf2a64[BPF_REG_7];
const u8 r8 = bpf2a64[BPF_REG_8];
const u8 r9 = bpf2a64[BPF_REG_9];
const u8 fp = bpf2a64[BPF_REG_FP];
const u8 tcc = bpf2a64[TCALL_CNT];
const int idx0 = ctx->idx;
int cur_offset;
/*
* BPF prog stack layout
@ -162,8 +171,6 @@ static void build_prologue(struct jit_ctx *ctx)
* |FP/LR|
* current A64_FP => -16:+-----+
* | ... | callee saved registers
* +-----+
* | | x25/x26
* BPF fp register => -64:+-----+ <= (BPF_FP)
* | |
* | ... | BPF prog stack
@ -183,18 +190,90 @@ static void build_prologue(struct jit_ctx *ctx)
emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx);
emit(A64_MOV(1, A64_FP, A64_SP), ctx);
/* Save callee-saved register */
/* Save callee-saved registers */
emit(A64_PUSH(r6, r7, A64_SP), ctx);
emit(A64_PUSH(r8, r9, A64_SP), ctx);
emit(A64_PUSH(fp, tcc, A64_SP), ctx);
/* Save fp (x25) and x26. SP requires 16 bytes alignment */
emit(A64_PUSH(fp, A64_R(26), A64_SP), ctx);
/* Set up BPF prog stack base register (x25) */
/* Set up BPF prog stack base register */
emit(A64_MOV(1, fp, A64_SP), ctx);
/* Initialize tail_call_cnt */
emit(A64_MOVZ(1, tcc, 0, 0), ctx);
/* Set up function call stack */
emit(A64_SUB_I(1, A64_SP, A64_SP, STACK_SIZE), ctx);
cur_offset = ctx->idx - idx0;
if (cur_offset != PROLOGUE_OFFSET) {
pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n",
cur_offset, PROLOGUE_OFFSET);
return -1;
}
return 0;
}
static int out_offset = -1; /* initialized on the first pass of build_body() */
static int emit_bpf_tail_call(struct jit_ctx *ctx)
{
/* bpf_tail_call(void *prog_ctx, struct bpf_array *array, u64 index) */
const u8 r2 = bpf2a64[BPF_REG_2];
const u8 r3 = bpf2a64[BPF_REG_3];
const u8 tmp = bpf2a64[TMP_REG_1];
const u8 prg = bpf2a64[TMP_REG_2];
const u8 tcc = bpf2a64[TCALL_CNT];
const int idx0 = ctx->idx;
#define cur_offset (ctx->idx - idx0)
#define jmp_offset (out_offset - (cur_offset))
size_t off;
/* if (index >= array->map.max_entries)
* goto out;
*/
off = offsetof(struct bpf_array, map.max_entries);
emit_a64_mov_i64(tmp, off, ctx);
emit(A64_LDR32(tmp, r2, tmp), ctx);
emit(A64_CMP(0, r3, tmp), ctx);
emit(A64_B_(A64_COND_GE, jmp_offset), ctx);
/* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
* goto out;
* tail_call_cnt++;
*/
emit_a64_mov_i64(tmp, MAX_TAIL_CALL_CNT, ctx);
emit(A64_CMP(1, tcc, tmp), ctx);
emit(A64_B_(A64_COND_GT, jmp_offset), ctx);
emit(A64_ADD_I(1, tcc, tcc, 1), ctx);
/* prog = array->ptrs[index];
* if (prog == NULL)
* goto out;
*/
off = offsetof(struct bpf_array, ptrs);
emit_a64_mov_i64(tmp, off, ctx);
emit(A64_LDR64(tmp, r2, tmp), ctx);
emit(A64_LDR64(prg, tmp, r3), ctx);
emit(A64_CBZ(1, prg, jmp_offset), ctx);
/* goto *(prog->bpf_func + prologue_size); */
off = offsetof(struct bpf_prog, bpf_func);
emit_a64_mov_i64(tmp, off, ctx);
emit(A64_LDR64(tmp, prg, tmp), ctx);
emit(A64_ADD_I(1, tmp, tmp, sizeof(u32) * PROLOGUE_OFFSET), ctx);
emit(A64_BR(tmp), ctx);
/* out: */
if (out_offset == -1)
out_offset = cur_offset;
if (cur_offset != out_offset) {
pr_err_once("tail_call out_offset = %d, expected %d!\n",
cur_offset, out_offset);
return -1;
}
return 0;
#undef cur_offset
#undef jmp_offset
}
static void build_epilogue(struct jit_ctx *ctx)
@ -499,13 +578,15 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
const u64 func = (u64)__bpf_call_base + imm;
emit_a64_mov_i64(tmp, func, ctx);
emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx);
emit(A64_MOV(1, A64_FP, A64_SP), ctx);
emit(A64_BLR(tmp), ctx);
emit(A64_MOV(1, r0, A64_R(0)), ctx);
emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx);
break;
}
/* tail call */
case BPF_JMP | BPF_CALL | BPF_X:
if (emit_bpf_tail_call(ctx))
return -EFAULT;
break;
/* function return */
case BPF_JMP | BPF_EXIT:
/* Optimization: when last instruction is EXIT,
@ -650,11 +731,8 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
emit_a64_mov_i64(r3, size, ctx);
emit(A64_SUB_I(1, r4, fp, STACK_SIZE), ctx);
emit_a64_mov_i64(r5, (unsigned long)bpf_load_pointer, ctx);
emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx);
emit(A64_MOV(1, A64_FP, A64_SP), ctx);
emit(A64_BLR(r5), ctx);
emit(A64_MOV(1, r0, A64_R(0)), ctx);
emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx);
jmp_offset = epilogue_offset(ctx);
check_imm19(jmp_offset);
@ -780,7 +858,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
goto out_off;
}
build_prologue(&ctx);
if (build_prologue(&ctx)) {
prog = orig_prog;
goto out_off;
}
ctx.epilogue_offset = ctx.idx;
build_epilogue(&ctx);

View File

@ -974,12 +974,15 @@ static int perf_push_sample(struct perf_event *event, struct sf_raw_sample *sfr)
struct pt_regs regs;
struct perf_sf_sde_regs *sde_regs;
struct perf_sample_data data;
struct perf_raw_record raw;
struct perf_raw_record raw = {
.frag = {
.size = sfr->size,
.data = sfr,
},
};
/* Setup perf sample */
perf_sample_data_init(&data, 0, event->hw.last_period);
raw.size = sfr->size;
raw.data = sfr;
data.raw = &raw;
/* Setup pt_regs to look like an CPU-measurement external interrupt

View File

@ -655,8 +655,12 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
}
if (event->attr.sample_type & PERF_SAMPLE_RAW) {
raw.size = sizeof(u32) + ibs_data.size;
raw.data = ibs_data.data;
raw = (struct perf_raw_record){
.frag = {
.size = sizeof(u32) + ibs_data.size,
.data = ibs_data.data,
},
};
data.raw = &raw;
}

View File

@ -2795,9 +2795,7 @@ static int hrz_probe(struct pci_dev *pci_dev,
dev->atm_dev->ci_range.vpi_bits = vpi_bits;
dev->atm_dev->ci_range.vci_bits = 10-vpi_bits;
init_timer(&dev->housekeeping);
dev->housekeeping.function = do_housekeeping;
dev->housekeeping.data = (unsigned long) dev;
setup_timer(&dev->housekeeping, do_housekeeping, (unsigned long) dev);
mod_timer(&dev->housekeeping, jiffies);
out:

View File

@ -874,7 +874,8 @@ static scq_info *get_scq(ns_dev *card, int size, u32 scd)
scq->skb = kmalloc(sizeof(struct sk_buff *) *
(size / NS_SCQE_SIZE), GFP_KERNEL);
if (!scq->skb) {
kfree(scq->org);
dma_free_coherent(&card->pcidev->dev,
2 * size, scq->org, scq->dma);
kfree(scq);
return NULL;
}

View File

@ -76,9 +76,16 @@ config BCMA_PFLASH
default y
config BCMA_SFLASH
bool
depends on BCMA_DRIVER_MIPS
bool "ChipCommon-attached serial flash support"
depends on BCMA_HOST_SOC
default y
help
Some cheap devices have serial flash connected to the ChipCommon
instead of independent SPI controller. It requires using a separated
driver that implements ChipCommon specific interface communication.
Enabling this symbol will let bcma recognize serial flash and register
it as platform device.
config BCMA_NFLASH
bool

View File

@ -33,11 +33,12 @@ static bool bcma_wait_reg(struct bcma_bus *bus, void __iomem *addr, u32 mask,
void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
{
struct bcma_bus *bus = ccb->core->bus;
void __iomem *mii = ccb->mii;
writel(offset, ccb->mii + 0x00);
bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
writel(value, ccb->mii + 0x04);
bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
writel(offset, mii + BCMA_CCB_MII_MNG_CTL);
bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
writel(value, mii + BCMA_CCB_MII_MNG_CMD_DATA);
bcma_wait_reg(bus, mii + BCMA_CCB_MII_MNG_CTL, 0x0100, 0x0000, 100);
}
EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write);

View File

@ -295,6 +295,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_FOXCONN, 0xe092) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },

View File

@ -123,6 +123,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3472) },
{ USB_DEVICE(0x13d3, 0x3474) },
{ USB_DEVICE(0x13d3, 0x3487) },
{ USB_DEVICE(0x13d3, 0x3490) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
@ -190,6 +191,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3487), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3490), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },

View File

@ -274,6 +274,8 @@ static int bpa10x_setup(struct hci_dev *hdev)
BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
hci_set_fw_info(hdev, "%s", skb->data + 1);
kfree_skb(skb);
return 0;
}

View File

@ -138,7 +138,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
if (event->length > 3 && event->data[3])
priv->btmrvl_dev.dev_type = HCI_AMP;
else
priv->btmrvl_dev.dev_type = HCI_BREDR;
priv->btmrvl_dev.dev_type = HCI_PRIMARY;
BT_DBG("dev_type: %d", priv->btmrvl_dev.dev_type);
} else if (priv->btmrvl_dev.sendcmdflag &&

View File

@ -1071,7 +1071,6 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
{
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
int ret = 0;
int buf_block_len;
int blksz;
int i = 0;
u8 *buf = NULL;
@ -1083,9 +1082,13 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
return -EINVAL;
}
blksz = DIV_ROUND_UP(nb, SDIO_BLOCK_SIZE) * SDIO_BLOCK_SIZE;
buf = payload;
if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1)) {
tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN);
if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1) ||
nb < blksz) {
tmpbufsz = ALIGN_SZ(blksz, BTSDIO_DMA_ALIGN) +
BTSDIO_DMA_ALIGN;
tmpbuf = kzalloc(tmpbufsz, GFP_KERNEL);
if (!tmpbuf)
return -ENOMEM;
@ -1093,15 +1096,12 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
memcpy(buf, payload, nb);
}
blksz = SDIO_BLOCK_SIZE;
buf_block_len = DIV_ROUND_UP(nb, blksz);
sdio_claim_host(card->func);
do {
/* Transfer data to card */
ret = sdio_writesb(card->func, card->ioport, buf,
buf_block_len * blksz);
blksz);
if (ret < 0) {
i++;
BT_ERR("i=%d writesb failed: %d", i, ret);
@ -1625,6 +1625,7 @@ static int btmrvl_sdio_suspend(struct device *dev)
if (priv->adapter->hs_state != HS_ACTIVATED) {
if (btmrvl_enable_hs(priv)) {
BT_ERR("HS not actived, suspend failed!");
priv->adapter->is_suspending = false;
return -EBUSY;
}
}

View File

@ -311,7 +311,7 @@ static int btsdio_probe(struct sdio_func *func,
if (id->class == SDIO_CLASS_BT_AMP)
hdev->dev_type = HCI_AMP;
else
hdev->dev_type = HCI_BREDR;
hdev->dev_type = HCI_PRIMARY;
data->hdev = hdev;

View File

@ -237,6 +237,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3487), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3490), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@ -249,6 +250,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
@ -314,6 +316,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
{ USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW },
{ USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL },
/* Other Intel Bluetooth devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01),
@ -2103,10 +2106,14 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
/* With this Intel bootloader only the hardware variant and device
* revision information are used to select the right firmware.
*
* Currently this bootloader support is limited to hardware variant
* iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b).
* The firmware filename is ibt-<hw_variant>-<dev_revid>.sfi.
*
* Currently the supported hardware variants are:
* 11 (0x0b) for iBT3.0 (LnP/SfP)
* 12 (0x0c) for iBT3.5 (WsP)
*/
snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi",
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi",
le16_to_cpu(ver.hw_variant),
le16_to_cpu(params->dev_revid));
err = request_firmware(&fw, fwname, &hdev->dev);
@ -2122,7 +2129,8 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
/* Save the DDC file name for later use to apply once the firmware
* downloading is done.
*/
snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc",
le16_to_cpu(ver.hw_variant),
le16_to_cpu(params->dev_revid));
kfree_skb(skb);
@ -2825,7 +2833,7 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_AMP)
hdev->dev_type = HCI_AMP;
else
hdev->dev_type = HCI_BREDR;
hdev->dev_type = HCI_PRIMARY;
data->hdev = hdev;

View File

@ -51,7 +51,7 @@
*/
struct ti_st {
struct hci_dev *hdev;
char reg_status;
int reg_status;
long (*st_write) (struct sk_buff *);
struct completion wait_reg_completion;
};
@ -83,7 +83,7 @@ static inline void ti_st_tx_complete(struct ti_st *hst, int pkt_type)
* status.ti_st_open() function will wait for signal from this
* API when st_register() function returns ST_PENDING.
*/
static void st_reg_completion_cb(void *priv_data, char data)
static void st_reg_completion_cb(void *priv_data, int data)
{
struct ti_st *lhst = priv_data;

View File

@ -537,9 +537,7 @@ static int intel_setup(struct hci_uart *hu)
{
static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
0x00, 0x08, 0x04, 0x00 };
static const u8 lpm_param[] = { 0x03, 0x07, 0x01, 0x0b };
struct intel_data *intel = hu->priv;
struct intel_device *idev = NULL;
struct hci_dev *hdev = hu->hdev;
struct sk_buff *skb;
struct intel_version ver;
@ -884,35 +882,23 @@ static int intel_setup(struct hci_uart *hu)
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
/* Enable LPM if matching pdev with wakeup enabled */
/* Enable LPM if matching pdev with wakeup enabled, set TX active
* until further LPM TX notification.
*/
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
struct intel_device *dev = list_entry(p, struct intel_device,
list);
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
if (device_may_wakeup(&dev->pdev->dev))
idev = dev;
if (device_may_wakeup(&dev->pdev->dev)) {
set_bit(STATE_LPM_ENABLED, &intel->flags);
set_bit(STATE_TX_ACTIVE, &intel->flags);
}
break;
}
}
mutex_unlock(&intel_device_list_lock);
if (!idev)
goto no_lpm;
bt_dev_info(hdev, "Enabling LPM");
skb = __hci_cmd_sync(hdev, 0xfc8b, sizeof(lpm_param), lpm_param,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to enable LPM");
goto no_lpm;
}
kfree_skb(skb);
set_bit(STATE_LPM_ENABLED, &intel->flags);
no_lpm:
/* Ignore errors, device can work without DDC parameters */
btintel_load_ddc_config(hdev, fwname);

View File

@ -609,7 +609,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
hdev->dev_type = HCI_AMP;
else
hdev->dev_type = HCI_BREDR;
hdev->dev_type = HCI_PRIMARY;
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
return 0;

View File

@ -97,10 +97,10 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
if (data->hdev)
return -EBADFD;
/* bits 0-1 are dev_type (BR/EDR or AMP) */
/* bits 0-1 are dev_type (Primary or AMP) */
dev_type = opcode & 0x03;
if (dev_type != HCI_BREDR && dev_type != HCI_AMP)
if (dev_type != HCI_PRIMARY && dev_type != HCI_AMP)
return -EINVAL;
/* bits 2-5 are reserved (must be zero) */
@ -316,7 +316,7 @@ static void vhci_open_timeout(struct work_struct *work)
struct vhci_data *data = container_of(work, struct vhci_data,
open_timeout.work);
vhci_create_device(data, amp ? HCI_AMP : HCI_BREDR);
vhci_create_device(data, amp ? HCI_AMP : HCI_PRIMARY);
}
static int vhci_open(struct inode *inode, struct file *file)

View File

@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/init.h>
@ -390,5 +389,4 @@ static int __init cn_proc_init(void)
}
return 0;
}
module_init(cn_proc_init);
device_initcall(cn_proc_init);

View File

@ -232,7 +232,7 @@ static void stamp_send_wqe(struct mlx4_ib_qp *qp, int n, int size)
}
} else {
ctrl = buf = get_send_wqe(qp, n & (qp->sq.wqe_cnt - 1));
s = (ctrl->fence_size & 0x3f) << 4;
s = (ctrl->qpn_vlan.fence_size & 0x3f) << 4;
for (i = 64; i < s; i += 64) {
wqe = buf + i;
*wqe = cpu_to_be32(0xffffffff);
@ -264,7 +264,7 @@ static void post_nop_wqe(struct mlx4_ib_qp *qp, int n, int size)
inl->byte_count = cpu_to_be32(1 << 31 | (size - s - sizeof *inl));
}
ctrl->srcrb_flags = 0;
ctrl->fence_size = size / 16;
ctrl->qpn_vlan.fence_size = size / 16;
/*
* Make sure descriptor is fully written before setting ownership bit
* (because HW can start executing as soon as we do).
@ -1992,7 +1992,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
ctrl = get_send_wqe(qp, i);
ctrl->owner_opcode = cpu_to_be32(1 << 31);
if (qp->sq_max_wqes_per_wr == 1)
ctrl->fence_size = 1 << (qp->sq.wqe_shift - 4);
ctrl->qpn_vlan.fence_size =
1 << (qp->sq.wqe_shift - 4);
stamp_send_wqe(qp, i, 1 << qp->sq.wqe_shift);
}
@ -3169,8 +3170,8 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
wmb();
*lso_wqe = lso_hdr_sz;
ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ?
MLX4_WQE_CTRL_FENCE : 0) | size;
ctrl->qpn_vlan.fence_size = (wr->send_flags & IB_SEND_FENCE ?
MLX4_WQE_CTRL_FENCE : 0) | size;
/*
* Make sure descriptor is fully written before

View File

@ -1528,21 +1528,18 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
{
struct mlx5_flow_table *ft = ft_prio->flow_table;
struct mlx5_ib_flow_handler *handler;
struct mlx5_flow_spec *spec;
void *ib_flow = flow_attr + 1;
u8 match_criteria_enable = 0;
unsigned int spec_index;
u32 *match_c;
u32 *match_v;
u32 action;
int err = 0;
if (!is_valid_attr(flow_attr))
return ERR_PTR(-EINVAL);
match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
spec = mlx5_vzalloc(sizeof(*spec));
handler = kzalloc(sizeof(*handler), GFP_KERNEL);
if (!handler || !match_c || !match_v) {
if (!handler || !spec) {
err = -ENOMEM;
goto free;
}
@ -1550,7 +1547,8 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
INIT_LIST_HEAD(&handler->list);
for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) {
err = parse_flow_attr(match_c, match_v, ib_flow);
err = parse_flow_attr(spec->match_criteria,
spec->match_value, ib_flow);
if (err < 0)
goto free;
@ -1558,11 +1556,11 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
}
/* Outer header support only */
match_criteria_enable = (!outer_header_zero(match_c)) << 0;
spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria))
<< 0;
action = dst ? MLX5_FLOW_CONTEXT_ACTION_FWD_DEST :
MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
handler->rule = mlx5_add_flow_rule(ft, match_criteria_enable,
match_c, match_v,
handler->rule = mlx5_add_flow_rule(ft, spec,
action,
MLX5_FS_DEFAULT_FLOW_TAG,
dst);
@ -1578,8 +1576,7 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev,
free:
if (err)
kfree(handler);
kfree(match_c);
kfree(match_v);
kvfree(spec);
return err ? ERR_PTR(err) : handler;
}

View File

@ -445,32 +445,32 @@ void divasa_unmap_pci_bar(void __iomem *bar)
/*********************************************************
** I/O port access
*********************************************************/
byte __inline__ inpp(void __iomem *addr)
inline byte inpp(void __iomem *addr)
{
return (inb((unsigned long) addr));
}
word __inline__ inppw(void __iomem *addr)
inline word inppw(void __iomem *addr)
{
return (inw((unsigned long) addr));
}
void __inline__ inppw_buffer(void __iomem *addr, void *P, int length)
inline void inppw_buffer(void __iomem *addr, void *P, int length)
{
insw((unsigned long) addr, (word *) P, length >> 1);
}
void __inline__ outppw_buffer(void __iomem *addr, void *P, int length)
inline void outppw_buffer(void __iomem *addr, void *P, int length)
{
outsw((unsigned long) addr, (word *) P, length >> 1);
}
void __inline__ outppw(void __iomem *addr, word w)
inline void outppw(void __iomem *addr, word w)
{
outw(w, (unsigned long) addr);
}
void __inline__ outpp(void __iomem *addr, word p)
inline void outpp(void __iomem *addr, word p)
{
outb(p, (unsigned long) addr);
}

View File

@ -203,7 +203,7 @@ void PCIread(byte bus, byte func, int offset, void *data, int length, void *pci_
/*
** I/O Port utilities
*/
int diva_os_register_io_port(void *adapter, int register, unsigned long port,
int diva_os_register_io_port(void *adapter, int reg, unsigned long port,
unsigned long length, const char *name, int id);
/*
** I/O port access abstraction
@ -271,13 +271,13 @@ void diva_os_get_time(dword *sec, dword *usec);
** atomic operation, fake because we use threads
*/
typedef int diva_os_atomic_t;
static diva_os_atomic_t __inline__
static inline diva_os_atomic_t
diva_os_atomic_increment(diva_os_atomic_t *pv)
{
*pv += 1;
return (*pv);
}
static diva_os_atomic_t __inline__
static inline diva_os_atomic_t
diva_os_atomic_decrement(diva_os_atomic_t *pv)
{
*pv -= 1;

View File

@ -1472,7 +1472,7 @@ static long fm_st_receive(void *arg, struct sk_buff *skb)
* Called by ST layer to indicate protocol registration completion
* status.
*/
static void fm_st_reg_comp_cb(void *arg, char data)
static void fm_st_reg_comp_cb(void *arg, int data)
{
struct fmdev *fmdev;

View File

@ -141,7 +141,7 @@ static void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
* This function is being called with spin lock held, protocol drivers are
* only expected to complete their waits and do nothing more than that.
*/
static void st_reg_complete(struct st_data_s *st_gdata, char err)
static void st_reg_complete(struct st_data_s *st_gdata, int err)
{
unsigned char i = 0;
pr_info(" %s ", __func__);

View File

@ -114,7 +114,7 @@ config MTD_SST25L
config MTD_BCM47XXSFLASH
tristate "R/O support for serial flash on BCMA bus"
depends on BCMA_SFLASH
depends on BCMA_SFLASH && (MIPS || ARM)
help
BCMA bus can have various flash memories attached, they are
registered by bcma as platform devices. This enables driver for

View File

@ -1422,7 +1422,16 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
return -EINVAL;
}
if (slave_ops->ndo_set_mac_address == NULL) {
if (slave_dev->type == ARPHRD_INFINIBAND &&
BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
netdev_warn(bond_dev, "Type (%d) supports only active-backup mode\n",
slave_dev->type);
res = -EOPNOTSUPP;
goto err_undo_flags;
}
if (!slave_ops->ndo_set_mac_address ||
slave_dev->type == ARPHRD_INFINIBAND) {
netdev_warn(bond_dev, "The slave device specified does not support setting the MAC address\n");
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
@ -4138,6 +4147,8 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_add_slave = bond_enslave,
.ndo_del_slave = bond_release,
.ndo_fix_features = bond_fix_features,
.ndo_neigh_construct = netdev_default_l2upper_neigh_construct,
.ndo_neigh_destroy = netdev_default_l2upper_neigh_destroy,
.ndo_bridge_setlink = switchdev_port_bridge_setlink,
.ndo_bridge_getlink = switchdev_port_bridge_getlink,
.ndo_bridge_dellink = switchdev_port_bridge_dellink,
@ -4608,26 +4619,6 @@ static int bond_check_params(struct bond_params *params)
return 0;
}
static struct lock_class_key bonding_netdev_xmit_lock_key;
static struct lock_class_key bonding_netdev_addr_lock_key;
static struct lock_class_key bonding_tx_busylock_key;
static void bond_set_lockdep_class_one(struct net_device *dev,
struct netdev_queue *txq,
void *_unused)
{
lockdep_set_class(&txq->_xmit_lock,
&bonding_netdev_xmit_lock_key);
}
static void bond_set_lockdep_class(struct net_device *dev)
{
lockdep_set_class(&dev->addr_list_lock,
&bonding_netdev_addr_lock_key);
netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL);
dev->qdisc_tx_busylock = &bonding_tx_busylock_key;
}
/* Called from registration process */
static int bond_init(struct net_device *bond_dev)
{
@ -4640,7 +4631,7 @@ static int bond_init(struct net_device *bond_dev)
if (!bond->wq)
return -ENOMEM;
bond_set_lockdep_class(bond_dev);
netdev_lockdep_set_classes(bond_dev);
list_add_tail(&bond->bond_list, &bn->dev_list);

View File

@ -1201,7 +1201,7 @@ static int cfhsi_open(struct net_device *ndev)
clear_bit(CFHSI_AWAKE, &cfhsi->bits);
/* Create work thread. */
cfhsi->wq = create_singlethread_workqueue(cfhsi->ndev->name);
cfhsi->wq = alloc_ordered_workqueue(cfhsi->ndev->name, WQ_MEM_RECLAIM);
if (!cfhsi->wq) {
netdev_err(cfhsi->ndev, "%s: Failed to create work queue.\n",
__func__);
@ -1267,9 +1267,6 @@ static int cfhsi_close(struct net_device *ndev)
/* going to shutdown driver */
set_bit(CFHSI_SHUTDOWN, &cfhsi->bits);
/* Flush workqueue */
flush_workqueue(cfhsi->wq);
/* Delete timers if pending */
del_timer_sync(&cfhsi->inactivity_timer);
del_timer_sync(&cfhsi->rx_slowpath_timer);

View File

@ -104,16 +104,6 @@ config CAN_JANZ_ICAN3
This driver can also be built as a module. If so, the module will be
called janz-ican3.ko.
config CAN_RCAR
tristate "Renesas R-Car CAN controller"
depends on ARCH_RENESAS || ARM
---help---
Say Y here if you want to use CAN controller found on Renesas R-Car
SoCs.
To compile this driver as a module, choose M here: the module will
be called rcar_can.
config CAN_SUN4I
tristate "Allwinner A10 CAN controller"
depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
@ -152,6 +142,7 @@ source "drivers/net/can/cc770/Kconfig"
source "drivers/net/can/ifi_canfd/Kconfig"
source "drivers/net/can/m_can/Kconfig"
source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/rcar/Kconfig"
source "drivers/net/can/sja1000/Kconfig"
source "drivers/net/can/softing/Kconfig"
source "drivers/net/can/spi/Kconfig"

View File

@ -10,6 +10,7 @@ can-dev-y := dev.o
can-dev-$(CONFIG_CAN_LEDS) += led.o
obj-y += rcar/
obj-y += spi/
obj-y += usb/
obj-y += softing/
@ -24,7 +25,6 @@ obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_MSCAN) += mscan/
obj-$(CONFIG_CAN_M_CAN) += m_can/
obj-$(CONFIG_CAN_RCAR) += rcar_can.o
obj-$(CONFIG_CAN_SJA1000) += sja1000/
obj-$(CONFIG_CAN_SUN4I) += sun4i_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o

View File

@ -69,6 +69,7 @@ EXPORT_SYMBOL_GPL(can_len2dlc);
#ifdef CONFIG_CAN_CALC_BITTIMING
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
#define CAN_CALC_SYNC_SEG 1
/*
* Bit-timing calculation derived from:
@ -83,98 +84,126 @@ EXPORT_SYMBOL_GPL(can_len2dlc);
* registers of the CAN controller. You can find more information
* in the header file linux/can/netlink.h.
*/
static int can_update_spt(const struct can_bittiming_const *btc,
int sampl_pt, int tseg, int *tseg1, int *tseg2)
static int can_update_sample_point(const struct can_bittiming_const *btc,
unsigned int sample_point_nominal, unsigned int tseg,
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
unsigned int *sample_point_error_ptr)
{
*tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
if (*tseg2 < btc->tseg2_min)
*tseg2 = btc->tseg2_min;
if (*tseg2 > btc->tseg2_max)
*tseg2 = btc->tseg2_max;
*tseg1 = tseg - *tseg2;
if (*tseg1 > btc->tseg1_max) {
*tseg1 = btc->tseg1_max;
*tseg2 = tseg - *tseg1;
unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
unsigned int sample_point, best_sample_point = 0;
unsigned int tseg1, tseg2;
int i;
for (i = 0; i <= 1; i++) {
tseg2 = tseg + CAN_CALC_SYNC_SEG - (sample_point_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000 - i;
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
tseg1 = tseg - tseg2;
if (tseg1 > btc->tseg1_max) {
tseg1 = btc->tseg1_max;
tseg2 = tseg - tseg1;
}
sample_point = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG);
sample_point_error = abs(sample_point_nominal - sample_point);
if ((sample_point <= sample_point_nominal) && (sample_point_error < best_sample_point_error)) {
best_sample_point = sample_point;
best_sample_point_error = sample_point_error;
*tseg1_ptr = tseg1;
*tseg2_ptr = tseg2;
}
}
return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
if (sample_point_error_ptr)
*sample_point_error_ptr = best_sample_point_error;
return best_sample_point;
}
static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc)
{
struct can_priv *priv = netdev_priv(dev);
long 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;
unsigned int bitrate; /* current bitrate */
unsigned int bitrate_error; /* difference between current and nominal value */
unsigned int best_bitrate_error = UINT_MAX;
unsigned int sample_point_error; /* difference between current and nominal value */
unsigned int best_sample_point_error = UINT_MAX;
unsigned int sample_point_nominal; /* nominal sample point */
unsigned int best_tseg = 0; /* current best value for tseg */
unsigned int best_brp = 0; /* current best value for brp */
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
u64 v64;
/* Use CiA recommended sample points */
if (bt->sample_point) {
sampl_pt = bt->sample_point;
sample_point_nominal = bt->sample_point;
} else {
if (bt->bitrate > 800000)
sampl_pt = 750;
sample_point_nominal = 750;
else if (bt->bitrate > 500000)
sampl_pt = 800;
sample_point_nominal = 800;
else
sampl_pt = 875;
sample_point_nominal = 875;
}
/* tseg even = round down, odd = round up */
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
tsegall = 1 + tseg / 2;
tsegall = CAN_CALC_SYNC_SEG + tseg / 2;
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
/* chose brp step which is possible in system */
/* choose brp step which is possible in system */
brp = (brp / btc->brp_inc) * btc->brp_inc;
if ((brp < btc->brp_min) || (brp > btc->brp_max))
continue;
rate = priv->clock.freq / (brp * tsegall);
error = bt->bitrate - rate;
bitrate = priv->clock.freq / (brp * tsegall);
bitrate_error = abs(bt->bitrate - bitrate);
/* tseg brp biterror */
if (error < 0)
error = -error;
if (error > best_error)
if (bitrate_error > best_bitrate_error)
continue;
best_error = error;
if (error == 0) {
spt = can_update_spt(btc, sampl_pt, tseg / 2,
&tseg1, &tseg2);
error = sampl_pt - spt;
if (error < 0)
error = -error;
if (error > spt_error)
continue;
spt_error = error;
}
/* reset sample point error if we have a better bitrate */
if (bitrate_error < best_bitrate_error)
best_sample_point_error = UINT_MAX;
can_update_sample_point(btc, sample_point_nominal, tseg / 2, &tseg1, &tseg2, &sample_point_error);
if (sample_point_error > best_sample_point_error)
continue;
best_sample_point_error = sample_point_error;
best_bitrate_error = bitrate_error;
best_tseg = tseg / 2;
best_brp = brp;
if (error == 0)
if (bitrate_error == 0 && sample_point_error == 0)
break;
}
if (best_error) {
if (best_bitrate_error) {
/* Error in one-tenth of a percent */
error = (best_error * 1000) / bt->bitrate;
if (error > CAN_CALC_MAX_ERROR) {
v64 = (u64)best_bitrate_error * 1000;
do_div(v64, bt->bitrate);
bitrate_error = (u32)v64;
if (bitrate_error > CAN_CALC_MAX_ERROR) {
netdev_err(dev,
"bitrate error %ld.%ld%% too high\n",
error / 10, error % 10);
"bitrate error %d.%d%% too high\n",
bitrate_error / 10, bitrate_error % 10);
return -EDOM;
} else {
netdev_warn(dev, "bitrate error %ld.%ld%%\n",
error / 10, error % 10);
}
netdev_warn(dev, "bitrate error %d.%d%%\n",
bitrate_error / 10, bitrate_error % 10);
}
/* real sample point */
bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg,
&tseg1, &tseg2);
bt->sample_point = can_update_sample_point(btc, sample_point_nominal, best_tseg,
&tseg1, &tseg2, NULL);
v64 = (u64)best_brp * 1000000000UL;
v64 = (u64)best_brp * 1000 * 1000 * 1000;
do_div(v64, priv->clock.freq);
bt->tq = (u32)v64;
bt->prop_seg = tseg1 / 2;
@ -182,9 +211,9 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
bt->phase_seg2 = tseg2;
/* check for sjw user settings */
if (!bt->sjw || !btc->sjw_max)
if (!bt->sjw || !btc->sjw_max) {
bt->sjw = 1;
else {
} else {
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
if (bt->sjw > btc->sjw_max)
bt->sjw = btc->sjw_max;
@ -194,8 +223,9 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
}
bt->brp = best_brp;
/* real bit-rate */
bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1));
/* real bitrate */
bt->bitrate = priv->clock.freq / (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2));
return 0;
}

View File

@ -0,0 +1,21 @@
config CAN_RCAR
tristate "Renesas R-Car CAN controller"
depends on ARCH_RENESAS || ARM
---help---
Say Y here if you want to use CAN controller found on Renesas R-Car
SoCs.
To compile this driver as a module, choose M here: the module will
be called rcar_can.
config CAN_RCAR_CANFD
tristate "Renesas R-Car CAN FD controller"
depends on ARCH_RENESAS || ARM
---help---
Say Y here if you want to use CAN FD controller found on
Renesas R-Car SoCs. The driver puts the controller in CAN FD only
mode, which can interoperate with CAN2.0 nodes but does not support
dedicated CAN 2.0 mode.
To compile this driver as a module, choose M here: the module will
be called rcar_canfd.

View File

@ -0,0 +1,6 @@
#
# Makefile for the Renesas R-Car CAN & CAN FD controller drivers
#
obj-$(CONFIG_CAN_RCAR) += rcar_can.o
obj-$(CONFIG_CAN_RCAR_CANFD) += rcar_canfd.o

File diff suppressed because it is too large Load Diff

View File

@ -203,14 +203,4 @@ static struct isa_driver tscan1_isa_driver = {
},
};
static int __init tscan1_init(void)
{
return isa_register_driver(&tscan1_isa_driver, TSCAN1_MAXDEV);
}
module_init(tscan1_init);
static void __exit tscan1_exit(void)
{
isa_unregister_driver(&tscan1_isa_driver);
}
module_exit(tscan1_exit);
module_isa_driver(tscan1_isa_driver, TSCAN1_MAXDEV);

View File

@ -354,7 +354,7 @@ static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct slcan *sl = netdev_priv(dev);
if (skb->len != sizeof(struct can_frame))
if (skb->len != CAN_MTU)
goto out;
spin_lock(&sl->lock);
@ -442,7 +442,7 @@ static void slc_setup(struct net_device *dev)
dev->addr_len = 0;
dev->tx_queue_len = 10;
dev->mtu = sizeof(struct can_frame);
dev->mtu = CAN_MTU;
dev->type = ARPHRD_CAN;
/* New-style flags. */

View File

@ -1145,8 +1145,11 @@ static int mcp251x_can_probe(struct spi_device *spi)
/* Here is OK to not lock the MCP, no one knows about it yet */
ret = mcp251x_hw_probe(spi);
if (ret)
if (ret) {
if (ret == -ENODEV)
dev_err(&spi->dev, "Cannot initialize MCP%x. Wrong wiring?\n", priv->model);
goto error_probe;
}
mcp251x_hw_sleep(spi);
@ -1156,6 +1159,7 @@ static int mcp251x_can_probe(struct spi_device *spi)
devm_can_led_init(net);
netdev_info(net, "MCP%x successfully initialized.\n", priv->model);
return 0;
error_probe:
@ -1168,6 +1172,7 @@ static int mcp251x_can_probe(struct spi_device *spi)
out_free:
free_candev(net);
dev_err(&spi->dev, "Probe failed, err=%d\n", -ret);
return ret;
}

View File

@ -44,7 +44,9 @@ enum gs_usb_breq {
GS_USB_BREQ_MODE,
GS_USB_BREQ_BERR,
GS_USB_BREQ_BT_CONST,
GS_USB_BREQ_DEVICE_CONFIG
GS_USB_BREQ_DEVICE_CONFIG,
GS_USB_BREQ_TIMESTAMP,
GS_USB_BREQ_IDENTIFY,
};
enum gs_can_mode {
@ -63,6 +65,11 @@ enum gs_can_state {
GS_CAN_STATE_SLEEPING
};
enum gs_can_identify_mode {
GS_CAN_IDENTIFY_OFF = 0,
GS_CAN_IDENTIFY_ON
};
/* data types passed between host and device */
struct gs_host_config {
u32 byte_order;
@ -82,10 +89,10 @@ struct gs_device_config {
} __packed;
#define GS_CAN_MODE_NORMAL 0
#define GS_CAN_MODE_LISTEN_ONLY (1<<0)
#define GS_CAN_MODE_LOOP_BACK (1<<1)
#define GS_CAN_MODE_TRIPLE_SAMPLE (1<<2)
#define GS_CAN_MODE_ONE_SHOT (1<<3)
#define GS_CAN_MODE_LISTEN_ONLY BIT(0)
#define GS_CAN_MODE_LOOP_BACK BIT(1)
#define GS_CAN_MODE_TRIPLE_SAMPLE BIT(2)
#define GS_CAN_MODE_ONE_SHOT BIT(3)
struct gs_device_mode {
u32 mode;
@ -106,10 +113,16 @@ struct gs_device_bittiming {
u32 brp;
} __packed;
#define GS_CAN_FEATURE_LISTEN_ONLY (1<<0)
#define GS_CAN_FEATURE_LOOP_BACK (1<<1)
#define GS_CAN_FEATURE_TRIPLE_SAMPLE (1<<2)
#define GS_CAN_FEATURE_ONE_SHOT (1<<3)
struct gs_identify_mode {
u32 mode;
} __packed;
#define GS_CAN_FEATURE_LISTEN_ONLY BIT(0)
#define GS_CAN_FEATURE_LOOP_BACK BIT(1)
#define GS_CAN_FEATURE_TRIPLE_SAMPLE BIT(2)
#define GS_CAN_FEATURE_ONE_SHOT BIT(3)
#define GS_CAN_FEATURE_HW_TIMESTAMP BIT(4)
#define GS_CAN_FEATURE_IDENTIFY BIT(5)
struct gs_device_bt_const {
u32 feature;
@ -214,7 +227,8 @@ static void gs_free_tx_context(struct gs_tx_context *txc)
/* Get a tx context by id.
*/
static struct gs_tx_context *gs_get_tx_context(struct gs_can *dev, unsigned int id)
static struct gs_tx_context *gs_get_tx_context(struct gs_can *dev,
unsigned int id)
{
unsigned long flags;
@ -457,7 +471,8 @@ static void gs_usb_xmit_callback(struct urb *urb)
netif_wake_queue(netdev);
}
static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, struct net_device *netdev)
static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct gs_can *dev = netdev_priv(netdev);
struct net_device_stats *stats = &dev->netdev->stats;
@ -663,7 +678,8 @@ static int gs_can_open(struct net_device *netdev)
rc = usb_control_msg(interface_to_usbdev(dev->iface),
usb_sndctrlpipe(interface_to_usbdev(dev->iface), 0),
GS_USB_BREQ_MODE,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_INTERFACE,
dev->channel,
0,
dm,
@ -726,7 +742,59 @@ static const struct net_device_ops gs_usb_netdev_ops = {
.ndo_change_mtu = can_change_mtu,
};
static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface *intf)
static int gs_usb_set_identify(struct net_device *netdev, bool do_identify)
{
struct gs_can *dev = netdev_priv(netdev);
struct gs_identify_mode imode;
int rc;
if (do_identify)
imode.mode = GS_CAN_IDENTIFY_ON;
else
imode.mode = GS_CAN_IDENTIFY_OFF;
rc = usb_control_msg(interface_to_usbdev(dev->iface),
usb_sndctrlpipe(interface_to_usbdev(dev->iface),
0),
GS_USB_BREQ_IDENTIFY,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_INTERFACE,
dev->channel,
0,
&imode,
sizeof(imode),
100);
return (rc > 0) ? 0 : rc;
}
/* blink LED's for finding the this interface */
static int gs_usb_set_phys_id(struct net_device *dev,
enum ethtool_phys_id_state state)
{
int rc = 0;
switch (state) {
case ETHTOOL_ID_ACTIVE:
rc = gs_usb_set_identify(dev, GS_CAN_IDENTIFY_ON);
break;
case ETHTOOL_ID_INACTIVE:
rc = gs_usb_set_identify(dev, GS_CAN_IDENTIFY_OFF);
break;
default:
break;
}
return rc;
}
static const struct ethtool_ops gs_usb_ethtool_ops = {
.set_phys_id = gs_usb_set_phys_id,
};
static struct gs_can *gs_make_candev(unsigned int channel,
struct usb_interface *intf,
struct gs_device_config *dconf)
{
struct gs_can *dev;
struct net_device *netdev;
@ -814,10 +882,14 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface
if (bt_const->feature & GS_CAN_FEATURE_ONE_SHOT)
dev->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
kfree(bt_const);
SET_NETDEV_DEV(netdev, &intf->dev);
if (dconf->sw_version > 1)
if (bt_const->feature & GS_CAN_FEATURE_IDENTIFY)
netdev->ethtool_ops = &gs_usb_ethtool_ops;
kfree(bt_const);
rc = register_candev(dev->netdev);
if (rc) {
free_candev(dev->netdev);
@ -835,19 +907,16 @@ static void gs_destroy_candev(struct gs_can *dev)
free_candev(dev->netdev);
}
static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
static int gs_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct gs_usb *dev;
int rc = -ENOMEM;
unsigned int icount, i;
struct gs_host_config *hconf;
struct gs_device_config *dconf;
hconf = kmalloc(sizeof(*hconf), GFP_KERNEL);
if (!hconf)
return -ENOMEM;
hconf->byte_order = 0x0000beef;
struct gs_host_config hconf = {
.byte_order = 0x0000beef,
};
struct gs_device_config dconf;
/* send host config */
rc = usb_control_msg(interface_to_usbdev(intf),
@ -856,22 +925,16 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
1,
intf->altsetting[0].desc.bInterfaceNumber,
hconf,
sizeof(*hconf),
&hconf,
sizeof(hconf),
1000);
kfree(hconf);
if (rc < 0) {
dev_err(&intf->dev, "Couldn't send data format (err=%d)\n",
rc);
return rc;
}
dconf = kmalloc(sizeof(*dconf), GFP_KERNEL);
if (!dconf)
return -ENOMEM;
/* read device config */
rc = usb_control_msg(interface_to_usbdev(intf),
usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
@ -879,22 +942,16 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
1,
intf->altsetting[0].desc.bInterfaceNumber,
dconf,
sizeof(*dconf),
&dconf,
sizeof(dconf),
1000);
if (rc < 0) {
dev_err(&intf->dev, "Couldn't get device config: (err=%d)\n",
rc);
kfree(dconf);
return rc;
}
icount = dconf->icount+1;
kfree(dconf);
icount = dconf.icount + 1;
dev_info(&intf->dev, "Configuring for %d interfaces\n", icount);
if (icount > GS_MAX_INTF) {
@ -915,7 +972,7 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
dev->udev = interface_to_usbdev(intf);
for (i = 0; i < icount; i++) {
dev->canch[i] = gs_make_candev(i, intf);
dev->canch[i] = gs_make_candev(i, intf, &dconf);
if (IS_ERR_OR_NULL(dev->canch[i])) {
/* save error code to return later */
rc = PTR_ERR(dev->canch[i]);

View File

@ -9,14 +9,6 @@ config NET_DSA_MV88E6060
This enables support for the Marvell 88E6060 ethernet switch
chip.
config NET_DSA_MV88E6XXX
tristate "Marvell 88E6xxx Ethernet switch chip support"
depends on NET_DSA
select NET_DSA_TAG_EDSA
---help---
This enables support for most of the Marvell 88E6xxx models of
Ethernet switch chips, except 88E6060.
config NET_DSA_BCM_SF2
tristate "Broadcom Starfighter 2 Ethernet switch support"
depends on HAS_IOMEM && NET_DSA
@ -28,4 +20,8 @@ config NET_DSA_BCM_SF2
This enables support for the Broadcom Starfighter 2 Ethernet
switch chips.
source "drivers/net/dsa/b53/Kconfig"
source "drivers/net/dsa/mv88e6xxx/Kconfig"
endmenu

View File

@ -1,3 +1,5 @@
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o
obj-y += b53/
obj-y += mv88e6xxx/

View File

@ -0,0 +1,33 @@
menuconfig B53
tristate "Broadcom BCM53xx managed switch support"
depends on NET_DSA
help
This driver adds support for Broadcom managed switch chips. It supports
BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
integrated switches.
config B53_SPI_DRIVER
tristate "B53 SPI connected switch driver"
depends on B53 && SPI
help
Select to enable support for registering switches configured through SPI.
config B53_MDIO_DRIVER
tristate "B53 MDIO connected switch driver"
depends on B53
help
Select to enable support for registering switches configured through MDIO.
config B53_MMAP_DRIVER
tristate "B53 MMAP connected switch driver"
depends on B53 && HAS_IOMEM
help
Select to enable support for memory-mapped switches like the BCM63XX
integrated switches.
config B53_SRAB_DRIVER
tristate "B53 SRAB connected switch driver"
depends on B53 && HAS_IOMEM
help
Select to enable support for memory-mapped Switch Register Access
Bridge Registers (SRAB) like it is found on the BCM53010

View File

@ -0,0 +1,6 @@
obj-$(CONFIG_B53) += b53_common.o
obj-$(CONFIG_B53_SPI_DRIVER) += b53_spi.o
obj-$(CONFIG_B53_MDIO_DRIVER) += b53_mdio.o
obj-$(CONFIG_B53_MMAP_DRIVER) += b53_mmap.o
obj-$(CONFIG_B53_SRAB_DRIVER) += b53_srab.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,392 @@
/*
* B53 register access through MII registers
*
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/phy.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/brcmphy.h>
#include <linux/rtnetlink.h>
#include <net/dsa.h>
#include "b53_priv.h"
/* MII registers */
#define REG_MII_PAGE 0x10 /* MII Page register */
#define REG_MII_ADDR 0x11 /* MII Address register */
#define REG_MII_DATA0 0x18 /* MII Data register 0 */
#define REG_MII_DATA1 0x19 /* MII Data register 1 */
#define REG_MII_DATA2 0x1a /* MII Data register 2 */
#define REG_MII_DATA3 0x1b /* MII Data register 3 */
#define REG_MII_PAGE_ENABLE BIT(0)
#define REG_MII_ADDR_WRITE BIT(0)
#define REG_MII_ADDR_READ BIT(1)
static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
{
int i;
u16 v;
int ret;
struct mii_bus *bus = dev->priv;
if (dev->current_page != page) {
/* set page number */
v = (page << 8) | REG_MII_PAGE_ENABLE;
ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_PAGE, v);
if (ret)
return ret;
dev->current_page = page;
}
/* set register address */
v = (reg << 8) | op;
ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_ADDR, v);
if (ret)
return ret;
/* check if operation completed */
for (i = 0; i < 5; ++i) {
v = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_ADDR);
if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
break;
usleep_range(10, 100);
}
if (WARN_ON(i == 5))
return -EIO;
return 0;
}
static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
{
struct mii_bus *bus = dev->priv;
int ret;
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
if (ret)
return ret;
*val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_DATA0) & 0xff;
return 0;
}
static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
{
struct mii_bus *bus = dev->priv;
int ret;
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
if (ret)
return ret;
*val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0);
return 0;
}
static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
{
struct mii_bus *bus = dev->priv;
int ret;
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
if (ret)
return ret;
*val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0);
*val |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_DATA1) << 16;
return 0;
}
static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
struct mii_bus *bus = dev->priv;
u64 temp = 0;
int i;
int ret;
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
if (ret)
return ret;
for (i = 2; i >= 0; i--) {
temp <<= 16;
temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_DATA0 + i);
}
*val = temp;
return 0;
}
static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
struct mii_bus *bus = dev->priv;
u64 temp = 0;
int i;
int ret;
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
if (ret)
return ret;
for (i = 3; i >= 0; i--) {
temp <<= 16;
temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_DATA0 + i);
}
*val = temp;
return 0;
}
static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
{
struct mii_bus *bus = dev->priv;
int ret;
ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_DATA0, value);
if (ret)
return ret;
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
}
static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg,
u16 value)
{
struct mii_bus *bus = dev->priv;
int ret;
ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_DATA0, value);
if (ret)
return ret;
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
}
static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg,
u32 value)
{
struct mii_bus *bus = dev->priv;
unsigned int i;
u32 temp = value;
for (i = 0; i < 2; i++) {
int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_DATA0 + i,
temp & 0xffff);
if (ret)
return ret;
temp >>= 16;
}
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
}
static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg,
u64 value)
{
struct mii_bus *bus = dev->priv;
unsigned int i;
u64 temp = value;
for (i = 0; i < 3; i++) {
int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_DATA0 + i,
temp & 0xffff);
if (ret)
return ret;
temp >>= 16;
}
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
}
static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg,
u64 value)
{
struct mii_bus *bus = dev->priv;
unsigned int i;
u64 temp = value;
for (i = 0; i < 4; i++) {
int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
REG_MII_DATA0 + i,
temp & 0xffff);
if (ret)
return ret;
temp >>= 16;
}
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
}
static int b53_mdio_phy_read16(struct b53_device *dev, int addr, int reg,
u16 *value)
{
struct mii_bus *bus = dev->priv;
*value = mdiobus_read_nested(bus, addr, reg);
return 0;
}
static int b53_mdio_phy_write16(struct b53_device *dev, int addr, int reg,
u16 value)
{
struct mii_bus *bus = dev->bus;
return mdiobus_write_nested(bus, addr, reg, value);
}
static struct b53_io_ops b53_mdio_ops = {
.read8 = b53_mdio_read8,
.read16 = b53_mdio_read16,
.read32 = b53_mdio_read32,
.read48 = b53_mdio_read48,
.read64 = b53_mdio_read64,
.write8 = b53_mdio_write8,
.write16 = b53_mdio_write16,
.write32 = b53_mdio_write32,
.write48 = b53_mdio_write48,
.write64 = b53_mdio_write64,
.phy_read16 = b53_mdio_phy_read16,
.phy_write16 = b53_mdio_phy_write16,
};
#define B53_BRCM_OUI_1 0x0143bc00
#define B53_BRCM_OUI_2 0x03625c00
#define B53_BRCM_OUI_3 0x00406000
static int b53_mdio_probe(struct mdio_device *mdiodev)
{
struct b53_device *dev;
u32 phy_id;
int ret;
/* allow the generic PHY driver to take over the non-management MDIO
* addresses
*/
if (mdiodev->addr != BRCM_PSEUDO_PHY_ADDR && mdiodev->addr != 0) {
dev_err(&mdiodev->dev, "leaving address %d to PHY\n",
mdiodev->addr);
return -ENODEV;
}
/* read the first port's id */
phy_id = mdiobus_read(mdiodev->bus, 0, 2) << 16;
phy_id |= mdiobus_read(mdiodev->bus, 0, 3);
/* BCM5325, BCM539x (OUI_1)
* BCM53125, BCM53128 (OUI_2)
* BCM5365 (OUI_3)
*/
if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 &&
(phy_id & 0xfffffc00) != B53_BRCM_OUI_2 &&
(phy_id & 0xfffffc00) != B53_BRCM_OUI_3) {
dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id);
return -ENODEV;
}
/* First probe will come from SWITCH_MDIO controller on the 7445D0
* switch, which will conflict with the 7445 integrated switch
* pseudo-phy (we end-up programming both). In that case, we return
* -EPROBE_DEFER for the first time we get here, and wait until we come
* back with the slave MDIO bus which has the correct indirection
* layer setup
*/
if (of_machine_is_compatible("brcm,bcm7445d0") &&
strcmp(mdiodev->bus->name, "sf2 slave mii"))
return -EPROBE_DEFER;
dev = b53_switch_alloc(&mdiodev->dev, &b53_mdio_ops, mdiodev->bus);
if (!dev)
return -ENOMEM;
/* we don't use page 0xff, so force a page set */
dev->current_page = 0xff;
dev->bus = mdiodev->bus;
dev_set_drvdata(&mdiodev->dev, dev);
ret = b53_switch_register(dev);
if (ret) {
dev_err(&mdiodev->dev, "failed to register switch: %i\n", ret);
return ret;
}
return ret;
}
static void b53_mdio_remove(struct mdio_device *mdiodev)
{
struct b53_device *dev = dev_get_drvdata(&mdiodev->dev);
struct dsa_switch *ds = dev->ds;
dsa_unregister_switch(ds);
}
static const struct of_device_id b53_of_match[] = {
{ .compatible = "brcm,bcm5325" },
{ .compatible = "brcm,bcm53115" },
{ .compatible = "brcm,bcm53125" },
{ .compatible = "brcm,bcm53128" },
{ .compatible = "brcm,bcm5365" },
{ .compatible = "brcm,bcm5395" },
{ .compatible = "brcm,bcm5397" },
{ .compatible = "brcm,bcm5398" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, b53_of_match);
static struct mdio_driver b53_mdio_driver = {
.probe = b53_mdio_probe,
.remove = b53_mdio_remove,
.mdiodrv.driver = {
.name = "bcm53xx",
.of_match_table = b53_of_match,
},
};
static int __init b53_mdio_driver_register(void)
{
return mdio_driver_register(&b53_mdio_driver);
}
module_init(b53_mdio_driver_register);
static void __exit b53_mdio_driver_unregister(void)
{
mdio_driver_unregister(&b53_mdio_driver);
}
module_exit(b53_mdio_driver_unregister);
MODULE_DESCRIPTION("B53 MDIO access driver");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -0,0 +1,274 @@
/*
* B53 register access through memory mapped registers
*
* Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/kconfig.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/platform_data/b53.h>
#include "b53_priv.h"
struct b53_mmap_priv {
void __iomem *regs;
};
static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
{
u8 __iomem *regs = dev->priv;
*val = readb(regs + (page << 8) + reg);
return 0;
}
static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
{
u8 __iomem *regs = dev->priv;
if (WARN_ON(reg % 2))
return -EINVAL;
if (dev->pdata && dev->pdata->big_endian)
*val = ioread16be(regs + (page << 8) + reg);
else
*val = readw(regs + (page << 8) + reg);
return 0;
}
static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
{
u8 __iomem *regs = dev->priv;
if (WARN_ON(reg % 4))
return -EINVAL;
if (dev->pdata && dev->pdata->big_endian)
*val = ioread32be(regs + (page << 8) + reg);
else
*val = readl(regs + (page << 8) + reg);
return 0;
}
static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
u8 __iomem *regs = dev->priv;
if (WARN_ON(reg % 2))
return -EINVAL;
if (reg % 4) {
u16 lo;
u32 hi;
if (dev->pdata && dev->pdata->big_endian) {
lo = ioread16be(regs + (page << 8) + reg);
hi = ioread32be(regs + (page << 8) + reg + 2);
} else {
lo = readw(regs + (page << 8) + reg);
hi = readl(regs + (page << 8) + reg + 2);
}
*val = ((u64)hi << 16) | lo;
} else {
u32 lo;
u16 hi;
if (dev->pdata && dev->pdata->big_endian) {
lo = ioread32be(regs + (page << 8) + reg);
hi = ioread16be(regs + (page << 8) + reg + 4);
} else {
lo = readl(regs + (page << 8) + reg);
hi = readw(regs + (page << 8) + reg + 4);
}
*val = ((u64)hi << 32) | lo;
}
return 0;
}
static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
u8 __iomem *regs = dev->priv;
u32 hi, lo;
if (WARN_ON(reg % 4))
return -EINVAL;
if (dev->pdata && dev->pdata->big_endian) {
lo = ioread32be(regs + (page << 8) + reg);
hi = ioread32be(regs + (page << 8) + reg + 4);
} else {
lo = readl(regs + (page << 8) + reg);
hi = readl(regs + (page << 8) + reg + 4);
}
*val = ((u64)hi << 32) | lo;
return 0;
}
static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
{
u8 __iomem *regs = dev->priv;
writeb(value, regs + (page << 8) + reg);
return 0;
}
static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
u16 value)
{
u8 __iomem *regs = dev->priv;
if (WARN_ON(reg % 2))
return -EINVAL;
if (dev->pdata && dev->pdata->big_endian)
iowrite16be(value, regs + (page << 8) + reg);
else
writew(value, regs + (page << 8) + reg);
return 0;
}
static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
u32 value)
{
u8 __iomem *regs = dev->priv;
if (WARN_ON(reg % 4))
return -EINVAL;
if (dev->pdata && dev->pdata->big_endian)
iowrite32be(value, regs + (page << 8) + reg);
else
writel(value, regs + (page << 8) + reg);
return 0;
}
static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
u64 value)
{
if (WARN_ON(reg % 2))
return -EINVAL;
if (reg % 4) {
u32 hi = (u32)(value >> 16);
u16 lo = (u16)value;
b53_mmap_write16(dev, page, reg, lo);
b53_mmap_write32(dev, page, reg + 2, hi);
} else {
u16 hi = (u16)(value >> 32);
u32 lo = (u32)value;
b53_mmap_write32(dev, page, reg, lo);
b53_mmap_write16(dev, page, reg + 4, hi);
}
return 0;
}
static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
u64 value)
{
u32 hi, lo;
hi = upper_32_bits(value);
lo = lower_32_bits(value);
if (WARN_ON(reg % 4))
return -EINVAL;
b53_mmap_write32(dev, page, reg, lo);
b53_mmap_write32(dev, page, reg + 4, hi);
return 0;
}
static struct b53_io_ops b53_mmap_ops = {
.read8 = b53_mmap_read8,
.read16 = b53_mmap_read16,
.read32 = b53_mmap_read32,
.read48 = b53_mmap_read48,
.read64 = b53_mmap_read64,
.write8 = b53_mmap_write8,
.write16 = b53_mmap_write16,
.write32 = b53_mmap_write32,
.write48 = b53_mmap_write48,
.write64 = b53_mmap_write64,
};
static int b53_mmap_probe(struct platform_device *pdev)
{
struct b53_platform_data *pdata = pdev->dev.platform_data;
struct b53_device *dev;
if (!pdata)
return -EINVAL;
dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
if (!dev)
return -ENOMEM;
if (pdata)
dev->pdata = pdata;
platform_set_drvdata(pdev, dev);
return b53_switch_register(dev);
}
static int b53_mmap_remove(struct platform_device *pdev)
{
struct b53_device *dev = platform_get_drvdata(pdev);
if (dev)
b53_switch_remove(dev);
return 0;
}
static const struct of_device_id b53_mmap_of_table[] = {
{ .compatible = "brcm,bcm3384-switch" },
{ .compatible = "brcm,bcm6328-switch" },
{ .compatible = "brcm,bcm6368-switch" },
{ .compatible = "brcm,bcm63xx-switch" },
{ /* sentinel */ },
};
static struct platform_driver b53_mmap_driver = {
.probe = b53_mmap_probe,
.remove = b53_mmap_remove,
.driver = {
.name = "b53-switch",
.of_match_table = b53_mmap_of_table,
},
};
module_platform_driver(b53_mmap_driver);
MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
MODULE_DESCRIPTION("B53 MMAP access driver");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -0,0 +1,388 @@
/*
* B53 common definitions
*
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __B53_PRIV_H
#define __B53_PRIV_H
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/phy.h>
#include <net/dsa.h>
#include "b53_regs.h"
struct b53_device;
struct net_device;
struct b53_io_ops {
int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value);
int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value);
int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value);
int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value);
int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value);
int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value);
int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
int (*phy_read16)(struct b53_device *dev, int addr, int reg, u16 *value);
int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value);
};
enum {
BCM5325_DEVICE_ID = 0x25,
BCM5365_DEVICE_ID = 0x65,
BCM5395_DEVICE_ID = 0x95,
BCM5397_DEVICE_ID = 0x97,
BCM5398_DEVICE_ID = 0x98,
BCM53115_DEVICE_ID = 0x53115,
BCM53125_DEVICE_ID = 0x53125,
BCM53128_DEVICE_ID = 0x53128,
BCM63XX_DEVICE_ID = 0x6300,
BCM53010_DEVICE_ID = 0x53010,
BCM53011_DEVICE_ID = 0x53011,
BCM53012_DEVICE_ID = 0x53012,
BCM53018_DEVICE_ID = 0x53018,
BCM53019_DEVICE_ID = 0x53019,
BCM58XX_DEVICE_ID = 0x5800,
};
#define B53_N_PORTS 9
#define B53_N_PORTS_25 6
struct b53_port {
u16 vlan_ctl_mask;
struct net_device *bridge_dev;
};
struct b53_vlan {
u16 members;
u16 untag;
bool valid;
};
struct b53_device {
struct dsa_switch *ds;
struct b53_platform_data *pdata;
const char *name;
struct mutex reg_mutex;
struct mutex stats_mutex;
const struct b53_io_ops *ops;
/* chip specific data */
u32 chip_id;
u8 core_rev;
u8 vta_regs[3];
u8 duplex_reg;
u8 jumbo_pm_reg;
u8 jumbo_size_reg;
int reset_gpio;
u8 num_arl_entries;
/* used ports mask */
u16 enabled_ports;
unsigned int cpu_port;
/* connect specific data */
u8 current_page;
struct device *dev;
/* Master MDIO bus we got probed from */
struct mii_bus *bus;
void *priv;
/* run time configuration */
bool enable_jumbo;
unsigned int num_vlans;
struct b53_vlan *vlans;
unsigned int num_ports;
struct b53_port *ports;
};
#define b53_for_each_port(dev, i) \
for (i = 0; i < B53_N_PORTS; i++) \
if (dev->enabled_ports & BIT(i))
static inline int is5325(struct b53_device *dev)
{
return dev->chip_id == BCM5325_DEVICE_ID;
}
static inline int is5365(struct b53_device *dev)
{
#ifdef CONFIG_BCM47XX
return dev->chip_id == BCM5365_DEVICE_ID;
#else
return 0;
#endif
}
static inline int is5397_98(struct b53_device *dev)
{
return dev->chip_id == BCM5397_DEVICE_ID ||
dev->chip_id == BCM5398_DEVICE_ID;
}
static inline int is539x(struct b53_device *dev)
{
return dev->chip_id == BCM5395_DEVICE_ID ||
dev->chip_id == BCM5397_DEVICE_ID ||
dev->chip_id == BCM5398_DEVICE_ID;
}
static inline int is531x5(struct b53_device *dev)
{
return dev->chip_id == BCM53115_DEVICE_ID ||
dev->chip_id == BCM53125_DEVICE_ID ||
dev->chip_id == BCM53128_DEVICE_ID;
}
static inline int is63xx(struct b53_device *dev)
{
#ifdef CONFIG_BCM63XX
return dev->chip_id == BCM63XX_DEVICE_ID;
#else
return 0;
#endif
}
static inline int is5301x(struct b53_device *dev)
{
return dev->chip_id == BCM53010_DEVICE_ID ||
dev->chip_id == BCM53011_DEVICE_ID ||
dev->chip_id == BCM53012_DEVICE_ID ||
dev->chip_id == BCM53018_DEVICE_ID ||
dev->chip_id == BCM53019_DEVICE_ID;
}
#define B53_CPU_PORT_25 5
#define B53_CPU_PORT 8
static inline int is_cpu_port(struct b53_device *dev, int port)
{
return dev->cpu_port;
}
struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
void *priv);
int b53_switch_detect(struct b53_device *dev);
int b53_switch_register(struct b53_device *dev);
static inline void b53_switch_remove(struct b53_device *dev)
{
dsa_unregister_switch(dev->ds);
}
static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->read8(dev, page, reg, val);
mutex_unlock(&dev->reg_mutex);
return ret;
}
static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->read16(dev, page, reg, val);
mutex_unlock(&dev->reg_mutex);
return ret;
}
static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->read32(dev, page, reg, val);
mutex_unlock(&dev->reg_mutex);
return ret;
}
static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->read48(dev, page, reg, val);
mutex_unlock(&dev->reg_mutex);
return ret;
}
static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->read64(dev, page, reg, val);
mutex_unlock(&dev->reg_mutex);
return ret;
}
static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->write8(dev, page, reg, value);
mutex_unlock(&dev->reg_mutex);
return ret;
}
static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg,
u16 value)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->write16(dev, page, reg, value);
mutex_unlock(&dev->reg_mutex);
return ret;
}
static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg,
u32 value)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->write32(dev, page, reg, value);
mutex_unlock(&dev->reg_mutex);
return ret;
}
static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg,
u64 value)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->write48(dev, page, reg, value);
mutex_unlock(&dev->reg_mutex);
return ret;
}
static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
u64 value)
{
int ret;
mutex_lock(&dev->reg_mutex);
ret = dev->ops->write64(dev, page, reg, value);
mutex_unlock(&dev->reg_mutex);
return ret;
}
struct b53_arl_entry {
u8 port;
u8 mac[ETH_ALEN];
u16 vid;
u8 is_valid:1;
u8 is_age:1;
u8 is_static:1;
};
static inline void b53_mac_from_u64(u64 src, u8 *dst)
{
unsigned int i;
for (i = 0; i < ETH_ALEN; i++)
dst[ETH_ALEN - 1 - i] = (src >> (8 * i)) & 0xff;
}
static inline u64 b53_mac_to_u64(const u8 *src)
{
unsigned int i;
u64 dst = 0;
for (i = 0; i < ETH_ALEN; i++)
dst |= (u64)src[ETH_ALEN - 1 - i] << (8 * i);
return dst;
}
static inline void b53_arl_to_entry(struct b53_arl_entry *ent,
u64 mac_vid, u32 fwd_entry)
{
memset(ent, 0, sizeof(*ent));
ent->port = fwd_entry & ARLTBL_DATA_PORT_ID_MASK;
ent->is_valid = !!(fwd_entry & ARLTBL_VALID);
ent->is_age = !!(fwd_entry & ARLTBL_AGE);
ent->is_static = !!(fwd_entry & ARLTBL_STATIC);
b53_mac_from_u64(mac_vid, ent->mac);
ent->vid = mac_vid >> ARLTBL_VID_S;
}
static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry,
const struct b53_arl_entry *ent)
{
*mac_vid = b53_mac_to_u64(ent->mac);
*mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK) << ARLTBL_VID_S;
*fwd_entry = ent->port & ARLTBL_DATA_PORT_ID_MASK;
if (ent->is_valid)
*fwd_entry |= ARLTBL_VALID;
if (ent->is_static)
*fwd_entry |= ARLTBL_STATIC;
if (ent->is_age)
*fwd_entry |= ARLTBL_AGE;
}
#ifdef CONFIG_BCM47XX
#include <linux/version.h>
#include <linux/bcm47xx_nvram.h>
#include <bcm47xx_board.h>
static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
{
enum bcm47xx_board board = bcm47xx_board_get();
switch (board) {
case BCM47XX_BOARD_LINKSYS_WRT300NV11:
case BCM47XX_BOARD_LINKSYS_WRT310NV1:
return 8;
default:
return bcm47xx_nvram_gpio_pin("robo_reset");
}
}
#else
static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
{
return -ENOENT;
}
#endif
#endif

View File

@ -0,0 +1,434 @@
/*
* B53 register definitions
*
* Copyright (C) 2004 Broadcom Corporation
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __B53_REGS_H
#define __B53_REGS_H
/* Management Port (SMP) Page offsets */
#define B53_CTRL_PAGE 0x00 /* Control */
#define B53_STAT_PAGE 0x01 /* Status */
#define B53_MGMT_PAGE 0x02 /* Management Mode */
#define B53_MIB_AC_PAGE 0x03 /* MIB Autocast */
#define B53_ARLCTRL_PAGE 0x04 /* ARL Control */
#define B53_ARLIO_PAGE 0x05 /* ARL Access */
#define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */
#define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */
/* PHY Registers */
#define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */
#define B53_IM_PORT_PAGE 0x18 /* Inverse MII Port (to EMAC) */
#define B53_ALL_PORT_PAGE 0x19 /* All ports MII (broadcast) */
/* MIB registers */
#define B53_MIB_PAGE(i) (0x20 + (i))
/* Quality of Service (QoS) Registers */
#define B53_QOS_PAGE 0x30
/* Port VLAN Page */
#define B53_PVLAN_PAGE 0x31
/* VLAN Registers */
#define B53_VLAN_PAGE 0x34
/* Jumbo Frame Registers */
#define B53_JUMBO_PAGE 0x40
/* CFP Configuration Registers Page */
#define B53_CFP_PAGE 0xa1
/*************************************************************************
* Control Page registers
*************************************************************************/
/* Port Control Register (8 bit) */
#define B53_PORT_CTRL(i) (0x00 + (i))
#define PORT_CTRL_RX_DISABLE BIT(0)
#define PORT_CTRL_TX_DISABLE BIT(1)
#define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */
#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */
#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */
#define PORT_CTRL_STP_STATE_S 5
#define PORT_CTRL_NO_STP (0 << PORT_CTRL_STP_STATE_S)
#define PORT_CTRL_DIS_STATE (1 << PORT_CTRL_STP_STATE_S)
#define PORT_CTRL_BLOCK_STATE (2 << PORT_CTRL_STP_STATE_S)
#define PORT_CTRL_LISTEN_STATE (3 << PORT_CTRL_STP_STATE_S)
#define PORT_CTRL_LEARN_STATE (4 << PORT_CTRL_STP_STATE_S)
#define PORT_CTRL_FWD_STATE (5 << PORT_CTRL_STP_STATE_S)
#define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S)
/* SMP Control Register (8 bit) */
#define B53_SMP_CTRL 0x0a
/* Switch Mode Control Register (8 bit) */
#define B53_SWITCH_MODE 0x0b
#define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */
#define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */
/* IMP Port state override register (8 bit) */
#define B53_PORT_OVERRIDE_CTRL 0x0e
#define PORT_OVERRIDE_LINK BIT(0)
#define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */
#define PORT_OVERRIDE_SPEED_S 2
#define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S)
#define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S)
#define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S)
#define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */
#define PORT_OVERRIDE_RX_FLOW BIT(4)
#define PORT_OVERRIDE_TX_FLOW BIT(5)
#define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */
#define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */
/* Power-down mode control */
#define B53_PD_MODE_CTRL_25 0x0f
/* IP Multicast control (8 bit) */
#define B53_IP_MULTICAST_CTRL 0x21
#define B53_IPMC_FWD_EN BIT(1)
#define B53_UC_FWD_EN BIT(6)
#define B53_MC_FWD_EN BIT(7)
/* (16 bit) */
#define B53_UC_FLOOD_MASK 0x32
#define B53_MC_FLOOD_MASK 0x34
#define B53_IPMC_FLOOD_MASK 0x36
/*
* Override Ports 0-7 State on devices with xMII interfaces (8 bit)
*
* For port 8 still use B53_PORT_OVERRIDE_CTRL
* Please note that not all ports are available on every hardware, e.g. BCM5301X
* don't include overriding port 6, BCM63xx also have some limitations.
*/
#define B53_GMII_PORT_OVERRIDE_CTRL(i) (0x58 + (i))
#define GMII_PO_LINK BIT(0)
#define GMII_PO_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */
#define GMII_PO_SPEED_S 2
#define GMII_PO_SPEED_10M (0 << GMII_PO_SPEED_S)
#define GMII_PO_SPEED_100M (1 << GMII_PO_SPEED_S)
#define GMII_PO_SPEED_1000M (2 << GMII_PO_SPEED_S)
#define GMII_PO_RX_FLOW BIT(4)
#define GMII_PO_TX_FLOW BIT(5)
#define GMII_PO_EN BIT(6) /* Use the register contents */
#define GMII_PO_SPEED_2000M BIT(7) /* BCM5301X only, requires setting 1000M */
#define B53_RGMII_CTRL_IMP 0x60
#define RGMII_CTRL_ENABLE_GMII BIT(7)
#define RGMII_CTRL_TIMING_SEL BIT(2)
#define RGMII_CTRL_DLL_RXC BIT(1)
#define RGMII_CTRL_DLL_TXC BIT(0)
#define B53_RGMII_CTRL_P(i) (B53_RGMII_CTRL_IMP + (i))
/* Software reset register (8 bit) */
#define B53_SOFTRESET 0x79
#define SW_RST BIT(7)
#define EN_SW_RST BIT(4)
/* Fast Aging Control register (8 bit) */
#define B53_FAST_AGE_CTRL 0x88
#define FAST_AGE_STATIC BIT(0)
#define FAST_AGE_DYNAMIC BIT(1)
#define FAST_AGE_PORT BIT(2)
#define FAST_AGE_VLAN BIT(3)
#define FAST_AGE_STP BIT(4)
#define FAST_AGE_MC BIT(5)
#define FAST_AGE_DONE BIT(7)
/* Fast Aging Port Control register (8 bit) */
#define B53_FAST_AGE_PORT_CTRL 0x89
/* Fast Aging VID Control register (16 bit) */
#define B53_FAST_AGE_VID_CTRL 0x8a
/*************************************************************************
* Status Page registers
*************************************************************************/
/* Link Status Summary Register (16bit) */
#define B53_LINK_STAT 0x00
/* Link Status Change Register (16 bit) */
#define B53_LINK_STAT_CHANGE 0x02
/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */
#define B53_SPEED_STAT 0x04
#define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1)
#define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3)
#define SPEED_STAT_10M 0
#define SPEED_STAT_100M 1
#define SPEED_STAT_1000M 2
/* Duplex Status Summary (16 bit) */
#define B53_DUPLEX_STAT_FE 0x06
#define B53_DUPLEX_STAT_GE 0x08
#define B53_DUPLEX_STAT_63XX 0x0c
/* Revision ID register for BCM5325 */
#define B53_REV_ID_25 0x50
/* Strap Value (48 bit) */
#define B53_STRAP_VALUE 0x70
#define SV_GMII_CTRL_115 BIT(27)
/*************************************************************************
* Management Mode Page Registers
*************************************************************************/
/* Global Management Config Register (8 bit) */
#define B53_GLOBAL_CONFIG 0x00
#define GC_RESET_MIB 0x01
#define GC_RX_BPDU_EN 0x02
#define GC_MIB_AC_HDR_EN 0x10
#define GC_MIB_AC_EN 0x20
#define GC_FRM_MGMT_PORT_M 0xC0
#define GC_FRM_MGMT_PORT_04 0x00
#define GC_FRM_MGMT_PORT_MII 0x80
/* Broadcom Header control register (8 bit) */
#define B53_BRCM_HDR 0x03
#define BRCM_HDR_P8_EN BIT(0) /* Enable tagging on port 8 */
#define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */
/* Device ID register (8 or 32 bit) */
#define B53_DEVICE_ID 0x30
/* Revision ID register (8 bit) */
#define B53_REV_ID 0x40
/*************************************************************************
* ARL Access Page Registers
*************************************************************************/
/* VLAN Table Access Register (8 bit) */
#define B53_VT_ACCESS 0x80
#define B53_VT_ACCESS_9798 0x60 /* for BCM5397/BCM5398 */
#define B53_VT_ACCESS_63XX 0x60 /* for BCM6328/62/68 */
#define VTA_CMD_WRITE 0
#define VTA_CMD_READ 1
#define VTA_CMD_CLEAR 2
#define VTA_START_CMD BIT(7)
/* VLAN Table Index Register (16 bit) */
#define B53_VT_INDEX 0x81
#define B53_VT_INDEX_9798 0x61
#define B53_VT_INDEX_63XX 0x62
/* VLAN Table Entry Register (32 bit) */
#define B53_VT_ENTRY 0x83
#define B53_VT_ENTRY_9798 0x63
#define B53_VT_ENTRY_63XX 0x64
#define VTE_MEMBERS 0x1ff
#define VTE_UNTAG_S 9
#define VTE_UNTAG (0x1ff << 9)
/*************************************************************************
* ARL I/O Registers
*************************************************************************/
/* ARL Table Read/Write Register (8 bit) */
#define B53_ARLTBL_RW_CTRL 0x00
#define ARLTBL_RW BIT(0)
#define ARLTBL_START_DONE BIT(7)
/* MAC Address Index Register (48 bit) */
#define B53_MAC_ADDR_IDX 0x02
/* VLAN ID Index Register (16 bit) */
#define B53_VLAN_ID_IDX 0x08
/* ARL Table MAC/VID Entry N Registers (64 bit)
*
* BCM5325 and BCM5365 share most definitions below
*/
#define B53_ARLTBL_MAC_VID_ENTRY(n) (0x10 * (n))
#define ARLTBL_MAC_MASK 0xffffffffffff
#define ARLTBL_VID_S 48
#define ARLTBL_VID_MASK_25 0xff
#define ARLTBL_VID_MASK 0xfff
#define ARLTBL_DATA_PORT_ID_S_25 48
#define ARLTBL_DATA_PORT_ID_MASK_25 0xf
#define ARLTBL_AGE_25 BIT(61)
#define ARLTBL_STATIC_25 BIT(62)
#define ARLTBL_VALID_25 BIT(63)
/* ARL Table Data Entry N Registers (32 bit) */
#define B53_ARLTBL_DATA_ENTRY(n) ((0x10 * (n)) + 0x08)
#define ARLTBL_DATA_PORT_ID_MASK 0x1ff
#define ARLTBL_TC(tc) ((3 & tc) << 11)
#define ARLTBL_AGE BIT(14)
#define ARLTBL_STATIC BIT(15)
#define ARLTBL_VALID BIT(16)
/* ARL Search Control Register (8 bit) */
#define B53_ARL_SRCH_CTL 0x50
#define B53_ARL_SRCH_CTL_25 0x20
#define ARL_SRCH_VLID BIT(0)
#define ARL_SRCH_STDN BIT(7)
/* ARL Search Address Register (16 bit) */
#define B53_ARL_SRCH_ADDR 0x51
#define B53_ARL_SRCH_ADDR_25 0x22
#define B53_ARL_SRCH_ADDR_65 0x24
#define ARL_ADDR_MASK GENMASK(14, 0)
/* ARL Search MAC/VID Result (64 bit) */
#define B53_ARL_SRCH_RSTL_0_MACVID 0x60
/* Single register search result on 5325 */
#define B53_ARL_SRCH_RSTL_0_MACVID_25 0x24
/* Single register search result on 5365 */
#define B53_ARL_SRCH_RSTL_0_MACVID_65 0x30
/* ARL Search Data Result (32 bit) */
#define B53_ARL_SRCH_RSTL_0 0x68
#define B53_ARL_SRCH_RSTL_MACVID(x) (B53_ARL_SRCH_RSTL_0_MACVID + ((x) * 0x10))
#define B53_ARL_SRCH_RSTL(x) (B53_ARL_SRCH_RSTL_0 + ((x) * 0x10))
/*************************************************************************
* Port VLAN Registers
*************************************************************************/
/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
#define B53_PVLAN_PORT_MASK(i) ((i) * 2)
/*************************************************************************
* 802.1Q Page Registers
*************************************************************************/
/* Global QoS Control (8 bit) */
#define B53_QOS_GLOBAL_CTL 0x00
/* Enable 802.1Q for individual Ports (16 bit) */
#define B53_802_1P_EN 0x04
/*************************************************************************
* VLAN Page Registers
*************************************************************************/
/* VLAN Control 0 (8 bit) */
#define B53_VLAN_CTRL0 0x00
#define VC0_8021PF_CTRL_MASK 0x3
#define VC0_8021PF_CTRL_NONE 0x0
#define VC0_8021PF_CTRL_CHANGE_PRI 0x1
#define VC0_8021PF_CTRL_CHANGE_VID 0x2
#define VC0_8021PF_CTRL_CHANGE_BOTH 0x3
#define VC0_8021QF_CTRL_MASK 0xc
#define VC0_8021QF_CTRL_CHANGE_PRI 0x1
#define VC0_8021QF_CTRL_CHANGE_VID 0x2
#define VC0_8021QF_CTRL_CHANGE_BOTH 0x3
#define VC0_RESERVED_1 BIT(1)
#define VC0_DROP_VID_MISS BIT(4)
#define VC0_VID_HASH_VID BIT(5)
#define VC0_VID_CHK_EN BIT(6) /* Use VID,DA or VID,SA */
#define VC0_VLAN_EN BIT(7) /* 802.1Q VLAN Enabled */
/* VLAN Control 1 (8 bit) */
#define B53_VLAN_CTRL1 0x01
#define VC1_RX_MCST_TAG_EN BIT(1)
#define VC1_RX_MCST_FWD_EN BIT(2)
#define VC1_RX_MCST_UNTAG_EN BIT(3)
/* VLAN Control 2 (8 bit) */
#define B53_VLAN_CTRL2 0x02
/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */
#define B53_VLAN_CTRL3 0x03
#define B53_VLAN_CTRL3_63XX 0x04
#define VC3_MAXSIZE_1532 BIT(6) /* 5325 only */
#define VC3_HIGH_8BIT_EN BIT(7) /* 5325 only */
/* VLAN Control 4 (8 bit) */
#define B53_VLAN_CTRL4 0x05
#define B53_VLAN_CTRL4_25 0x04
#define B53_VLAN_CTRL4_63XX 0x06
#define VC4_ING_VID_CHECK_S 6
#define VC4_ING_VID_CHECK_MASK (0x3 << VC4_ING_VID_CHECK_S)
#define VC4_ING_VID_VIO_FWD 0 /* forward, but do not learn */
#define VC4_ING_VID_VIO_DROP 1 /* drop VID violations */
#define VC4_NO_ING_VID_CHK 2 /* do not check */
#define VC4_ING_VID_VIO_TO_IMP 3 /* redirect to MII port */
/* VLAN Control 5 (8 bit) */
#define B53_VLAN_CTRL5 0x06
#define B53_VLAN_CTRL5_25 0x05
#define B53_VLAN_CTRL5_63XX 0x07
#define VC5_VID_FFF_EN BIT(2)
#define VC5_DROP_VTABLE_MISS BIT(3)
/* VLAN Control 6 (8 bit) */
#define B53_VLAN_CTRL6 0x07
#define B53_VLAN_CTRL6_63XX 0x08
/* VLAN Table Access Register (16 bit) */
#define B53_VLAN_TABLE_ACCESS_25 0x06 /* BCM5325E/5350 */
#define B53_VLAN_TABLE_ACCESS_65 0x08 /* BCM5365 */
#define VTA_VID_LOW_MASK_25 0xf
#define VTA_VID_LOW_MASK_65 0xff
#define VTA_VID_HIGH_S_25 4
#define VTA_VID_HIGH_S_65 8
#define VTA_VID_HIGH_MASK_25 (0xff << VTA_VID_HIGH_S_25E)
#define VTA_VID_HIGH_MASK_65 (0xf << VTA_VID_HIGH_S_65)
#define VTA_RW_STATE BIT(12)
#define VTA_RW_STATE_RD 0
#define VTA_RW_STATE_WR BIT(12)
#define VTA_RW_OP_EN BIT(13)
/* VLAN Read/Write Registers for (16/32 bit) */
#define B53_VLAN_WRITE_25 0x08
#define B53_VLAN_WRITE_65 0x0a
#define B53_VLAN_READ 0x0c
#define VA_MEMBER_MASK 0x3f
#define VA_UNTAG_S_25 6
#define VA_UNTAG_MASK_25 0x3f
#define VA_UNTAG_S_65 7
#define VA_UNTAG_MASK_65 0x1f
#define VA_VID_HIGH_S 12
#define VA_VID_HIGH_MASK (0xffff << VA_VID_HIGH_S)
#define VA_VALID_25 BIT(20)
#define VA_VALID_25_R4 BIT(24)
#define VA_VALID_65 BIT(14)
/* VLAN Port Default Tag (16 bit) */
#define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i))
/*************************************************************************
* Jumbo Frame Page Registers
*************************************************************************/
/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */
#define B53_JUMBO_PORT_MASK 0x01
#define B53_JUMBO_PORT_MASK_63XX 0x04
#define JPM_10_100_JUMBO_EN BIT(24) /* GigE always enabled */
/* Good Frame Max Size without 802.1Q TAG (16 bit) */
#define B53_JUMBO_MAX_SIZE 0x05
#define B53_JUMBO_MAX_SIZE_63XX 0x08
#define JMS_MIN_SIZE 1518
#define JMS_MAX_SIZE 9724
/*************************************************************************
* CFP Configuration Page Registers
*************************************************************************/
/* CFP Control Register with ports map (8 bit) */
#define B53_CFP_CTRL 0x00
#endif /* !__B53_REGS_H */

View File

@ -0,0 +1,331 @@
/*
* B53 register access through SPI
*
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <asm/unaligned.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/platform_data/b53.h>
#include "b53_priv.h"
#define B53_SPI_DATA 0xf0
#define B53_SPI_STATUS 0xfe
#define B53_SPI_CMD_SPIF BIT(7)
#define B53_SPI_CMD_RACK BIT(5)
#define B53_SPI_CMD_READ 0x00
#define B53_SPI_CMD_WRITE 0x01
#define B53_SPI_CMD_NORMAL 0x60
#define B53_SPI_CMD_FAST 0x10
#define B53_SPI_PAGE_SELECT 0xff
static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
unsigned int len)
{
u8 txbuf[2];
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
txbuf[1] = reg;
return spi_write_then_read(spi, txbuf, 2, val, len);
}
static inline int b53_spi_clear_status(struct spi_device *spi)
{
unsigned int i;
u8 rxbuf;
int ret;
for (i = 0; i < 10; i++) {
ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
if (ret)
return ret;
if (!(rxbuf & B53_SPI_CMD_SPIF))
break;
mdelay(1);
}
if (i == 10)
return -EIO;
return 0;
}
static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
{
u8 txbuf[3];
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
txbuf[1] = B53_SPI_PAGE_SELECT;
txbuf[2] = page;
return spi_write(spi, txbuf, sizeof(txbuf));
}
static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
{
int ret = b53_spi_clear_status(spi);
if (ret)
return ret;
return b53_spi_set_page(spi, page);
}
static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
{
u8 rxbuf;
int retry_count;
int ret;
ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
if (ret)
return ret;
for (retry_count = 0; retry_count < 10; retry_count++) {
ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
if (ret)
return ret;
if (rxbuf & B53_SPI_CMD_RACK)
break;
mdelay(1);
}
if (retry_count == 10)
return -EIO;
return 0;
}
static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
unsigned int len)
{
struct spi_device *spi = dev->priv;
int ret;
ret = b53_prepare_reg_access(spi, page);
if (ret)
return ret;
ret = b53_spi_prepare_reg_read(spi, reg);
if (ret)
return ret;
return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
}
static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
{
return b53_spi_read(dev, page, reg, val, 1);
}
static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
{
int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2);
if (!ret)
*val = le16_to_cpu(*val);
return ret;
}
static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
{
int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4);
if (!ret)
*val = le32_to_cpu(*val);
return ret;
}
static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
int ret;
*val = 0;
ret = b53_spi_read(dev, page, reg, (u8 *)val, 6);
if (!ret)
*val = le64_to_cpu(*val);
return ret;
}
static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8);
if (!ret)
*val = le64_to_cpu(*val);
return ret;
}
static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
{
struct spi_device *spi = dev->priv;
int ret;
u8 txbuf[3];
ret = b53_prepare_reg_access(spi, page);
if (ret)
return ret;
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
txbuf[1] = reg;
txbuf[2] = value;
return spi_write(spi, txbuf, sizeof(txbuf));
}
static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
{
struct spi_device *spi = dev->priv;
int ret;
u8 txbuf[4];
ret = b53_prepare_reg_access(spi, page);
if (ret)
return ret;
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
txbuf[1] = reg;
put_unaligned_le16(value, &txbuf[2]);
return spi_write(spi, txbuf, sizeof(txbuf));
}
static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
{
struct spi_device *spi = dev->priv;
int ret;
u8 txbuf[6];
ret = b53_prepare_reg_access(spi, page);
if (ret)
return ret;
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
txbuf[1] = reg;
put_unaligned_le32(value, &txbuf[2]);
return spi_write(spi, txbuf, sizeof(txbuf));
}
static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
{
struct spi_device *spi = dev->priv;
int ret;
u8 txbuf[10];
ret = b53_prepare_reg_access(spi, page);
if (ret)
return ret;
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
txbuf[1] = reg;
put_unaligned_le64(value, &txbuf[2]);
return spi_write(spi, txbuf, sizeof(txbuf) - 2);
}
static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
{
struct spi_device *spi = dev->priv;
int ret;
u8 txbuf[10];
ret = b53_prepare_reg_access(spi, page);
if (ret)
return ret;
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
txbuf[1] = reg;
put_unaligned_le64(value, &txbuf[2]);
return spi_write(spi, txbuf, sizeof(txbuf));
}
static struct b53_io_ops b53_spi_ops = {
.read8 = b53_spi_read8,
.read16 = b53_spi_read16,
.read32 = b53_spi_read32,
.read48 = b53_spi_read48,
.read64 = b53_spi_read64,
.write8 = b53_spi_write8,
.write16 = b53_spi_write16,
.write32 = b53_spi_write32,
.write48 = b53_spi_write48,
.write64 = b53_spi_write64,
};
static int b53_spi_probe(struct spi_device *spi)
{
struct b53_device *dev;
int ret;
dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
if (!dev)
return -ENOMEM;
if (spi->dev.platform_data)
dev->pdata = spi->dev.platform_data;
ret = b53_switch_register(dev);
if (ret)
return ret;
spi_set_drvdata(spi, dev);
return 0;
}
static int b53_spi_remove(struct spi_device *spi)
{
struct b53_device *dev = spi_get_drvdata(spi);
if (dev)
b53_switch_remove(dev);
return 0;
}
static struct spi_driver b53_spi_driver = {
.driver = {
.name = "b53-switch",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = b53_spi_probe,
.remove = b53_spi_remove,
};
module_spi_driver(b53_spi_driver);
MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
MODULE_DESCRIPTION("B53 SPI access driver");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -0,0 +1,442 @@
/*
* B53 register access through Switch Register Access Bridge Registers
*
* Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/platform_data/b53.h>
#include <linux/of.h>
#include "b53_priv.h"
/* command and status register of the SRAB */
#define B53_SRAB_CMDSTAT 0x2c
#define B53_SRAB_CMDSTAT_RST BIT(2)
#define B53_SRAB_CMDSTAT_WRITE BIT(1)
#define B53_SRAB_CMDSTAT_GORDYN BIT(0)
#define B53_SRAB_CMDSTAT_PAGE 24
#define B53_SRAB_CMDSTAT_REG 16
/* high order word of write data to switch registe */
#define B53_SRAB_WD_H 0x30
/* low order word of write data to switch registe */
#define B53_SRAB_WD_L 0x34
/* high order word of read data from switch register */
#define B53_SRAB_RD_H 0x38
/* low order word of read data from switch register */
#define B53_SRAB_RD_L 0x3c
/* command and status register of the SRAB */
#define B53_SRAB_CTRLS 0x40
#define B53_SRAB_CTRLS_RCAREQ BIT(3)
#define B53_SRAB_CTRLS_RCAGNT BIT(4)
#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6)
/* the register captures interrupt pulses from the switch */
#define B53_SRAB_INTR 0x44
#define B53_SRAB_INTR_P(x) BIT(x)
#define B53_SRAB_SWITCH_PHY BIT(8)
#define B53_SRAB_1588_SYNC BIT(9)
#define B53_SRAB_IMP1_SLEEP_TIMER BIT(10)
#define B53_SRAB_P7_SLEEP_TIMER BIT(11)
#define B53_SRAB_IMP0_SLEEP_TIMER BIT(12)
struct b53_srab_priv {
void __iomem *regs;
};
static int b53_srab_request_grant(struct b53_device *dev)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
u32 ctrls;
int i;
ctrls = readl(regs + B53_SRAB_CTRLS);
ctrls |= B53_SRAB_CTRLS_RCAREQ;
writel(ctrls, regs + B53_SRAB_CTRLS);
for (i = 0; i < 20; i++) {
ctrls = readl(regs + B53_SRAB_CTRLS);
if (ctrls & B53_SRAB_CTRLS_RCAGNT)
break;
usleep_range(10, 100);
}
if (WARN_ON(i == 5))
return -EIO;
return 0;
}
static void b53_srab_release_grant(struct b53_device *dev)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
u32 ctrls;
ctrls = readl(regs + B53_SRAB_CTRLS);
ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
writel(ctrls, regs + B53_SRAB_CTRLS);
}
static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int i;
u32 cmdstat;
/* set register address */
cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
(reg << B53_SRAB_CMDSTAT_REG) |
B53_SRAB_CMDSTAT_GORDYN |
op;
writel(cmdstat, regs + B53_SRAB_CMDSTAT);
/* check if operation completed */
for (i = 0; i < 5; ++i) {
cmdstat = readl(regs + B53_SRAB_CMDSTAT);
if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
break;
usleep_range(10, 100);
}
if (WARN_ON(i == 5))
return -EIO;
return 0;
}
static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
ret = b53_srab_op(dev, page, reg, 0);
if (ret)
goto err;
*val = readl(regs + B53_SRAB_RD_L) & 0xff;
err:
b53_srab_release_grant(dev);
return ret;
}
static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
ret = b53_srab_op(dev, page, reg, 0);
if (ret)
goto err;
*val = readl(regs + B53_SRAB_RD_L) & 0xffff;
err:
b53_srab_release_grant(dev);
return ret;
}
static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
ret = b53_srab_op(dev, page, reg, 0);
if (ret)
goto err;
*val = readl(regs + B53_SRAB_RD_L);
err:
b53_srab_release_grant(dev);
return ret;
}
static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
ret = b53_srab_op(dev, page, reg, 0);
if (ret)
goto err;
*val = readl(regs + B53_SRAB_RD_L);
*val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
err:
b53_srab_release_grant(dev);
return ret;
}
static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
ret = b53_srab_op(dev, page, reg, 0);
if (ret)
goto err;
*val = readl(regs + B53_SRAB_RD_L);
*val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
err:
b53_srab_release_grant(dev);
return ret;
}
static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
writel(value, regs + B53_SRAB_WD_L);
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
err:
b53_srab_release_grant(dev);
return ret;
}
static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
u16 value)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
writel(value, regs + B53_SRAB_WD_L);
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
err:
b53_srab_release_grant(dev);
return ret;
}
static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
u32 value)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
writel(value, regs + B53_SRAB_WD_L);
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
err:
b53_srab_release_grant(dev);
return ret;
}
static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
u64 value)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
writel((u32)value, regs + B53_SRAB_WD_L);
writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
err:
b53_srab_release_grant(dev);
return ret;
}
static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
u64 value)
{
struct b53_srab_priv *priv = dev->priv;
u8 __iomem *regs = priv->regs;
int ret = 0;
ret = b53_srab_request_grant(dev);
if (ret)
goto err;
writel((u32)value, regs + B53_SRAB_WD_L);
writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
err:
b53_srab_release_grant(dev);
return ret;
}
static struct b53_io_ops b53_srab_ops = {
.read8 = b53_srab_read8,
.read16 = b53_srab_read16,
.read32 = b53_srab_read32,
.read48 = b53_srab_read48,
.read64 = b53_srab_read64,
.write8 = b53_srab_write8,
.write16 = b53_srab_write16,
.write32 = b53_srab_write32,
.write48 = b53_srab_write48,
.write64 = b53_srab_write64,
};
static const struct of_device_id b53_srab_of_match[] = {
{ .compatible = "brcm,bcm53010-srab" },
{ .compatible = "brcm,bcm53011-srab" },
{ .compatible = "brcm,bcm53012-srab" },
{ .compatible = "brcm,bcm53018-srab" },
{ .compatible = "brcm,bcm53019-srab" },
{ .compatible = "brcm,bcm5301x-srab" },
{ .compatible = "brcm,bcm58522-srab", .data = (void *)BCM58XX_DEVICE_ID },
{ .compatible = "brcm,bcm58525-srab", .data = (void *)BCM58XX_DEVICE_ID },
{ .compatible = "brcm,bcm58535-srab", .data = (void *)BCM58XX_DEVICE_ID },
{ .compatible = "brcm,bcm58622-srab", .data = (void *)BCM58XX_DEVICE_ID },
{ .compatible = "brcm,bcm58623-srab", .data = (void *)BCM58XX_DEVICE_ID },
{ .compatible = "brcm,bcm58625-srab", .data = (void *)BCM58XX_DEVICE_ID },
{ .compatible = "brcm,bcm88312-srab", .data = (void *)BCM58XX_DEVICE_ID },
{ .compatible = "brcm,nsp-srab", .data = (void *)BCM58XX_DEVICE_ID },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, b53_srab_of_match);
static int b53_srab_probe(struct platform_device *pdev)
{
struct b53_platform_data *pdata = pdev->dev.platform_data;
struct device_node *dn = pdev->dev.of_node;
const struct of_device_id *of_id = NULL;
struct b53_srab_priv *priv;
struct b53_device *dev;
struct resource *r;
if (dn)
of_id = of_match_node(b53_srab_of_match, dn);
if (of_id) {
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdata->chip_id = (u32)(unsigned long)of_id->data;
}
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->regs = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(priv->regs))
return -ENOMEM;
dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv);
if (!dev)
return -ENOMEM;
if (pdata)
dev->pdata = pdata;
platform_set_drvdata(pdev, dev);
return b53_switch_register(dev);
}
static int b53_srab_remove(struct platform_device *pdev)
{
struct b53_device *dev = platform_get_drvdata(pdev);
if (dev)
b53_switch_remove(dev);
return 0;
}
static struct platform_driver b53_srab_driver = {
.probe = b53_srab_probe,
.remove = b53_srab_remove,
.driver = {
.name = "b53-srab-switch",
.of_match_table = b53_srab_of_match,
},
};
module_platform_driver(b53_srab_driver);
MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -22,6 +22,7 @@
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
#include <net/dsa.h>
#include <linux/ethtool.h>
#include <linux/if_bridge.h>
@ -460,19 +461,13 @@ static int bcm_sf2_sw_set_eee(struct dsa_switch *ds, int port,
return 0;
}
/* Fast-ageing of ARL entries for a given port, equivalent to an ARL
* flush for that port.
*/
static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port)
static int bcm_sf2_fast_age_op(struct bcm_sf2_priv *priv)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
unsigned int timeout = 1000;
u32 reg;
core_writel(priv, port, CORE_FAST_AGE_PORT);
reg = core_readl(priv, CORE_FAST_AGE_CTRL);
reg |= EN_AGE_PORT | EN_AGE_DYNAMIC | FAST_AGE_STR_DONE;
reg |= EN_AGE_PORT | EN_AGE_VLAN | EN_AGE_DYNAMIC | FAST_AGE_STR_DONE;
core_writel(priv, reg, CORE_FAST_AGE_CTRL);
do {
@ -491,13 +486,98 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port)
return 0;
}
/* Fast-ageing of ARL entries for a given port, equivalent to an ARL
* flush for that port.
*/
static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
core_writel(priv, port, CORE_FAST_AGE_PORT);
return bcm_sf2_fast_age_op(priv);
}
static int bcm_sf2_sw_fast_age_vlan(struct bcm_sf2_priv *priv, u16 vid)
{
core_writel(priv, vid, CORE_FAST_AGE_VID);
return bcm_sf2_fast_age_op(priv);
}
static int bcm_sf2_vlan_op_wait(struct bcm_sf2_priv *priv)
{
unsigned int timeout = 10;
u32 reg;
do {
reg = core_readl(priv, CORE_ARLA_VTBL_RWCTRL);
if (!(reg & ARLA_VTBL_STDN))
return 0;
usleep_range(1000, 2000);
} while (timeout--);
return -ETIMEDOUT;
}
static int bcm_sf2_vlan_op(struct bcm_sf2_priv *priv, u8 op)
{
core_writel(priv, ARLA_VTBL_STDN | op, CORE_ARLA_VTBL_RWCTRL);
return bcm_sf2_vlan_op_wait(priv);
}
static void bcm_sf2_set_vlan_entry(struct bcm_sf2_priv *priv, u16 vid,
struct bcm_sf2_vlan *vlan)
{
int ret;
core_writel(priv, vid & VTBL_ADDR_INDEX_MASK, CORE_ARLA_VTBL_ADDR);
core_writel(priv, vlan->untag << UNTAG_MAP_SHIFT | vlan->members,
CORE_ARLA_VTBL_ENTRY);
ret = bcm_sf2_vlan_op(priv, ARLA_VTBL_CMD_WRITE);
if (ret)
pr_err("failed to write VLAN entry\n");
}
static int bcm_sf2_get_vlan_entry(struct bcm_sf2_priv *priv, u16 vid,
struct bcm_sf2_vlan *vlan)
{
u32 entry;
int ret;
core_writel(priv, vid & VTBL_ADDR_INDEX_MASK, CORE_ARLA_VTBL_ADDR);
ret = bcm_sf2_vlan_op(priv, ARLA_VTBL_CMD_READ);
if (ret)
return ret;
entry = core_readl(priv, CORE_ARLA_VTBL_ENTRY);
vlan->members = entry & FWD_MAP_MASK;
vlan->untag = (entry >> UNTAG_MAP_SHIFT) & UNTAG_MAP_MASK;
return 0;
}
static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
struct net_device *bridge)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
s8 cpu_port = ds->dst->cpu_port;
unsigned int i;
u32 reg, p_ctl;
/* Make this port leave the all VLANs join since we will have proper
* VLAN entries from now on
*/
reg = core_readl(priv, CORE_JOIN_ALL_VLAN_EN);
reg &= ~BIT(port);
if ((reg & BIT(cpu_port)) == BIT(cpu_port))
reg &= ~BIT(cpu_port);
core_writel(priv, reg, CORE_JOIN_ALL_VLAN_EN);
priv->port_sts[port].bridge_dev = bridge;
p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
@ -529,6 +609,7 @@ static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
struct net_device *bridge = priv->port_sts[port].bridge_dev;
s8 cpu_port = ds->dst->cpu_port;
unsigned int i;
u32 reg, p_ctl;
@ -552,6 +633,13 @@ static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port)
core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port));
priv->port_sts[port].vlan_ctl_mask = p_ctl;
priv->port_sts[port].bridge_dev = NULL;
/* Make this port join all VLANs without VLAN entries */
reg = core_readl(priv, CORE_JOIN_ALL_VLAN_EN);
reg |= BIT(port);
if (!(reg & BIT(cpu_port)))
reg |= BIT(cpu_port);
core_writel(priv, reg, CORE_JOIN_ALL_VLAN_EN);
}
static void bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
@ -804,7 +892,7 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
int (*cb)(struct switchdev_obj *obj))
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
struct net_device *dev = ds->ports[port];
struct net_device *dev = ds->ports[port].netdev;
struct bcm_sf2_arl_entry results[2];
unsigned int count = 0;
int ret;
@ -836,6 +924,66 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
return 0;
}
static int bcm_sf2_sw_indir_rw(struct bcm_sf2_priv *priv, int op, int addr,
int regnum, u16 val)
{
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_mdio_read(struct mii_bus *bus, int addr, int regnum)
{
struct bcm_sf2_priv *priv = bus->priv;
/* Intercept reads from Broadcom pseudo-PHY address, else, send
* them to our master MDIO bus controller
*/
if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0);
else
return mdiobus_read(priv->master_mii_bus, addr, regnum);
}
static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
u16 val)
{
struct bcm_sf2_priv *priv = bus->priv;
/* Intercept writes to the Broadcom pseudo-PHY address, else,
* send them to our master MDIO bus controller
*/
if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val);
else
mdiobus_write(priv->master_mii_bus, addr, regnum, val);
return 0;
}
static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
{
struct bcm_sf2_priv *priv = dev_id;
@ -932,133 +1080,70 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv,
}
}
static int bcm_sf2_sw_setup(struct dsa_switch *ds)
static int bcm_sf2_mdio_register(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;
static int index;
int err;
spin_lock_init(&priv->indir_lock);
mutex_init(&priv->stats_mutex);
/* Find our integrated MDIO bus node */
dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio");
priv->master_mii_bus = of_mdio_find_bus(dn);
if (!priv->master_mii_bus)
return -EPROBE_DEFER;
/* All the interesting properties are at the parent device_node
* level
*/
dn = ds->cd->of_node->parent;
bcm_sf2_identify_ports(priv, ds->cd->of_node);
get_device(&priv->master_mii_bus->dev);
priv->master_mii_dn = dn;
priv->irq0 = irq_of_parse_and_map(dn, 0);
priv->irq1 = irq_of_parse_and_map(dn, 1);
priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
if (!priv->slave_mii_bus)
return -ENOMEM;
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]);
ret = -ENOMEM;
goto out_unmap;
}
base++;
}
priv->slave_mii_bus->priv = priv;
priv->slave_mii_bus->name = "sf2 slave mii";
priv->slave_mii_bus->read = bcm_sf2_sw_mdio_read;
priv->slave_mii_bus->write = bcm_sf2_sw_mdio_write;
snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d",
index++);
priv->slave_mii_bus->dev.of_node = dn;
ret = bcm_sf2_sw_rst(priv);
if (ret) {
pr_err("unable to software reset switch: %d\n", ret);
goto out_unmap;
}
/* Disable all interrupts and request them */
bcm_sf2_intr_disable(priv);
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->enabled_port_mask)
bcm_sf2_port_setup(ds, port, NULL);
else if (dsa_is_cpu_port(ds, port))
bcm_sf2_imp_setup(ds, port);
else
bcm_sf2_port_disable(ds, port, NULL);
}
/* Include the pseudo-PHY address and the broadcast PHY address to
* divert reads towards our workaround. This is only required for
* 7445D0, since 7445E0 disconnects the internal switch pseudo-PHY such
* that we can use the regular SWITCH_MDIO master controller instead.
/* Include the pseudo-PHY address to divert reads towards our
* workaround. This is only required for 7445D0, since 7445E0
* disconnects the internal switch pseudo-PHY such that we can use the
* regular SWITCH_MDIO master controller instead.
*
* By default, DSA initializes ds->phys_mii_mask to
* ds->enabled_port_mask to have a 1:1 mapping between Port address
* and PHY address in order to utilize the slave_mii_bus instance to
* read from Port PHYs. This is not what we want here, so we
* initialize phys_mii_mask 0 to always utilize the "master" MDIO
* bus backed by the "mdio-unimac" driver.
* Here we flag the pseudo PHY as needing special treatment and would
* otherwise make all other PHY read/writes go to the master MDIO bus
* controller that comes with this switch backed by the "mdio-unimac"
* driver.
*/
if (of_machine_is_compatible("brcm,bcm7445d0"))
ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0));
priv->indir_phy_mask |= (1 << BRCM_PSEUDO_PHY_ADDR);
else
ds->phys_mii_mask = 0;
priv->indir_phy_mask = 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);
ds->phys_mii_mask = priv->indir_phy_mask;
ds->slave_mii_bus = priv->slave_mii_bus;
priv->slave_mii_bus->parent = ds->dev->parent;
priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask;
rev = reg_readl(priv, REG_PHY_REVISION);
priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;
if (dn)
err = of_mdiobus_register(priv->slave_mii_bus, dn);
else
err = mdiobus_register(priv->slave_mii_bus);
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);
if (err)
of_node_put(dn);
return 0;
return err;
}
out_free_irq0:
free_irq(priv->irq0, priv);
out_unmap:
base = &priv->core;
for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
if (*base)
iounmap(*base);
base++;
}
return ret;
static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv)
{
mdiobus_unregister(priv->slave_mii_bus);
if (priv->master_mii_dn)
of_node_put(priv->master_mii_dn);
}
static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr)
@ -1078,68 +1163,6 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
return priv->hw_params.gphy_rev;
}
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 BRCM_PSEUDO_PHY_ADDR:
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 BRCM_PSEUDO_PHY_ADDR:
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)
{
@ -1248,7 +1271,7 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
* state machine and make it go in PHY_FORCING state instead.
*/
if (!status->link)
netif_carrier_off(ds->ports[port]);
netif_carrier_off(ds->ports[port].netdev);
status->duplex = 1;
} else {
status->link = 1;
@ -1370,14 +1393,309 @@ static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port,
return p->ethtool_ops->set_wol(p, wol);
}
static void bcm_sf2_enable_vlan(struct bcm_sf2_priv *priv, bool enable)
{
u32 mgmt, vc0, vc1, vc4, vc5;
mgmt = core_readl(priv, CORE_SWMODE);
vc0 = core_readl(priv, CORE_VLAN_CTRL0);
vc1 = core_readl(priv, CORE_VLAN_CTRL1);
vc4 = core_readl(priv, CORE_VLAN_CTRL4);
vc5 = core_readl(priv, CORE_VLAN_CTRL5);
mgmt &= ~SW_FWDG_MODE;
if (enable) {
vc0 |= VLAN_EN | VLAN_LEARN_MODE_IVL;
vc1 |= EN_RSV_MCAST_UNTAG | EN_RSV_MCAST_FWDMAP;
vc4 &= ~(INGR_VID_CHK_MASK << INGR_VID_CHK_SHIFT);
vc4 |= INGR_VID_CHK_DROP;
vc5 |= DROP_VTABLE_MISS | EN_VID_FFF_FWD;
} else {
vc0 &= ~(VLAN_EN | VLAN_LEARN_MODE_IVL);
vc1 &= ~(EN_RSV_MCAST_UNTAG | EN_RSV_MCAST_FWDMAP);
vc4 &= ~(INGR_VID_CHK_MASK << INGR_VID_CHK_SHIFT);
vc5 &= ~(DROP_VTABLE_MISS | EN_VID_FFF_FWD);
vc4 |= INGR_VID_CHK_VID_VIOL_IMP;
}
core_writel(priv, vc0, CORE_VLAN_CTRL0);
core_writel(priv, vc1, CORE_VLAN_CTRL1);
core_writel(priv, 0, CORE_VLAN_CTRL3);
core_writel(priv, vc4, CORE_VLAN_CTRL4);
core_writel(priv, vc5, CORE_VLAN_CTRL5);
core_writel(priv, mgmt, CORE_SWMODE);
}
static void bcm_sf2_sw_configure_vlan(struct dsa_switch *ds)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
unsigned int port;
/* Clear all VLANs */
bcm_sf2_vlan_op(priv, ARLA_VTBL_CMD_CLEAR);
for (port = 0; port < priv->hw_params.num_ports; port++) {
if (!((1 << port) & ds->enabled_port_mask))
continue;
core_writel(priv, 1, CORE_DEFAULT_1Q_TAG_P(port));
}
}
static int bcm_sf2_sw_vlan_filtering(struct dsa_switch *ds, int port,
bool vlan_filtering)
{
return 0;
}
static int bcm_sf2_sw_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
bcm_sf2_enable_vlan(priv, true);
return 0;
}
static void bcm_sf2_sw_vlan_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
s8 cpu_port = ds->dst->cpu_port;
struct bcm_sf2_vlan *vl;
u16 vid;
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
vl = &priv->vlans[vid];
bcm_sf2_get_vlan_entry(priv, vid, vl);
vl->members |= BIT(port) | BIT(cpu_port);
if (untagged)
vl->untag |= BIT(port) | BIT(cpu_port);
else
vl->untag &= ~(BIT(port) | BIT(cpu_port));
bcm_sf2_set_vlan_entry(priv, vid, vl);
bcm_sf2_sw_fast_age_vlan(priv, vid);
}
if (pvid) {
core_writel(priv, vlan->vid_end, CORE_DEFAULT_1Q_TAG_P(port));
core_writel(priv, vlan->vid_end,
CORE_DEFAULT_1Q_TAG_P(cpu_port));
bcm_sf2_sw_fast_age_vlan(priv, vid);
}
}
static int bcm_sf2_sw_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
s8 cpu_port = ds->dst->cpu_port;
struct bcm_sf2_vlan *vl;
u16 vid, pvid;
int ret;
pvid = core_readl(priv, CORE_DEFAULT_1Q_TAG_P(port));
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
vl = &priv->vlans[vid];
ret = bcm_sf2_get_vlan_entry(priv, vid, vl);
if (ret)
return ret;
vl->members &= ~BIT(port);
if ((vl->members & BIT(cpu_port)) == BIT(cpu_port))
vl->members = 0;
if (pvid == vid)
pvid = 0;
if (untagged) {
vl->untag &= ~BIT(port);
if ((vl->untag & BIT(port)) == BIT(cpu_port))
vl->untag = 0;
}
bcm_sf2_set_vlan_entry(priv, vid, vl);
bcm_sf2_sw_fast_age_vlan(priv, vid);
}
core_writel(priv, pvid, CORE_DEFAULT_1Q_TAG_P(port));
core_writel(priv, pvid, CORE_DEFAULT_1Q_TAG_P(cpu_port));
bcm_sf2_sw_fast_age_vlan(priv, vid);
return 0;
}
static int bcm_sf2_sw_vlan_dump(struct dsa_switch *ds, int port,
struct switchdev_obj_port_vlan *vlan,
int (*cb)(struct switchdev_obj *obj))
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
struct bcm_sf2_port_status *p = &priv->port_sts[port];
struct bcm_sf2_vlan *vl;
u16 vid, pvid;
int err = 0;
pvid = core_readl(priv, CORE_DEFAULT_1Q_TAG_P(port));
for (vid = 0; vid < VLAN_N_VID; vid++) {
vl = &priv->vlans[vid];
if (!(vl->members & BIT(port)))
continue;
vlan->vid_begin = vlan->vid_end = vid;
vlan->flags = 0;
if (vl->untag & BIT(port))
vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
if (p->pvid == vid)
vlan->flags |= BRIDGE_VLAN_INFO_PVID;
err = cb(&vlan->obj);
if (err)
break;
}
return err;
}
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->cd->of_node->parent;
bcm_sf2_identify_ports(priv, ds->cd->of_node);
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]);
ret = -ENOMEM;
goto out_unmap;
}
base++;
}
ret = bcm_sf2_sw_rst(priv);
if (ret) {
pr_err("unable to software reset switch: %d\n", ret);
goto out_unmap;
}
ret = bcm_sf2_mdio_register(ds);
if (ret) {
pr_err("failed to register MDIO bus\n");
goto out_unmap;
}
/* Disable all interrupts and request them */
bcm_sf2_intr_disable(priv);
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->enabled_port_mask)
bcm_sf2_port_setup(ds, port, NULL);
else if (dsa_is_cpu_port(ds, port))
bcm_sf2_imp_setup(ds, port);
else
bcm_sf2_port_disable(ds, port, NULL);
}
bcm_sf2_sw_configure_vlan(ds);
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);
rev = reg_readl(priv, REG_PHY_REVISION);
priv->hw_params.gphy_rev = rev & PHY_REVISION_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++) {
if (*base)
iounmap(*base);
base++;
}
bcm_sf2_mdio_unregister(priv);
return ret;
}
static struct dsa_switch_driver bcm_sf2_switch_driver = {
.tag_protocol = DSA_TAG_PROTO_BRCM,
.probe = bcm_sf2_sw_drv_probe,
.setup = bcm_sf2_sw_setup,
.set_addr = bcm_sf2_sw_set_addr,
.get_phy_flags = bcm_sf2_sw_get_phy_flags,
.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,
@ -1398,6 +1716,11 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
.port_fdb_add = bcm_sf2_sw_fdb_add,
.port_fdb_del = bcm_sf2_sw_fdb_del,
.port_fdb_dump = bcm_sf2_sw_fdb_dump,
.port_vlan_filtering = bcm_sf2_sw_vlan_filtering,
.port_vlan_prepare = bcm_sf2_sw_vlan_prepare,
.port_vlan_add = bcm_sf2_sw_vlan_add,
.port_vlan_del = bcm_sf2_sw_vlan_del,
.port_vlan_dump = bcm_sf2_sw_vlan_dump,
};
static int __init bcm_sf2_init(void)

View File

@ -21,6 +21,7 @@
#include <linux/ethtool.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/if_vlan.h>
#include <net/dsa.h>
@ -50,6 +51,7 @@ struct bcm_sf2_port_status {
struct ethtool_eee eee;
u32 vlan_ctl_mask;
u16 pvid;
struct net_device *bridge_dev;
};
@ -63,6 +65,11 @@ struct bcm_sf2_arl_entry {
u8 is_static:1;
};
struct bcm_sf2_vlan {
u16 members;
u16 untag;
};
static inline void bcm_sf2_mac_from_u64(u64 src, u8 *dst)
{
unsigned int i;
@ -142,6 +149,15 @@ struct bcm_sf2_priv {
/* Bitmask of ports having an integrated PHY */
unsigned int int_phy_mask;
/* Master and slave MDIO bus controller */
unsigned int indir_phy_mask;
struct device_node *master_mii_dn;
struct mii_bus *slave_mii_bus;
struct mii_bus *master_mii_bus;
/* Cache of programmed VLANs */
struct bcm_sf2_vlan vlans[VLAN_N_VID];
};
struct bcm_sf2_hw_stats {

View File

@ -274,6 +274,23 @@
#define CORE_ARLA_SRCH_RSLT_MACVID(x) (CORE_ARLA_SRCH_RSLT_0_MACVID + ((x) * 0x40))
#define CORE_ARLA_SRCH_RSLT(x) (CORE_ARLA_SRCH_RSLT_0 + ((x) * 0x40))
#define CORE_ARLA_VTBL_RWCTRL 0x1600
#define ARLA_VTBL_CMD_WRITE 0
#define ARLA_VTBL_CMD_READ 1
#define ARLA_VTBL_CMD_CLEAR 2
#define ARLA_VTBL_STDN (1 << 7)
#define CORE_ARLA_VTBL_ADDR 0x1604
#define VTBL_ADDR_INDEX_MASK 0xfff
#define CORE_ARLA_VTBL_ENTRY 0x160c
#define FWD_MAP_MASK 0x1ff
#define UNTAG_MAP_MASK 0x1ff
#define UNTAG_MAP_SHIFT 9
#define MSTP_INDEX_MASK 0x7
#define MSTP_INDEX_SHIFT 18
#define FWD_MODE (1 << 21)
#define CORE_MEM_PSM_VDD_CTRL 0x2380
#define P_TXQ_PSM_VDD_SHIFT 2
#define P_TXQ_PSM_VDD_MASK 0x3
@ -287,6 +304,59 @@
#define CORE_PORT_VLAN_CTL_PORT(x) (0xc400 + ((x) * 0x8))
#define PORT_VLAN_CTRL_MASK 0x1ff
#define CORE_VLAN_CTRL0 0xd000
#define CHANGE_1P_VID_INNER (1 << 0)
#define CHANGE_1P_VID_OUTER (1 << 1)
#define CHANGE_1Q_VID (1 << 3)
#define VLAN_LEARN_MODE_SVL (0 << 5)
#define VLAN_LEARN_MODE_IVL (3 << 5)
#define VLAN_EN (1 << 7)
#define CORE_VLAN_CTRL1 0xd004
#define EN_RSV_MCAST_FWDMAP (1 << 2)
#define EN_RSV_MCAST_UNTAG (1 << 3)
#define EN_IPMC_BYPASS_FWDMAP (1 << 5)
#define EN_IPMC_BYPASS_UNTAG (1 << 6)
#define CORE_VLAN_CTRL2 0xd008
#define EN_MIIM_BYPASS_V_FWDMAP (1 << 2)
#define EN_GMRP_GVRP_V_FWDMAP (1 << 5)
#define EN_GMRP_GVRP_UNTAG_MAP (1 << 6)
#define CORE_VLAN_CTRL3 0xd00c
#define EN_DROP_NON1Q_MASK 0x1ff
#define CORE_VLAN_CTRL4 0xd014
#define RESV_MCAST_FLOOD (1 << 1)
#define EN_DOUBLE_TAG_MASK 0x3
#define EN_DOUBLE_TAG_SHIFT 2
#define EN_MGE_REV_GMRP (1 << 4)
#define EN_MGE_REV_GVRP (1 << 5)
#define INGR_VID_CHK_SHIFT 6
#define INGR_VID_CHK_MASK 0x3
#define INGR_VID_CHK_FWD (0 << INGR_VID_CHK_SHIFT)
#define INGR_VID_CHK_DROP (1 << INGR_VID_CHK_SHIFT)
#define INGR_VID_CHK_NO_CHK (2 << INGR_VID_CHK_SHIFT)
#define INGR_VID_CHK_VID_VIOL_IMP (3 << INGR_VID_CHK_SHIFT)
#define CORE_VLAN_CTRL5 0xd018
#define EN_CPU_RX_BYP_INNER_CRCCHCK (1 << 0)
#define EN_VID_FFF_FWD (1 << 2)
#define DROP_VTABLE_MISS (1 << 3)
#define EGRESS_DIR_FRM_BYP_TRUNK_EN (1 << 4)
#define PRESV_NON1Q (1 << 6)
#define CORE_VLAN_CTRL6 0xd01c
#define STRICT_SFD_DETECT (1 << 0)
#define DIS_ARL_BUST_LMIT (1 << 4)
#define CORE_DEFAULT_1Q_TAG_P(x) (0xd040 + ((x) * 8))
#define CFI_SHIFT 12
#define PRI_SHIFT 13
#define PRI_MASK 0x7
#define CORE_JOIN_ALL_VLAN_EN 0xd140
#define CORE_EEE_EN_CTRL 0x24800
#define CORE_EEE_LPI_INDICATE 0x24810

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
config NET_DSA_MV88E6XXX
tristate "Marvell 88E6xxx Ethernet switch fabric support"
depends on NET_DSA
select NET_DSA_TAG_EDSA
help
This driver adds support for most of the Marvell 88E6xxx models of
Ethernet switch chips, except 88E6060.

View File

@ -0,0 +1 @@
obj-$(CONFIG_NET_DSA_MV88E6XXX) += chip.o

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
/*
* net/dsa/mv88e6xxx.h - Marvell 88e6xxx switch chip support
* Marvell 88e6xxx common definitions
*
* Copyright (c) 2008 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
@ -293,28 +294,38 @@
#define GLOBAL2_TRUNK_MASK 0x07
#define GLOBAL2_TRUNK_MASK_UPDATE BIT(15)
#define GLOBAL2_TRUNK_MASK_NUM_SHIFT 12
#define GLOBAL2_TRUNK_MASK_HASK BIT(11)
#define GLOBAL2_TRUNK_MAPPING 0x08
#define GLOBAL2_TRUNK_MAPPING_UPDATE BIT(15)
#define GLOBAL2_TRUNK_MAPPING_ID_SHIFT 11
#define GLOBAL2_INGRESS_OP 0x09
#define GLOBAL2_INGRESS_DATA 0x0a
#define GLOBAL2_IRL_CMD 0x09
#define GLOBAL2_IRL_CMD_BUSY BIT(15)
#define GLOBAL2_IRL_CMD_OP_INIT_ALL ((0x001 << 12) | GLOBAL2_IRL_CMD_BUSY)
#define GLOBAL2_IRL_CMD_OP_INIT_SEL ((0x010 << 12) | GLOBAL2_IRL_CMD_BUSY)
#define GLOBAL2_IRL_CMD_OP_WRITE_SEL ((0x011 << 12) | GLOBAL2_IRL_CMD_BUSY)
#define GLOBAL2_IRL_CMD_OP_READ_SEL ((0x100 << 12) | GLOBAL2_IRL_CMD_BUSY)
#define GLOBAL2_IRL_DATA 0x0a
#define GLOBAL2_PVT_ADDR 0x0b
#define GLOBAL2_PVT_ADDR_BUSY BIT(15)
#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY)
#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY)
#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY)
#define GLOBAL2_PVT_DATA 0x0c
#define GLOBAL2_SWITCH_MAC 0x0d
#define GLOBAL2_SWITCH_MAC_BUSY BIT(15)
#define GLOBAL2_ATU_STATS 0x0e
#define GLOBAL2_PRIO_OVERRIDE 0x0f
#define GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP BIT(7)
#define GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT 4
#define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3)
#define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0
#define GLOBAL2_EEPROM_OP 0x14
#define GLOBAL2_EEPROM_OP_BUSY BIT(15)
#define GLOBAL2_EEPROM_OP_WRITE ((3 << 12) | GLOBAL2_EEPROM_OP_BUSY)
#define GLOBAL2_EEPROM_OP_READ ((4 << 12) | GLOBAL2_EEPROM_OP_BUSY)
#define GLOBAL2_EEPROM_OP_LOAD BIT(11)
#define GLOBAL2_EEPROM_OP_WRITE_EN BIT(10)
#define GLOBAL2_EEPROM_OP_ADDR_MASK 0xff
#define GLOBAL2_EEPROM_CMD 0x14
#define GLOBAL2_EEPROM_CMD_BUSY BIT(15)
#define GLOBAL2_EEPROM_CMD_OP_WRITE ((0x3 << 12) | GLOBAL2_EEPROM_CMD_BUSY)
#define GLOBAL2_EEPROM_CMD_OP_READ ((0x4 << 12) | GLOBAL2_EEPROM_CMD_BUSY)
#define GLOBAL2_EEPROM_CMD_OP_LOAD ((0x6 << 12) | GLOBAL2_EEPROM_CMD_BUSY)
#define GLOBAL2_EEPROM_CMD_RUNNING BIT(11)
#define GLOBAL2_EEPROM_CMD_WRITE_EN BIT(10)
#define GLOBAL2_EEPROM_CMD_ADDR_MASK 0xff
#define GLOBAL2_EEPROM_DATA 0x15
#define GLOBAL2_PTP_AVB_OP 0x16
#define GLOBAL2_PTP_AVB_DATA 0x17
@ -373,24 +384,30 @@ enum mv88e6xxx_family {
};
enum mv88e6xxx_cap {
/* Address Translation Unit.
* The ATU is used to lookup and learn MAC addresses. See GLOBAL_ATU_OP.
*/
MV88E6XXX_CAP_ATU,
/* Energy Efficient Ethernet.
*/
MV88E6XXX_CAP_EEE,
/* EEPROM Command and Data registers.
* See GLOBAL2_EEPROM_OP and GLOBAL2_EEPROM_DATA.
/* Switch Global 2 Registers.
* The device contains a second set of global 16-bit registers.
*/
MV88E6XXX_CAP_EEPROM,
MV88E6XXX_CAP_GLOBAL2,
MV88E6XXX_CAP_G2_MGMT_EN_2X, /* (0x02) MGMT Enable Register 2x */
MV88E6XXX_CAP_G2_MGMT_EN_0X, /* (0x03) MGMT Enable Register 0x */
MV88E6XXX_CAP_G2_IRL_CMD, /* (0x09) Ingress Rate Command */
MV88E6XXX_CAP_G2_IRL_DATA, /* (0x0a) Ingress Rate Data */
MV88E6XXX_CAP_G2_PVT_ADDR, /* (0x0b) Cross Chip Port VLAN Addr */
MV88E6XXX_CAP_G2_PVT_DATA, /* (0x0c) Cross Chip Port VLAN Data */
MV88E6XXX_CAP_G2_SWITCH_MAC, /* (0x0d) Switch MAC/WoL/WoF */
MV88E6XXX_CAP_G2_POT, /* (0x0f) Priority Override Table */
MV88E6XXX_CAP_G2_EEPROM_CMD, /* (0x14) EEPROM Command */
MV88E6XXX_CAP_G2_EEPROM_DATA, /* (0x15) EEPROM Data */
/* Port State Filtering for 802.1D Spanning Tree.
* See PORT_CONTROL_STATE_* values in the PORT_CONTROL register.
/* Multi-chip Addressing Mode.
* Some chips require an indirect SMI access when their SMI device
* address is not zero. See SMI_CMD and SMI_DATA.
*/
MV88E6XXX_CAP_PORTSTATE,
MV88E6XXX_CAP_MULTI_CHIP,
/* PHY Polling Unit.
* See GLOBAL_CONTROL_PPU_ENABLE and GLOBAL_STATUS_PPU_POLLING.
@ -410,25 +427,12 @@ enum mv88e6xxx_cap {
*/
MV88E6XXX_CAP_STU,
/* Switch MAC/WoL/WoF register.
* This requires an indirect access to set the switch MAC address
* through GLOBAL2_SWITCH_MAC, otherwise GLOBAL_MAC_01, GLOBAL_MAC_23,
* and GLOBAL_MAC_45 are used with a direct access.
*/
MV88E6XXX_CAP_SWITCH_MAC_WOL_WOF,
/* Internal temperature sensor.
* Available from any enabled port's PHY register 26, page 6.
*/
MV88E6XXX_CAP_TEMP,
MV88E6XXX_CAP_TEMP_LIMIT,
/* In-chip Port Based VLANs.
* Each port VLANTable register (see PORT_BASE_VLAN) is used to restrict
* the output (or egress) ports to which it is allowed to send frames.
*/
MV88E6XXX_CAP_VLANTABLE,
/* VLAN Table Unit.
* The VTU is used to program 802.1Q VLANs. See GLOBAL_VTU_OP.
*/
@ -436,82 +440,130 @@ enum mv88e6xxx_cap {
};
/* Bitmask of capabilities */
#define MV88E6XXX_FLAG_ATU BIT(MV88E6XXX_CAP_ATU)
#define MV88E6XXX_FLAG_EEE BIT(MV88E6XXX_CAP_EEE)
#define MV88E6XXX_FLAG_EEPROM BIT(MV88E6XXX_CAP_EEPROM)
#define MV88E6XXX_FLAG_PORTSTATE BIT(MV88E6XXX_CAP_PORTSTATE)
#define MV88E6XXX_FLAG_GLOBAL2 BIT(MV88E6XXX_CAP_GLOBAL2)
#define MV88E6XXX_FLAG_G2_MGMT_EN_2X BIT(MV88E6XXX_CAP_G2_MGMT_EN_2X)
#define MV88E6XXX_FLAG_G2_MGMT_EN_0X BIT(MV88E6XXX_CAP_G2_MGMT_EN_0X)
#define MV88E6XXX_FLAG_G2_IRL_CMD BIT(MV88E6XXX_CAP_G2_IRL_CMD)
#define MV88E6XXX_FLAG_G2_IRL_DATA BIT(MV88E6XXX_CAP_G2_IRL_DATA)
#define MV88E6XXX_FLAG_G2_PVT_ADDR BIT(MV88E6XXX_CAP_G2_PVT_ADDR)
#define MV88E6XXX_FLAG_G2_PVT_DATA BIT(MV88E6XXX_CAP_G2_PVT_DATA)
#define MV88E6XXX_FLAG_G2_SWITCH_MAC BIT(MV88E6XXX_CAP_G2_SWITCH_MAC)
#define MV88E6XXX_FLAG_G2_POT BIT(MV88E6XXX_CAP_G2_POT)
#define MV88E6XXX_FLAG_G2_EEPROM_CMD BIT(MV88E6XXX_CAP_G2_EEPROM_CMD)
#define MV88E6XXX_FLAG_G2_EEPROM_DATA BIT(MV88E6XXX_CAP_G2_EEPROM_DATA)
#define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP)
#define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU)
#define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE)
#define MV88E6XXX_FLAG_SMI_PHY BIT(MV88E6XXX_CAP_SMI_PHY)
#define MV88E6XXX_FLAG_STU BIT(MV88E6XXX_CAP_STU)
#define MV88E6XXX_FLAG_SWITCH_MAC BIT(MV88E6XXX_CAP_SWITCH_MAC_WOL_WOF)
#define MV88E6XXX_FLAG_TEMP BIT(MV88E6XXX_CAP_TEMP)
#define MV88E6XXX_FLAG_TEMP_LIMIT BIT(MV88E6XXX_CAP_TEMP_LIMIT)
#define MV88E6XXX_FLAG_VLANTABLE BIT(MV88E6XXX_CAP_VLANTABLE)
#define MV88E6XXX_FLAG_VTU BIT(MV88E6XXX_CAP_VTU)
/* EEPROM Programming via Global2 with 16-bit data */
#define MV88E6XXX_FLAGS_EEPROM16 \
(MV88E6XXX_FLAG_G2_EEPROM_CMD | \
MV88E6XXX_FLAG_G2_EEPROM_DATA)
/* Ingress Rate Limit unit */
#define MV88E6XXX_FLAGS_IRL \
(MV88E6XXX_FLAG_G2_IRL_CMD | \
MV88E6XXX_FLAG_G2_IRL_DATA)
/* Cross-chip Port VLAN Table */
#define MV88E6XXX_FLAGS_PVT \
(MV88E6XXX_FLAG_G2_PVT_ADDR | \
MV88E6XXX_FLAG_G2_PVT_DATA)
#define MV88E6XXX_FLAGS_FAMILY_6095 \
(MV88E6XXX_FLAG_ATU | \
(MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_VLANTABLE | \
MV88E6XXX_FLAG_VTU)
#define MV88E6XXX_FLAGS_FAMILY_6097 \
(MV88E6XXX_FLAG_ATU | \
(MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_VLANTABLE | \
MV88E6XXX_FLAG_VTU)
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_PVT)
#define MV88E6XXX_FLAGS_FAMILY_6165 \
(MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_SWITCH_MAC | \
(MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_SWITCH_MAC | \
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_VTU)
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_PVT)
#define MV88E6XXX_FLAGS_FAMILY_6185 \
(MV88E6XXX_FLAG_ATU | \
(MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU | \
MV88E6XXX_FLAG_VLANTABLE | \
MV88E6XXX_FLAG_VTU)
#define MV88E6XXX_FLAGS_FAMILY_6320 \
(MV88E6XXX_FLAG_ATU | \
MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_EEPROM | \
MV88E6XXX_FLAG_PORTSTATE | \
(MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_SWITCH_MAC | \
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_SMI_PHY | \
MV88E6XXX_FLAG_SWITCH_MAC | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_TEMP_LIMIT | \
MV88E6XXX_FLAG_VLANTABLE | \
MV88E6XXX_FLAG_VTU)
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_EEPROM16 | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_PVT)
#define MV88E6XXX_FLAGS_FAMILY_6351 \
(MV88E6XXX_FLAG_ATU | \
MV88E6XXX_FLAG_PORTSTATE | \
(MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_SWITCH_MAC | \
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_SMI_PHY | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_SWITCH_MAC | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_VLANTABLE | \
MV88E6XXX_FLAG_VTU)
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_PVT)
#define MV88E6XXX_FLAGS_FAMILY_6352 \
(MV88E6XXX_FLAG_ATU | \
MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_EEPROM | \
MV88E6XXX_FLAG_PORTSTATE | \
(MV88E6XXX_FLAG_EEE | \
MV88E6XXX_FLAG_GLOBAL2 | \
MV88E6XXX_FLAG_G2_MGMT_EN_2X | \
MV88E6XXX_FLAG_G2_MGMT_EN_0X | \
MV88E6XXX_FLAG_G2_SWITCH_MAC | \
MV88E6XXX_FLAG_G2_POT | \
MV88E6XXX_FLAG_MULTI_CHIP | \
MV88E6XXX_FLAG_PPU_ACTIVE | \
MV88E6XXX_FLAG_SMI_PHY | \
MV88E6XXX_FLAG_STU | \
MV88E6XXX_FLAG_SWITCH_MAC | \
MV88E6XXX_FLAG_TEMP | \
MV88E6XXX_FLAG_TEMP_LIMIT | \
MV88E6XXX_FLAG_VLANTABLE | \
MV88E6XXX_FLAG_VTU)
MV88E6XXX_FLAG_VTU | \
MV88E6XXX_FLAGS_EEPROM16 | \
MV88E6XXX_FLAGS_IRL | \
MV88E6XXX_FLAGS_PVT)
struct mv88e6xxx_info {
enum mv88e6xxx_family family;
@ -519,6 +571,8 @@ struct mv88e6xxx_info {
const char *name;
unsigned int num_databases;
unsigned int num_ports;
unsigned int port_base_addr;
unsigned int age_time_coeff;
unsigned long flags;
};
@ -541,11 +595,13 @@ struct mv88e6xxx_vtu_stu_entry {
u8 data[DSA_MAX_PORTS];
};
struct mv88e6xxx_ops;
struct mv88e6xxx_priv_port {
struct net_device *bridge_dev;
};
struct mv88e6xxx_priv_state {
struct mv88e6xxx_chip {
const struct mv88e6xxx_info *info;
/* The dsa_switch this private structure is related to */
@ -554,15 +610,13 @@ struct mv88e6xxx_priv_state {
/* The device this structure is associated to */
struct device *dev;
/* When using multi-chip addressing, this mutex protects
* access to the indirect access registers. (In single-chip
* mode, this mutex is effectively useless.)
*/
struct mutex smi_mutex;
/* This mutex protects the access to the switch registers */
struct mutex reg_lock;
/* The MII bus and the address on the bus that is used to
* communication with the switch
*/
const struct mv88e6xxx_ops *smi_ops;
struct mii_bus *bus;
int sw_addr;
@ -579,17 +633,6 @@ struct mv88e6xxx_priv_state {
*/
struct mutex stats_mutex;
/* This mutex serializes phy access for chips with
* indirect phy addressing. It is unused for chips
* with direct phy access.
*/
struct mutex phy_mutex;
/* This mutex serializes eeprom access for chips with
* eeprom support.
*/
struct mutex eeprom_mutex;
struct mv88e6xxx_priv_port ports[DSA_MAX_PORTS];
/* A switch may have a GPIO line tied to its reset pin. Parse
@ -600,6 +643,17 @@ struct mv88e6xxx_priv_state {
/* set to size of eeprom if supported by the switch */
int eeprom_len;
/* Device node for the MDIO bus */
struct device_node *mdio_np;
/* And the MDIO bus itself */
struct mii_bus *mdio_bus;
};
struct mv88e6xxx_ops {
int (*read)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
int (*write)(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
};
enum stat_type {
@ -615,10 +669,10 @@ struct mv88e6xxx_hw_stat {
enum stat_type type;
};
static inline bool mv88e6xxx_has(struct mv88e6xxx_priv_state *ps,
static inline bool mv88e6xxx_has(struct mv88e6xxx_chip *chip,
unsigned long flags)
{
return (ps->info->flags & flags) == flags;
return (chip->info->flags & flags) == flags;
}
#endif

View File

@ -84,7 +84,6 @@ static u32 ax_msg_enable;
struct ax_device {
struct mii_bus *mii_bus;
struct mdiobb_ctrl bb_ctrl;
struct phy_device *phy_dev;
void __iomem *addr_memr;
u8 reg_memr;
int link;
@ -320,7 +319,7 @@ static void ax_block_output(struct net_device *dev, int count,
static void ax_handle_link_change(struct net_device *dev)
{
struct ax_device *ax = to_ax_dev(dev);
struct phy_device *phy_dev = ax->phy_dev;
struct phy_device *phy_dev = dev->phydev;
int status_change = 0;
if (phy_dev->link && ((ax->speed != phy_dev->speed) ||
@ -369,8 +368,6 @@ static int ax_mii_probe(struct net_device *dev)
phy_dev->supported &= PHY_BASIC_FEATURES;
phy_dev->advertising = phy_dev->supported;
ax->phy_dev = phy_dev;
netdev_info(dev, "PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
phy_dev->drv->name, phydev_name(phy_dev), phy_dev->irq);
@ -410,7 +407,7 @@ static int ax_open(struct net_device *dev)
ret = ax_mii_probe(dev);
if (ret)
goto failed_mii_probe;
phy_start(ax->phy_dev);
phy_start(dev->phydev);
ret = ax_ei_open(dev);
if (ret)
@ -421,7 +418,7 @@ static int ax_open(struct net_device *dev)
return 0;
failed_ax_ei_open:
phy_disconnect(ax->phy_dev);
phy_disconnect(dev->phydev);
failed_mii_probe:
ax_phy_switch(dev, 0);
free_irq(dev->irq, dev);
@ -442,7 +439,7 @@ static int ax_close(struct net_device *dev)
/* turn the phy off */
ax_phy_switch(dev, 0);
phy_disconnect(ax->phy_dev);
phy_disconnect(dev->phydev);
free_irq(dev->irq, dev);
return 0;
@ -450,8 +447,7 @@ static int ax_close(struct net_device *dev)
static int ax_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
{
struct ax_device *ax = to_ax_dev(dev);
struct phy_device *phy_dev = ax->phy_dev;
struct phy_device *phy_dev = dev->phydev;
if (!netif_running(dev))
return -EINVAL;
@ -474,28 +470,6 @@ static void ax_get_drvinfo(struct net_device *dev,
strlcpy(info->bus_info, pdev->name, sizeof(info->bus_info));
}
static int ax_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct ax_device *ax = to_ax_dev(dev);
struct phy_device *phy_dev = ax->phy_dev;
if (!phy_dev)
return -ENODEV;
return phy_ethtool_gset(phy_dev, cmd);
}
static int ax_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct ax_device *ax = to_ax_dev(dev);
struct phy_device *phy_dev = ax->phy_dev;
if (!phy_dev)
return -ENODEV;
return phy_ethtool_sset(phy_dev, cmd);
}
static u32 ax_get_msglevel(struct net_device *dev)
{
struct ei_device *ei_local = netdev_priv(dev);
@ -512,12 +486,12 @@ static void ax_set_msglevel(struct net_device *dev, u32 v)
static const struct ethtool_ops ax_ethtool_ops = {
.get_drvinfo = ax_get_drvinfo,
.get_settings = ax_get_settings,
.set_settings = ax_set_settings,
.get_link = ethtool_op_get_link,
.get_ts_info = ethtool_op_get_ts_info,
.get_msglevel = ax_get_msglevel,
.set_msglevel = ax_set_msglevel,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
#ifdef CONFIG_AX88796_93CX6

View File

@ -310,7 +310,7 @@ static int bfin_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
static void bfin_mac_adjust_link(struct net_device *dev)
{
struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = lp->phydev;
struct phy_device *phydev = dev->phydev;
unsigned long flags;
int new_state = 0;
@ -430,7 +430,6 @@ static int mii_probe(struct net_device *dev, int phy_mode)
lp->old_link = 0;
lp->old_speed = 0;
lp->old_duplex = -1;
lp->phydev = phydev;
phy_attached_print(phydev, "mdc_clk=%dHz(mdc_div=%d)@sclk=%dMHz)\n",
MDC_CLK, mdc_div, sclk / 1000000);
@ -450,31 +449,6 @@ static irqreturn_t bfin_mac_wake_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int
bfin_mac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bfin_mac_local *lp = netdev_priv(dev);
if (lp->phydev)
return phy_ethtool_gset(lp->phydev, cmd);
return -EINVAL;
}
static int
bfin_mac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bfin_mac_local *lp = netdev_priv(dev);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (lp->phydev)
return phy_ethtool_sset(lp->phydev, cmd);
return -EINVAL;
}
static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
@ -552,8 +526,6 @@ static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
#endif
static const struct ethtool_ops bfin_mac_ethtool_ops = {
.get_settings = bfin_mac_ethtool_getsettings,
.set_settings = bfin_mac_ethtool_setsettings,
.get_link = ethtool_op_get_link,
.get_drvinfo = bfin_mac_ethtool_getdrvinfo,
.get_wol = bfin_mac_ethtool_getwol,
@ -561,6 +533,8 @@ static const struct ethtool_ops bfin_mac_ethtool_ops = {
#ifdef CONFIG_BFIN_MAC_USE_HWSTAMP
.get_ts_info = bfin_mac_ethtool_get_ts_info,
#endif
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
/**************************************************************************/
@ -1427,7 +1401,7 @@ static void bfin_mac_timeout(struct net_device *dev)
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
bfin_mac_enable(lp->phydev);
bfin_mac_enable(dev->phydev);
/* We can accept TX packets again */
netif_trans_update(dev); /* prevent tx timeout */
@ -1491,8 +1465,6 @@ static void bfin_mac_set_multicast_list(struct net_device *dev)
static int bfin_mac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
struct bfin_mac_local *lp = netdev_priv(netdev);
if (!netif_running(netdev))
return -EINVAL;
@ -1502,8 +1474,8 @@ static int bfin_mac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
case SIOCGHWTSTAMP:
return bfin_mac_hwtstamp_get(netdev, ifr);
default:
if (lp->phydev)
return phy_mii_ioctl(lp->phydev, ifr, cmd);
if (netdev->phydev)
return phy_mii_ioctl(netdev->phydev, ifr, cmd);
else
return -EOPNOTSUPP;
}
@ -1547,12 +1519,12 @@ static int bfin_mac_open(struct net_device *dev)
if (ret)
return ret;
phy_start(lp->phydev);
phy_start(dev->phydev);
setup_system_regs(dev);
setup_mac_addr(dev->dev_addr);
bfin_mac_disable();
ret = bfin_mac_enable(lp->phydev);
ret = bfin_mac_enable(dev->phydev);
if (ret)
return ret;
pr_debug("hardware init finished\n");
@ -1578,8 +1550,8 @@ static int bfin_mac_close(struct net_device *dev)
napi_disable(&lp->napi);
netif_carrier_off(dev);
phy_stop(lp->phydev);
phy_write(lp->phydev, MII_BMCR, BMCR_PDOWN);
phy_stop(dev->phydev);
phy_write(dev->phydev, MII_BMCR, BMCR_PDOWN);
/* clear everything */
bfin_mac_shutdown(dev);

Some files were not shown because too many files have changed in this diff Show More