Newer
Older
if (!ds->ops->phylink_mac_config)
return;
ds->ops->phylink_mac_config(ds, dp->index, mode, state);
}
static void dsa_port_phylink_mac_an_restart(struct phylink_config *config)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_an_restart)
return;
ds->ops->phylink_mac_an_restart(ds, dp->index);
}
static void dsa_port_phylink_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct phy_device *phydev = NULL;
struct dsa_switch *ds = dp->ds;
if (dsa_is_user_port(ds, dp->index))
phydev = dp->slave->phydev;
if (!ds->ops->phylink_mac_link_down) {
if (ds->ops->adjust_link && phydev)
ds->ops->adjust_link(ds, dp->index, phydev);
return;
}
ds->ops->phylink_mac_link_down(ds, dp->index, mode, interface);
}
static void dsa_port_phylink_mac_link_up(struct phylink_config *config,
struct phy_device *phydev,
unsigned int mode,
phy_interface_t interface,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
struct dsa_switch *ds = dp->ds;
if (!ds->ops->phylink_mac_link_up) {
if (ds->ops->adjust_link && phydev)
ds->ops->adjust_link(ds, dp->index, phydev);
return;
}
ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev,
speed, duplex, tx_pause, rx_pause);
}
const struct phylink_mac_ops dsa_port_phylink_mac_ops = {
.validate = dsa_port_phylink_validate,
.mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state,
.mac_config = dsa_port_phylink_mac_config,
.mac_an_restart = dsa_port_phylink_mac_an_restart,
.mac_link_down = dsa_port_phylink_mac_link_down,
.mac_link_up = dsa_port_phylink_mac_link_up,
};
static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
{
struct dsa_switch *ds = dp->ds;
struct phy_device *phydev;
int port = dp->index;
int err = 0;
phydev = dsa_port_get_phy_device(dp);
if (!phydev)
return 0;
if (IS_ERR(phydev))
return PTR_ERR(phydev);
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
if (enable) {
err = genphy_resume(phydev);
if (err < 0)
goto err_put_dev;
err = genphy_read_status(phydev);
if (err < 0)
goto err_put_dev;
} else {
err = genphy_suspend(phydev);
if (err < 0)
goto err_put_dev;
}
if (ds->ops->adjust_link)
ds->ops->adjust_link(ds, port, phydev);
dev_dbg(ds->dev, "enabled port's phy: %s", phydev_name(phydev));
err_put_dev:
put_device(&phydev->mdio.dev);
return err;
}
static int dsa_port_fixed_link_register_of(struct dsa_port *dp)
{
struct device_node *dn = dp->dn;
struct dsa_switch *ds = dp->ds;
struct phy_device *phydev;
int port = dp->index;
phy_interface_t mode;
err = of_phy_register_fixed_link(dn);
if (err) {
dev_err(ds->dev,
"failed to register the fixed PHY of port %d\n",
port);
return err;
}
phydev = of_phy_find_device(dn);
err = of_get_phy_mode(dn, &mode);
if (err)
mode = PHY_INTERFACE_MODE_NA;
phydev->interface = mode;
genphy_read_status(phydev);
if (ds->ops->adjust_link)
ds->ops->adjust_link(ds, port, phydev);
put_device(&phydev->mdio.dev);
return 0;
}
static int dsa_port_phylink_register(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
struct device_node *port_dn = dp->dn;
phy_interface_t mode;
int err;
err = of_get_phy_mode(port_dn, &mode);
if (err)
mode = PHY_INTERFACE_MODE_NA;
dp->pl_config.dev = ds->dev;
dp->pl_config.type = PHYLINK_DEV;
dp->pl_config.pcs_poll = ds->pcs_poll;
dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn),
mode, &dsa_port_phylink_mac_ops);
if (IS_ERR(dp->pl)) {
pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl));
return PTR_ERR(dp->pl);
}
err = phylink_of_phy_connect(dp->pl, port_dn, 0);
if (err && err != -ENODEV) {
pr_err("could not attach to PHY: %d\n", err);
goto err_phy_connect;
}
return 0;
err_phy_connect:
phylink_destroy(dp->pl);
return err;
}
int dsa_port_link_register_of(struct dsa_port *dp)
struct dsa_switch *ds = dp->ds;
struct device_node *phy_np;
if (!ds->ops->adjust_link) {
phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
if (of_phy_is_fixed_link(dp->dn) || phy_np) {
if (ds->ops->phylink_mac_link_down)
ds->ops->phylink_mac_link_down(ds, port,
MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
return dsa_port_phylink_register(dp);
return 0;
}
dev_warn(ds->dev,
"Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n");
if (of_phy_is_fixed_link(dp->dn))
return dsa_port_fixed_link_register_of(dp);
else
return dsa_port_setup_phy_of(dp, true);
}
void dsa_port_link_unregister_of(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
if (!ds->ops->adjust_link && dp->pl) {
rtnl_lock();
phylink_disconnect_phy(dp->pl);
rtnl_unlock();
phylink_destroy(dp->pl);
dp->pl = NULL;
if (of_phy_is_fixed_link(dp->dn))
of_phy_deregister_fixed_link(dp->dn);
else
dsa_port_setup_phy_of(dp, false);
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data)
{
struct phy_device *phydev;
int ret = -EOPNOTSUPP;
if (of_phy_is_fixed_link(dp->dn))
return ret;
phydev = dsa_port_get_phy_device(dp);
if (IS_ERR_OR_NULL(phydev))
return ret;
ret = phy_ethtool_get_strings(phydev, data);
put_device(&phydev->mdio.dev);
return ret;
}
EXPORT_SYMBOL_GPL(dsa_port_get_phy_strings);
int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data)
{
struct phy_device *phydev;
int ret = -EOPNOTSUPP;
if (of_phy_is_fixed_link(dp->dn))
return ret;
phydev = dsa_port_get_phy_device(dp);
if (IS_ERR_OR_NULL(phydev))
return ret;
ret = phy_ethtool_get_stats(phydev, NULL, data);
put_device(&phydev->mdio.dev);
return ret;
}
EXPORT_SYMBOL_GPL(dsa_port_get_ethtool_phy_stats);
int dsa_port_get_phy_sset_count(struct dsa_port *dp)
{
struct phy_device *phydev;
int ret = -EOPNOTSUPP;
if (of_phy_is_fixed_link(dp->dn))
return ret;
phydev = dsa_port_get_phy_device(dp);
if (IS_ERR_OR_NULL(phydev))
return ret;
ret = phy_ethtool_get_sset_count(phydev);
put_device(&phydev->mdio.dev);
return ret;
}
EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr)
{
struct dsa_notifier_hsr_info info = {
.sw_index = dp->ds->index,
.port = dp->index,
.hsr = hsr,
};
int err;
dp->hsr_dev = hsr;
err = dsa_port_notify(dp, DSA_NOTIFIER_HSR_JOIN, &info);
if (err)
dp->hsr_dev = NULL;
return err;
}
void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr)
{
struct dsa_notifier_hsr_info info = {
.sw_index = dp->ds->index,
.port = dp->index,
.hsr = hsr,
};
int err;
dp->hsr_dev = NULL;
err = dsa_port_notify(dp, DSA_NOTIFIER_HSR_LEAVE, &info);
if (err)
pr_err("DSA: failed to notify DSA_NOTIFIER_HSR_LEAVE\n");
}
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid)
{
struct dsa_notifier_tag_8021q_vlan_info info = {
.tree_index = dp->ds->dst->index,
.sw_index = dp->ds->index,
.port = dp->index,
.vid = vid,
};
return dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, &info);
}
void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid)
{
struct dsa_notifier_tag_8021q_vlan_info info = {
.tree_index = dp->ds->dst->index,
.sw_index = dp->ds->index,
.port = dp->index,
.vid = vid,
};
int err;
err = dsa_broadcast(DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, &info);
if (err)
pr_err("DSA: failed to notify tag_8021q VLAN deletion: %pe\n",
ERR_PTR(err));
}