Merge branch 'rework-resource-allocation-in-felix-dsa-driver'

Vladimir Oltean says:

====================
Rework resource allocation in Felix DSA driver

The Felix DSA driver controls NXP variations of Microchip switches.
Colin Foster is trying to add support in this driver for "genuine"
Microchip hardware, but some of the NXP-isms in this driver need to go
away before that happens cleanly.
https://patchwork.kernel.org/project/netdevbpf/cover/20220926002928.2744638-1-colin.foster@in-advantage.com/

The starting point was Colin's patch 08/14 "net: dsa: felix: update
init_regmap to be string-based", and this continues to be the central
theme here, but things are done differently.

In short (full explanations are in patches), the goal is for MFD-based
switches like Colin's SPI-controlled VSC7512 to be able to request a
regmap that was created 100% externally (by drivers/mfd/ocelot-core.c)
in a very simple way, that does not create dependencies on other
modules. That is dev_get_regmap(), and as input it wants a string, for
the resource name. So we rework the resource allocation in this driver
to be based on string names provided by the specific instantiation (in
Colin's case, ocelot_ext.c).

Patch set was boot-tested on NXP LS1028A.
====================

Link: https://lore.kernel.org/r/20220927191521.1578084-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2022-09-28 19:15:29 -07:00
commit 8278ddb161
4 changed files with 133 additions and 229 deletions

View File

@ -1312,11 +1312,55 @@ static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes)
return err;
}
static struct regmap *felix_request_regmap_by_name(struct felix *felix,
const char *resource_name)
{
struct ocelot *ocelot = &felix->ocelot;
struct resource res;
int i;
for (i = 0; i < felix->info->num_resources; i++) {
if (strcmp(resource_name, felix->info->resources[i].name))
continue;
memcpy(&res, &felix->info->resources[i], sizeof(res));
res.start += felix->switch_base;
res.end += felix->switch_base;
return ocelot_regmap_init(ocelot, &res);
}
return ERR_PTR(-ENOENT);
}
static struct regmap *felix_request_regmap(struct felix *felix,
enum ocelot_target target)
{
const char *resource_name = felix->info->resource_names[target];
/* If the driver didn't provide a resource name for the target,
* the resource is optional.
*/
if (!resource_name)
return NULL;
return felix_request_regmap_by_name(felix, resource_name);
}
static struct regmap *felix_request_port_regmap(struct felix *felix, int port)
{
char resource_name[32];
sprintf(resource_name, "port%d", port);
return felix_request_regmap_by_name(felix, resource_name);
}
static int felix_init_structs(struct felix *felix, int num_phys_ports)
{
struct ocelot *ocelot = &felix->ocelot;
phy_interface_t *port_phy_modes;
struct resource res;
struct regmap *target;
int port, i, err;
ocelot->num_phys_ports = num_phys_ports;
@ -1350,20 +1394,11 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
}
for (i = 0; i < TARGET_MAX; i++) {
struct regmap *target;
if (!felix->info->target_io_res[i].name)
continue;
memcpy(&res, &felix->info->target_io_res[i], sizeof(res));
res.flags = IORESOURCE_MEM;
res.start += felix->switch_base;
res.end += felix->switch_base;
target = felix->info->init_regmap(ocelot, &res);
target = felix_request_regmap(felix, i);
if (IS_ERR(target)) {
dev_err(ocelot->dev,
"Failed to map device memory space\n");
"Failed to map device memory space: %pe\n",
target);
kfree(port_phy_modes);
return PTR_ERR(target);
}
@ -1380,7 +1415,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
for (port = 0; port < num_phys_ports; port++) {
struct ocelot_port *ocelot_port;
struct regmap *target;
ocelot_port = devm_kzalloc(ocelot->dev,
sizeof(struct ocelot_port),
@ -1392,16 +1426,11 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
return -ENOMEM;
}
memcpy(&res, &felix->info->port_io_res[port], sizeof(res));
res.flags = IORESOURCE_MEM;
res.start += felix->switch_base;
res.end += felix->switch_base;
target = felix->info->init_regmap(ocelot, &res);
target = felix_request_port_regmap(felix, port);
if (IS_ERR(target)) {
dev_err(ocelot->dev,
"Failed to map memory space for port %d\n",
port);
"Failed to map memory space for port %d: %pe\n",
port, target);
kfree(port_phy_modes);
return PTR_ERR(target);
}

View File

