Skip to content

Commit 4aabe35

Browse files
Russell King (Oracle)davem330
authored andcommitted
net: dsa: mv88e6xxx: convert 88e6185 to phylink_pcs
Convert the 88E6185 SERDES code to use the phylink_pcs infrastructure. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 05407b0 commit 4aabe35

File tree

5 files changed

+196
-129
lines changed

5 files changed

+196
-129
lines changed

drivers/net/dsa/mv88e6xxx/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o
99
mv88e6xxx-objs += global2_avb.o
1010
mv88e6xxx-objs += global2_scratch.o
1111
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
12+
mv88e6xxx-objs += pcs-6185.o
1213
mv88e6xxx-objs += phy.o
1314
mv88e6xxx-objs += port.o
1415
mv88e6xxx-objs += port_hidden.o

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4230,15 +4230,13 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
42304230
.stats_get_strings = mv88e6095_stats_get_strings,
42314231
.stats_get_stats = mv88e6095_stats_get_stats,
42324232
.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
4233-
.serdes_power = mv88e6185_serdes_power,
4234-
.serdes_get_lane = mv88e6185_serdes_get_lane,
4235-
.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
42364233
.ppu_enable = mv88e6185_g1_ppu_enable,
42374234
.ppu_disable = mv88e6185_g1_ppu_disable,
42384235
.reset = mv88e6185_g1_reset,
42394236
.vtu_getnext = mv88e6185_g1_vtu_getnext,
42404237
.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
42414238
.phylink_get_caps = mv88e6095_phylink_get_caps,
4239+
.pcs_ops = &mv88e6185_pcs_ops,
42424240
.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
42434241
};
42444242

@@ -4276,18 +4274,14 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
42764274
.set_egress_port = mv88e6095_g1_set_egress_port,
42774275
.watchdog_ops = &mv88e6097_watchdog_ops,
42784276
.mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
4279-
.serdes_power = mv88e6185_serdes_power,
4280-
.serdes_get_lane = mv88e6185_serdes_get_lane,
4281-
.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
42824277
.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
4283-
.serdes_irq_enable = mv88e6097_serdes_irq_enable,
4284-
.serdes_irq_status = mv88e6097_serdes_irq_status,
42854278
.pot_clear = mv88e6xxx_g2_pot_clear,
42864279
.reset = mv88e6352_g1_reset,
42874280
.rmu_disable = mv88e6085_g1_rmu_disable,
42884281
.vtu_getnext = mv88e6352_g1_vtu_getnext,
42894282
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
42904283
.phylink_get_caps = mv88e6095_phylink_get_caps,
4284+
.pcs_ops = &mv88e6185_pcs_ops,
42914285
.stu_getnext = mv88e6352_g1_stu_getnext,
42924286
.stu_loadpurge = mv88e6352_g1_stu_loadpurge,
42934287
.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
@@ -4768,16 +4762,14 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
47684762
.set_egress_port = mv88e6095_g1_set_egress_port,
47694763
.watchdog_ops = &mv88e6097_watchdog_ops,
47704764
.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
4771-
.serdes_power = mv88e6185_serdes_power,
4772-
.serdes_get_lane = mv88e6185_serdes_get_lane,
4773-
.serdes_pcs_get_state = mv88e6185_serdes_pcs_get_state,
47744765
.set_cascade_port = mv88e6185_g1_set_cascade_port,
47754766
.ppu_enable = mv88e6185_g1_ppu_enable,
47764767
.ppu_disable = mv88e6185_g1_ppu_disable,
47774768
.reset = mv88e6185_g1_reset,
47784769
.vtu_getnext = mv88e6185_g1_vtu_getnext,
47794770
.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
47804771
.phylink_get_caps = mv88e6185_phylink_get_caps,
4772+
.pcs_ops = &mv88e6185_pcs_ops,
47814773
.set_max_frame_size = mv88e6185_g1_set_max_frame_size,
47824774
};
47834775

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Marvell 88E6185 family SERDES PCS support
4+
*
5+
* Copyright (c) 2008 Marvell Semiconductor
6+
*
7+
* Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
8+
*/
9+
#include <linux/phylink.h>
10+
11+
#include "global2.h"
12+
#include "port.h"
13+
#include "serdes.h"
14+
15+
struct mv88e6185_pcs {
16+
struct phylink_pcs phylink_pcs;
17+
unsigned int irq;
18+
char name[64];
19+
20+
struct mv88e6xxx_chip *chip;
21+
int port;
22+
};
23+
24+
static struct mv88e6185_pcs *pcs_to_mv88e6185_pcs(struct phylink_pcs *pcs)
25+
{
26+
return container_of(pcs, struct mv88e6185_pcs, phylink_pcs);
27+
}
28+
29+
static irqreturn_t mv88e6185_pcs_handle_irq(int irq, void *dev_id)
30+
{
31+
struct mv88e6185_pcs *mpcs = dev_id;
32+
struct mv88e6xxx_chip *chip;
33+
irqreturn_t ret = IRQ_NONE;
34+
bool link_up;
35+
u16 status;
36+
int port;
37+
int err;
38+
39+
chip = mpcs->chip;
40+
port = mpcs->port;
41+
42+
mv88e6xxx_reg_lock(chip);
43+
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
44+
mv88e6xxx_reg_unlock(chip);
45+
46+
if (!err) {
47+
link_up = !!(status & MV88E6XXX_PORT_STS_LINK);
48+
49+
phylink_pcs_change(&mpcs->phylink_pcs, link_up);
50+
51+
ret = IRQ_HANDLED;
52+
}
53+
54+
return ret;
55+
}
56+
57+
static void mv88e6185_pcs_get_state(struct phylink_pcs *pcs,
58+
struct phylink_link_state *state)
59+
{
60+
struct mv88e6185_pcs *mpcs = pcs_to_mv88e6185_pcs(pcs);
61+
struct mv88e6xxx_chip *chip = mpcs->chip;
62+
int port = mpcs->port;
63+
u16 status;
64+
int err;
65+
66+
mv88e6xxx_reg_lock(chip);
67+
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
68+
mv88e6xxx_reg_unlock(chip);
69+
70+
if (err)
71+
status = 0;
72+
73+
state->link = !!(status & MV88E6XXX_PORT_STS_LINK);
74+
if (state->link) {
75+
state->duplex = status & MV88E6XXX_PORT_STS_DUPLEX ?
76+
DUPLEX_FULL : DUPLEX_HALF;
77+
78+
switch (status & MV88E6XXX_PORT_STS_SPEED_MASK) {
79+
case MV88E6XXX_PORT_STS_SPEED_1000:
80+
state->speed = SPEED_1000;
81+
break;
82+
83+
case MV88E6XXX_PORT_STS_SPEED_100:
84+
state->speed = SPEED_100;
85+
break;
86+
87+
case MV88E6XXX_PORT_STS_SPEED_10:
88+
state->speed = SPEED_10;
89+
break;
90+
91+
default:
92+
state->link = false;
93+
break;
94+
}
95+
}
96+
}
97+
98+
static int mv88e6185_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
99+
phy_interface_t interface,
100+
const unsigned long *advertising,
101+
bool permit_pause_to_mac)
102+
{
103+
return 0;
104+
}
105+
106+
static void mv88e6185_pcs_an_restart(struct phylink_pcs *pcs)
107+
{
108+
}
109+
110+
static const struct phylink_pcs_ops mv88e6185_phylink_pcs_ops = {
111+
.pcs_get_state = mv88e6185_pcs_get_state,
112+
.pcs_config = mv88e6185_pcs_config,
113+
.pcs_an_restart = mv88e6185_pcs_an_restart,
114+
};
115+
116+
static int mv88e6185_pcs_init(struct mv88e6xxx_chip *chip, int port)
117+
{
118+
struct mv88e6185_pcs *mpcs;
119+
struct device *dev;
120+
unsigned int irq;
121+
int err;
122+
123+
/* There are no configurable serdes lanes on this switch chip, so
124+
* we use the static cmode configuration to determine whether we
125+
* have a PCS or not.
126+
*/
127+
if (chip->ports[port].cmode != MV88E6185_PORT_STS_CMODE_SERDES &&
128+
chip->ports[port].cmode != MV88E6185_PORT_STS_CMODE_1000BASE_X)
129+
return 0;
130+
131+
dev = chip->dev;
132+
133+
mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
134+
if (!mpcs)
135+
return -ENOMEM;
136+
137+
mpcs->chip = chip;
138+
mpcs->port = port;
139+
mpcs->phylink_pcs.ops = &mv88e6185_phylink_pcs_ops;
140+
141+
irq = mv88e6xxx_serdes_irq_mapping(chip, port);
142+
if (irq) {
143+
snprintf(mpcs->name, sizeof(mpcs->name),
144+
"mv88e6xxx-%s-serdes-%d", dev_name(dev), port);
145+
146+
err = request_threaded_irq(irq, NULL, mv88e6185_pcs_handle_irq,
147+
IRQF_ONESHOT, mpcs->name, mpcs);
148+
if (err) {
149+
kfree(mpcs);
150+
return err;
151+
}
152+
153+
mpcs->irq = irq;
154+
} else {
155+
mpcs->phylink_pcs.poll = true;
156+
}
157+
158+
chip->ports[port].pcs_private = &mpcs->phylink_pcs;
159+
160+
return 0;
161+
}
162+
163+
static void mv88e6185_pcs_teardown(struct mv88e6xxx_chip *chip, int port)
164+
{
165+
struct mv88e6185_pcs *mpcs;
166+
167+
mpcs = chip->ports[port].pcs_private;
168+
if (!mpcs)
169+
return;
170+
171+
if (mpcs->irq)
172+
free_irq(mpcs->irq, mpcs);
173+
174+
kfree(mpcs);
175+
176+
chip->ports[port].pcs_private = NULL;
177+
}
178+
179+
static struct phylink_pcs *mv88e6185_pcs_select(struct mv88e6xxx_chip *chip,
180+
int port,
181+
phy_interface_t interface)
182+
{
183+
return chip->ports[port].pcs_private;
184+
}
185+
186+
const struct mv88e6xxx_pcs_ops mv88e6185_pcs_ops = {
187+
.pcs_init = mv88e6185_pcs_init,
188+
.pcs_teardown = mv88e6185_pcs_teardown,
189+
.pcs_select = mv88e6185_pcs_select,
190+
};

