Skip to content

Commit df2c2ba

Browse files
committed
Merge branch 'Convert-Felix-DSA-switch-to-PHYLINK'
Vladimir Oltean says: ==================== Convert Felix DSA switch to PHYLINK Unlike most other conversions, this one is not by far a trivial one, and should be seen as "Layerscape PCS meets PHYLINK". Actually, the PCS doesn't need a lot of hand-holding and most of our other devices 'just work' (this one included) without any sort of operating system awareness, just an initialization procedure done typically in the bootloader. Our issues start when the PCS stops from "just working", and that is where PHYLINK comes in handy. The PCS is not specific to the Vitesse / Microsemi / Microchip switching core at all. Variations of this SerDes/PCS design can also be found on DPAA1 and DPAA2 hardware. The main idea of the abstraction provided is that the PCS looks so much like a PHY device, that we model it as an actual PHY device and run the generic PHY functions on it, where appropriate. The 4xSGMII, QSGMII and QSXGMII modes are fairly straightforward. The SerDes protocol which the driver calls 2500Base-X mode (a misnomer) is more interesting. There is a description of how it works and what can be done with it in patch 9/9 (in a comment above vsc9959_pcs_init_2500basex). In short, it is a fixed speed protocol with no auto-negotiation whatsoever. From my research of the SGMII-2500 patent [1], it has nothing to do with SGMII-2500. That one: * does not define any change to the AN base page compared to plain 10/100/1000 SGMII. This implies that the 2500 speed is not negotiable, but the other speeds are. In our case, when the SerDes is configured for this protocol it's configured for good, there's no going back to SGMII. * runs at a higher base frequency than regular SGMII. So SGMII-2500 operating at 1000 Mbps wouldn't interoperate with plain SGMII at 1000 Mbps. Strange, but ok.. * Emulates lower link speeds than 2500 by duplicating the codewords twice, then thrice, then twice again etc (2.5/25/250 times on average). The Layerscape PCS doesn't do that (it is fixed at 2500 Mbaud). But on the other hand it isn't completely compatible with Base-X either, since it doesn't do 802.3z / clause 37 auto negotiation (flow control, local/remote fault etc). It is compatible with 2500Base-X without in-band AN, and that is exactly how we decided to expose it (this is actually similar to what others do). For SGMII and USXGMII, the driver is using the PHYLINK 'managed = "in-band-status"' DTS binding to figure out whether in-band AN is expected to be enabled in the PCS or not. It is expected that the attached PHY follows suite, but there is a gap here: the PHY driver does not react to this setting, so only one of "AN on" and "AN off" works on any particular PHY, even though that PHY might support bypassing the SGMII AN process, as is the case on the VSC8514 PHY present on the LS1028A-RDB board. A separate series will be sent to propose a way to deal with that. I dropped the Ocelot PHYLINK conversion because: * I don't have VSC7514 hardware anyway * The hardware is so different in this regard that there's almost nothing to share anyway. Changes in v5: - Added the register write to DEV_CLOCK_CFG back in felix_phylink_mac_config in patch 9/9. Changes in v4: - This is mostly a resend of v3, with the only notable change that I've dropped the PHY core patches for in_band_autoneg and I'll propose them independently. v1 series: https://www.spinics.net/lists/netdev/msg613869.html RFC v2 series: https://www.spinics.net/lists/netdev/msg620128.html v3 series: https://www.spinics.net/lists/netdev/msg622060.html v4 series: https://www.spinics.net/lists/netdev/msg622606.html [0]: https://www.spinics.net/lists/netdev/msg613869.html [1]: https://patents.google.com/patent/US7356047B1/en ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents de1b23b + bdeced7 commit df2c2ba

File tree

27 files changed

+1036
-130
lines changed

27 files changed

+1036
-130
lines changed

Documentation/networking/sfp-phylink.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ this documentation.
251251
phylink_mac_change(priv->phylink, link_is_up);
252252

253253
where ``link_is_up`` is true if the link is currently up or false
254-
otherwise.
254+
otherwise. If a MAC is unable to provide these interrupts, then
255+
it should set ``priv->phylink_config.pcs_poll = true;`` in step 9.
255256

256257
11. Verify that the driver does not call::
257258

drivers/net/dsa/ocelot/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ config NET_DSA_MSCC_FELIX
33
tristate "Ocelot / Felix Ethernet switch support"
44
depends on NET_DSA && PCI
55
depends on NET_VENDOR_MICROSEMI
6+
depends on NET_VENDOR_FREESCALE
67
select MSCC_OCELOT_SWITCH
78
select NET_DSA_TAG_OCELOT
9+
select FSL_ENETC_MDIO
810
help
911
This driver supports the VSC9959 network switch, which is a member of
1012
the Vitesse / Microsemi / Microchip Ocelot family of switching cores.

