Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'sf2'

Florian Fainelli says:

====================
dsa: Broadcom Starfighter 2 switch support

This patch series adds support for the Broadcom Starfighter 2 (Roboswitch
successor) using the existing DSA infrastructure. This integrated switch
is heavily used in Set Top Box, Cable gateways and DSL gateways products
from Broadcom, and to a larger extent the new ARM-based Wi-Fi routers although
slightly differently.

Changes in v5 are the introduction of ETH_P_XDSA as suggested by Alexander to
help capture applications see this is a multiplexed DSA approach now.

Changes in v4 are the introducing of an indirection level for DSA switch tag
protocols receive and transmit functions.

I intentionnaly did not address one comment from Alexander who suggested to
move port_names and port_dn in a separate structure since that involves
touching arch/arm/ and arch/blackfin/ code which I am not yet comfortable
doing.

Notable changes in v3 is the preliminary patch that reworks the skb->protocol
override helpers for non-Ethertype switch tags, based on feedback from
Alexander Duyck.

The biggest changes from v1 of this patch series are:

- use the new fixed PHY helpers
- improved the switch driver with more complete features (interrupts,
(RG)MII configuration, memory arrays power down/up, port disabling/enable
VLAN separation

Future work will focus on bringing the upstream driver in feature parity with
the current downstream driver, including:

- adding Wake-on-LAN support to the switch
- adding suspend/resume callbacks for S2/S3 Power Management modes
- extending the switch register interface to cover BCM5310X SoCs
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1772 -112
+39
Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
··· 1 + * Broadcom UniMAC MDIO bus controller 2 + 3 + Required properties: 4 + - compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2", 5 + "brcm,genet-mdio-v3", "brcm,genet-mdio-v4" or "brcm,unimac-mdio" 6 + - reg: address and length of the regsiter set for the device, first one is the 7 + base register, and the second one is optional and for indirect accesses to 8 + larger than 16-bits MDIO transactions 9 + - reg-names: name(s) of the register must be "mdio" and optional "mdio_indir_rw" 10 + - #size-cells: must be 1 11 + - #address-cells: must be 0 12 + 13 + Optional properties: 14 + - interrupts: must be one if the interrupt is shared with the Ethernet MAC or 15 + Ethernet switch this MDIO block is integrated from, or must be two, if there 16 + are two separate interrupts, first one must be "mdio done" and second must be 17 + for "mdio error" 18 + - interrupt-names: must be "mdio_done_error" when there is a share interrupt fed 19 + to this hardware block, or must be "mdio_done" for the first interrupt and 20 + "mdio_error" for the second when there are separate interrupts 21 + 22 + Child nodes of this MDIO bus controller node are standard Ethernet PHY device 23 + nodes as described in Documentation/devicetree/bindings/net/phy.txt 24 + 25 + Example: 26 + 27 + mdio@403c0 { 28 + compatible = "brcm,unimac-mdio"; 29 + reg = <0x403c0 0x8 0x40300 0x18>; 30 + reg-names = "mdio", "mdio_indir_rw"; 31 + #size-cells = <1>; 32 + #address-cells = <0>; 33 + 34 + ... 35 + phy@0 { 36 + compatible = "ethernet-phy-ieee802.3-c22"; 37 + reg = <0>; 38 + }; 39 + };
+78
Documentation/devicetree/bindings/net/broadcom-sf2.txt
··· 1 + * Broadcom Starfighter 2 integrated swich 2 + 3 + Required properties: 4 + 5 + - compatible: should be "brcm,bcm7445-switch-v4.0" 6 + - reg: addresses and length of the register sets for the device, must be 6 7 + pairs of register addresses and lengths 8 + - interrupts: interrupts for the devices, must be two interrupts 9 + - dsa,mii-bus: phandle to the MDIO bus controller, see dsa/dsa.txt 10 + - dsa,ethernet: phandle to the CPU network interface controller, see dsa/dsa.txt 11 + - #size-cells: must be 0 12 + - #address-cells: must be 2, see dsa/dsa.txt 13 + 14 + Subnodes: 15 + 16 + The integrated switch subnode should be specified according to the binding 17 + described in dsa/dsa.txt. 18 + 19 + Optional properties: 20 + 21 + - reg-names: litteral names for the device base register addresses, when present 22 + must be: "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb" 23 + 24 + - interrupt-names: litternal names for the device interrupt lines, when present 25 + must be: "switch_0" and "switch_1" 26 + 27 + - brcm,num-gphy: specify the maximum number of integrated gigabit PHYs in the 28 + switch 29 + 30 + - brcm,num-rgmii-ports: specify the maximum number of RGMII interfaces supported 31 + by the switch 32 + 33 + - brcm,fcb-pause-override: boolean property, if present indicates that the switch 34 + supports Failover Control Block pause override capability 35 + 36 + - brcm,acb-packets-inflight: boolean property, if present indicates that the switch 37 + Admission Control Block supports reporting the number of packets in-flight in a 38 + switch queue 39 + 40 + Example: 41 + 42 + switch_top@f0b00000 { 43 + compatible = "simple-bus"; 44 + #size-cells = <1>; 45 + #address-cells = <1>; 46 + ranges = <0 0xf0b00000 0x40804>; 47 + 48 + ethernet_switch@0 { 49 + compatible = "brcm,bcm7445-switch-v4.0"; 50 + #size-cells = <0>; 51 + #address-cells = <2>; 52 + reg = <0x0 0x40000 53 + 0x40000 0x110 54 + 0x40340 0x30 55 + 0x40380 0x30 56 + 0x40400 0x34 57 + 0x40600 0x208>; 58 + interrupts = <0 0x18 0 59 + 0 0x19 0>; 60 + brcm,num-gphy = <1>; 61 + brcm,num-rgmii-ports = <2>; 62 + brcm,fcb-pause-override; 63 + brcm,acb-packets-inflight; 64 + 65 + ... 66 + switch@0 { 67 + reg = <0 0>; 68 + #size-cells = <0>; 69 + #address-cells <1>; 70 + 71 + port@0 { 72 + label = "gphy"; 73 + reg = <0>; 74 + }; 75 + ... 76 + }; 77 + }; 78 + };
+17
Documentation/devicetree/bindings/net/dsa/dsa.txt
··· 39 39 This property is only used when switches are being 40 40 chained/cascaded together. 41 41 42 + - phy-handle : Phandle to a PHY on an external MDIO bus, not the 43 + switch internal one. See 44 + Documentation/devicetree/bindings/net/ethernet.txt 45 + for details. 46 + 47 + - phy-mode : String representing the connection to the designated 48 + PHY node specified by the 'phy-handle' property. See 49 + Documentation/devicetree/bindings/net/ethernet.txt 50 + for details. 51 + 52 + Optional subnodes: 53 + - fixed-link : Fixed-link subnode describing a link to a non-MDIO 54 + managed entity. See 55 + Documentation/devicetree/bindings/net/fixed-link.txt 56 + for details. 57 + 42 58 Example: 43 59 44 60 dsa@0 { ··· 74 58 port@0 { 75 59 reg = <0>; 76 60 label = "lan1"; 61 + phy-handle = <&phy0>; 77 62 }; 78 63 79 64 port@1 {
+11
drivers/net/dsa/Kconfig
··· 36 36 This enables support for the Marvell 88E6123/6161/6165 37 37 ethernet switch chips. 38 38 39 + config NET_DSA_BCM_SF2 40 + tristate "Broadcom Starfighter 2 Ethernet switch support" 41 + select NET_DSA 42 + select NET_DSA_TAG_BRCM 43 + select FIXED_PHY if NET_DSA_BCM_SF2=y 44 + select BCM7XXX_PHY 45 + select MDIO_BCM_UNIMAC 46 + ---help--- 47 + This enables support for the Broadcom Starfighter 2 Ethernet 48 + switch chips. 49 + 39 50 endmenu
+1
drivers/net/dsa/Makefile
··· 7 7 ifdef CONFIG_NET_DSA_MV88E6131 8 8 mv88e6xxx_drv-y += mv88e6131.o 9 9 endif 10 + obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o
+626
drivers/net/dsa/bcm_sf2.c
··· 1 + /* 2 + * Broadcom Starfighter 2 DSA switch driver 3 + * 4 + * Copyright (C) 2014, Broadcom Corporation 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + */ 11 + 12 + #include <linux/list.h> 13 + #include <linux/module.h> 14 + #include <linux/netdevice.h> 15 + #include <linux/interrupt.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/of.h> 18 + #include <linux/phy.h> 19 + #include <linux/phy_fixed.h> 20 + #include <linux/mii.h> 21 + #include <linux/of.h> 22 + #include <linux/of_irq.h> 23 + #include <linux/of_address.h> 24 + #include <net/dsa.h> 25 + 26 + #include "bcm_sf2.h" 27 + #include "bcm_sf2_regs.h" 28 + 29 + /* String, offset, and register size in bytes if different from 4 bytes */ 30 + static const struct bcm_sf2_hw_stats bcm_sf2_mib[] = { 31 + { "TxOctets", 0x000, 8 }, 32 + { "TxDropPkts", 0x020 }, 33 + { "TxQPKTQ0", 0x030 }, 34 + { "TxBroadcastPkts", 0x040 }, 35 + { "TxMulticastPkts", 0x050 }, 36 + { "TxUnicastPKts", 0x060 }, 37 + { "TxCollisions", 0x070 }, 38 + { "TxSingleCollision", 0x080 }, 39 + { "TxMultipleCollision", 0x090 }, 40 + { "TxDeferredCollision", 0x0a0 }, 41 + { "TxLateCollision", 0x0b0 }, 42 + { "TxExcessiveCollision", 0x0c0 }, 43 + { "TxFrameInDisc", 0x0d0 }, 44 + { "TxPausePkts", 0x0e0 }, 45 + { "TxQPKTQ1", 0x0f0 }, 46 + { "TxQPKTQ2", 0x100 }, 47 + { "TxQPKTQ3", 0x110 }, 48 + { "TxQPKTQ4", 0x120 }, 49 + { "TxQPKTQ5", 0x130 }, 50 + { "RxOctets", 0x140, 8 }, 51 + { "RxUndersizePkts", 0x160 }, 52 + { "RxPausePkts", 0x170 }, 53 + { "RxPkts64Octets", 0x180 }, 54 + { "RxPkts65to127Octets", 0x190 }, 55 + { "RxPkts128to255Octets", 0x1a0 }, 56 + { "RxPkts256to511Octets", 0x1b0 }, 57 + { "RxPkts512to1023Octets", 0x1c0 }, 58 + { "RxPkts1024toMaxPktsOctets", 0x1d0 }, 59 + { "RxOversizePkts", 0x1e0 }, 60 + { "RxJabbers", 0x1f0 }, 61 + { "RxAlignmentErrors", 0x200 }, 62 + { "RxFCSErrors", 0x210 }, 63 + { "RxGoodOctets", 0x220, 8 }, 64 + { "RxDropPkts", 0x240 }, 65 + { "RxUnicastPkts", 0x250 }, 66 + { "RxMulticastPkts", 0x260 }, 67 + { "RxBroadcastPkts", 0x270 }, 68 + { "RxSAChanges", 0x280 }, 69 + { "RxFragments", 0x290 }, 70 + { "RxJumboPkt", 0x2a0 }, 71 + { "RxSymblErr", 0x2b0 }, 72 + { "InRangeErrCount", 0x2c0 }, 73 + { "OutRangeErrCount", 0x2d0 }, 74 + { "EEELpiEvent", 0x2e0 }, 75 + { "EEELpiDuration", 0x2f0 }, 76 + { "RxDiscard", 0x300, 8 }, 77 + { "TxQPKTQ6", 0x320 }, 78 + { "TxQPKTQ7", 0x330 }, 79 + { "TxPkts64Octets", 0x340 }, 80 + { "TxPkts65to127Octets", 0x350 }, 81 + { "TxPkts128to255Octets", 0x360 }, 82 + { "TxPkts256to511Ocets", 0x370 }, 83 + { "TxPkts512to1023Ocets", 0x380 }, 84 + { "TxPkts1024toMaxPktOcets", 0x390 }, 85 + }; 86 + 87 + #define BCM_SF2_STATS_SIZE ARRAY_SIZE(bcm_sf2_mib) 88 + 89 + static void bcm_sf2_sw_get_strings(struct dsa_switch *ds, 90 + int port, uint8_t *data) 91 + { 92 + unsigned int i; 93 + 94 + for (i = 0; i < BCM_SF2_STATS_SIZE; i++) 95 + memcpy(data + i * ETH_GSTRING_LEN, 96 + bcm_sf2_mib[i].string, ETH_GSTRING_LEN); 97 + } 98 + 99 + static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds, 100 + int port, uint64_t *data) 101 + { 102 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 103 + const struct bcm_sf2_hw_stats *s; 104 + unsigned int i; 105 + u64 val = 0; 106 + u32 offset; 107 + 108 + mutex_lock(&priv->stats_mutex); 109 + 110 + /* Now fetch the per-port counters */ 111 + for (i = 0; i < BCM_SF2_STATS_SIZE; i++) { 112 + s = &bcm_sf2_mib[i]; 113 + 114 + /* Do a latched 64-bit read if needed */ 115 + offset = s->reg + CORE_P_MIB_OFFSET(port); 116 + if (s->sizeof_stat == 8) 117 + val = core_readq(priv, offset); 118 + else 119 + val = core_readl(priv, offset); 120 + 121 + data[i] = (u64)val; 122 + } 123 + 124 + mutex_unlock(&priv->stats_mutex); 125 + } 126 + 127 + static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds) 128 + { 129 + return BCM_SF2_STATS_SIZE; 130 + } 131 + 132 + static char *bcm_sf2_sw_probe(struct mii_bus *bus, int sw_addr) 133 + { 134 + return "Broadcom Starfighter 2"; 135 + } 136 + 137 + static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) 138 + { 139 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 140 + unsigned int i; 141 + u32 reg, val; 142 + 143 + /* Enable the port memories */ 144 + reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); 145 + reg &= ~P_TXQ_PSM_VDD(port); 146 + core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL); 147 + 148 + /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */ 149 + reg = core_readl(priv, CORE_IMP_CTL); 150 + reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN); 151 + reg &= ~(RX_DIS | TX_DIS); 152 + core_writel(priv, reg, CORE_IMP_CTL); 153 + 154 + /* Enable forwarding */ 155 + core_writel(priv, SW_FWDG_EN, CORE_SWMODE); 156 + 157 + /* Enable IMP port in dumb mode */ 158 + reg = core_readl(priv, CORE_SWITCH_CTRL); 159 + reg |= MII_DUMB_FWDG_EN; 160 + core_writel(priv, reg, CORE_SWITCH_CTRL); 161 + 162 + /* Resolve which bit controls the Broadcom tag */ 163 + switch (port) { 164 + case 8: 165 + val = BRCM_HDR_EN_P8; 166 + break; 167 + case 7: 168 + val = BRCM_HDR_EN_P7; 169 + break; 170 + case 5: 171 + val = BRCM_HDR_EN_P5; 172 + break; 173 + default: 174 + val = 0; 175 + break; 176 + } 177 + 178 + /* Enable Broadcom tags for IMP port */ 179 + reg = core_readl(priv, CORE_BRCM_HDR_CTRL); 180 + reg |= val; 181 + core_writel(priv, reg, CORE_BRCM_HDR_CTRL); 182 + 183 + /* Enable reception Broadcom tag for CPU TX (switch RX) to 184 + * allow us to tag outgoing frames 185 + */ 186 + reg = core_readl(priv, CORE_BRCM_HDR_RX_DIS); 187 + reg &= ~(1 << port); 188 + core_writel(priv, reg, CORE_BRCM_HDR_RX_DIS); 189 + 190 + /* Enable transmission of Broadcom tags from the switch (CPU RX) to 191 + * allow delivering frames to the per-port net_devices 192 + */ 193 + reg = core_readl(priv, CORE_BRCM_HDR_TX_DIS); 194 + reg &= ~(1 << port); 195 + core_writel(priv, reg, CORE_BRCM_HDR_TX_DIS); 196 + 197 + /* Force link status for IMP port */ 198 + reg = core_readl(priv, CORE_STS_OVERRIDE_IMP); 199 + reg |= (MII_SW_OR | LINK_STS); 200 + core_writel(priv, reg, CORE_STS_OVERRIDE_IMP); 201 + 202 + /* Enable the IMP Port to be in the same VLAN as the other ports 203 + * on a per-port basis such that we only have Port i and IMP in 204 + * the same VLAN. 205 + */ 206 + for (i = 0; i < priv->hw_params.num_ports; i++) { 207 + if (!((1 << i) & ds->phys_port_mask)) 208 + continue; 209 + 210 + reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i)); 211 + reg |= (1 << port); 212 + core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i)); 213 + } 214 + } 215 + 216 + static void bcm_sf2_port_setup(struct dsa_switch *ds, int port) 217 + { 218 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 219 + u32 reg; 220 + 221 + /* Clear the memory power down */ 222 + reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); 223 + reg &= ~P_TXQ_PSM_VDD(port); 224 + core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL); 225 + 226 + /* Clear the Rx and Tx disable bits and set to no spanning tree */ 227 + core_writel(priv, 0, CORE_G_PCTL_PORT(port)); 228 + 229 + /* Enable port 7 interrupts to get notified */ 230 + if (port == 7) 231 + intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF)); 232 + 233 + /* Set this port, and only this one to be in the default VLAN */ 234 + reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port)); 235 + reg &= ~PORT_VLAN_CTRL_MASK; 236 + reg |= (1 << port); 237 + core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port)); 238 + } 239 + 240 + static void bcm_sf2_port_disable(struct dsa_switch *ds, int port) 241 + { 242 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 243 + u32 off, reg; 244 + 245 + if (dsa_is_cpu_port(ds, port)) 246 + off = CORE_IMP_CTL; 247 + else 248 + off = CORE_G_PCTL_PORT(port); 249 + 250 + reg = core_readl(priv, off); 251 + reg |= RX_DIS | TX_DIS; 252 + core_writel(priv, reg, off); 253 + 254 + /* Power down the port memory */ 255 + reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); 256 + reg |= P_TXQ_PSM_VDD(port); 257 + core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL); 258 + } 259 + 260 + static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id) 261 + { 262 + struct bcm_sf2_priv *priv = dev_id; 263 + 264 + priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) & 265 + ~priv->irq0_mask; 266 + intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR); 267 + 268 + return IRQ_HANDLED; 269 + } 270 + 271 + static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id) 272 + { 273 + struct bcm_sf2_priv *priv = dev_id; 274 + 275 + priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) & 276 + ~priv->irq1_mask; 277 + intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR); 278 + 279 + if (priv->irq1_stat & P_LINK_UP_IRQ(P7_IRQ_OFF)) 280 + priv->port_sts[7].link = 1; 281 + if (priv->irq1_stat & P_LINK_DOWN_IRQ(P7_IRQ_OFF)) 282 + priv->port_sts[7].link = 0; 283 + 284 + return IRQ_HANDLED; 285 + } 286 + 287 + static int bcm_sf2_sw_setup(struct dsa_switch *ds) 288 + { 289 + const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME; 290 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 291 + struct device_node *dn; 292 + void __iomem **base; 293 + unsigned int port; 294 + unsigned int i; 295 + u32 reg, rev; 296 + int ret; 297 + 298 + spin_lock_init(&priv->indir_lock); 299 + mutex_init(&priv->stats_mutex); 300 + 301 + /* All the interesting properties are at the parent device_node 302 + * level 303 + */ 304 + dn = ds->pd->of_node->parent; 305 + 306 + priv->irq0 = irq_of_parse_and_map(dn, 0); 307 + priv->irq1 = irq_of_parse_and_map(dn, 1); 308 + 309 + base = &priv->core; 310 + for (i = 0; i < BCM_SF2_REGS_NUM; i++) { 311 + *base = of_iomap(dn, i); 312 + if (*base == NULL) { 313 + pr_err("unable to find register: %s\n", reg_names[i]); 314 + return -ENODEV; 315 + } 316 + base++; 317 + } 318 + 319 + /* Disable all interrupts and request them */ 320 + intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); 321 + intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); 322 + intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); 323 + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); 324 + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); 325 + intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); 326 + 327 + ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0, 328 + "switch_0", priv); 329 + if (ret < 0) { 330 + pr_err("failed to request switch_0 IRQ\n"); 331 + goto out_unmap; 332 + } 333 + 334 + ret = request_irq(priv->irq1, bcm_sf2_switch_1_isr, 0, 335 + "switch_1", priv); 336 + if (ret < 0) { 337 + pr_err("failed to request switch_1 IRQ\n"); 338 + goto out_free_irq0; 339 + } 340 + 341 + /* Reset the MIB counters */ 342 + reg = core_readl(priv, CORE_GMNCFGCFG); 343 + reg |= RST_MIB_CNT; 344 + core_writel(priv, reg, CORE_GMNCFGCFG); 345 + reg &= ~RST_MIB_CNT; 346 + core_writel(priv, reg, CORE_GMNCFGCFG); 347 + 348 + /* Get the maximum number of ports for this switch */ 349 + priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1; 350 + if (priv->hw_params.num_ports > DSA_MAX_PORTS) 351 + priv->hw_params.num_ports = DSA_MAX_PORTS; 352 + 353 + /* Assume a single GPHY setup if we can't read that property */ 354 + if (of_property_read_u32(dn, "brcm,num-gphy", 355 + &priv->hw_params.num_gphy)) 356 + priv->hw_params.num_gphy = 1; 357 + 358 + /* Enable all valid ports and disable those unused */ 359 + for (port = 0; port < priv->hw_params.num_ports; port++) { 360 + /* IMP port receives special treatment */ 361 + if ((1 << port) & ds->phys_port_mask) 362 + bcm_sf2_port_setup(ds, port); 363 + else if (dsa_is_cpu_port(ds, port)) 364 + bcm_sf2_imp_setup(ds, port); 365 + else 366 + bcm_sf2_port_disable(ds, port); 367 + } 368 + 369 + /* Include the pseudo-PHY address and the broadcast PHY address to 370 + * divert reads towards our workaround 371 + */ 372 + ds->phys_mii_mask |= ((1 << 30) | (1 << 0)); 373 + 374 + rev = reg_readl(priv, REG_SWITCH_REVISION); 375 + priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) & 376 + SWITCH_TOP_REV_MASK; 377 + priv->hw_params.core_rev = (rev & SF2_REV_MASK); 378 + 379 + pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n", 380 + priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff, 381 + priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff, 382 + priv->core, priv->irq0, priv->irq1); 383 + 384 + return 0; 385 + 386 + out_free_irq0: 387 + free_irq(priv->irq0, priv); 388 + out_unmap: 389 + base = &priv->core; 390 + for (i = 0; i < BCM_SF2_REGS_NUM; i++) { 391 + iounmap(*base); 392 + base++; 393 + } 394 + return ret; 395 + } 396 + 397 + static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr) 398 + { 399 + return 0; 400 + } 401 + 402 + static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr, 403 + int regnum, u16 val) 404 + { 405 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 406 + int ret = 0; 407 + u32 reg; 408 + 409 + reg = reg_readl(priv, REG_SWITCH_CNTRL); 410 + reg |= MDIO_MASTER_SEL; 411 + reg_writel(priv, reg, REG_SWITCH_CNTRL); 412 + 413 + /* Page << 8 | offset */ 414 + reg = 0x70; 415 + reg <<= 2; 416 + core_writel(priv, addr, reg); 417 + 418 + /* Page << 8 | offset */ 419 + reg = 0x80 << 8 | regnum << 1; 420 + reg <<= 2; 421 + 422 + if (op) 423 + ret = core_readl(priv, reg); 424 + else 425 + core_writel(priv, val, reg); 426 + 427 + reg = reg_readl(priv, REG_SWITCH_CNTRL); 428 + reg &= ~MDIO_MASTER_SEL; 429 + reg_writel(priv, reg, REG_SWITCH_CNTRL); 430 + 431 + return ret & 0xffff; 432 + } 433 + 434 + static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum) 435 + { 436 + /* Intercept reads from the MDIO broadcast address or Broadcom 437 + * pseudo-PHY address 438 + */ 439 + switch (addr) { 440 + case 0: 441 + case 30: 442 + return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0); 443 + default: 444 + return 0xffff; 445 + } 446 + } 447 + 448 + static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum, 449 + u16 val) 450 + { 451 + /* Intercept writes to the MDIO broadcast address or Broadcom 452 + * pseudo-PHY address 453 + */ 454 + switch (addr) { 455 + case 0: 456 + case 30: 457 + bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val); 458 + break; 459 + } 460 + 461 + return 0; 462 + } 463 + 464 + static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port, 465 + struct phy_device *phydev) 466 + { 467 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 468 + u32 id_mode_dis = 0, port_mode; 469 + const char *str = NULL; 470 + u32 reg; 471 + 472 + switch (phydev->interface) { 473 + case PHY_INTERFACE_MODE_RGMII: 474 + str = "RGMII (no delay)"; 475 + id_mode_dis = 1; 476 + case PHY_INTERFACE_MODE_RGMII_TXID: 477 + if (!str) 478 + str = "RGMII (TX delay)"; 479 + port_mode = EXT_GPHY; 480 + break; 481 + case PHY_INTERFACE_MODE_MII: 482 + str = "MII"; 483 + port_mode = EXT_EPHY; 484 + break; 485 + case PHY_INTERFACE_MODE_REVMII: 486 + str = "Reverse MII"; 487 + port_mode = EXT_REVMII; 488 + break; 489 + default: 490 + goto force_link; 491 + } 492 + 493 + /* Clear id_mode_dis bit, and the existing port mode, but 494 + * make sure we enable the RGMII block for data to pass 495 + */ 496 + reg = reg_readl(priv, REG_RGMII_CNTRL_P(port)); 497 + reg &= ~ID_MODE_DIS; 498 + reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT); 499 + reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN); 500 + 501 + reg |= port_mode | RGMII_MODE_EN; 502 + if (id_mode_dis) 503 + reg |= ID_MODE_DIS; 504 + 505 + if (phydev->pause) { 506 + if (phydev->asym_pause) 507 + reg |= TX_PAUSE_EN; 508 + reg |= RX_PAUSE_EN; 509 + } 510 + 511 + reg_writel(priv, reg, REG_RGMII_CNTRL_P(port)); 512 + 513 + pr_info("Port %d configured for %s\n", port, str); 514 + 515 + force_link: 516 + /* Force link settings detected from the PHY */ 517 + reg = SW_OVERRIDE; 518 + switch (phydev->speed) { 519 + case SPEED_1000: 520 + reg |= SPDSTS_1000 << SPEED_SHIFT; 521 + break; 522 + case SPEED_100: 523 + reg |= SPDSTS_100 << SPEED_SHIFT; 524 + break; 525 + } 526 + 527 + if (phydev->link) 528 + reg |= LINK_STS; 529 + if (phydev->duplex == DUPLEX_FULL) 530 + reg |= DUPLX_MODE; 531 + 532 + core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port)); 533 + } 534 + 535 + static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port, 536 + struct fixed_phy_status *status) 537 + { 538 + struct bcm_sf2_priv *priv = ds_to_priv(ds); 539 + u32 link, duplex, pause, speed; 540 + u32 reg; 541 + 542 + link = core_readl(priv, CORE_LNKSTS); 543 + duplex = core_readl(priv, CORE_DUPSTS); 544 + pause = core_readl(priv, CORE_PAUSESTS); 545 + speed = core_readl(priv, CORE_SPDSTS); 546 + 547 + speed >>= (port * SPDSTS_SHIFT); 548 + speed &= SPDSTS_MASK; 549 + 550 + status->link = 0; 551 + 552 + /* Port 7 is special as we do not get link status from CORE_LNKSTS, 553 + * which means that we need to force the link at the port override 554 + * level to get the data to flow. We do use what the interrupt handler 555 + * did determine before. 556 + */ 557 + if (port == 7) { 558 + status->link = priv->port_sts[port].link; 559 + reg = core_readl(priv, CORE_STS_OVERRIDE_GMIIP_PORT(7)); 560 + reg |= SW_OVERRIDE; 561 + if (status->link) 562 + reg |= LINK_STS; 563 + else 564 + reg &= ~LINK_STS; 565 + core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(7)); 566 + status->duplex = 1; 567 + } else { 568 + status->link = !!(link & (1 << port)); 569 + status->duplex = !!(duplex & (1 << port)); 570 + } 571 + 572 + switch (speed) { 573 + case SPDSTS_10: 574 + status->speed = SPEED_10; 575 + break; 576 + case SPDSTS_100: 577 + status->speed = SPEED_100; 578 + break; 579 + case SPDSTS_1000: 580 + status->speed = SPEED_1000; 581 + break; 582 + } 583 + 584 + if ((pause & (1 << port)) && 585 + (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) { 586 + status->asym_pause = 1; 587 + status->pause = 1; 588 + } 589 + 590 + if (pause & (1 << port)) 591 + status->pause = 1; 592 + } 593 + 594 + static struct dsa_switch_driver bcm_sf2_switch_driver = { 595 + .tag_protocol = htons(ETH_P_BRCMTAG), 596 + .priv_size = sizeof(struct bcm_sf2_priv), 597 + .probe = bcm_sf2_sw_probe, 598 + .setup = bcm_sf2_sw_setup, 599 + .set_addr = bcm_sf2_sw_set_addr, 600 + .phy_read = bcm_sf2_sw_phy_read, 601 + .phy_write = bcm_sf2_sw_phy_write, 602 + .get_strings = bcm_sf2_sw_get_strings, 603 + .get_ethtool_stats = bcm_sf2_sw_get_ethtool_stats, 604 + .get_sset_count = bcm_sf2_sw_get_sset_count, 605 + .adjust_link = bcm_sf2_sw_adjust_link, 606 + .fixed_link_update = bcm_sf2_sw_fixed_link_update, 607 + }; 608 + 609 + static int __init bcm_sf2_init(void) 610 + { 611 + register_switch_driver(&bcm_sf2_switch_driver); 612 + 613 + return 0; 614 + } 615 + module_init(bcm_sf2_init); 616 + 617 + static void __exit bcm_sf2_exit(void) 618 + { 619 + unregister_switch_driver(&bcm_sf2_switch_driver); 620 + } 621 + module_exit(bcm_sf2_exit); 622 + 623 + MODULE_AUTHOR("Broadcom Corporation"); 624 + MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip"); 625 + MODULE_LICENSE("GPL"); 626 + MODULE_ALIAS("platform:brcm-sf2");
+140
drivers/net/dsa/bcm_sf2.h
··· 1 + /* 2 + * Broadcom Starfighter2 private context 3 + * 4 + * Copyright (C) 2014, Broadcom Corporation 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + */ 11 + 12 + #ifndef __BCM_SF2_H 13 + #define __BCM_SF2_H 14 + 15 + #include <linux/platform_device.h> 16 + #include <linux/kernel.h> 17 + #include <linux/io.h> 18 + #include <linux/spinlock.h> 19 + #include <linux/mutex.h> 20 + #include <linux/mii.h> 21 + 22 + #include <net/dsa.h> 23 + 24 + #include "bcm_sf2_regs.h" 25 + 26 + struct bcm_sf2_hw_params { 27 + u16 top_rev; 28 + u16 core_rev; 29 + u32 num_gphy; 30 + u8 num_acb_queue; 31 + u8 num_rgmii; 32 + u8 num_ports; 33 + u8 fcb_pause_override:1; 34 + u8 acb_packets_inflight:1; 35 + }; 36 + 37 + #define BCM_SF2_REGS_NAME {\ 38 + "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb" \ 39 + } 40 + 41 + #define BCM_SF2_REGS_NUM 6 42 + 43 + struct bcm_sf2_port_status { 44 + unsigned int link; 45 + }; 46 + 47 + struct bcm_sf2_priv { 48 + /* Base registers, keep those in order with BCM_SF2_REGS_NAME */ 49 + void __iomem *core; 50 + void __iomem *reg; 51 + void __iomem *intrl2_0; 52 + void __iomem *intrl2_1; 53 + void __iomem *fcb; 54 + void __iomem *acb; 55 + 56 + /* spinlock protecting access to the indirect registers */ 57 + spinlock_t indir_lock; 58 + 59 + int irq0; 60 + int irq1; 61 + u32 irq0_stat; 62 + u32 irq0_mask; 63 + u32 irq1_stat; 64 + u32 irq1_mask; 65 + 66 + /* Mutex protecting access to the MIB counters */ 67 + struct mutex stats_mutex; 68 + 69 + struct bcm_sf2_hw_params hw_params; 70 + 71 + struct bcm_sf2_port_status port_sts[DSA_MAX_PORTS]; 72 + }; 73 + 74 + struct bcm_sf2_hw_stats { 75 + const char *string; 76 + u16 reg; 77 + u8 sizeof_stat; 78 + }; 79 + 80 + #define SF2_IO_MACRO(name) \ 81 + static inline u32 name##_readl(struct bcm_sf2_priv *priv, u32 off) \ 82 + { \ 83 + return __raw_readl(priv->name + off); \ 84 + } \ 85 + static inline void name##_writel(struct bcm_sf2_priv *priv, \ 86 + u32 val, u32 off) \ 87 + { \ 88 + __raw_writel(val, priv->name + off); \ 89 + } \ 90 + 91 + /* Accesses to 64-bits register requires us to latch the hi/lo pairs 92 + * using the REG_DIR_DATA_{READ,WRITE} ancillary registers. The 'indir_lock' 93 + * spinlock is automatically grabbed and released to provide relative 94 + * atomiticy with latched reads/writes. 95 + */ 96 + #define SF2_IO64_MACRO(name) \ 97 + static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off) \ 98 + { \ 99 + u32 indir, dir; \ 100 + spin_lock(&priv->indir_lock); \ 101 + indir = reg_readl(priv, REG_DIR_DATA_READ); \ 102 + dir = __raw_readl(priv->name + off); \ 103 + spin_unlock(&priv->indir_lock); \ 104 + return (u64)indir << 32 | dir; \ 105 + } \ 106 + static inline void name##_writeq(struct bcm_sf2_priv *priv, u32 off, \ 107 + u64 val) \ 108 + { \ 109 + spin_lock(&priv->indir_lock); \ 110 + reg_writel(priv, upper_32_bits(val), REG_DIR_DATA_WRITE); \ 111 + __raw_writel(lower_32_bits(val), priv->name + off); \ 112 + spin_unlock(&priv->indir_lock); \ 113 + } 114 + 115 + #define SWITCH_INTR_L2(which) \ 116 + static inline void intrl2_##which##_mask_clear(struct bcm_sf2_priv *priv, \ 117 + u32 mask) \ 118 + { \ 119 + intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR); \ 120 + priv->irq##which##_mask &= ~(mask); \ 121 + } \ 122 + static inline void intrl2_##which##_mask_set(struct bcm_sf2_priv *priv, \ 123 + u32 mask) \ 124 + { \ 125 + intrl2_## which##_writel(priv, mask, INTRL2_CPU_MASK_SET); \ 126 + priv->irq##which##_mask |= (mask); \ 127 + } \ 128 + 129 + SF2_IO_MACRO(core); 130 + SF2_IO_MACRO(reg); 131 + SF2_IO64_MACRO(core); 132 + SF2_IO_MACRO(intrl2_0); 133 + SF2_IO_MACRO(intrl2_1); 134 + SF2_IO_MACRO(fcb); 135 + SF2_IO_MACRO(acb); 136 + 137 + SWITCH_INTR_L2(0); 138 + SWITCH_INTR_L2(1); 139 + 140 + #endif /* __BCM_SF2_H */
+227
drivers/net/dsa/bcm_sf2_regs.h
··· 1 + /* 2 + * Broadcom Starfighter 2 switch register defines 3 + * 4 + * Copyright (C) 2014, Broadcom Corporation 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + */ 11 + #ifndef __BCM_SF2_REGS_H 12 + #define __BCM_SF2_REGS_H 13 + 14 + /* Register set relative to 'REG' */ 15 + #define REG_SWITCH_CNTRL 0x00 16 + #define MDIO_MASTER_SEL (1 << 0) 17 + 18 + #define REG_SWITCH_STATUS 0x04 19 + #define REG_DIR_DATA_WRITE 0x08 20 + #define REG_DIR_DATA_READ 0x0C 21 + 22 + #define REG_SWITCH_REVISION 0x18 23 + #define SF2_REV_MASK 0xffff 24 + #define SWITCH_TOP_REV_SHIFT 16 25 + #define SWITCH_TOP_REV_MASK 0xffff 26 + 27 + #define REG_PHY_REVISION 0x1C 28 + 29 + #define REG_SPHY_CNTRL 0x2C 30 + #define IDDQ_BIAS (1 << 0) 31 + #define EXT_PWR_DOWN (1 << 1) 32 + #define FORCE_DLL_EN (1 << 2) 33 + #define IDDQ_GLOBAL_PWR (1 << 3) 34 + #define CK25_DIS (1 << 4) 35 + #define PHY_RESET (1 << 5) 36 + #define PHY_PHYAD_SHIFT 8 37 + #define PHY_PHYAD_MASK 0x1F 38 + 39 + #define REG_RGMII_0_BASE 0x34 40 + #define REG_RGMII_CNTRL 0x00 41 + #define REG_RGMII_IB_STATUS 0x04 42 + #define REG_RGMII_RX_CLOCK_DELAY_CNTRL 0x08 43 + #define REG_RGMII_CNTRL_SIZE 0x0C 44 + #define REG_RGMII_CNTRL_P(x) (REG_RGMII_0_BASE + \ 45 + ((x) * REG_RGMII_CNTRL_SIZE)) 46 + /* Relative to REG_RGMII_CNTRL */ 47 + #define RGMII_MODE_EN (1 << 0) 48 + #define ID_MODE_DIS (1 << 1) 49 + #define PORT_MODE_SHIFT 2 50 + #define INT_EPHY (0 << PORT_MODE_SHIFT) 51 + #define INT_GPHY (1 << PORT_MODE_SHIFT) 52 + #define EXT_EPHY (2 << PORT_MODE_SHIFT) 53 + #define EXT_GPHY (3 << PORT_MODE_SHIFT) 54 + #define EXT_REVMII (4 << PORT_MODE_SHIFT) 55 + #define PORT_MODE_MASK 0x7 56 + #define RVMII_REF_SEL (1 << 5) 57 + #define RX_PAUSE_EN (1 << 6) 58 + #define TX_PAUSE_EN (1 << 7) 59 + #define TX_CLK_STOP_EN (1 << 8) 60 + #define LPI_COUNT_SHIFT 9 61 + #define LPI_COUNT_MASK 0x3F 62 + 63 + /* Register set relative to 'INTRL2_0' and 'INTRL2_1' */ 64 + #define INTRL2_CPU_STATUS 0x00 65 + #define INTRL2_CPU_SET 0x04 66 + #define INTRL2_CPU_CLEAR 0x08 67 + #define INTRL2_CPU_MASK_STATUS 0x0c 68 + #define INTRL2_CPU_MASK_SET 0x10 69 + #define INTRL2_CPU_MASK_CLEAR 0x14 70 + 71 + /* Shared INTRL2_0 and INTRL2_ interrupt sources macros */ 72 + #define P_LINK_UP_IRQ(x) (1 << (0 + (x))) 73 + #define P_LINK_DOWN_IRQ(x) (1 << (1 + (x))) 74 + #define P_ENERGY_ON_IRQ(x) (1 << (2 + (x))) 75 + #define P_ENERGY_OFF_IRQ(x) (1 << (3 + (x))) 76 + #define P_GPHY_IRQ(x) (1 << (4 + (x))) 77 + #define P_NUM_IRQ 5 78 + #define P_IRQ_MASK(x) (P_LINK_UP_IRQ((x)) | \ 79 + P_LINK_DOWN_IRQ((x)) | \ 80 + P_ENERGY_ON_IRQ((x)) | \ 81 + P_ENERGY_OFF_IRQ((x)) | \ 82 + P_GPHY_IRQ((x))) 83 + 84 + /* INTRL2_0 interrupt sources */ 85 + #define P0_IRQ_OFF 0 86 + #define MEM_DOUBLE_IRQ (1 << 5) 87 + #define EEE_LPI_IRQ (1 << 6) 88 + #define P5_CPU_WAKE_IRQ (1 << 7) 89 + #define P8_CPU_WAKE_IRQ (1 << 8) 90 + #define P7_CPU_WAKE_IRQ (1 << 9) 91 + #define IEEE1588_IRQ (1 << 10) 92 + #define MDIO_ERR_IRQ (1 << 11) 93 + #define MDIO_DONE_IRQ (1 << 12) 94 + #define GISB_ERR_IRQ (1 << 13) 95 + #define UBUS_ERR_IRQ (1 << 14) 96 + #define FAILOVER_ON_IRQ (1 << 15) 97 + #define FAILOVER_OFF_IRQ (1 << 16) 98 + #define TCAM_SOFT_ERR_IRQ (1 << 17) 99 + 100 + /* INTRL2_1 interrupt sources */ 101 + #define P7_IRQ_OFF 0 102 + #define P_IRQ_OFF(x) ((6 - (x)) * P_NUM_IRQ) 103 + 104 + /* Register set relative to 'CORE' */ 105 + #define CORE_G_PCTL_PORT0 0x00000 106 + #define CORE_G_PCTL_PORT(x) (CORE_G_PCTL_PORT0 + (x * 0x4)) 107 + #define CORE_IMP_CTL 0x00020 108 + #define RX_DIS (1 << 0) 109 + #define TX_DIS (1 << 1) 110 + #define RX_BCST_EN (1 << 2) 111 + #define RX_MCST_EN (1 << 3) 112 + #define RX_UCST_EN (1 << 4) 113 + #define G_MISTP_STATE_SHIFT 5 114 + #define G_MISTP_NO_STP (0 << G_MISTP_STATE_SHIFT) 115 + #define G_MISTP_DIS_STATE (1 << G_MISTP_STATE_SHIFT) 116 + #define G_MISTP_BLOCK_STATE (2 << G_MISTP_STATE_SHIFT) 117 + #define G_MISTP_LISTEN_STATE (3 << G_MISTP_STATE_SHIFT) 118 + #define G_MISTP_LEARN_STATE (4 << G_MISTP_STATE_SHIFT) 119 + #define G_MISTP_FWD_STATE (5 << G_MISTP_STATE_SHIFT) 120 + #define G_MISTP_STATE_MASK 0x7 121 + 122 + #define CORE_SWMODE 0x0002c 123 + #define SW_FWDG_MODE (1 << 0) 124 + #define SW_FWDG_EN (1 << 1) 125 + #define RTRY_LMT_DIS (1 << 2) 126 + 127 + #define CORE_STS_OVERRIDE_IMP 0x00038 128 + #define GMII_SPEED_UP_2G (1 << 6) 129 + #define MII_SW_OR (1 << 7) 130 + 131 + #define CORE_NEW_CTRL 0x00084 132 + #define IP_MC (1 << 0) 133 + #define OUTRANGEERR_DISCARD (1 << 1) 134 + #define INRANGEERR_DISCARD (1 << 2) 135 + #define CABLE_DIAG_LEN (1 << 3) 136 + #define OVERRIDE_AUTO_PD_WAR (1 << 4) 137 + #define EN_AUTO_PD_WAR (1 << 5) 138 + #define UC_FWD_EN (1 << 6) 139 + #define MC_FWD_EN (1 << 7) 140 + 141 + #define CORE_SWITCH_CTRL 0x00088 142 + #define MII_DUMB_FWDG_EN (1 << 6) 143 + 144 + #define CORE_SFT_LRN_CTRL 0x000f8 145 + #define SW_LEARN_CNTL(x) (1 << (x)) 146 + 147 + #define CORE_STS_OVERRIDE_GMIIP_PORT(x) (0x160 + (x) * 4) 148 + #define LINK_STS (1 << 0) 149 + #define DUPLX_MODE (1 << 1) 150 + #define SPEED_SHIFT 2 151 + #define SPEED_MASK 0x3 152 + #define RXFLOW_CNTL (1 << 4) 153 + #define TXFLOW_CNTL (1 << 5) 154 + #define SW_OVERRIDE (1 << 6) 155 + 156 + #define CORE_WATCHDOG_CTRL 0x001e4 157 + #define SOFTWARE_RESET (1 << 7) 158 + #define EN_CHIP_RST (1 << 6) 159 + #define EN_SW_RESET (1 << 4) 160 + 161 + #define CORE_LNKSTS 0x00400 162 + #define LNK_STS_MASK 0x1ff 163 + 164 + #define CORE_SPDSTS 0x00410 165 + #define SPDSTS_10 0 166 + #define SPDSTS_100 1 167 + #define SPDSTS_1000 2 168 + #define SPDSTS_SHIFT 2 169 + #define SPDSTS_MASK 0x3 170 + 171 + #define CORE_DUPSTS 0x00420 172 + #define CORE_DUPSTS_MASK 0x1ff 173 + 174 + #define CORE_PAUSESTS 0x00428 175 + #define PAUSESTS_TX_PAUSE_SHIFT 9 176 + 177 + #define CORE_GMNCFGCFG 0x0800 178 + #define RST_MIB_CNT (1 << 0) 179 + #define RXBPDU_EN (1 << 1) 180 + 181 + #define CORE_IMP0_PRT_ID 0x0804 182 + 183 + #define CORE_BRCM_HDR_CTRL 0x0080c 184 + #define BRCM_HDR_EN_P8 (1 << 0) 185 + #define BRCM_HDR_EN_P5 (1 << 1) 186 + #define BRCM_HDR_EN_P7 (1 << 2) 187 + 188 + #define CORE_BRCM_HDR_CTRL2 0x0828 189 + 190 + #define CORE_HL_PRTC_CTRL 0x0940 191 + #define ARP_EN (1 << 0) 192 + #define RARP_EN (1 << 1) 193 + #define DHCP_EN (1 << 2) 194 + #define ICMPV4_EN (1 << 3) 195 + #define ICMPV6_EN (1 << 4) 196 + #define ICMPV6_FWD_MODE (1 << 5) 197 + #define IGMP_DIP_EN (1 << 8) 198 + #define IGMP_RPTLVE_EN (1 << 9) 199 + #define IGMP_RTPLVE_FWD_MODE (1 << 10) 200 + #define IGMP_QRY_EN (1 << 11) 201 + #define IGMP_QRY_FWD_MODE (1 << 12) 202 + #define IGMP_UKN_EN (1 << 13) 203 + #define IGMP_UKN_FWD_MODE (1 << 14) 204 + #define MLD_RPTDONE_EN (1 << 15) 205 + #define MLD_RPTDONE_FWD_MODE (1 << 16) 206 + #define MLD_QRY_EN (1 << 17) 207 + #define MLD_QRY_FWD_MODE (1 << 18) 208 + 209 + #define CORE_RST_MIB_CNT_EN 0x0950 210 + 211 + #define CORE_BRCM_HDR_RX_DIS 0x0980 212 + #define CORE_BRCM_HDR_TX_DIS 0x0988 213 + 214 + #define CORE_MEM_PSM_VDD_CTRL 0x2380 215 + #define P_TXQ_PSM_VDD_SHIFT 2 216 + #define P_TXQ_PSM_VDD_MASK 0x3 217 + #define P_TXQ_PSM_VDD(x) (P_TXQ_PSM_VDD_MASK << \ 218 + ((x) * P_TXQ_PSM_VDD_SHIFT)) 219 + 220 + #define CORE_P0_MIB_OFFSET 0x8000 221 + #define P_MIB_SIZE 0x400 222 + #define CORE_P_MIB_OFFSET(x) (CORE_P0_MIB_OFFSET + (x) * P_MIB_SIZE) 223 + 224 + #define CORE_PORT_VLAN_CTL_PORT(x) (0xc400 + ((x) * 0x8)) 225 + #define PORT_VLAN_CTRL_MASK 0x1ff 226 + 227 + #endif /* __BCM_SF2_REGS_H */
+8
drivers/net/phy/Kconfig
··· 205 205 206 206 Currently, only 8-bit registers are supported. 207 207 208 + config MDIO_BCM_UNIMAC 209 + tristate "Broadcom UniMAC MDIO bus controller" 210 + help 211 + This module provides a driver for the Broadcom UniMAC MDIO busses. 212 + This hardware can be found in the Broadcom GENET Ethernet MAC 213 + controllers as well as some Broadcom Ethernet switches such as the 214 + Starfighter 2 switches. 215 + 208 216 endif # PHYLIB 209 217 210 218 config MICREL_KS8995MA
+1
drivers/net/phy/Makefile
··· 34 34 obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o 35 35 obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o 36 36 obj-$(CONFIG_AMD_XGBE_PHY) += amd-xgbe-phy.o 37 + obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
+212
drivers/net/phy/mdio-bcm-unimac.c
··· 1 + /* 2 + * Broadcom UniMAC MDIO bus controller driver 3 + * 4 + * Copyright (C) 2014, Broadcom Corporation 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + */ 11 + 12 + #include <linux/kernel.h> 13 + #include <linux/phy.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/sched.h> 16 + #include <linux/module.h> 17 + #include <linux/io.h> 18 + #include <linux/delay.h> 19 + 20 + #include <linux/of.h> 21 + #include <linux/of_platform.h> 22 + #include <linux/of_mdio.h> 23 + 24 + #define MDIO_CMD 0x00 25 + #define MDIO_START_BUSY (1 << 29) 26 + #define MDIO_READ_FAIL (1 << 28) 27 + #define MDIO_RD (2 << 26) 28 + #define MDIO_WR (1 << 26) 29 + #define MDIO_PMD_SHIFT 21 30 + #define MDIO_PMD_MASK 0x1F 31 + #define MDIO_REG_SHIFT 16 32 + #define MDIO_REG_MASK 0x1F 33 + 34 + #define MDIO_CFG 0x04 35 + #define MDIO_C22 (1 << 0) 36 + #define MDIO_C45 0 37 + #define MDIO_CLK_DIV_SHIFT 4 38 + #define MDIO_CLK_DIV_MASK 0x3F 39 + #define MDIO_SUPP_PREAMBLE (1 << 12) 40 + 41 + struct unimac_mdio_priv { 42 + struct mii_bus *mii_bus; 43 + void __iomem *base; 44 + }; 45 + 46 + static inline void unimac_mdio_start(struct unimac_mdio_priv *priv) 47 + { 48 + u32 reg; 49 + 50 + reg = __raw_readl(priv->base + MDIO_CMD); 51 + reg |= MDIO_START_BUSY; 52 + __raw_writel(reg, priv->base + MDIO_CMD); 53 + } 54 + 55 + static inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv *priv) 56 + { 57 + return __raw_readl(priv->base + MDIO_CMD) & MDIO_START_BUSY; 58 + } 59 + 60 + static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg) 61 + { 62 + struct unimac_mdio_priv *priv = bus->priv; 63 + unsigned int timeout = 1000; 64 + u32 cmd; 65 + 66 + /* Prepare the read operation */ 67 + cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT); 68 + __raw_writel(cmd, priv->base + MDIO_CMD); 69 + 70 + /* Start MDIO transaction */ 71 + unimac_mdio_start(priv); 72 + 73 + do { 74 + if (!unimac_mdio_busy(priv)) 75 + break; 76 + 77 + usleep_range(1000, 2000); 78 + } while (timeout--); 79 + 80 + if (!timeout) 81 + return -ETIMEDOUT; 82 + 83 + cmd = __raw_readl(priv->base + MDIO_CMD); 84 + if (cmd & MDIO_READ_FAIL) 85 + return -EIO; 86 + 87 + return cmd & 0xffff; 88 + } 89 + 90 + static int unimac_mdio_write(struct mii_bus *bus, int phy_id, 91 + int reg, u16 val) 92 + { 93 + struct unimac_mdio_priv *priv = bus->priv; 94 + unsigned int timeout = 1000; 95 + u32 cmd; 96 + 97 + /* Prepare the write operation */ 98 + cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) | 99 + (reg << MDIO_REG_SHIFT) | (0xffff & val); 100 + __raw_writel(cmd, priv->base + MDIO_CMD); 101 + 102 + unimac_mdio_start(priv); 103 + 104 + do { 105 + if (!unimac_mdio_busy(priv)) 106 + break; 107 + 108 + usleep_range(1000, 2000); 109 + } while (timeout--); 110 + 111 + if (!timeout) 112 + return -ETIMEDOUT; 113 + 114 + return 0; 115 + } 116 + 117 + static int unimac_mdio_probe(struct platform_device *pdev) 118 + { 119 + struct unimac_mdio_priv *priv; 120 + struct device_node *np; 121 + struct mii_bus *bus; 122 + struct resource *r; 123 + int ret; 124 + 125 + np = pdev->dev.of_node; 126 + 127 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 128 + if (!priv) 129 + return -ENOMEM; 130 + 131 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 132 + 133 + /* Just ioremap, as this MDIO block is usually integrated into an 134 + * Ethernet MAC controller register range 135 + */ 136 + priv->base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); 137 + if (!priv->base) { 138 + dev_err(&pdev->dev, "failed to remap register\n"); 139 + return -ENOMEM; 140 + } 141 + 142 + priv->mii_bus = mdiobus_alloc(); 143 + if (!priv->mii_bus) 144 + return -ENOMEM; 145 + 146 + bus = priv->mii_bus; 147 + bus->priv = priv; 148 + bus->name = "unimac MII bus"; 149 + bus->parent = &pdev->dev; 150 + bus->read = unimac_mdio_read; 151 + bus->write = unimac_mdio_write; 152 + snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name); 153 + 154 + bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); 155 + if (!bus->irq) { 156 + ret = -ENOMEM; 157 + goto out_mdio_free; 158 + } 159 + 160 + ret = of_mdiobus_register(bus, np); 161 + if (ret) { 162 + dev_err(&pdev->dev, "MDIO bus registration failed\n"); 163 + goto out_mdio_irq; 164 + } 165 + 166 + platform_set_drvdata(pdev, priv); 167 + 168 + dev_info(&pdev->dev, "Broadcom UniMAC MDIO bus at 0x%p\n", priv->base); 169 + 170 + return 0; 171 + 172 + out_mdio_irq: 173 + kfree(bus->irq); 174 + out_mdio_free: 175 + mdiobus_free(bus); 176 + return ret; 177 + } 178 + 179 + static int unimac_mdio_remove(struct platform_device *pdev) 180 + { 181 + struct unimac_mdio_priv *priv = platform_get_drvdata(pdev); 182 + 183 + mdiobus_unregister(priv->mii_bus); 184 + kfree(priv->mii_bus->irq); 185 + mdiobus_free(priv->mii_bus); 186 + 187 + return 0; 188 + } 189 + 190 + static struct of_device_id unimac_mdio_ids[] = { 191 + { .compatible = "brcm,genet-mdio-v4", }, 192 + { .compatible = "brcm,genet-mdio-v3", }, 193 + { .compatible = "brcm,genet-mdio-v2", }, 194 + { .compatible = "brcm,genet-mdio-v1", }, 195 + { .compatible = "brcm,unimac-mdio", }, 196 + }; 197 + 198 + static struct platform_driver unimac_mdio_driver = { 199 + .driver = { 200 + .name = "unimac-mdio", 201 + .owner = THIS_MODULE, 202 + .of_match_table = unimac_mdio_ids, 203 + }, 204 + .probe = unimac_mdio_probe, 205 + .remove = unimac_mdio_remove, 206 + }; 207 + module_platform_driver(unimac_mdio_driver); 208 + 209 + MODULE_AUTHOR("Broadcom Corporation"); 210 + MODULE_DESCRIPTION("Broadcom UniMAC MDIO bus controller"); 211 + MODULE_LICENSE("GPL"); 212 + MODULE_ALIAS("platform:unimac-mdio");
+11 -15
include/linux/netdevice.h
··· 1781 1781 #endif 1782 1782 } 1783 1783 1784 - static inline bool netdev_uses_dsa_tags(struct net_device *dev) 1784 + static inline bool netdev_uses_dsa(struct net_device *dev) 1785 1785 { 1786 - #ifdef CONFIG_NET_DSA_TAG_DSA 1786 + #ifdef CONFIG_NET_DSA 1787 1787 if (dev->dsa_ptr != NULL) 1788 - return dsa_uses_dsa_tags(dev->dsa_ptr); 1788 + return dsa_uses_tagged_protocol(dev->dsa_ptr); 1789 1789 #endif 1790 - 1791 - return 0; 1792 - } 1793 - 1794 - static inline bool netdev_uses_trailer_tags(struct net_device *dev) 1795 - { 1796 - #ifdef CONFIG_NET_DSA_TAG_TRAILER 1797 - if (dev->dsa_ptr != NULL) 1798 - return dsa_uses_trailer_tags(dev->dsa_ptr); 1799 - #endif 1800 - 1801 - return 0; 1790 + return false; 1802 1791 } 1803 1792 1804 1793 /** ··· 1921 1932 __be16 port; 1922 1933 struct offload_callbacks callbacks; 1923 1934 }; 1935 + 1936 + struct dsa_device_ops { 1937 + netdev_tx_t (*xmit)(struct sk_buff *skb, struct net_device *dev); 1938 + int (*rcv)(struct sk_buff *skb, struct net_device *dev, 1939 + struct packet_type *pt, struct net_device *orig_dev); 1940 + }; 1941 + 1924 1942 1925 1943 /* often modified stats are per cpu, other are shared (netdev->stats) */ 1926 1944 struct pcpu_sw_netstats {
+9 -8
include/linux/phy_fixed.h
··· 18 18 struct fixed_phy_status *status, 19 19 struct device_node *np); 20 20 extern void fixed_phy_del(int phy_addr); 21 + extern int fixed_phy_set_link_update(struct phy_device *phydev, 22 + int (*link_update)(struct net_device *, 23 + struct fixed_phy_status *)); 21 24 #else 22 25 static inline int fixed_phy_add(unsigned int irq, int phy_id, 23 26 struct fixed_phy_status *status) ··· 37 34 { 38 35 return -ENODEV; 39 36 } 40 - #endif /* CONFIG_FIXED_PHY */ 41 - 42 - /* 43 - * This function issued only by fixed_phy-aware drivers, no need 44 - * protect it with #ifdef 45 - */ 46 - extern int fixed_phy_set_link_update(struct phy_device *phydev, 37 + static inline int fixed_phy_set_link_update(struct phy_device *phydev, 47 38 int (*link_update)(struct net_device *, 48 - struct fixed_phy_status *)); 39 + struct fixed_phy_status *)) 40 + { 41 + return -ENODEV; 42 + } 43 + #endif /* CONFIG_FIXED_PHY */ 49 44 50 45 #endif /* __PHY_FIXED_H */
+29 -14
include/net/dsa.h
··· 15 15 #include <linux/list.h> 16 16 #include <linux/timer.h> 17 17 #include <linux/workqueue.h> 18 + #include <linux/of.h> 19 + #include <linux/phy.h> 20 + #include <linux/phy_fixed.h> 21 + 22 + /* Not an official ethertype value, used only internally for DSA 23 + * demultiplexing 24 + */ 25 + #define ETH_P_BRCMTAG (ETH_P_XDSA + 1) 18 26 19 27 #define DSA_MAX_SWITCHES 4 20 28 #define DSA_MAX_PORTS 12 ··· 34 26 struct device *mii_bus; 35 27 int sw_addr; 36 28 29 + /* Device tree node pointer for this specific switch chip 30 + * used during switch setup in case additional properties 31 + * and resources needs to be used 32 + */ 33 + struct device_node *of_node; 34 + 37 35 /* 38 36 * The names of the switch's ports. Use "cpu" to 39 37 * designate the switch port that the cpu is connected to, ··· 48 34 * or any other string to indicate this is a physical port. 49 35 */ 50 36 char *port_names[DSA_MAX_PORTS]; 37 + struct device_node *port_dn[DSA_MAX_PORTS]; 51 38 52 39 /* 53 40 * An array (with nr_chips elements) of which element [a] ··· 74 59 struct dsa_chip_data *chip; 75 60 }; 76 61 62 + struct dsa_device_ops; 63 + 77 64 struct dsa_switch_tree { 78 65 /* 79 66 * Configuration data for the platform device that owns ··· 88 71 * protocol to use. 89 72 */ 90 73 struct net_device *master_netdev; 74 + const struct dsa_device_ops *ops; 91 75 __be16 tag_protocol; 92 76 93 77 /* ··· 137 119 */ 138 120 u32 dsa_port_mask; 139 121 u32 phys_port_mask; 122 + u32 phys_mii_mask; 140 123 struct mii_bus *slave_mii_bus; 141 124 struct net_device *ports[DSA_MAX_PORTS]; 142 125 }; ··· 189 170 void (*poll_link)(struct dsa_switch *ds); 190 171 191 172 /* 173 + * Link state adjustment (called from libphy) 174 + */ 175 + void (*adjust_link)(struct dsa_switch *ds, int port, 176 + struct phy_device *phydev); 177 + void (*fixed_link_update)(struct dsa_switch *ds, int port, 178 + struct fixed_phy_status *st); 179 + 180 + /* 192 181 * ethtool hardware statistics. 193 182 */ 194 183 void (*get_strings)(struct dsa_switch *ds, int port, uint8_t *data); ··· 213 186 return (void *)(ds + 1); 214 187 } 215 188 216 - /* 217 - * The original DSA tag format and some other tag formats have no 218 - * ethertype, which means that we need to add a little hack to the 219 - * networking receive path to make sure that received frames get 220 - * the right ->protocol assigned to them when one of those tag 221 - * formats is in use. 222 - */ 223 - static inline bool dsa_uses_dsa_tags(struct dsa_switch_tree *dst) 189 + static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst) 224 190 { 225 - return !!(dst->tag_protocol == htons(ETH_P_DSA)); 226 - } 227 - 228 - static inline bool dsa_uses_trailer_tags(struct dsa_switch_tree *dst) 229 - { 230 - return !!(dst->tag_protocol == htons(ETH_P_TRAILER)); 191 + return dst->tag_protocol != 0; 231 192 } 232 193 233 194 #endif
+1
include/uapi/linux/if_ether.h
··· 128 128 #define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */ 129 129 #define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */ 130 130 #define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */ 131 + #define ETH_P_XDSA 0x00F8 /* Multiplexed DSA protocol */ 131 132 132 133 /* 133 134 * This is an Ethernet frame header.
+3
net/dsa/Kconfig
··· 12 12 if NET_DSA 13 13 14 14 # tagging formats 15 + config NET_DSA_TAG_BRCM 16 + bool 17 + 15 18 config NET_DSA_TAG_DSA 16 19 bool 17 20
+1
net/dsa/Makefile
··· 3 3 dsa_core-y += dsa.o slave.o 4 4 5 5 # tagging formats 6 + dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o 6 7 dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o 7 8 dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o 8 9 dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
+30 -18
net/dsa/dsa.c
··· 144 144 goto out; 145 145 } 146 146 147 + /* Make the built-in MII bus mask match the number of ports, 148 + * switch drivers can override this later 149 + */ 150 + ds->phys_mii_mask = ds->phys_port_mask; 151 + 147 152 /* 148 153 * If the CPU connects to this switch, set the switch tree 149 154 * tagging protocol to the preferred tagging format of this ··· 415 410 chip_index++; 416 411 cd = &pd->chip[chip_index]; 417 412 413 + cd->of_node = child; 418 414 cd->mii_bus = &mdio_bus->dev; 419 415 420 416 sw_addr = of_get_property(child, "reg", NULL); ··· 436 430 port_name = of_get_property(port, "label", NULL); 437 431 if (!port_name) 438 432 continue; 433 + 434 + cd->port_dn[port_index] = port; 439 435 440 436 cd->port_names[port_index] = kstrdup(port_name, 441 437 GFP_KERNEL); ··· 616 608 { 617 609 } 618 610 611 + static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, 612 + struct packet_type *pt, struct net_device *orig_dev) 613 + { 614 + struct dsa_switch_tree *dst = dev->dsa_ptr; 615 + 616 + if (unlikely(dst == NULL)) { 617 + kfree_skb(skb); 618 + return 0; 619 + } 620 + 621 + return dst->ops->rcv(skb, dev, pt, orig_dev); 622 + } 623 + 624 + struct packet_type dsa_pack_type __read_mostly = { 625 + .type = cpu_to_be16(ETH_P_XDSA), 626 + .func = dsa_switch_rcv, 627 + }; 628 + 619 629 static const struct of_device_id dsa_of_match_table[] = { 630 + { .compatible = "brcm,bcm7445-switch-v4.0" }, 620 631 { .compatible = "marvell,dsa", }, 621 632 {} 622 633 }; ··· 660 633 if (rc) 661 634 return rc; 662 635 663 - #ifdef CONFIG_NET_DSA_TAG_DSA 664 - dev_add_pack(&dsa_packet_type); 665 - #endif 666 - #ifdef CONFIG_NET_DSA_TAG_EDSA 667 - dev_add_pack(&edsa_packet_type); 668 - #endif 669 - #ifdef CONFIG_NET_DSA_TAG_TRAILER 670 - dev_add_pack(&trailer_packet_type); 671 - #endif 636 + dev_add_pack(&dsa_pack_type); 637 + 672 638 return 0; 673 639 } 674 640 module_init(dsa_init_module); 675 641 676 642 static void __exit dsa_cleanup_module(void) 677 643 { 678 - #ifdef CONFIG_NET_DSA_TAG_TRAILER 679 - dev_remove_pack(&trailer_packet_type); 680 - #endif 681 - #ifdef CONFIG_NET_DSA_TAG_EDSA 682 - dev_remove_pack(&edsa_packet_type); 683 - #endif 684 - #ifdef CONFIG_NET_DSA_TAG_DSA 685 - dev_remove_pack(&dsa_packet_type); 686 - #endif 644 + dev_remove_pack(&dsa_pack_type); 687 645 platform_driver_unregister(&dsa_driver); 688 646 } 689 647 module_exit(dsa_cleanup_module);
+10 -6
net/dsa/dsa_priv.h
··· 33 33 * to this port. 34 34 */ 35 35 struct phy_device *phy; 36 + phy_interface_t phy_interface; 37 + int old_link; 38 + int old_pause; 39 + int old_duplex; 36 40 }; 37 41 38 42 /* dsa.c */ ··· 49 45 int port, char *name); 50 46 51 47 /* tag_dsa.c */ 52 - netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev); 53 - extern struct packet_type dsa_packet_type; 48 + extern const struct dsa_device_ops dsa_netdev_ops; 54 49 55 50 /* tag_edsa.c */ 56 - netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev); 57 - extern struct packet_type edsa_packet_type; 51 + extern const struct dsa_device_ops edsa_netdev_ops; 58 52 59 53 /* tag_trailer.c */ 60 - netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev); 61 - extern struct packet_type trailer_packet_type; 54 + extern const struct dsa_device_ops trailer_netdev_ops; 55 + 56 + /* tag_brcm.c */ 57 + extern const struct dsa_device_ops brcm_netdev_ops; 62 58 63 59 64 60 #endif
+131 -34
net/dsa/slave.c
··· 12 12 #include <linux/netdevice.h> 13 13 #include <linux/etherdevice.h> 14 14 #include <linux/phy.h> 15 + #include <linux/of_net.h> 16 + #include <linux/of_mdio.h> 15 17 #include "dsa_priv.h" 16 18 17 19 /* slave mii_bus handling ***************************************************/ ··· 21 19 { 22 20 struct dsa_switch *ds = bus->priv; 23 21 24 - if (ds->phys_port_mask & (1 << addr)) 22 + if (ds->phys_mii_mask & (1 << addr)) 25 23 return ds->drv->phy_read(ds, addr, reg); 26 24 27 25 return 0xffff; ··· 31 29 { 32 30 struct dsa_switch *ds = bus->priv; 33 31 34 - if (ds->phys_port_mask & (1 << addr)) 32 + if (ds->phys_mii_mask & (1 << addr)) 35 33 return ds->drv->phy_write(ds, addr, reg, val); 36 34 37 35 return 0; ··· 173 171 return -EOPNOTSUPP; 174 172 } 175 173 174 + static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) 175 + { 176 + struct dsa_slave_priv *p = netdev_priv(dev); 177 + struct dsa_switch_tree *dst = p->parent->dst; 178 + 179 + return dst->ops->xmit(skb, dev); 180 + } 181 + 182 + static netdev_tx_t dsa_slave_notag_xmit(struct sk_buff *skb, 183 + struct net_device *dev) 184 + { 185 + struct dsa_slave_priv *p = netdev_priv(dev); 186 + 187 + skb->dev = p->parent->dst->master_netdev; 188 + dev_queue_xmit(skb); 189 + 190 + return NETDEV_TX_OK; 191 + } 192 + 176 193 177 194 /* ethtool operations *******************************************************/ 178 195 static int ··· 314 293 .get_sset_count = dsa_slave_get_sset_count, 315 294 }; 316 295 317 - #ifdef CONFIG_NET_DSA_TAG_DSA 318 - static const struct net_device_ops dsa_netdev_ops = { 296 + static const struct net_device_ops dsa_slave_netdev_ops = { 319 297 .ndo_init = dsa_slave_init, 320 298 .ndo_open = dsa_slave_open, 321 299 .ndo_stop = dsa_slave_close, 322 - .ndo_start_xmit = dsa_xmit, 300 + .ndo_start_xmit = dsa_slave_xmit, 323 301 .ndo_change_rx_flags = dsa_slave_change_rx_flags, 324 302 .ndo_set_rx_mode = dsa_slave_set_rx_mode, 325 303 .ndo_set_mac_address = dsa_slave_set_mac_address, 326 304 .ndo_do_ioctl = dsa_slave_ioctl, 327 305 }; 328 - #endif 329 - #ifdef CONFIG_NET_DSA_TAG_EDSA 330 - static const struct net_device_ops edsa_netdev_ops = { 331 - .ndo_init = dsa_slave_init, 332 - .ndo_open = dsa_slave_open, 333 - .ndo_stop = dsa_slave_close, 334 - .ndo_start_xmit = edsa_xmit, 335 - .ndo_change_rx_flags = dsa_slave_change_rx_flags, 336 - .ndo_set_rx_mode = dsa_slave_set_rx_mode, 337 - .ndo_set_mac_address = dsa_slave_set_mac_address, 338 - .ndo_do_ioctl = dsa_slave_ioctl, 306 + 307 + static const struct dsa_device_ops notag_netdev_ops = { 308 + .xmit = dsa_slave_notag_xmit, 309 + .rcv = NULL, 339 310 }; 340 - #endif 341 - #ifdef CONFIG_NET_DSA_TAG_TRAILER 342 - static const struct net_device_ops trailer_netdev_ops = { 343 - .ndo_init = dsa_slave_init, 344 - .ndo_open = dsa_slave_open, 345 - .ndo_stop = dsa_slave_close, 346 - .ndo_start_xmit = trailer_xmit, 347 - .ndo_change_rx_flags = dsa_slave_change_rx_flags, 348 - .ndo_set_rx_mode = dsa_slave_set_rx_mode, 349 - .ndo_set_mac_address = dsa_slave_set_mac_address, 350 - .ndo_do_ioctl = dsa_slave_ioctl, 351 - }; 352 - #endif 311 + 312 + static void dsa_slave_adjust_link(struct net_device *dev) 313 + { 314 + struct dsa_slave_priv *p = netdev_priv(dev); 315 + struct dsa_switch *ds = p->parent; 316 + unsigned int status_changed = 0; 317 + 318 + if (p->old_link != p->phy->link) { 319 + status_changed = 1; 320 + p->old_link = p->phy->link; 321 + } 322 + 323 + if (p->old_duplex != p->phy->duplex) { 324 + status_changed = 1; 325 + p->old_duplex = p->phy->duplex; 326 + } 327 + 328 + if (p->old_pause != p->phy->pause) { 329 + status_changed = 1; 330 + p->old_pause = p->phy->pause; 331 + } 332 + 333 + if (ds->drv->adjust_link && status_changed) 334 + ds->drv->adjust_link(ds, p->port, p->phy); 335 + 336 + if (status_changed) 337 + phy_print_status(p->phy); 338 + } 339 + 340 + static int dsa_slave_fixed_link_update(struct net_device *dev, 341 + struct fixed_phy_status *status) 342 + { 343 + struct dsa_slave_priv *p = netdev_priv(dev); 344 + struct dsa_switch *ds = p->parent; 345 + 346 + if (ds->drv->fixed_link_update) 347 + ds->drv->fixed_link_update(ds, p->port, status); 348 + 349 + return 0; 350 + } 353 351 354 352 /* slave device setup *******************************************************/ 353 + static void dsa_slave_phy_setup(struct dsa_slave_priv *p, 354 + struct net_device *slave_dev) 355 + { 356 + struct dsa_switch *ds = p->parent; 357 + struct dsa_chip_data *cd = ds->pd; 358 + struct device_node *phy_dn, *port_dn; 359 + bool phy_is_fixed = false; 360 + int ret; 361 + 362 + port_dn = cd->port_dn[p->port]; 363 + p->phy_interface = of_get_phy_mode(port_dn); 364 + 365 + phy_dn = of_parse_phandle(port_dn, "phy-handle", 0); 366 + if (of_phy_is_fixed_link(port_dn)) { 367 + /* In the case of a fixed PHY, the DT node associated 368 + * to the fixed PHY is the Port DT node 369 + */ 370 + ret = of_phy_register_fixed_link(port_dn); 371 + if (ret) { 372 + pr_err("failed to register fixed PHY\n"); 373 + return; 374 + } 375 + phy_is_fixed = true; 376 + phy_dn = port_dn; 377 + } 378 + 379 + if (phy_dn) 380 + p->phy = of_phy_connect(slave_dev, phy_dn, 381 + dsa_slave_adjust_link, 0, 382 + p->phy_interface); 383 + 384 + if (p->phy && phy_is_fixed) 385 + fixed_phy_set_link_update(p->phy, dsa_slave_fixed_link_update); 386 + 387 + /* We could not connect to a designated PHY, so use the switch internal 388 + * MDIO bus instead 389 + */ 390 + if (!p->phy) 391 + p->phy = ds->slave_mii_bus->phy_map[p->port]; 392 + else 393 + pr_info("attached PHY at address %d [%s]\n", 394 + p->phy->addr, p->phy->drv->name); 395 + } 396 + 355 397 struct net_device * 356 398 dsa_slave_create(struct dsa_switch *ds, struct device *parent, 357 399 int port, char *name) ··· 433 349 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; 434 350 eth_hw_addr_inherit(slave_dev, master); 435 351 slave_dev->tx_queue_len = 0; 352 + slave_dev->netdev_ops = &dsa_slave_netdev_ops; 436 353 437 354 switch (ds->dst->tag_protocol) { 438 355 #ifdef CONFIG_NET_DSA_TAG_DSA 439 356 case htons(ETH_P_DSA): 440 - slave_dev->netdev_ops = &dsa_netdev_ops; 357 + ds->dst->ops = &dsa_netdev_ops; 441 358 break; 442 359 #endif 443 360 #ifdef CONFIG_NET_DSA_TAG_EDSA 444 361 case htons(ETH_P_EDSA): 445 - slave_dev->netdev_ops = &edsa_netdev_ops; 362 + ds->dst->ops = &edsa_netdev_ops; 446 363 break; 447 364 #endif 448 365 #ifdef CONFIG_NET_DSA_TAG_TRAILER 449 366 case htons(ETH_P_TRAILER): 450 - slave_dev->netdev_ops = &trailer_netdev_ops; 367 + ds->dst->ops = &trailer_netdev_ops; 368 + break; 369 + #endif 370 + #ifdef CONFIG_NET_DSA_TAG_BRCM 371 + case htons(ETH_P_BRCMTAG): 372 + ds->dst->ops = &brcm_netdev_ops; 451 373 break; 452 374 #endif 453 375 default: 454 - BUG(); 376 + ds->dst->ops = &notag_netdev_ops; 377 + break; 455 378 } 456 379 457 380 SET_NETDEV_DEV(slave_dev, parent); 381 + slave_dev->dev.of_node = ds->pd->port_dn[port]; 458 382 slave_dev->vlan_features = master->vlan_features; 459 383 460 384 p = netdev_priv(slave_dev); 461 385 p->dev = slave_dev; 462 386 p->parent = ds; 463 387 p->port = port; 464 - p->phy = ds->slave_mii_bus->phy_map[port]; 388 + 389 + p->old_pause = -1; 390 + p->old_link = -1; 391 + p->old_duplex = -1; 392 + 393 + dsa_slave_phy_setup(p, slave_dev); 465 394 466 395 ret = register_netdev(slave_dev); 467 396 if (ret) {
+173
net/dsa/tag_brcm.c
··· 1 + /* 2 + * Broadcom tag support 3 + * 4 + * Copyright (C) 2014 Broadcom Corporation 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + */ 11 + 12 + #include <linux/etherdevice.h> 13 + #include <linux/list.h> 14 + #include <linux/netdevice.h> 15 + #include <linux/slab.h> 16 + #include "dsa_priv.h" 17 + 18 + /* This tag length is 4 bytes, older ones were 6 bytes, we do not 19 + * handle them 20 + */ 21 + #define BRCM_TAG_LEN 4 22 + 23 + /* Tag is constructed and desconstructed using byte by byte access 24 + * because the tag is placed after the MAC Source Address, which does 25 + * not make it 4-bytes aligned, so this might cause unaligned accesses 26 + * on most systems where this is used. 27 + */ 28 + 29 + /* Ingress and egress opcodes */ 30 + #define BRCM_OPCODE_SHIFT 5 31 + #define BRCM_OPCODE_MASK 0x7 32 + 33 + /* Ingress fields */ 34 + /* 1st byte in the tag */ 35 + #define BRCM_IG_TC_SHIFT 2 36 + #define BRCM_IG_TC_MASK 0x7 37 + /* 2nd byte in the tag */ 38 + #define BRCM_IG_TE_MASK 0x3 39 + #define BRCM_IG_TS_SHIFT 7 40 + /* 3rd byte in the tag */ 41 + #define BRCM_IG_DSTMAP2_MASK 1 42 + #define BRCM_IG_DSTMAP1_MASK 0xff 43 + 44 + /* Egress fields */ 45 + 46 + /* 2nd byte in the tag */ 47 + #define BRCM_EG_CID_MASK 0xff 48 + 49 + /* 3rd byte in the tag */ 50 + #define BRCM_EG_RC_MASK 0xff 51 + #define BRCM_EG_RC_RSVD (3 << 6) 52 + #define BRCM_EG_RC_EXCEPTION (1 << 5) 53 + #define BRCM_EG_RC_PROT_SNOOP (1 << 4) 54 + #define BRCM_EG_RC_PROT_TERM (1 << 3) 55 + #define BRCM_EG_RC_SWITCH (1 << 2) 56 + #define BRCM_EG_RC_MAC_LEARN (1 << 1) 57 + #define BRCM_EG_RC_MIRROR (1 << 0) 58 + #define BRCM_EG_TC_SHIFT 5 59 + #define BRCM_EG_TC_MASK 0x7 60 + #define BRCM_EG_PID_MASK 0x1f 61 + 62 + static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev) 63 + { 64 + struct dsa_slave_priv *p = netdev_priv(dev); 65 + u8 *brcm_tag; 66 + 67 + dev->stats.tx_packets++; 68 + dev->stats.tx_bytes += skb->len; 69 + 70 + if (skb_cow_head(skb, BRCM_TAG_LEN) < 0) 71 + goto out_free; 72 + 73 + skb_push(skb, BRCM_TAG_LEN); 74 + 75 + memmove(skb->data, skb->data + BRCM_TAG_LEN, 2 * ETH_ALEN); 76 + 77 + /* Build the tag after the MAC Source Address */ 78 + brcm_tag = skb->data + 2 * ETH_ALEN; 79 + 80 + /* Set the ingress opcode, traffic class, tag enforcment is 81 + * deprecated 82 + */ 83 + brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) | 84 + ((skb->priority << BRCM_IG_TC_SHIFT) & BRCM_IG_TC_MASK); 85 + brcm_tag[1] = 0; 86 + brcm_tag[2] = 0; 87 + if (p->port == 8) 88 + brcm_tag[2] = BRCM_IG_DSTMAP2_MASK; 89 + brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK; 90 + 91 + /* Queue the SKB for transmission on the parent interface, but 92 + * do not modify its EtherType 93 + */ 94 + skb->protocol = htons(ETH_P_BRCMTAG); 95 + skb->dev = p->parent->dst->master_netdev; 96 + dev_queue_xmit(skb); 97 + 98 + return NETDEV_TX_OK; 99 + 100 + out_free: 101 + kfree_skb(skb); 102 + return NETDEV_TX_OK; 103 + } 104 + 105 + static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev, 106 + struct packet_type *pt, struct net_device *orig_dev) 107 + { 108 + struct dsa_switch_tree *dst = dev->dsa_ptr; 109 + struct dsa_switch *ds; 110 + int source_port; 111 + u8 *brcm_tag; 112 + 113 + if (unlikely(dst == NULL)) 114 + goto out_drop; 115 + 116 + ds = dst->ds[0]; 117 + 118 + skb = skb_unshare(skb, GFP_ATOMIC); 119 + if (skb == NULL) 120 + goto out; 121 + 122 + if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN))) 123 + goto out_drop; 124 + 125 + /* skb->data points to the EtherType, the tag is right before it */ 126 + brcm_tag = skb->data - 2; 127 + 128 + /* The opcode should never be different than 0b000 */ 129 + if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK)) 130 + goto out_drop; 131 + 132 + /* We should never see a reserved reason code without knowing how to 133 + * handle it 134 + */ 135 + WARN_ON(brcm_tag[2] & BRCM_EG_RC_RSVD); 136 + 137 + /* Locate which port this is coming from */ 138 + source_port = brcm_tag[3] & BRCM_EG_PID_MASK; 139 + 140 + /* Validate port against switch setup, either the port is totally */ 141 + if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) 142 + goto out_drop; 143 + 144 + /* Remove Broadcom tag and update checksum */ 145 + skb_pull_rcsum(skb, BRCM_TAG_LEN); 146 + 147 + /* Move the Ethernet DA and SA */ 148 + memmove(skb->data - ETH_HLEN, 149 + skb->data - ETH_HLEN - BRCM_TAG_LEN, 150 + 2 * ETH_ALEN); 151 + 152 + skb_push(skb, ETH_HLEN); 153 + skb->pkt_type = PACKET_HOST; 154 + skb->dev = ds->ports[source_port]; 155 + skb->protocol = eth_type_trans(skb, skb->dev); 156 + 157 + skb->dev->stats.rx_packets++; 158 + skb->dev->stats.rx_bytes += skb->len; 159 + 160 + netif_receive_skb(skb); 161 + 162 + return 0; 163 + 164 + out_drop: 165 + kfree_skb(skb); 166 + out: 167 + return 0; 168 + } 169 + 170 + const struct dsa_device_ops brcm_netdev_ops = { 171 + .xmit = brcm_tag_xmit, 172 + .rcv = brcm_tag_rcv, 173 + };
+4 -4
net/dsa/tag_dsa.c
··· 16 16 17 17 #define DSA_HLEN 4 18 18 19 - netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev) 19 + static netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev) 20 20 { 21 21 struct dsa_slave_priv *p = netdev_priv(dev); 22 22 u8 *dsa_header; ··· 186 186 return 0; 187 187 } 188 188 189 - struct packet_type dsa_packet_type __read_mostly = { 190 - .type = cpu_to_be16(ETH_P_DSA), 191 - .func = dsa_rcv, 189 + const struct dsa_device_ops dsa_netdev_ops = { 190 + .xmit = dsa_xmit, 191 + .rcv = dsa_rcv, 192 192 };
+4 -4
net/dsa/tag_edsa.c
··· 17 17 #define DSA_HLEN 4 18 18 #define EDSA_HLEN 8 19 19 20 - netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev) 20 + static netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev) 21 21 { 22 22 struct dsa_slave_priv *p = netdev_priv(dev); 23 23 u8 *edsa_header; ··· 205 205 return 0; 206 206 } 207 207 208 - struct packet_type edsa_packet_type __read_mostly = { 209 - .type = cpu_to_be16(ETH_P_EDSA), 210 - .func = edsa_rcv, 208 + const struct dsa_device_ops edsa_netdev_ops = { 209 + .xmit = edsa_xmit, 210 + .rcv = edsa_rcv, 211 211 };
+4 -4
net/dsa/tag_trailer.c
··· 14 14 #include <linux/slab.h> 15 15 #include "dsa_priv.h" 16 16 17 - netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev) 17 + static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev) 18 18 { 19 19 struct dsa_slave_priv *p = netdev_priv(dev); 20 20 struct sk_buff *nskb; ··· 114 114 return 0; 115 115 } 116 116 117 - struct packet_type trailer_packet_type __read_mostly = { 118 - .type = cpu_to_be16(ETH_P_TRAILER), 119 - .func = trailer_rcv, 117 + const struct dsa_device_ops trailer_netdev_ops = { 118 + .xmit = trailer_xmit, 119 + .rcv = trailer_rcv, 120 120 };
+2 -5
net/ethernet/eth.c
··· 181 181 * variants has been configured on the receiving interface, 182 182 * and if so, set skb->protocol without looking at the packet. 183 183 */ 184 - if (unlikely(netdev_uses_dsa_tags(dev))) 185 - return htons(ETH_P_DSA); 186 - 187 - if (unlikely(netdev_uses_trailer_tags(dev))) 188 - return htons(ETH_P_TRAILER); 184 + if (unlikely(netdev_uses_dsa(dev))) 185 + return htons(ETH_P_XDSA); 189 186 190 187 if (likely(ntohs(eth->h_proto) >= ETH_P_802_3_MIN)) 191 188 return eth->h_proto;