drivers/net/dsa/mv88e6xxx/serdes.c

Lines changed: 0 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -460,115 +460,6 @@ int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
460460
return lane;
461461
}
462462

463-
int mv88e6185_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
464-
bool up)
465-
{
466-
/* The serdes power can't be controlled on this switch chip but we need
467-
* to supply this function to avoid returning -EOPNOTSUPP in
468-
* mv88e6xxx_serdes_power_up/mv88e6xxx_serdes_power_down
469-
*/
470-
return 0;
471-
}
472-
473-
int mv88e6185_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
474-
{
475-
/* There are no configurable serdes lanes on this switch chip but we
476-
* need to return a non-negative lane number so that callers of
477-
* mv88e6xxx_serdes_get_lane() know this is a serdes port.
478-
*/
479-
switch (chip->ports[port].cmode) {
480-
case MV88E6185_PORT_STS_CMODE_SERDES:
481-
case MV88E6185_PORT_STS_CMODE_1000BASE_X:
482-
return 0;
483-
default:
484-
return -ENODEV;
485-
}
486-
}
487-
488-
int mv88e6185_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
489-
int lane, struct phylink_link_state *state)
490-
{
491-
int err;
492-
u16 status;
493-
494-
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
495-
if (err)
496-
return err;
497-
498-
state->link = !!(status & MV88E6XXX_PORT_STS_LINK);
499-
500-
if (state->link) {
501-
state->duplex = status & MV88E6XXX_PORT_STS_DUPLEX ? DUPLEX_FULL : DUPLEX_HALF;
502-
503-
switch (status & MV88E6XXX_PORT_STS_SPEED_MASK) {
504-
case MV88E6XXX_PORT_STS_SPEED_1000:
505-
state->speed = SPEED_1000;
506-
break;
507-
case MV88E6XXX_PORT_STS_SPEED_100:
508-
state->speed = SPEED_100;
509-
break;
510-
case MV88E6XXX_PORT_STS_SPEED_10:
511-
state->speed = SPEED_10;
512-
break;
513-
default:
514-
dev_err(chip->dev, "invalid PHY speed\n");
515-
return -EINVAL;
516-
}
517-
} else {
518-
state->duplex = DUPLEX_UNKNOWN;
519-
state->speed = SPEED_UNKNOWN;
520-
}
521-
522-
return 0;
523-
}
524-
525-
int mv88e6097_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int lane,
526-
bool enable)
527-
{
528-
u8 cmode = chip->ports[port].cmode;
529-
530-
/* The serdes interrupts are enabled in the G2_INT_MASK register. We
531-
* need to return 0 to avoid returning -EOPNOTSUPP in
532-
* mv88e6xxx_serdes_irq_enable/mv88e6xxx_serdes_irq_disable
533-
*/
534-
switch (cmode) {
535-
case MV88E6185_PORT_STS_CMODE_SERDES:
536-
case MV88E6185_PORT_STS_CMODE_1000BASE_X:
537-
return 0;
538-
}
539-
540-
return -EOPNOTSUPP;
541-
}
542-
543-
static void mv88e6097_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
544-
{
545-
u16 status;
546-
int err;
547-
548-
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &status);
549-
if (err) {
550-
dev_err(chip->dev, "can't read port status: %d\n", err);
551-
return;
552-
}
553-
554-
dsa_port_phylink_mac_change(chip->ds, port, !!(status & MV88E6XXX_PORT_STS_LINK));
555-
}
556-
557-
irqreturn_t mv88e6097_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
558-
int lane)
559-
{
560-
u8 cmode = chip->ports[port].cmode;
561-
562-
switch (cmode) {
563-
case MV88E6185_PORT_STS_CMODE_SERDES:
564-
case MV88E6185_PORT_STS_CMODE_1000BASE_X:
565-
mv88e6097_serdes_irq_link(chip, port);
566-
return IRQ_HANDLED;
567-
}
568-
569-
return IRQ_NONE;
570-
}
571-
572463
int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
573464
{
574465
u8 cmode = chip->ports[port].cmode;

0 commit comments

Comments
 (0)