drivers/net/dsa/ocelot/felix.c

Lines changed: 250 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
/* Copyright 2019 NXP Semiconductors
33
*/
44
#include <uapi/linux/if_bridge.h>
5+
#include <soc/mscc/ocelot_qsys.h>
6+
#include <soc/mscc/ocelot_sys.h>
7+
#include <soc/mscc/ocelot_dev.h>
8+
#include <soc/mscc/ocelot_ana.h>
59
#include <soc/mscc/ocelot.h>
610
#include <linux/packing.h>
711
#include <linux/module.h>
12+
#include <linux/of_net.h>
813
#include <linux/pci.h>
914
#include <linux/of.h>
1015
#include <net/dsa.h>
@@ -26,14 +31,6 @@ static int felix_set_ageing_time(struct dsa_switch *ds,
2631
return 0;
2732
}
2833

29-
static void felix_adjust_link(struct dsa_switch *ds, int port,
30-
struct phy_device *phydev)
31-
{
32-
struct ocelot *ocelot = ds->priv;
33-
34-
ocelot_adjust_link(ocelot, port, phydev);
35-
}
36-
3734
static int felix_fdb_dump(struct dsa_switch *ds, int port,
3835
dsa_fdb_dump_cb_t *cb, void *data)
3936
{
@@ -155,6 +152,138 @@ static void felix_port_disable(struct dsa_switch *ds, int port)
155152
return ocelot_port_disable(ocelot, port);
156153
}
157154

155+
static void felix_phylink_validate(struct dsa_switch *ds, int port,
156+
unsigned long *supported,
157+
struct phylink_link_state *state)
158+
{
159+
struct ocelot *ocelot = ds->priv;
160+
struct ocelot_port *ocelot_port = ocelot->ports[port];
161+
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
162+
163+
if (state->interface != PHY_INTERFACE_MODE_NA &&
164+
state->interface != ocelot_port->phy_mode) {
165+
bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
166+
return;
167+
}
168+
169+
/* No half-duplex. */
170+
phylink_set_port_modes(mask);
171+
phylink_set(mask, Autoneg);
172+
phylink_set(mask, Pause);
173+
phylink_set(mask, Asym_Pause);
174+
if (state->interface != PHY_INTERFACE_MODE_2500BASEX) {
175+
phylink_set(mask, 10baseT_Full);
176+
phylink_set(mask, 100baseT_Full);
177+
phylink_set(mask, 1000baseT_Full);
178+
}
179+
/* The internal ports that run at 2.5G are overclocked GMII */
180+
if (state->interface == PHY_INTERFACE_MODE_GMII ||
181+
state->interface == PHY_INTERFACE_MODE_2500BASEX ||
182+
state->interface == PHY_INTERFACE_MODE_USXGMII) {
183+
phylink_set(mask, 2500baseT_Full);
184+
phylink_set(mask, 2500baseX_Full);
185+
}
186+
187+
bitmap_and(supported, supported, mask,
188+
__ETHTOOL_LINK_MODE_MASK_NBITS);
189+
bitmap_and(state->advertising, state->advertising, mask,
190+
__ETHTOOL_LINK_MODE_MASK_NBITS);
191+
}
192+
193+
static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port,
194+
struct phylink_link_state *state)
195+
{
196+
struct ocelot *ocelot = ds->priv;
197+
struct felix *felix = ocelot_to_felix(ocelot);
198+
199+
if (felix->info->pcs_link_state)
200+
felix->info->pcs_link_state(ocelot, port, state);
201+
202+
return 0;
203+
}
204+
205+
static void felix_phylink_mac_config(struct dsa_switch *ds, int port,
206+
unsigned int link_an_mode,
207+
const struct phylink_link_state *state)
208+
{
209+
struct ocelot *ocelot = ds->priv;
210+
struct ocelot_port *ocelot_port = ocelot->ports[port];
211+
struct felix *felix = ocelot_to_felix(ocelot);
212+
u32 mac_fc_cfg;
213+
214+
/* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and
215+
* PORT_RST bits in CLOCK_CFG
216+
*/
217+
ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(state->speed),
218+
DEV_CLOCK_CFG);
219+
220+
/* Flow control. Link speed is only used here to evaluate the time
221+
* specification in incoming pause frames.
222+
*/
223+
mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(state->speed);
224+
if (state->pause & MLO_PAUSE_RX)
225+
mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA;
226+
if (state->pause & MLO_PAUSE_TX)
227+
mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA |
228+
SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
229+
SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
230+
SYS_MAC_FC_CFG_ZERO_PAUSE_ENA;
231+
ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port);
232+
233+
ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port);
234+
235+
if (felix->info->pcs_init)
236+
felix->info->pcs_init(ocelot, port, link_an_mode, state);
237+
}
238+
239+
static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port)
240+
{
241+
struct ocelot *ocelot = ds->priv;
242+
struct felix *felix = ocelot_to_felix(ocelot);
243+
244+
if (felix->info->pcs_an_restart)
245+
felix->info->pcs_an_restart(ocelot, port);
246+
}
247+
248+
static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port,
249+
unsigned int link_an_mode,
250+
phy_interface_t interface)
251+
{
252+
struct ocelot *ocelot = ds->priv;
253+
struct ocelot_port *ocelot_port = ocelot->ports[port];
254+
255+
ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG);
256+
ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA,
257+
QSYS_SWITCH_PORT_MODE, port);
258+
}
259+
260+
static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
261+
unsigned int link_an_mode,
262+
phy_interface_t interface,
263+
struct phy_device *phydev)
264+
{
265+
struct ocelot *ocelot = ds->priv;
266+
struct ocelot_port *ocelot_port = ocelot->ports[port];
267+
268+
/* Enable MAC module */
269+
ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA |
270+
DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG);
271+
272+
/* Enable receiving frames on the port, and activate auto-learning of
273+
* MAC addresses.
274+
*/
275+
ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO |
276+
ANA_PORT_PORT_CFG_RECV_ENA |
277+
ANA_PORT_PORT_CFG_PORTID_VAL(port),
278+
ANA_PORT_PORT_CFG, port);
279+
280+
/* Core: Enable port for frame transfer */
281+
ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
282+
QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) |
283+
QSYS_SWITCH_PORT_MODE_PORT_ENA,
284+
QSYS_SWITCH_PORT_MODE, port);
285+
}
286+
158287
static void felix_get_strings(struct dsa_switch *ds, int port,
159288
u32 stringset, u8 *data)
160289
{
@@ -185,10 +314,76 @@ static int felix_get_ts_info(struct dsa_switch *ds, int port,
185314
return ocelot_get_ts_info(ocelot, port, info);
186315
}
187316

317+
static int felix_parse_ports_node(struct felix *felix,
318+
struct device_node *ports_node,
319+
phy_interface_t *port_phy_modes)
320+
{
321+
struct ocelot *ocelot = &felix->ocelot;
322+
struct device *dev = felix->ocelot.dev;
323+
struct device_node *child;
324+
325+
for_each_child_of_node(ports_node, child) {
326+
phy_interface_t phy_mode;
327+
u32 port;
328+
int err;
329+
330+
/* Get switch port number from DT */
331+
if (of_property_read_u32(child, "reg", &port) < 0) {
332+
dev_err(dev, "Port number not defined in device tree "
333+
"(property \"reg\")\n");
334+
of_node_put(child);
335+
return -ENODEV;
336+
}
337+
338+
/* Get PHY mode from DT */
339+
err = of_get_phy_mode(child, &phy_mode);
340+
if (err) {
341+
dev_err(dev, "Failed to read phy-mode or "
342+
"phy-interface-type property for port %d\n",
343+
port);
344+
of_node_put(child);
345+
return -ENODEV;
346+
}
347+
348+
err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode);
349+
if (err < 0) {
350+
dev_err(dev, "Unsupported PHY mode %s on port %d\n",
351+
phy_modes(phy_mode), port);
352+
return err;
353+
}
354+
355+
port_phy_modes[port] = phy_mode;
356+
}
357+
358+
return 0;
359+
}
360+
361+
static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes)
362+
{
363+
struct device *dev = felix->ocelot.dev;
364+
struct device_node *switch_node;
365+
struct device_node *ports_node;
366+
int err;
367+
368+
switch_node = dev->of_node;
369+
370+
ports_node = of_get_child_by_name(switch_node, "ports");
371+
if (!ports_node) {
372+
dev_err(dev, "Incorrect bindings: absent \"ports\" node\n");
373+
return -ENODEV;
374+
}
375+
376+
err = felix_parse_ports_node(felix, ports_node, port_phy_modes);
377+
of_node_put(ports_node);
378+
379+
return err;
380+
}
381+
188382
static int felix_init_structs(struct felix *felix, int num_phys_ports)
189383
{
190384
struct ocelot *ocelot = &felix->ocelot;
191-
resource_size_t base;
385+
phy_interface_t *port_phy_modes;
386+
resource_size_t switch_base;
192387
int port, i, err;
193388

194389
ocelot->num_phys_ports = num_phys_ports;
@@ -203,7 +398,19 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
203398
ocelot->shared_queue_sz = felix->info->shared_queue_sz;
204399
ocelot->ops = felix->info->ops;
205400

206-
base = pci_resource_start(felix->pdev, felix->info->pci_bar);
401+
port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t),
402+
GFP_KERNEL);
403+
if (!port_phy_modes)
404+
return -ENOMEM;
405+
406+
err = felix_parse_dt(felix, port_phy_modes);
407+
if (err) {
408+
kfree(port_phy_modes);
409+
return err;
410+
}
411+
412+
switch_base = pci_resource_start(felix->pdev,
413+
felix->info->switch_pci_bar);
207414