@ -16,9 +16,13 @@
/* Platform-specific information */
struct felix_info {
const struct resource *target_io_res;
const struct resource *port_io_res;
const struct resource *imdio_res;
/* Hardcoded resources provided by the hardware instantiation. */
const struct resource *resources;
size_t num_resources;
/* Names of the mandatory resources that will be requested during
* probe. Must have TARGET_MAX elements, since it is indexed by target.
*/
const char *const *resource_names;
const struct reg_field *regfields;
const u32 *const *map;
const struct ocelot_ops *ops;
@ -56,8 +60,6 @@ struct felix_info {
void (*tas_guard_bands_update)(struct ocelot *ocelot, int port);
void (*port_sched_speed_set)(struct ocelot *ocelot, int port,
u32 speed);
struct regmap *(*init_regmap)(struct ocelot *ocelot,
struct resource *res);
};
/* Methods for initializing the hardware resources specific to a tagging
@ -86,7 +88,6 @@ struct felix {
struct mii_bus *imdio;
struct phylink_pcs **pcs;
resource_size_t switch_base;
resource_size_t imdio_base;
enum dsa_tag_protocol tag_proto;
const struct felix_tag_proto_ops *tag_proto_ops;
struct kthread_worker *xmit_worker;

View File

@ -477,100 +477,43 @@ static const u32 *vsc9959_regmap[TARGET_MAX] = {
};
/* Addresses are relative to the PCI device's base address */
static const struct resource vsc9959_target_io_res[TARGET_MAX] = {
[ANA] = {
.start = 0x0280000,
.end = 0x028ffff,
.name = "ana",
},
[QS] = {
.start = 0x0080000,
.end = 0x00800ff,
.name = "qs",
},
[QSYS] = {
.start = 0x0200000,
.end = 0x021ffff,
.name = "qsys",
},
[REW] = {
.start = 0x0030000,
.end = 0x003ffff,
.name = "rew",
},
[SYS] = {
.start = 0x0010000,
.end = 0x001ffff,
.name = "sys",
},
[S0] = {
.start = 0x0040000,
.end = 0x00403ff,
.name = "s0",
},
[S1] = {
.start = 0x0050000,
.end = 0x00503ff,
.name = "s1",
},
[S2] = {
.start = 0x0060000,
.end = 0x00603ff,
.name = "s2",
},
[PTP] = {
.start = 0x0090000,
.end = 0x00900cb,
.name = "ptp",
},
[GCB] = {
.start = 0x0070000,
.end = 0x00701ff,
.name = "devcpu_gcb",
},
static const struct resource vsc9959_resources[] = {
DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"),
DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"),
DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"),
DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"),
DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"),
DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"),
DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"),
DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"),
DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"),
DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"),
DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"),
DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"),
DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"),
DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"),
DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"),
DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"),
};
static const struct resource vsc9959_port_io_res[] = {
{
.start = 0x0100000,
.end = 0x010ffff,
.name = "port0",
},
{
.start = 0x0110000,
.end = 0x011ffff,
.name = "port1",
},
{
.start = 0x0120000,
.end = 0x012ffff,
.name = "port2",
},
{
.start = 0x0130000,
.end = 0x013ffff,
.name = "port3",
},
{
.start = 0x0140000,
.end = 0x014ffff,
.name = "port4",
},
{
.start = 0x0150000,
.end = 0x015ffff,
.name = "port5",
},
static const char * const vsc9959_resource_names[TARGET_MAX] = {
[SYS] = "sys",
[REW] = "rew",
[S0] = "s0",
[S1] = "s1",
[S2] = "s2",
[GCB] = "devcpu_gcb",
[QS] = "qs",
[PTP] = "ptp",
[QSYS] = "qsys",
[ANA] = "ana",
};
/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an
* SGMII/QSGMII MAC PCS can be found.
*/
static const struct resource vsc9959_imdio_res = {
.start = 0x8030,
.end = 0x8040,
.name = "imdio",
};
static const struct resource vsc9959_imdio_res =
DEFINE_RES_MEM_NAMED(0x8030, 0x8040, "imdio");
static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = {
[ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
@ -1003,9 +946,11 @@ static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
{
struct pci_dev *pdev = to_pci_dev(ocelot->dev);
struct felix *felix = ocelot_to_felix(ocelot);
struct enetc_mdio_priv *mdio_priv;
struct device *dev = ocelot->dev;
resource_size_t imdio_base;
void __iomem *imdio_regs;
struct resource res;
struct enetc_hw *hw;
@ -1021,10 +966,11 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
return -ENOMEM;
}
memcpy(&res, felix->info->imdio_res, sizeof(res));
res.flags = IORESOURCE_MEM;
res.start += felix->imdio_base;
res.end += felix->imdio_base;
imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR);
memcpy(&res, &vsc9959_imdio_res, sizeof(res));
res.start += imdio_base;
res.end += imdio_base;
imdio_regs = devm_ioremap_resource(dev, &res);
if (IS_ERR(imdio_regs))
@ -2590,9 +2536,9 @@ static const struct ocelot_ops vsc9959_ops = {
};
static const struct felix_info felix_info_vsc9959 = {
.target_io_res = vsc9959_target_io_res,
.port_io_res = vsc9959_port_io_res,
.imdio_res = &vsc9959_imdio_res,
.resources = vsc9959_resources,
.num_resources = ARRAY_SIZE(vsc9959_resources),
.resource_names = vsc9959_resource_names,
.regfields = vsc9959_regfields,
.map = vsc9959_regmap,
.ops = &vsc9959_ops,
@ -2614,7 +2560,6 @@ static const struct felix_info felix_info_vsc9959 = {
.port_setup_tc = vsc9959_port_setup_tc,
.port_sched_speed_set = vsc9959_sched_speed_set,
.tas_guard_bands_update = vsc9959_tas_guard_bands_update,
.init_regmap = ocelot_regmap_init,
};
static irqreturn_t felix_irq_handler(int irq, void *data)
@ -2666,7 +2611,6 @@ static int felix_pci_probe(struct pci_dev *pdev,
ocelot->num_flooding_pgids = OCELOT_NUM_TC;
felix->info = &felix_info_vsc9959;
felix->switch_base = pci_resource_start(pdev, VSC9959_SWITCH_PCI_BAR);
felix->imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR);
pci_set_master(pdev);

View File

@ -458,110 +458,40 @@ static const u32 *vsc9953_regmap[TARGET_MAX] = {
};
/* Addresses are relative to the device's base address */
static const struct resource vsc9953_target_io_res[TARGET_MAX] = {
[ANA] = {
.start = 0x0280000,
.end = 0x028ffff,
.name = "ana",
},
[QS] = {
.start = 0x0080000,
.end = 0x00800ff,
.name = "qs",
},
[QSYS] = {
.start = 0x0200000,
.end = 0x021ffff,
.name = "qsys",
},
[REW] = {
.start = 0x0030000,
.end = 0x003ffff,
.name = "rew",
},
[SYS] = {
.start = 0x0010000,
.end = 0x001ffff,
.name = "sys",
},
[S0] = {
.start = 0x0040000,
.end = 0x00403ff,
.name = "s0",
},
[S1] = {
.start = 0x0050000,
.end = 0x00503ff,
.name = "s1",
},
[S2] = {
.start = 0x0060000,
.end = 0x00603ff,
.name = "s2",
},
[PTP] = {
.start = 0x0090000,
.end = 0x00900cb,
.name = "ptp",
},
[GCB] = {
.start = 0x0070000,
.end = 0x00701ff,
.name = "devcpu_gcb",
},
static const struct resource vsc9953_resources[] = {
DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"),
DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"),
DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"),
DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"),
DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"),
DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"),
DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"),
DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"),
DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"),
DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"),
DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"),
DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"),
DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"),
DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"),
DEFINE_RES_MEM_NAMED(0x0160000, 0x0010000, "port6"),
DEFINE_RES_MEM_NAMED(0x0170000, 0x0010000, "port7"),
DEFINE_RES_MEM_NAMED(0x0180000, 0x0010000, "port8"),
DEFINE_RES_MEM_NAMED(0x0190000, 0x0010000, "port9"),
DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"),
DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"),
};
static const struct resource vsc9953_port_io_res[] = {
{
.start = 0x0100000,
.end = 0x010ffff,
.name = "port0",
},
{
.start = 0x0110000,
.end = 0x011ffff,
.name = "port1",
},
{
.start = 0x0120000,
.end = 0x012ffff,
.name = "port2",
},
{
.start = 0x0130000,
.end = 0x013ffff,
.name = "port3",
},
{
.start = 0x0140000,
.end = 0x014ffff,
.name = "port4",
},
{
.start = 0x0150000,
.end = 0x015ffff,
.name = "port5",
},
{
.start = 0x0160000,
.end = 0x016ffff,
.name = "port6",
},
{
.start = 0x0170000,
.end = 0x017ffff,
.name = "port7",
},
{
.start = 0x0180000,
.end = 0x018ffff,
.name = "port8",
},
{
.start = 0x0190000,
.end = 0x019ffff,
.name = "port9",
},
static const char * const vsc9953_resource_names[TARGET_MAX] = {
[SYS] = "sys",
[REW] = "rew",
[S0] = "s0",
[S1] = "s1",
[S2] = "s2",
[GCB] = "devcpu_gcb",
[QS] = "qs",
[PTP] = "ptp",
[QSYS] = "qsys",
[ANA] = "ana",
};
static const struct reg_field vsc9953_regfields[REGFIELD_MAX] = {
@ -1060,8 +990,9 @@ static void vsc9953_mdio_bus_free(struct ocelot *ocelot)
}
static const struct felix_info seville_info_vsc9953 = {
.target_io_res = vsc9953_target_io_res,
.port_io_res = vsc9953_port_io_res,
.resources = vsc9953_resources,
.num_resources = ARRAY_SIZE(vsc9953_resources),
.resource_names = vsc9953_resource_names,
.regfields = vsc9953_regfields,
.map = vsc9953_regmap,
.ops = &vsc9953_ops,
@ -1078,7 +1009,6 @@ static const struct felix_info seville_info_vsc9953 = {
.mdio_bus_free = vsc9953_mdio_bus_free,
.phylink_validate = vsc9953_phylink_validate,
.port_modes = vsc9953_port_modes,
.init_regmap = ocelot_regmap_init,
};
static int seville_probe(struct platform_device *pdev)