Skip to content

Commit

Permalink
Merge branch 'net-sparx5-prepare-for-lan969x-switch-driver'
Browse files Browse the repository at this point in the history
Daniel Machon says:

====================
net: sparx5: prepare for lan969x switch driver

== Description:

This series is the first of a multi-part series, that prepares and adds
support for the new lan969x switch driver.

The upstreaming efforts is split into multiple series (might change a
bit as we go along):

    1) Prepare the Sparx5 driver for lan969x (this series)
    2) Add support lan969x (same basic features as Sparx5 provides +
       RGMII, excl.  FDMA and VCAP)
    3) Add support for lan969x FDMA
    4) Add support for lan969x VCAP

== Lan969x in short:

The lan969x Ethernet switch family [1] provides a rich set of
switching features and port configurations (up to 30 ports) from 10Mbps
to 10Gbps, with support for RGMII, SGMII, QSGMII, USGMII, and USXGMII,
ideal for industrial & process automation infrastructure applications,
transport, grid automation, power substation automation, and ring &
intra-ring topologies. The LAN969x family is hardware and software
compatible and scalable supporting 46Gbps to 102Gbps switch bandwidths.

== Preparing Sparx5 for lan969x:

The lan969x switch chip reuses many of the IP's of the Sparx5 switch
chip, therefore it has been decided to add support through the existing
Sparx5 driver, in order to avoid a bunch of duplicate code. However, in
order to reuse the Sparx5 switch driver, we have to introduce some
mechanisms to handle the chip differences that are there.  These
mechanisms are:

    - Platform match data to contain all the differences that needs to
      be handled (constants, ops etc.)

    - Register macro indirection layer so that we can reuse the existing
      register macros.

    - Function for branching out on platform type where required.

In some places we ops out functions and in other places we branch on the
chip type. Exactly when we choose one over the other, is an estimate in
each case.

After this series is applied, the Sparx5 driver will be prepared for
lan969x and still function exactly as before.

== Patch breakdown:

Patch #1        adds private match data

Patch #2        adds register macro indirection layer

Patch #3-#4     does some preparation work

Patch #5-torvalds#7     adds chip constants and updates the code to use them

Patch torvalds#8-torvalds#13    adds and uses ops for handling functions differently on the
                two platforms.

Patch torvalds#14       adds and uses a macro for branching out on the chip type.

Patch torvalds#15 (NEW) redefines macros for internal ports and PGID's.

[1] https://www.microchip.com/en-us/product/lan9698

To: David S. Miller <davem@davemloft.net>
To: Eric Dumazet <edumazet@google.com>
To: Jakub Kicinski <kuba@kernel.org>
To: Paolo Abeni <pabeni@redhat.com>
To: Lars Povlsen <lars.povlsen@microchip.com>
To: Steen Hegelund <Steen.Hegelund@microchip.com>
To: horatiu.vultur@microchip.com
To: jensemil.schulzostergaard@microchip.com
To: UNGLinuxDriver@microchip.com
To: Richard Cochran <richardcochran@gmail.com>
To: horms@kernel.org
To: justinstitt@google.com
To: gal@nvidia.com
To: aakash.r.menon@gmail.com
To: jacob.e.keller@intel.com
To: ast@fiberby.net
Cc: netdev@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
====================

Link: https://patch.msgid.link/20241004-b4-sparx5-lan969x-switch-driver-v2-0-d3290f581663@microchip.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Paolo Abeni committed Oct 8, 2024
2 parents e793b86 + 8cc4102 commit 5d6a8ae
Show file tree
Hide file tree
Showing 26 changed files with 3,531 additions and 2,226 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/microchip/sparx5/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sparx5-switch-y := sparx5_main.o sparx5_packet.o \
sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \
sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o \
sparx5_tc_matchall.o sparx5_pool.o sparx5_sdlb.o sparx5_police.o \
sparx5_psfp.o sparx5_mirror.o
sparx5_psfp.o sparx5_mirror.o sparx5_regs.o

sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o
sparx5-switch-$(CONFIG_DEBUG_FS) += sparx5_vcap_debugfs.o
Expand Down
56 changes: 25 additions & 31 deletions drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
#define SPX5_CALBITS_PER_PORT 3 /* Bit per port in calendar register */