208415
for (i = 0; i < TARGET_MAX; i++) {
209416
struct regmap *target;
@@ -214,13 +421,14 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
214421

215422
res = &felix->info->target_io_res[i];
216423
res->flags = IORESOURCE_MEM;
217-
res->start += base;
218-
res->end += base;
424+
res->start += switch_base;
425+
res->end += switch_base;
219426

220427
target = ocelot_regmap_init(ocelot, res);
221428
if (IS_ERR(target)) {
222429
dev_err(ocelot->dev,
223430
"Failed to map device memory space\n");
431+
kfree(port_phy_modes);
224432
return PTR_ERR(target);
225433
}
226434

@@ -230,6 +438,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
230438
err = ocelot_regfields_init(ocelot, felix->info->regfields);
231439
if (err) {
232440
dev_err(ocelot->dev, "failed to init reg fields map\n");
441+
kfree(port_phy_modes);
233442
return err;
234443
}
235444

@@ -244,26 +453,37 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
244453
if (!ocelot_port) {
245454
dev_err(ocelot->dev,
246455
"failed to allocate port memory\n");
456+
kfree(port_phy_modes);
247457
return -ENOMEM;
248458
}
249459

250460
res = &felix->info->port_io_res[port];
251461
res->flags = IORESOURCE_MEM;
252-
res->start += base;
253-
res->end += base;
462+
res->start += switch_base;
463+
res->end += switch_base;
254464

255465
port_regs = devm_ioremap_resource(ocelot->dev, res);
256466
if (IS_ERR(port_regs)) {
257467
dev_err(ocelot->dev,
258468
"failed to map registers for port %d\n", port);
469+
kfree(port_phy_modes);
259470
return PTR_ERR(port_regs);
260471
}
261472

473+
ocelot_port->phy_mode = port_phy_modes[port];
262474
ocelot_port->ocelot = ocelot;
263475
ocelot_port->regs = port_regs;
264476
ocelot->ports[port] = ocelot_port;
265477
}
266478

479+
kfree(port_phy_modes);
480+
481+
if (felix->info->mdio_bus_alloc) {
482+
err = felix->info->mdio_bus_alloc(ocelot);
483+
if (err < 0)
484+
return err;
485+
}
486+
267487
return 0;
268488
}
269489

@@ -293,12 +513,22 @@ static int felix_setup(struct dsa_switch *ds)
293513
OCELOT_TAG_PREFIX_LONG);
294514
}
295515

516+
/* It looks like the MAC/PCS interrupt register - PM0_IEVENT (0x8040)
517+
* isn't instantiated for the Felix PF.
518+
* In-band AN may take a few ms to complete, so we need to poll.
519+
*/
520+
ds->pcs_poll = true;
521+
296522
return 0;
297523
}
298524

299525
static void felix_teardown(struct dsa_switch *ds)
300526
{
301527
struct ocelot *ocelot = ds->priv;
528+
struct felix *felix = ocelot_to_felix(ocelot);
529+
530+
if (felix->info->mdio_bus_free)
531+
felix->info->mdio_bus_free(ocelot);
302532

303533
/* stop workqueue thread */
304534
ocelot_deinit(ocelot);
@@ -369,7 +599,12 @@ static const struct dsa_switch_ops felix_switch_ops = {
369599
.get_ethtool_stats = felix_get_ethtool_stats,
370600
.get_sset_count = felix_get_sset_count,
371601
.get_ts_info = felix_get_ts_info,
372-
.adjust_link = felix_adjust_link,
602+
.phylink_validate = felix_phylink_validate,
603+
.phylink_mac_link_state = felix_phylink_mac_pcs_get_state,
604+
.phylink_mac_config = felix_phylink_mac_config,
605+
.phylink_mac_an_restart = felix_phylink_mac_an_restart,
606+
.phylink_mac_link_down = felix_phylink_mac_link_down,
607+
.phylink_mac_link_up = felix_phylink_mac_link_up,
373608
.port_enable = felix_port_enable,
374609
.port_disable = felix_port_disable,
375610
.port_fdb_dump = felix_fdb_dump,

0 commit comments

Comments
 (0)