Skip to content

Commit 7ec3281

Browse files
fchanfrank-w
authored andcommitted
net: dsa: mxl862xx: Add PCS operations for the Serdes1 combo port.
1 parent 54e0ed7 commit 7ec3281

File tree

4 files changed

+258
-7
lines changed

4 files changed

+258
-7
lines changed

drivers/net/dsa/mxl862xx/mxl862xx-api.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,3 +1466,36 @@ struct mxl862xx_sys_fw_image_version {
14661466
__le16 iv_revision;
14671467
__le32 iv_build_num;
14681468
} __packed;
1469+
1470+
/**
1471+
* struct mxl862xx_sys_sfp_cfg - Config SFP/Serdes ports
1472+
* @port_id: port id (0 or 1)
1473+
* @option: config options (0 - SFP mode/speed/link-status, 1 - flow control)
1474+
* @mode: SFP mode (0 - auto, 1 - fix, 2 - disable)
1475+
* @speed: select speed when mode is 1
1476+
* @link: get link state
1477+
* @fc_en: flow control (0 - disable, 1 - enable)
1478+
*/
1479+
struct mxl862xx_sys_sfp_cfg {
1480+
u8 port_id: 4;
1481+
u8 option: 4;
1482+
union {
1483+
struct {
1484+
u8 mode;
1485+
/** select speed when mode is 1
1486+
* 0 - 10G Quad USXGMII
1487+
* 1 - 1000BaseX ANeg
1488+
* 2 - 10G XFI
1489+
* 3 - 10G Single USXGMII
1490+
* 4 - 2.5G SGMII
1491+
* 5 - 2500 Single USXGMI
1492+
* 6 - 2500BaseX NonANeg
1493+
* 7 - 1000BaseX NonANeg
1494+
* 8 - 1G SGMI
1495+
*/
1496+
u8 speed;
1497+
u8 link;
1498+
};
1499+
u8 fc_en;
1500+
};
1501+
};

drivers/net/dsa/mxl862xx/mxl862xx-cmd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,5 +212,7 @@
212212
#define SYS_MISC_FW_VERSION (SYS_MISC_MAGIC + 0x02)
213213
#define SYS_MISC_PVT_TEMP (SYS_MISC_MAGIC + 0x03)
214214
#define SYS_MISC_PVT_VOLTAGE (SYS_MISC_MAGIC + 0x04)
215+
#define SYS_MISC_SFP_GET (SYS_MISC_MAGIC + 0x0D)
216+
#define SYS_MISC_SFP_SET (SYS_MISC_MAGIC + 0x0E)
215217

216218
#define MMD_API_MAXIMUM_ID 0x7FFF

drivers/net/dsa/mxl862xx/mxl862xx.c

Lines changed: 215 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2968,19 +2968,140 @@ static int mxl862xx_setup_mdio(struct dsa_switch *ds)
29682968
return ret;
29692969
}
29702970

