Commit fb4be9a4 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'ocelot-felix-driver-cleanup'

Vladimir Oltean says:

====================
Ocelot/Felix driver cleanup

The cleanup mostly handles the statistics code path - some issues
regarding understandability became apparent after the series
"Fix trainwreck with Ocelot switch statistics counters":
https://lore.kernel.org/netdev/20230321010325.897817-1-vladimir.oltean@nxp.com/

There is also one patch which cleans up a misleading comment
in the DSA felix_setup().
====================

Link: https://lore.kernel.org/r/20230412124737.2243527-1-vladimir.oltean@nxp.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents c2865b11 a291399e
...@@ -1550,11 +1550,6 @@ static int felix_connect_tag_protocol(struct dsa_switch *ds, ...@@ -1550,11 +1550,6 @@ static int felix_connect_tag_protocol(struct dsa_switch *ds,
} }
} }
/* Hardware initialization done here so that we can allocate structures with
* devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing
* us to allocate structures twice (leak memory) and map PCI memory twice
* (which will not work).
*/
static int felix_setup(struct dsa_switch *ds) static int felix_setup(struct dsa_switch *ds)
{ {
struct ocelot *ocelot = ds->priv; struct ocelot *ocelot = ds->priv;
......
...@@ -74,6 +74,15 @@ struct ocelot_multicast { ...@@ -74,6 +74,15 @@ struct ocelot_multicast {
struct ocelot_pgid *pgid; struct ocelot_pgid *pgid;
}; };
static inline void ocelot_reg_to_target_addr(struct ocelot *ocelot,
enum ocelot_reg reg,
enum ocelot_target *target,
u32 *addr)
{
*target = reg >> TARGET_OFFSET;
*addr = ocelot->map[*target][reg & REG_MASK];
}
int ocelot_bridge_num_find(struct ocelot *ocelot, int ocelot_bridge_num_find(struct ocelot *ocelot,
const struct net_device *bridge); const struct net_device *bridge);
......
...@@ -10,57 +10,60 @@ ...@@ -10,57 +10,60 @@
#include "ocelot.h" #include "ocelot.h"
int __ocelot_bulk_read_ix(struct ocelot *ocelot, u32 reg, u32 offset, void *buf, int __ocelot_bulk_read_ix(struct ocelot *ocelot, enum ocelot_reg reg,
int count) u32 offset, void *buf, int count)
{ {
u16 target = reg >> TARGET_OFFSET; enum ocelot_target target;
u32 addr;
ocelot_reg_to_target_addr(ocelot, reg, &target, &addr);
WARN_ON(!target); WARN_ON(!target);
return regmap_bulk_read(ocelot->targets[target], return regmap_bulk_read(ocelot->targets[target], addr + offset,
ocelot->map[target][reg & REG_MASK] + offset,
buf, count); buf, count);
} }
EXPORT_SYMBOL_GPL(__ocelot_bulk_read_ix); EXPORT_SYMBOL_GPL(__ocelot_bulk_read_ix);
u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset) u32 __ocelot_read_ix(struct ocelot *ocelot, enum ocelot_reg reg, u32 offset)
{ {
u16 target = reg >> TARGET_OFFSET; enum ocelot_target target;
u32 val; u32 addr, val;
ocelot_reg_to_target_addr(ocelot, reg, &target, &addr);
WARN_ON(!target); WARN_ON(!target);
regmap_read(ocelot->targets[target], regmap_read(ocelot->targets[target], addr + offset, &val);
ocelot->map[target][reg & REG_MASK] + offset, &val);
return val; return val;
} }
EXPORT_SYMBOL_GPL(__ocelot_read_ix); EXPORT_SYMBOL_GPL(__ocelot_read_ix);
void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset) void __ocelot_write_ix(struct ocelot *ocelot, u32 val, enum ocelot_reg reg,
u32 offset)
{ {
u16 target = reg >> TARGET_OFFSET; enum ocelot_target target;
u32 addr;
ocelot_reg_to_target_addr(ocelot, reg, &target, &addr);
WARN_ON(!target); WARN_ON(!target);
regmap_write(ocelot->targets[target], regmap_write(ocelot->targets[target], addr + offset, val);
ocelot->map[target][reg & REG_MASK] + offset, val);
} }
EXPORT_SYMBOL_GPL(__ocelot_write_ix); EXPORT_SYMBOL_GPL(__ocelot_write_ix);
void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg, void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask,
u32 offset) enum ocelot_reg reg, u32 offset)
{ {
u16 target = reg >> TARGET_OFFSET; enum ocelot_target target;
u32 addr;
ocelot_reg_to_target_addr(ocelot, reg, &target, &addr);
WARN_ON(!target); WARN_ON(!target);
regmap_update_bits(ocelot->targets[target], regmap_update_bits(ocelot->targets[target], addr + offset, mask, val);
ocelot->map[target][reg & REG_MASK] + offset,
mask, val);
} }
EXPORT_SYMBOL_GPL(__ocelot_rmw_ix); EXPORT_SYMBOL_GPL(__ocelot_rmw_ix);
u32 ocelot_port_readl(struct ocelot_port *port, u32 reg) u32 ocelot_port_readl(struct ocelot_port *port, enum ocelot_reg reg)
{ {
struct ocelot *ocelot = port->ocelot; struct ocelot *ocelot = port->ocelot;
u16 target = reg >> TARGET_OFFSET; u16 target = reg >> TARGET_OFFSET;
...@@ -73,7 +76,7 @@ u32 ocelot_port_readl(struct ocelot_port *port, u32 reg) ...@@ -73,7 +76,7 @@ u32 ocelot_port_readl(struct ocelot_port *port, u32 reg)
} }
EXPORT_SYMBOL_GPL(ocelot_port_readl); EXPORT_SYMBOL_GPL(ocelot_port_readl);
void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg) void ocelot_port_writel(struct ocelot_port *port, u32 val, enum ocelot_reg reg)
{ {
struct ocelot *ocelot = port->ocelot; struct ocelot *ocelot = port->ocelot;
u16 target = reg >> TARGET_OFFSET; u16 target = reg >> TARGET_OFFSET;
...@@ -84,7 +87,8 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg) ...@@ -84,7 +87,8 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg)
} }
EXPORT_SYMBOL_GPL(ocelot_port_writel); EXPORT_SYMBOL_GPL(ocelot_port_writel);
void ocelot_port_rmwl(struct ocelot_port *port, u32 val, u32 mask, u32 reg) void ocelot_port_rmwl(struct ocelot_port *port, u32 val, u32 mask,
enum ocelot_reg reg)
{ {
u32 cur = ocelot_port_readl(port, reg); u32 cur = ocelot_port_readl(port, reg);
......
...@@ -145,7 +145,7 @@ enum ocelot_stat { ...@@ -145,7 +145,7 @@ enum ocelot_stat {
}; };
struct ocelot_stat_layout { struct ocelot_stat_layout {
u32 reg; enum ocelot_reg reg;
char name[ETH_GSTRING_LEN]; char name[ETH_GSTRING_LEN];
}; };
...@@ -257,7 +257,7 @@ struct ocelot_stat_layout { ...@@ -257,7 +257,7 @@ struct ocelot_stat_layout {
struct ocelot_stats_region { struct ocelot_stats_region {
struct list_head node; struct list_head node;
u32 base; enum ocelot_reg base;
enum ocelot_stat first_stat; enum ocelot_stat first_stat;
int count; int count;
u32 *buf; u32 *buf;
...@@ -395,7 +395,7 @@ static void ocelot_check_stats_work(struct work_struct *work) ...@@ -395,7 +395,7 @@ static void ocelot_check_stats_work(struct work_struct *work)
void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data) void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
{ {
const struct ocelot_stat_layout *layout; const struct ocelot_stat_layout *layout;
int i; enum ocelot_stat i;
if (sset != ETH_SS_STATS) if (sset != ETH_SS_STATS)
return; return;
...@@ -442,7 +442,8 @@ static void ocelot_port_stats_run(struct ocelot *ocelot, int port, void *priv, ...@@ -442,7 +442,8 @@ static void ocelot_port_stats_run(struct ocelot *ocelot, int port, void *priv,
int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset) int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
{ {
const struct ocelot_stat_layout *layout; const struct ocelot_stat_layout *layout;
int i, num_stats = 0; enum ocelot_stat i;
int num_stats = 0;
if (sset != ETH_SS_STATS) if (sset != ETH_SS_STATS)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -461,8 +462,8 @@ static void ocelot_port_ethtool_stats_cb(struct ocelot *ocelot, int port, ...@@ -461,8 +462,8 @@ static void ocelot_port_ethtool_stats_cb(struct ocelot *ocelot, int port,
void *priv) void *priv)
{ {
const struct ocelot_stat_layout *layout; const struct ocelot_stat_layout *layout;
enum ocelot_stat i;
u64 *data = priv; u64 *data = priv;
int i;
layout = ocelot_get_stats_layout(ocelot); layout = ocelot_get_stats_layout(ocelot);
...@@ -889,8 +890,8 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot) ...@@ -889,8 +890,8 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
{ {
struct ocelot_stats_region *region = NULL; struct ocelot_stats_region *region = NULL;
const struct ocelot_stat_layout *layout; const struct ocelot_stat_layout *layout;
unsigned int last = 0; enum ocelot_reg last = 0;
int i; enum ocelot_stat i;
INIT_LIST_HEAD(&ocelot->stats_regions); INIT_LIST_HEAD(&ocelot->stats_regions);
...@@ -900,6 +901,17 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot) ...@@ -900,6 +901,17 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
if (!layout[i].reg) if (!layout[i].reg)
continue; continue;
/* enum ocelot_stat must be kept sorted in the same order
* as the addresses behind layout[i].reg in order to have
* efficient bulking
*/
if (last) {
WARN(ocelot->map[SYS][last & REG_MASK] >= ocelot->map[SYS][layout[i].reg & REG_MASK],
"reg 0x%x had address 0x%x but reg 0x%x has address 0x%x, bulking broken!",
last, ocelot->map[SYS][last & REG_MASK],
layout[i].reg, ocelot->map[SYS][layout[i].reg & REG_MASK]);
}
if (region && ocelot->map[SYS][layout[i].reg & REG_MASK] == if (region && ocelot->map[SYS][layout[i].reg & REG_MASK] ==
ocelot->map[SYS][last & REG_MASK] + 4) { ocelot->map[SYS][last & REG_MASK] + 4) {
region->count++; region->count++;
...@@ -909,12 +921,6 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot) ...@@ -909,12 +921,6 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
if (!region) if (!region)
return -ENOMEM; return -ENOMEM;
/* enum ocelot_stat must be kept sorted in the same
* order as layout[i].reg in order to have efficient
* bulking
*/
WARN_ON(last >= layout[i].reg);
region->base = layout[i].reg; region->base = layout[i].reg;
region->first_stat = i; region->first_stat = i;
region->count = 1; region->count = 1;
...@@ -925,6 +931,15 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot) ...@@ -925,6 +931,15 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
} }
list_for_each_entry(region, &ocelot->stats_regions, node) { list_for_each_entry(region, &ocelot->stats_regions, node) {
enum ocelot_target target;
u32 addr;
ocelot_reg_to_target_addr(ocelot, region->base, &target,
&addr);
dev_dbg(ocelot->dev,
"region of %d contiguous counters starting with SYS:STAT:CNT[0x%03x]\n",
region->count, addr / 4);
region->buf = devm_kcalloc(ocelot->dev, region->count, region->buf = devm_kcalloc(ocelot->dev, region->count,
sizeof(*region->buf), GFP_KERNEL); sizeof(*region->buf), GFP_KERNEL);
if (!region->buf) if (!region->buf)
...@@ -972,4 +987,3 @@ void ocelot_stats_deinit(struct ocelot *ocelot) ...@@ -972,4 +987,3 @@ void ocelot_stats_deinit(struct ocelot *ocelot)
cancel_delayed_work(&ocelot->stats_work); cancel_delayed_work(&ocelot->stats_work);
destroy_workqueue(ocelot->stats_queue); destroy_workqueue(ocelot->stats_queue);
} }
...@@ -940,15 +940,17 @@ struct ocelot_policer { ...@@ -940,15 +940,17 @@ struct ocelot_policer {
__ocelot_target_write_ix(ocelot, target, val, reg, 0) __ocelot_target_write_ix(ocelot, target, val, reg, 0)
/* I/O */ /* I/O */
u32 ocelot_port_readl(struct ocelot_port *port, u32 reg); u32 ocelot_port_readl(struct ocelot_port *port, enum ocelot_reg reg);
void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); void ocelot_port_writel(struct ocelot_port *port, u32 val, enum ocelot_reg reg);
void ocelot_port_rmwl(struct ocelot_port *port, u32 val, u32 mask, u32 reg); void ocelot_port_rmwl(struct ocelot_port *port, u32 val, u32 mask,
int __ocelot_bulk_read_ix(struct ocelot *ocelot, u32 reg, u32 offset, void *buf, enum ocelot_reg reg);
int count); int __ocelot_bulk_read_ix(struct ocelot *ocelot, enum ocelot_reg reg,
u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset); u32 offset, void *buf, int count);
void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset); u32 __ocelot_read_ix(struct ocelot *ocelot, enum ocelot_reg reg, u32 offset);
void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg, void __ocelot_write_ix(struct ocelot *ocelot, u32 val, enum ocelot_reg reg,
u32 offset); u32 offset);
void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask,
enum ocelot_reg reg, u32 offset);
u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target, u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 reg, u32 offset); u32 reg, u32 offset);
void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target, void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment