Skip to content

Commit b4024c9

Browse files
claudiu-mdavem330
authored andcommitted
felix: Fix initialization of ioremap resources
The caller of devm_ioremap_resource(), either accidentally or by wrong assumption, is writing back derived resource data to global static resource initialization tables that should have been constant. Meaning that after it computes the final physical start address it saves the address for no reason in the static tables. This doesn't affect the first driver probing after reboot, but it breaks consecutive driver reloads (i.e. driver unbind & bind) because the initialization tables no longer have the correct initial values. So the next probe() will map the device registers to wrong physical addresses, causing ARM SError async exceptions. This patch fixes all of the above. Fixes: 5605194 ("net: dsa: ocelot: add driver for Felix switch family") Signed-off-by: Claudiu Manoil <[email protected]> Reviewed-by: Vladimir Oltean <[email protected]> Tested-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bd69722 commit b4024c9

File tree

3 files changed

+24
-27
lines changed

3 files changed

+24
-27
lines changed

drivers/net/dsa/ocelot/felix.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
388388
struct ocelot *ocelot = &felix->ocelot;
389389
phy_interface_t *port_phy_modes;
390390
resource_size_t switch_base;
391+
struct resource res;
391392
int port, i, err;
392393

393394
ocelot->num_phys_ports = num_phys_ports;
@@ -422,17 +423,16 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
422423

423424
for (i = 0; i < TARGET_MAX; i++) {
424425
struct regmap *target;
425-
struct resource *res;
426426

427427
if (!felix->info->target_io_res[i].name)
428428
continue;
429429

430-
res = &felix->info->target_io_res[i];
431-
res->flags = IORESOURCE_MEM;
432-
res->start += switch_base;
433-
res->end += switch_base;
430+
memcpy(&res, &felix->info->target_io_res[i], sizeof(res));
431+
res.flags = IORESOURCE_MEM;
432+
res.start += switch_base;
433+
res.end += switch_base;
434434

435-
target = ocelot_regmap_init(ocelot, res);
435+
target = ocelot_regmap_init(ocelot, &res);
436436
if (IS_ERR(target)) {
437437
dev_err(ocelot->dev,
438438
"Failed to map device memory space\n");
@@ -453,7 +453,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
453453
for (port = 0; port < num_phys_ports; port++) {
454454
struct ocelot_port *ocelot_port;
455455
void __iomem *port_regs;
456-
struct resource *res;
457456

458457
ocelot_port = devm_kzalloc(ocelot->dev,
459458
sizeof(struct ocelot_port),
@@ -465,12 +464,12 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
465464
return -ENOMEM;
466465
}
467466

468-
res = &felix->info->port_io_res[port];
469-
res->flags = IORESOURCE_MEM;
470-
res->start += switch_base;
471-
res->end += switch_base;
467+
memcpy(&res, &felix->info->port_io_res[port], sizeof(res));
468+
res.flags = IORESOURCE_MEM;
469+
res.start += switch_base;
470+
res.end += switch_base;
472471

473-
port_regs = devm_ioremap_resource(ocelot->dev, res);
472+
port_regs = devm_ioremap_resource(ocelot->dev, &res);
474473
if (IS_ERR(port_regs)) {
475474
dev_err(ocelot->dev,
476475
"failed to map registers for port %d\n", port);

drivers/net/dsa/ocelot/felix.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
/* Platform-specific information */
1010
struct felix_info {
11-
struct resource *target_io_res;
12-
struct resource *port_io_res;
13-
struct resource *imdio_res;
11+
const struct resource *target_io_res;
12+
const struct resource *port_io_res;
13+
const struct resource *imdio_res;
1414
const struct reg_field *regfields;
1515
const u32 *const *map;
1616
const struct ocelot_ops *ops;

drivers/net/dsa/ocelot/felix_vsc9959.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,8 @@ static const u32 *vsc9959_regmap[] = {
333333
[GCB] = vsc9959_gcb_regmap,
334334
};
335335

336-
/* Addresses are relative to the PCI device's base address and
337-
* will be fixed up at ioremap time.
338-
*/
339-
static struct resource vsc9959_target_io_res[] = {
336+
/* Addresses are relative to the PCI device's base address */
337+
static const struct resource vsc9959_target_io_res[] = {
340338
[ANA] = {
341339
.start = 0x0280000,
342340
.end = 0x028ffff,
@@ -379,7 +377,7 @@ static struct resource vsc9959_target_io_res[] = {
379377
},
380378
};
381379

382-
static struct resource vsc9959_port_io_res[] = {
380+
static const struct resource vsc9959_port_io_res[] = {
383381
{
384382
.start = 0x0100000,
385383
.end = 0x010ffff,
@@ -415,7 +413,7 @@ static struct resource vsc9959_port_io_res[] = {
415413
/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an
416414
* SGMII/QSGMII MAC PCS can be found.
417415
*/
418-
static struct resource vsc9959_imdio_res = {
416+
static const struct resource vsc9959_imdio_res = {
419417
.start = 0x8030,
420418
.end = 0x8040,
421419
.name = "imdio",
@@ -1111,7 +1109,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
11111109
struct device *dev = ocelot->dev;
11121110
resource_size_t imdio_base;
11131111
void __iomem *imdio_regs;
1114-
struct resource *res;
1112+
struct resource res;
11151113
struct enetc_hw *hw;
11161114
struct mii_bus *bus;
11171115
int port;
@@ -1128,12 +1126,12 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
11281126
imdio_base = pci_resource_start(felix->pdev,
11291127
felix->info->imdio_pci_bar);
11301128

1131-
res = felix->info->imdio_res;
1132-
res->flags = IORESOURCE_MEM;
1133-
res->start += imdio_base;
1134-
res->end += imdio_base;
1129+
memcpy(&res, felix->info->imdio_res, sizeof(res));
1130+
res.flags = IORESOURCE_MEM;
1131+
res.start += imdio_base;
1132+
res.end += imdio_base;
11351133

1136-
imdio_regs = devm_ioremap_resource(dev, res);
1134+
imdio_regs = devm_ioremap_resource(dev, &res);
11371135
if (IS_ERR(imdio_regs)) {
11381136
dev_err(dev, "failed to map internal MDIO registers\n");
11391137
return PTR_ERR(imdio_regs);

0 commit comments

Comments
 (0)