2971+
static struct mxl862xx_pcs *pcs_to_mxl862xx_pcs(struct phylink_pcs *pcs)
2972+
{
2973+
return container_of(pcs, struct mxl862xx_pcs, pcs);
2974+
}
2975+
2976+
static void mxl862xx_pcs_get_state(struct phylink_pcs *pcs,
2977+
struct phylink_link_state *state)
2978+
{
2979+
struct mxl862xx_priv *priv = pcs_to_mxl862xx_pcs(pcs)->priv;
2980+
int port = pcs_to_mxl862xx_pcs(pcs)->port;
2981+
2982+
struct mxl862xx_port_link_cfg port_link_cfg = {
2983+
.port_id = port,
2984+
};
2985+
struct mxl862xx_port_cfg port_cfg = {
2986+
.port_id = port,
2987+
};
2988+
int ret;
2989+
2990+
ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTLINKCFGGET, port_link_cfg);
2991+
if (ret) {
2992+
dev_err(priv->dev, "failed to read link configuration on port %d\n", port);
2993+
return;
2994+
}
2995+
ret = MXL862XX_API_READ(priv, MXL862XX_COMMON_PORTCFGGET, port_cfg);
2996+
if (ret) {
2997+
dev_err(priv->dev, "failed to read configuration on port %d\n", port);
2998+
return;
2999+
}
3000+
3001+
if (port_link_cfg.link == MXL862XX_PORT_LINK_UP)
3002+
state->link = 1;
3003+
else
3004+
state->link = 0;
3005+
state->an_complete = state->link;
3006+
3007+
switch (port_link_cfg.speed) {
3008+
case MXL862XX_PORT_SPEED_10:
3009+
state->speed = SPEED_10;
3010+
break;
3011+
case MXL862XX_PORT_SPEED_100:
3012+
state->speed = SPEED_100;
3013+
break;
3014+
case MXL862XX_PORT_SPEED_1000:
3015+
state->speed = SPEED_1000;
3016+
break;
3017+
case MXL862XX_PORT_SPEED_2500:
3018+
state->speed = SPEED_2500;
3019+
break;
3020+
case MXL862XX_PORT_SPEED_5000:
3021+
state->speed = SPEED_5000;
3022+
break;
3023+
case MXL862XX_PORT_SPEED_10000:
3024+
state->speed = SPEED_10000;
3025+
break;
3026+
default:
3027+
state->speed = SPEED_UNKNOWN;
3028+
dev_err(priv->dev, "unsupported links speed on port %d\n", port);
3029+
break;
3030+
}
3031+
3032+
switch (port_link_cfg.duplex) {
3033+
case MXL862XX_DUPLEX_HALF:
3034+
state->duplex = DUPLEX_HALF;
3035+
break;
3036+
case MXL862XX_DUPLEX_FULL:
3037+
state->duplex = DUPLEX_FULL;
3038+
break;
3039+
default:
3040+
state->duplex = DUPLEX_UNKNOWN;
3041+
break;
3042+
}
3043+
3044+
state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX);
3045+
switch (port_cfg.flow_ctrl) {
3046+
case MXL862XX_FLOW_RXTX:
3047+
state->pause |= MLO_PAUSE_TXRX_MASK;
3048+
break;
3049+
case MXL862XX_FLOW_TX:
3050+
state->pause |= MLO_PAUSE_TX;
3051+
break;
3052+
case MXL862XX_FLOW_RX:
3053+
state->pause |= MLO_PAUSE_RX;
3054+
break;
3055+
case MXL862XX_FLOW_OFF:
3056+
default:
3057+
break;
3058+
}
3059+
}
3060+
3061+
static int mxl862xx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
3062+
phy_interface_t interface,
3063+
const unsigned long *advertising,
3064+
bool permit_pause_to_mac)
3065+
{
3066+
return 0;
3067+
}
3068+
3069+
static const struct phylink_pcs_ops mxl862xx_pcs_ops = {
3070+
.pcs_get_state = mxl862xx_pcs_get_state,
3071+
.pcs_config = mxl862xx_pcs_config,
3072+
};
3073+
3074+
static void mxl862xx_setup_pcs(struct mxl862xx_priv *priv, struct mxl862xx_pcs *pcs,
3075+
int port)
3076+
{
3077+
pcs->pcs.ops = &mxl862xx_pcs_ops;
3078+
3079+
/* poll link changes */
3080+
pcs->pcs.poll = true;
3081+
pcs->priv = priv;
3082+
pcs->port = port;
3083+
}
3084+
29713085
static int mxl862xx_setup(struct dsa_switch *ds)
29723086
{
29733087
struct mxl862xx_priv *priv = ds->priv;
29743088
unsigned int cpu_port, j;
29753089
int ret;
29763090
u8 i;
3091+
struct mxl862xx_bridge_port_config br_port_cfg = {
3092+
.mask = MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP,
3093+
};
29773094

29783095
priv->user_pnum = 0;
29793096
for (j = 0; j < ds->num_ports; j++) {
29803097
if (dsa_is_user_port(ds, j))
29813098
priv->user_pnum++;
29823099
else if (dsa_is_cpu_port(ds, j))
29833100
priv->cpu_port = cpu_port = j;
3101+
3102+
if (DSA_MXL_PORT(j) == 13) {
3103+
mxl862xx_setup_pcs(priv, &priv->pcs_port_1, 13);
3104+
}
29843105
}
29853106
dev_info(ds->dev, "\tMxl862xx CPU Port %u, User Port number %u\n",
29863107
cpu_port, priv->user_pnum);
@@ -3014,7 +3135,7 @@ static int mxl862xx_setup(struct dsa_switch *ds)
30143135

30153136
mxl862xx_mac_learning(ds, cpu_port, true);
30163137

3017-
for (i = 0; i < MAX_BRIDGES; i++)
3138+
for (i = 1; i < MAX_BRIDGES; i++)
30183139
priv->bridge_portmap[i] = BIT(DSA_MXL_PORT(cpu_port));
30193140

30203141
mxl862xx_set_vlan_filter_limits(ds);
@@ -3035,6 +3156,16 @@ static int mxl862xx_setup(struct dsa_switch *ds)
30353156
mxl862xx_port_state(ds, i, false);
30363157
mxl862xx_isolate_port(ds, i);
30373158
mxl862xx_port_fast_age(ds, i);
3159+
priv->bridge_portmap[0] |= BIT(DSA_MXL_PORT(i));
3160+
}
3161+
3162+
/* Update CPU bridge port */
3163+
br_port_cfg.bridge_port_id = DSA_MXL_PORT(cpu_port),
3164+
br_port_cfg.bridge_port_map[0] = priv->bridge_portmap[0];
3165+
ret = MXL862XX_API_WRITE(priv, MXL862XX_BRIDGEPORT_CONFIGSET, br_port_cfg);
3166+
if (ret) {
3167+
dev_err(ds->dev, "failed to set the cpu portmap\n");
3168+
return ret;
30383169
}
30393170

