Skip to content

Commit de143c0

Browse files
Xiaoliang Yangdavem330
authored andcommitted
net: dsa: felix: Configure Time-Aware Scheduler via taprio offload
Ocelot VSC9959 switch supports time-based egress shaping in hardware according to IEEE 802.1Qbv. This patch add support for TAS configuration on egress port of VSC9959 switch. Felix driver is an instance of Ocelot family, with a DSA front-end. The patch uses tc taprio hardware offload to setup TAS set function on felix driver. Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com> Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent bd2b316 commit de143c0

File tree

3 files changed

+164
-0
lines changed

3 files changed

+164
-0
lines changed

drivers/net/dsa/ocelot/felix.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port,
237237

238238
if (felix->info->pcs_init)
239239
felix->info->pcs_init(ocelot, port, link_an_mode, state);
240+
241+
if (felix->info->port_sched_speed_set)
242+
felix->info->port_sched_speed_set(ocelot, port,
243+
state->speed);
240244
}
241245

242246
static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port)
@@ -730,6 +734,19 @@ static void felix_port_policer_del(struct dsa_switch *ds, int port)
730734
ocelot_port_policer_del(ocelot, port);
731735
}
732736

737+
static int felix_port_setup_tc(struct dsa_switch *ds, int port,
738+
enum tc_setup_type type,
739+
void *type_data)
740+
{
741+
struct ocelot *ocelot = ds->priv;
742+
struct felix *felix = ocelot_to_felix(ocelot);
743+
744+
if (felix->info->port_setup_tc)
745+
return felix->info->port_setup_tc(ds, port, type, type_data);
746+
else
747+
return -EOPNOTSUPP;
748+
}
749+
733750
static const struct dsa_switch_ops felix_switch_ops = {
734751
.get_tag_protocol = felix_get_tag_protocol,
735752
.setup = felix_setup,
@@ -768,6 +785,7 @@ static const struct dsa_switch_ops felix_switch_ops = {
768785
.cls_flower_add = felix_cls_flower_add,
769786
.cls_flower_del = felix_cls_flower_del,
770787
.cls_flower_stats = felix_cls_flower_stats,
788+
.port_setup_tc = felix_port_setup_tc,
771789
};
772790

773791
static struct felix_info *felix_instance_tbl[] = {
@@ -856,6 +874,7 @@ static int felix_pci_probe(struct pci_dev *pdev,
856874

857875
ds->dev = &pdev->dev;
858876
ds->num_ports = felix->info->num_ports;
877+
ds->num_tx_queues = felix->info->num_tx_queues;
859878
ds->ops = &felix_switch_ops;
860879
ds->priv = ocelot;
861880
felix->ds = ds;

drivers/net/dsa/ocelot/felix.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct felix_info {
2020
const struct ocelot_stat_layout *stats_layout;
2121
unsigned int num_stats;
2222
int num_ports;
23+
int num_tx_queues;
2324
struct vcap_field *vcap_is2_keys;
2425
struct vcap_field *vcap_is2_actions;
2526
const struct vcap_props *vcap;
@@ -35,6 +36,10 @@ struct felix_info {
3536
struct phylink_link_state *state);
3637
int (*prevalidate_phy_mode)(struct ocelot *ocelot, int port,
3738
phy_interface_t phy_mode);
39+
int (*port_setup_tc)(struct dsa_switch *ds, int port,
40+
enum tc_setup_type type, void *type_data);
41+
void (*port_sched_speed_set)(struct ocelot *ocelot, int port,
42+
u32 speed);
3843
};
3944

4045
extern struct felix_info felix_info_vsc9959;

drivers/net/dsa/ocelot/felix_vsc9959.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
* Copyright 2018-2019 NXP Semiconductors
44
*/
55
#include <linux/fsl/enetc_mdio.h>
6+
#include <soc/mscc/ocelot_qsys.h>
67
#include <soc/mscc/ocelot_vcap.h>
8+
#include <soc/mscc/ocelot_ptp.h>
79
#include <soc/mscc/ocelot_sys.h>
810
#include <soc/mscc/ocelot.h>
11+
#include <net/pkt_sched.h>
912
#include <linux/iopoll.h>
1013
#include <linux/pci.h>
1114
#include "felix.h"
@@ -27,6 +30,8 @@
2730
#define USXGMII_LPA_DUPLEX(lpa) (((lpa) & GENMASK(12, 12)) >> 12)
2831
#define USXGMII_LPA_SPEED(lpa) (((lpa) & GENMASK(11, 9)) >> 9)
2932

33+
#define VSC9959_TAS_GCL_ENTRY_MAX 63
34+
3035
enum usxgmii_speed {
3136
USXGMII_SPEED_10 = 0,
3237
USXGMII_SPEED_100 = 1,
@@ -1209,6 +1214,138 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
12091214
mdiobus_unregister(felix->imdio);
12101215
}
12111216

1217+
static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
1218+
u32 speed)
1219+
{
1220+
ocelot_rmw_rix(ocelot,
1221+
QSYS_TAG_CONFIG_LINK_SPEED(speed),
1222+
QSYS_TAG_CONFIG_LINK_SPEED_M,
1223+
QSYS_TAG_CONFIG, port);
1224+
}
1225+
1226+
static void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time,
1227+
u64 cycle_time,
1228+
struct timespec64 *new_base_ts)
1229+
{
1230+
struct timespec64 ts;
1231+
ktime_t new_base_time;
1232+
ktime_t current_time;
1233+
1234+
ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
1235+
current_time = timespec64_to_ktime(ts);
1236+
new_base_time = base_time;
1237+
1238+
if (base_time < current_time) {
1239+
u64 nr_of_cycles = current_time - base_time;
1240+
1241+
do_div(nr_of_cycles, cycle_time);
1242+
new_base_time += cycle_time * (nr_of_cycles + 1);
1243+
}
1244+
1245+
*new_base_ts = ktime_to_timespec64(new_base_time);
1246+
}
1247+
1248+
static u32 vsc9959_tas_read_cfg_status(struct ocelot *ocelot)
1249+
{
1250+
return ocelot_read(ocelot, QSYS_TAS_PARAM_CFG_CTRL);
1251+
}
1252+
1253+
static void vsc9959_tas_gcl_set(struct ocelot *ocelot, const u32 gcl_ix,
1254+
struct tc_taprio_sched_entry *entry)
1255+
{
1256+
ocelot_write(ocelot,
1257+
QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(gcl_ix) |
1258+
QSYS_GCL_CFG_REG_1_GATE_STATE(entry->gate_mask),
1259+
QSYS_GCL_CFG_REG_1);
1260+
ocelot_write(ocelot, entry->interval, QSYS_GCL_CFG_REG_2);
1261+
}
1262+
1263+
static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port,
1264+
struct tc_taprio_qopt_offload *taprio)
1265+
{
1266+
struct timespec64 base_ts;
1267+
int ret, i;
1268+
u32 val;
1269+
1270+
if (!taprio->enable) {
1271+
ocelot_rmw_rix(ocelot,
1272+
QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF),
1273+
QSYS_TAG_CONFIG_ENABLE |
1274+
QSYS_TAG_CONFIG_INIT_GATE_STATE_M,
1275+
QSYS_TAG_CONFIG, port);
1276+
1277+
return 0;
1278+
}
1279+
1280+
if (taprio->cycle_time > NSEC_PER_SEC ||
1281+
taprio->cycle_time_extension >= NSEC_PER_SEC)
1282+
return -EINVAL;
1283+
1284+
if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX)
1285+
return -ERANGE;
1286+
1287+
ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port) |
1288+
QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q,
1289+
QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M |
1290+
QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q,
1291+
QSYS_TAS_PARAM_CFG_CTRL);
1292+
1293+
/* Hardware errata - Admin config could not be overwritten if
1294+
* config is pending, need reset the TAS module
1295+
*/
1296+
val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
1297+
if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING)
1298+
return -EBUSY;
1299+
1300+
ocelot_rmw_rix(ocelot,
1301+
QSYS_TAG_CONFIG_ENABLE |
1302+
QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF) |
1303+
QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(0xFF),
1304+
QSYS_TAG_CONFIG_ENABLE |
1305+
QSYS_TAG_CONFIG_INIT_GATE_STATE_M |
1306+
QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M,
1307+
QSYS_TAG_CONFIG, port);
1308+
1309+
vsc9959_new_base_time(ocelot, taprio->base_time,
1310+
taprio->cycle_time, &base_ts);
1311+
ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1);
1312+
ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), QSYS_PARAM_CFG_REG_2);
1313+
val = upper_32_bits(base_ts.tv_sec);
1314+
ocelot_write(ocelot,
1315+
QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val) |
1316+
QSYS_PARAM_CFG_REG_3_LIST_LENGTH(taprio->num_entries),
1317+
QSYS_PARAM_CFG_REG_3);
1318+
ocelot_write(ocelot, taprio->cycle_time, QSYS_PARAM_CFG_REG_4);
1319+
ocelot_write(ocelot, taprio->cycle_time_extension, QSYS_PARAM_CFG_REG_5);
1320+
1321+
for (i = 0; i < taprio->num_entries; i++)
1322+
vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]);
1323+
1324+
ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
1325+
QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
1326+
QSYS_TAS_PARAM_CFG_CTRL);
1327+
1328+
ret = readx_poll_timeout(vsc9959_tas_read_cfg_status, ocelot, val,
1329+
!(val & QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE),
1330+
10, 100000);
1331+
1332+
return ret;
1333+
}
1334+
1335+
static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
1336+
enum tc_setup_type type,
1337+
void *type_data)
1338+
{
1339+
struct ocelot *ocelot = ds->priv;
1340+
1341+
switch (type) {
1342+
case TC_SETUP_QDISC_TAPRIO:
1343+
return vsc9959_qos_port_tas_set(ocelot, port, type_data);
1344+
default:
1345+
return -EOPNOTSUPP;
1346+
}
1347+
}
1348+
12121349
struct felix_info felix_info_vsc9959 = {
12131350
.target_io_res = vsc9959_target_io_res,
12141351
.port_io_res = vsc9959_port_io_res,
@@ -1224,6 +1361,7 @@ struct felix_info felix_info_vsc9959 = {
12241361
.shared_queue_sz = 128 * 1024,
12251362
.num_mact_rows = 2048,
12261363
.num_ports = 6,
1364+
.num_tx_queues = FELIX_NUM_TC,
12271365
.switch_pci_bar = 4,
12281366
.imdio_pci_bar = 0,
12291367
.mdio_bus_alloc = vsc9959_mdio_bus_alloc,
@@ -1232,4 +1370,6 @@ struct felix_info felix_info_vsc9959 = {
12321370
.pcs_an_restart = vsc9959_pcs_an_restart,
12331371
.pcs_link_state = vsc9959_pcs_link_state,
12341372
.prevalidate_phy_mode = vsc9959_prevalidate_phy_mode,
1373+
.port_setup_tc = vsc9959_port_setup_tc,
1374+
.port_sched_speed_set = vsc9959_sched_speed_set,
12351375
};

0 commit comments

Comments
 (0)