/* DSM calendar information */
#define SPX5_DSM_CAL_LEN 64
#define SPX5_DSM_CAL_EMPTY 0xFFFF
#define SPX5_DSM_CAL_MAX_DEVS_PER_TAXI 13
#define SPX5_DSM_CAL_TAXIS 8
#define SPX5_DSM_CAL_BW_LOSS 553

Expand All @@ -37,19 +35,6 @@ static u32 sparx5_taxi_ports[SPX5_DSM_CAL_TAXIS][SPX5_DSM_CAL_MAX_DEVS_PER_TAXI]
{64, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99},
};

struct sparx5_calendar_data {
u32 schedule[SPX5_DSM_CAL_LEN];
u32 avg_dist[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI];
u32 taxi_ports[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI];
u32 taxi_speeds[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI];
u32 dev_slots[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI];
u32 new_slots[SPX5_DSM_CAL_LEN];
u32 temp_sched[SPX5_DSM_CAL_LEN];
u32 indices[SPX5_DSM_CAL_LEN];
u32 short_list[SPX5_DSM_CAL_LEN];
u32 long_list[SPX5_DSM_CAL_LEN];
};

static u32 sparx5_target_bandwidth(struct sparx5 *sparx5)
{
switch (sparx5->target_ct) {
Expand Down Expand Up @@ -131,18 +116,24 @@ static enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5,
{
struct sparx5_port *port;

if (portno >= SPX5_PORTS) {
if (portno >= sparx5->data->consts->n_ports) {
/* Internal ports */
if (portno == SPX5_PORT_CPU_0 || portno == SPX5_PORT_CPU_1) {
if (portno ==
sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_0) ||
portno ==
sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_1)) {
/* Equals 1.25G */
return SPX5_CAL_SPEED_2G5;
} else if (portno == SPX5_PORT_VD0) {
} else if (portno ==
sparx5_get_internal_port(sparx5, SPX5_PORT_VD0)) {
/* IPMC only idle BW */
return SPX5_CAL_SPEED_NONE;
} else if (portno == SPX5_PORT_VD1) {
} else if (portno ==
sparx5_get_internal_port(sparx5, SPX5_PORT_VD1)) {
/* OAM only idle BW */
return SPX5_CAL_SPEED_NONE;
} else if (portno == SPX5_PORT_VD2) {
} else if (portno ==
sparx5_get_internal_port(sparx5, SPX5_PORT_VD2)) {
/* IPinIP gets only idle BW */
return SPX5_CAL_SPEED_NONE;
}
Expand All @@ -159,6 +150,7 @@ static enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5,
/* Auto configure the QSYS calendar based on port configuration */
int sparx5_config_auto_calendar(struct sparx5 *sparx5)
{
const struct sparx5_consts *consts = sparx5->data->consts;
u32 cal[7], value, idx, portno;
u32 max_core_bw;
u32 total_bw = 0, used_port_bw = 0;
Expand All @@ -174,15 +166,15 @@ int sparx5_config_auto_calendar(struct sparx5 *sparx5)
}

/* Setup the calendar with the bandwidth to each port */
for (portno = 0; portno < SPX5_PORTS_ALL; portno++) {
for (portno = 0; portno < consts->n_ports_all; portno++) {
u64 reg, offset, this_bw;

spd = sparx5_get_port_cal_speed(sparx5, portno);
if (spd == SPX5_CAL_SPEED_NONE)
continue;

this_bw = sparx5_cal_speed_to_value(spd);
if (portno < SPX5_PORTS)
if (portno < consts->n_ports)
used_port_bw += this_bw;
else
/* Internal ports are granted half the value */
Expand All @@ -208,12 +200,13 @@ int sparx5_config_auto_calendar(struct sparx5 *sparx5)
}

/* Halt the calendar while changing it */
spx5_rmw(QSYS_CAL_CTRL_CAL_MODE_SET(10),
QSYS_CAL_CTRL_CAL_MODE,
sparx5, QSYS_CAL_CTRL);
if (is_sparx5(sparx5))
spx5_rmw(QSYS_CAL_CTRL_CAL_MODE_SET(10),
QSYS_CAL_CTRL_CAL_MODE,
sparx5, QSYS_CAL_CTRL);

/* Assign port bandwidth to auto calendar */
for (idx = 0; idx < ARRAY_SIZE(cal); idx++)
for (idx = 0; idx < consts->n_auto_cals; idx++)
spx5_wr(cal[idx], sparx5, QSYS_CAL_AUTO(idx));

/* Increase grant rate of all ports to account for
Expand Down Expand Up @@ -278,8 +271,8 @@ static u32 sparx5_dsm_cp_cal(u32 *sched)
return SPX5_DSM_CAL_EMPTY;
}

static int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
struct sparx5_calendar_data *data)
int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
struct sparx5_calendar_data *data)
{
bool slow_mode;
u32 gcd, idx, sum, min, factor;
Expand All @@ -304,7 +297,7 @@ static int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
for (idx = 0; idx < SPX5_DSM_CAL_MAX_DEVS_PER_TAXI; idx++) {
u32 portno = data->taxi_ports[idx];

if (portno < SPX5_TAXI_PORT_MAX) {
if (portno < sparx5->data->consts->n_ports_all) {
data->taxi_speeds[idx] = sparx5_cal_speed_to_value
(sparx5_get_port_cal_speed(sparx5, portno));
} else {
Expand Down Expand Up @@ -565,6 +558,7 @@ static int sparx5_dsm_calendar_update(struct sparx5 *sparx5, u32 taxi,
/* Configure the DSM calendar based on port configuration */
int sparx5_config_dsm_calendar(struct sparx5 *sparx5)
{
const struct sparx5_ops *ops = sparx5->data->ops;
int taxi;
struct sparx5_calendar_data *data;
int err = 0;
Expand All @@ -573,8 +567,8 @@ int sparx5_config_dsm_calendar(struct sparx5 *sparx5)
if (!data)
return -ENOMEM;

for (taxi = 0; taxi < SPX5_DSM_CAL_TAXIS; ++taxi) {
err = sparx5_dsm_calendar_calc(sparx5, taxi, data);
for (taxi = 0; taxi < sparx5->data->consts->n_dsm_cal_taxis; ++taxi) {
err = ops->dsm_calendar_calc(sparx5, taxi, data);
if (err) {
dev_err(sparx5->dev, "DSM calendar calculation failed\n");
goto cal_out;
Expand Down
5 changes: 3 additions & 2 deletions drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,11 @@ static int sparx5_dcb_ieee_dscp_setdel(struct net_device *dev,
struct dcb_app *))
{
struct sparx5_port *port = netdev_priv(dev);
struct sparx5 *sparx5 = port->sparx5;
struct sparx5_port *port_itr;
int err, i;

for (i = 0; i < SPX5_PORTS; i++) {
for (i = 0; i < sparx5->data->consts->n_ports; i++) {
port_itr = port->sparx5->ports[i];
if (!port_itr)
continue;
Expand Down Expand Up @@ -386,7 +387,7 @@ int sparx5_dcb_init(struct sparx5 *sparx5)
struct sparx5_port *port;
int i;

for (i = 0; i < SPX5_PORTS; i++) {
for (i = 0; i < sparx5->data->consts->n_ports; i++) {
port = sparx5->ports[i];
if (!port)
continue;
Expand Down
34 changes: 18 additions & 16 deletions drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,8 +505,8 @@ static void sparx5_get_dev_misc_stats(u64 *portstats, void __iomem *inst, u32
static void sparx5_get_device_stats(struct sparx5 *sparx5, int portno)
{
u64 *portstats = &sparx5->stats[portno * sparx5->num_stats];
u32 tinst = sparx5_port_dev_index(portno);
u32 dev = sparx5_to_high_dev(portno);
u32 tinst = sparx5_port_dev_index(sparx5, portno);
u32 dev = sparx5_to_high_dev(sparx5, portno);
void __iomem *inst;

inst = spx5_inst_get(sparx5, dev, tinst);
Expand Down Expand Up @@ -819,8 +819,8 @@ static void sparx5_get_eth_phy_stats(struct net_device *ndev,

portstats = &sparx5->stats[portno * sparx5->num_stats];
if (sparx5_is_baser(port->conf.portmode)) {
u32 tinst = sparx5_port_dev_index(portno);
u32 dev = sparx5_to_high_dev(portno);
u32 tinst = sparx5_port_dev_index(sparx5, portno);
u32 dev = sparx5_to_high_dev(sparx5, portno);

inst = spx5_inst_get(sparx5, dev, tinst);
sparx5_get_dev_phy_stats(portstats, inst, tinst);
Expand All @@ -844,8 +844,8 @@ static void sparx5_get_eth_mac_stats(struct net_device *ndev,

portstats = &sparx5->stats[portno * sparx5->num_stats];
if (sparx5_is_baser(port->conf.portmode)) {
u32 tinst = sparx5_port_dev_index(portno);
u32 dev = sparx5_to_high_dev(portno);
u32 tinst = sparx5_port_dev_index(sparx5, portno);
u32 dev = sparx5_to_high_dev(sparx5, portno);

inst = spx5_inst_get(sparx5, dev, tinst);
sparx5_get_dev_mac_stats(portstats, inst, tinst);
Expand Down Expand Up @@ -912,8 +912,8 @@ static void sparx5_get_eth_mac_ctrl_stats(struct net_device *ndev,

portstats = &sparx5->stats[portno * sparx5->num_stats];
if (sparx5_is_baser(port->conf.portmode)) {
u32 tinst = sparx5_port_dev_index(portno);
u32 dev = sparx5_to_high_dev(portno);
u32 tinst = sparx5_port_dev_index(sparx5, portno);
u32 dev = sparx5_to_high_dev(sparx5, portno);

inst = spx5_inst_get(sparx5, dev, tinst);
sparx5_get_dev_mac_ctrl_stats(portstats, inst, tinst);
Expand Down Expand Up @@ -944,8 +944,8 @@ static void sparx5_get_eth_rmon_stats(struct net_device *ndev,

portstats = &sparx5->stats[portno * sparx5->num_stats];
if (sparx5_is_baser(port->conf.portmode)) {
u32 tinst = sparx5_port_dev_index(portno);
u32 dev = sparx5_to_high_dev(portno);
u32 tinst = sparx5_port_dev_index(sparx5, portno);
u32 dev = sparx5_to_high_dev(sparx5, portno);

inst = spx5_inst_get(sparx5, dev, tinst);
sparx5_get_dev_rmon_stats(portstats, inst, tinst);
Expand Down Expand Up @@ -1027,8 +1027,8 @@ static void sparx5_get_sset_data(struct net_device *ndev,

portstats = &sparx5->stats[portno * sparx5->num_stats];
if (sparx5_is_baser(port->conf.portmode)) {
u32 tinst = sparx5_port_dev_index(portno);
u32 dev = sparx5_to_high_dev(portno);
u32 tinst = sparx5_port_dev_index(sparx5, portno);
u32 dev = sparx5_to_high_dev(sparx5, portno);

inst = spx5_inst_get(sparx5, dev, tinst);
sparx5_get_dev_misc_stats(portstats, inst, tinst);
Expand Down Expand Up @@ -1122,7 +1122,7 @@ static void sparx5_update_stats(struct sparx5 *sparx5)
{
int idx;

for (idx = 0; idx < SPX5_PORTS; idx++)
for (idx = 0; idx < sparx5->data->consts->n_ports; idx++)
if (sparx5->ports[idx])
sparx5_update_port_stats(sparx5, idx);
}
Expand Down Expand Up @@ -1189,7 +1189,7 @@ static int sparx5_get_ts_info(struct net_device *dev,
struct sparx5 *sparx5 = port->sparx5;
struct sparx5_phc *phc;

if (!sparx5->ptp)
if (!sparx5->ptp && is_sparx5(sparx5))
return ethtool_op_get_ts_info(dev, info);

phc = &sparx5->phc[SPARX5_PHC_PORT];
Expand Down Expand Up @@ -1228,21 +1228,23 @@ const struct ethtool_ops sparx5_ethtool_ops = {

int sparx_stats_init(struct sparx5 *sparx5)
{
const struct sparx5_consts *consts = sparx5->data->consts;
char queue_name[32];
int portno;

sparx5->stats_layout = sparx5_stats_layout;
sparx5->num_stats = spx5_stats_count;
sparx5->num_ethtool_stats = ARRAY_SIZE(sparx5_stats_layout);
sparx5->stats = devm_kcalloc(sparx5->dev,
SPX5_PORTS_ALL * sparx5->num_stats,
consts->n_ports_all *
sparx5->num_stats,
sizeof(u64), GFP_KERNEL);
if (!sparx5->stats)
return -ENOMEM;

mutex_init(&sparx5->queue_stats_lock);
sparx5_config_stats(sparx5);
for (portno = 0; portno < SPX5_PORTS; portno++)
for (portno = 0; portno < consts->n_ports; portno++)
if (sparx5->ports[portno])
sparx5_config_port_stats(sparx5, portno);

Expand Down
10 changes: 7 additions & 3 deletions drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ static bool sparx5_fdma_rx_get_frame(struct sparx5 *sparx5, struct sparx5_rx *rx
/* Now do the normal processing of the skb */
sparx5_ifh_parse((u32 *)skb->data, &fi);
/* Map to port netdev */
port = fi.src_port < SPX5_PORTS ? sparx5->ports[fi.src_port] : NULL;
port = fi.src_port < sparx5->data->consts->n_ports ?
sparx5->ports[fi.src_port] :
NULL;
if (!port || !port->ndev) {
dev_err(sparx5->dev, "Data on inactive port %d\n", fi.src_port);
sparx5_xtr_flush(sparx5, XTR_QUEUE);
Expand Down Expand Up @@ -296,7 +298,7 @@ static void sparx5_fdma_rx_init(struct sparx5 *sparx5,
fdma->ops.dataptr_cb = &sparx5_fdma_rx_dataptr_cb;
fdma->ops.nextptr_cb = &fdma_nextptr_cb;
/* Fetch a netdev for SKB and NAPI use, any will do */
for (idx = 0; idx < SPX5_PORTS; ++idx) {
for (idx = 0; idx < sparx5->data->consts->n_ports; ++idx) {
struct sparx5_port *port = sparx5->ports[idx];

if (port && port->ndev) {
Expand Down Expand Up @@ -362,7 +364,9 @@ static void sparx5_fdma_injection_mode(struct sparx5 *sparx5)
sparx5, QS_INJ_GRP_CFG(INJ_QUEUE));

/* CPU ports capture setup */
for (portno = SPX5_PORT_CPU_0; portno <= SPX5_PORT_CPU_1; portno++) {
for (portno = sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_0);
portno <= sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_1);
portno++) {
/* ASM CPU port: No preamble, IFH, enable padding */
spx5_wr(ASM_PORT_CFG_PAD_ENA_SET(1) |
ASM_PORT_CFG_NO_PREAMBLE_ENA_SET(1) |
Expand Down
10 changes: 6 additions & 4 deletions drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,16 @@ static void sparx5_mact_select(struct sparx5 *sparx5,
int sparx5_mact_learn(struct sparx5 *sparx5, int pgid,
const unsigned char mac[ETH_ALEN], u16 vid)
{
const struct sparx5_consts *consts = sparx5->data->consts;
int addr, type, ret;

if (pgid < SPX5_PORTS) {
if (pgid < consts->n_ports) {
type = MAC_ENTRY_ADDR_TYPE_UPSID_PN;
addr = pgid % 32;
addr += (pgid / 32) << 5; /* Add upsid */
} else {
type = MAC_ENTRY_ADDR_TYPE_MC_IDX;
addr = pgid - SPX5_PORTS;
addr = pgid - consts->n_ports;
}

mutex_lock(&sparx5->lock);
Expand Down Expand Up @@ -128,7 +129,8 @@ int sparx5_mc_sync(struct net_device *dev, const unsigned char *addr)
struct sparx5_port *port = netdev_priv(dev);
struct sparx5 *sparx5 = port->sparx5;

return sparx5_mact_learn(sparx5, PGID_CPU, addr, port->pvid);
return sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU),
addr, port->pvid);
}

static int sparx5_mact_get(struct sparx5 *sparx5,
Expand Down Expand Up @@ -371,7 +373,7 @@ static void sparx5_mact_handle_entry(struct sparx5 *sparx5,
return;

port = LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_GET(cfg2);
if (port >= SPX5_PORTS)
if (port >= sparx5->data->consts->n_ports)
return;

if (!test_bit(port, sparx5->bridge_mask))
Expand Down
Loading

0 comments on commit 5d6a8ae

Please sign in to comment.