30403171
mxl862xx_port_fast_age(ds, cpu_port);
@@ -3105,16 +3236,93 @@ static void mxl862xx_phylink_mac_config(struct phylink_config *config, unsigned
31053236
const struct phylink_link_state *state)
31063237
{
31073238
struct dsa_port *dp = dsa_phylink_to_port(config);
3239+
int hw_port = DSA_MXL_PORT(dp->index);
3240+
int ret;
3241+
3242+
if (dsa_is_cpu_port(dp->ds, dp->index))
3243+
return;
3244+
3245+
if (hw_port == 9 || hw_port == 13) {
3246+
struct mxl862xx_sys_sfp_cfg ser_intf = {
3247+
.option = 0,
3248+
.mode = 1,
3249+
};
31083250

3109-
switch (state->interface) {
3110-
case PHY_INTERFACE_MODE_INTERNAL:
3251+
if (hw_port == 9)
3252+
ser_intf.port_id = 0;
3253+
else
3254+
ser_intf.port_id = 1;
3255+
3256+
/** select speed when mode is 1
3257+
* 0 - 10G Quad USXGMII
3258+
* 1 - 1000BaseX ANeg
3259+
* 2 - 10G XFI
3260+
* 3 - 10G Single USXGMII
3261+
* 4 - 2.5G SGMII
3262+
* 5 - 2500 Single USXGMI
3263+
* 6 - 2500BaseX NonANeg
3264+
* 7 - 1000BaseX NonANeg
3265+
* 8 - 1G SGMI
3266+
*/
3267+
switch (state->interface) {
3268+
case PHY_INTERFACE_MODE_SGMII:
3269+
ser_intf.speed = 8;
3270+
break;
3271+
case PHY_INTERFACE_MODE_1000BASEX:
3272+
ser_intf.speed = 7;
3273+
break;
3274+
case PHY_INTERFACE_MODE_2500BASEX:
3275+
ser_intf.speed = 4;
3276+
break;
3277+
case PHY_INTERFACE_MODE_10GBASER:
3278+
ser_intf.speed = 2;
3279+
break;
3280+
case PHY_INTERFACE_MODE_USXGMII:
3281+
ser_intf.speed = 3;
3282+
break;
3283+
default:
3284+
dev_err(dp->ds->dev, "Unsupported interface: %d\n", state->interface);
3285+
return;
3286+
}
3287+
3288+
ret = MXL862XX_API_WRITE(dp->ds->priv, SYS_MISC_SFP_SET, ser_intf);
3289+
if (ret)
3290+
dev_err(dp->ds->dev, "failed to set intf on port %d\n", dp->index);
3291+
} else {
3292+
/* Internal phy */
3293+
if (state->interface != PHY_INTERFACE_MODE_INTERNAL) {
3294+
dev_err(dp->ds->dev, "Unsupported interface: %d\n", state->interface);
3295+
return;
3296+
}
3297+
}
3298+
}
3299+
3300+
static struct phylink_pcs *
3301+
mxl862xx_phylink_mac_select_pcs(struct phylink_config *config,
3302+
phy_interface_t interface)
3303+
{
3304+
struct dsa_port *dp = dsa_phylink_to_port(config);
3305+
struct mxl862xx_priv *priv = dp->ds->priv;
3306+
struct phylink_pcs *pcs = NULL;
3307+
3308+
switch (interface) {
31113309
case PHY_INTERFACE_MODE_SGMII:
3310+
case PHY_INTERFACE_MODE_1000BASEX:
3311+
case PHY_INTERFACE_MODE_2500BASEX:
3312+
case PHY_INTERFACE_MODE_10GBASER:
31123313
case PHY_INTERFACE_MODE_USXGMII:
3113-
return;
3314+
switch (DSA_MXL_PORT(dp->index)) {
3315+
case 13:
3316+
pcs = &priv->pcs_port_1.pcs;
3317+
break;
3318+
}
3319+
break;
3320+
31143321
default:
3115-
dev_err(dp->ds->dev, "Unsupported interface: %d\n", state->interface);
3116-
return;
3322+
break;
31173323
}
3324+
3325+
return pcs;
31183326
}
31193327

31203328
static void mxl862xx_phylink_mac_link_down(struct phylink_config *config, unsigned int mode,
@@ -3445,6 +3653,7 @@ static const struct phylink_mac_ops mxl862xx_phylink_mac_ops = {
34453653
.mac_config = mxl862xx_phylink_mac_config,
34463654
.mac_link_down = mxl862xx_phylink_mac_link_down,
34473655
.mac_link_up = mxl862xx_phylink_mac_link_up,
3656+
.mac_select_pcs = mxl862xx_phylink_mac_select_pcs,
34483657
};
34493658

34503659
static const struct dsa_switch_ops mxl862xx_switch_ops = {

drivers/net/dsa/mxl862xx/mxl862xx.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#define VID_RULES 2
1515
#define MAX_VLANS 100
1616
#define MAX_PORTS MXL862XX_MAX_PORT_NUM
17-
#define MAX_BRIDGES 16
17+
#define MAX_BRIDGES 17
1818

1919
struct mxl862xx_hw_info {
2020
u8 max_ports;
@@ -81,6 +81,12 @@ struct mxl862xx_port_info {
8181
struct mxl862xx_port_vlan_info vlan;
8282
};
8383

84+
struct mxl862xx_pcs {
85+
struct phylink_pcs pcs;
86+
struct mxl862xx_priv *priv;
87+
int port;
88+
};
89+
8490
struct mxl862xx_priv {
8591
struct dsa_switch *ds;
8692
struct mii_bus *bus;
@@ -100,4 +106,5 @@ struct mxl862xx_priv {
100106
uint8_t user_pnum;
101107
bool force_isolate;
102108
bool c22_extended;
109+
struct mxl862xx_pcs pcs_port_1;
103110
};

0 commit comments

Comments
 (0)