Skip to content

Commit e7a0187

Browse files
paliLorenzo Pieralisi
authored andcommitted
PCI: mvebu: Propagate errors when updating PCI_IO_BASE and PCI_MEM_BASE registers
Properly propagate failure from mvebu_pcie_add_windows() function back to the caller mvebu_pci_bridge_emul_base_conf_write() and correctly updates PCI_IO_BASE, PCI_MEM_BASE and PCI_IO_BASE_UPPER16 registers on error. On error set base value higher than limit value which indicates that address range is disabled. When IO is unsupported then let IO registers zeroed as required by PCIe base specification. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Pali Rohár <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]>
1 parent 2cf1502 commit e7a0187

File tree

1 file changed

+55
-27
lines changed

1 file changed

+55
-27
lines changed

drivers/pci/controller/pci-mvebu.c

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ static void mvebu_pcie_del_windows(struct mvebu_pcie_port *port,
304304
* areas each having a power of two size. We start from the largest
305305
* one (i.e highest order bit set in the size).
306306
*/
307-
static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
307+
static int mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
308308
unsigned int target, unsigned int attribute,
309309
phys_addr_t base, size_t size,
310310
phys_addr_t remap)
@@ -325,7 +325,7 @@ static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
325325
&base, &end, ret);
326326
mvebu_pcie_del_windows(port, base - size_mapped,
327327
size_mapped);
328-
return;
328+
return ret;
329329
}
330330

331331
size -= sz;
@@ -334,16 +334,20 @@ static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port,
334334
if (remap != MVEBU_MBUS_NO_REMAP)
335335
remap += sz;
336336
}
337+
338+
return 0;
337339
}
338340

339-
static void mvebu_pcie_set_window(struct mvebu_pcie_port *port,
341+
static int mvebu_pcie_set_window(struct mvebu_pcie_port *port,
340342
unsigned int target, unsigned int attribute,
341343
const struct mvebu_pcie_window *desired,
342344
struct mvebu_pcie_window *cur)
343345
{
346+
int ret;
347+
344348
if (desired->base == cur->base && desired->remap == cur->remap &&
345349
desired->size == cur->size)
346-
return;
350+
return 0;
347351

348352
if (cur->size != 0) {
349353
mvebu_pcie_del_windows(port, cur->base, cur->size);
@@ -358,30 +362,35 @@ static void mvebu_pcie_set_window(struct mvebu_pcie_port *port,
358362
}
359363

360364
if (desired->size == 0)
361-
return;
365+
return 0;
366+
367+
ret = mvebu_pcie_add_windows(port, target, attribute, desired->base,
368+
desired->size, desired->remap);
369+
if (ret) {
370+
cur->size = 0;
371+
cur->base = 0;
372+
return ret;
373+
}
362374

363-
mvebu_pcie_add_windows(port, target, attribute, desired->base,
364-
desired->size, desired->remap);
365375
*cur = *desired;
376+
return 0;
366377
}
367378

368-
static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
379+
static int mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
369380
{
370381
struct mvebu_pcie_window desired = {};
371382
struct pci_bridge_emul_conf *conf = &port->bridge.conf;
372383

373384
/* Are the new iobase/iolimit values invalid? */
374385
if (conf->iolimit < conf->iobase ||
375-
conf->iolimitupper < conf->iobaseupper) {
376-
mvebu_pcie_set_window(port, port->io_target, port->io_attr,
377-
&desired, &port->iowin);
378-
return;
379-
}
386+
conf->iolimitupper < conf->iobaseupper)
387+
return mvebu_pcie_set_window(port, port->io_target, port->io_attr,
388+
&desired, &port->iowin);
380389

381390
if (!mvebu_has_ioport(port)) {
382391
dev_WARN(&port->pcie->pdev->dev,
383392
"Attempt to set IO when IO is disabled\n");
384-
return;
393+
return -EOPNOTSUPP;
385394
}
386395

387396
/*
@@ -399,21 +408,19 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
399408
desired.remap) +
400409
1;
401410

402-
mvebu_pcie_set_window(port, port->io_target, port->io_attr, &desired,
403-
&port->iowin);
411+
return mvebu_pcie_set_window(port, port->io_target, port->io_attr, &desired,
412+
&port->iowin);
404413
}
405414

406-
static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
415+
static int mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
407416
{
408417
struct mvebu_pcie_window desired = {.remap = MVEBU_MBUS_NO_REMAP};
409418
struct pci_bridge_emul_conf *conf = &port->bridge.conf;
410419

411420
/* Are the new membase/memlimit values invalid? */
412-
if (conf->memlimit < conf->membase) {
413-
mvebu_pcie_set_window(port, port->mem_target, port->mem_attr,
414-
&desired, &port->memwin);
415-
return;
416-
}
421+
if (conf->memlimit < conf->membase)
422+
return mvebu_pcie_set_window(port, port->mem_target, port->mem_attr,
423+
&desired, &port->memwin);
417424

418425
/*
419426
* We read the PCI-to-PCI bridge emulated registers, and
@@ -425,8 +432,8 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
425432
desired.size = (((conf->memlimit & 0xFFF0) << 16) | 0xFFFFF) -
426433
desired.base + 1;
427434

428-
mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired,
429-
&port->memwin);
435+
return mvebu_pcie_set_window(port, port->mem_target, port->mem_attr, &desired,
436+
&port->memwin);
430437
}
431438

432439
static pci_bridge_emul_read_status_t
@@ -511,15 +518,36 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
511518
break;
512519

513520
case PCI_IO_BASE:
514-
mvebu_pcie_handle_iobase_change(port);
521+
if ((mask & 0xffff) && mvebu_pcie_handle_iobase_change(port)) {
522+
/* On error disable IO range */
523+
conf->iobase &= ~0xf0;
524+
conf->iolimit &= ~0xf0;
525+
conf->iobaseupper = cpu_to_le16(0x0000);
526+
conf->iolimitupper = cpu_to_le16(0x0000);
527+
if (mvebu_has_ioport(port))
528+
conf->iobase |= 0xf0;
529+
}
515530
break;
516531

517532
case PCI_MEMORY_BASE:
518-
mvebu_pcie_handle_membase_change(port);
533+
if (mvebu_pcie_handle_membase_change(port)) {
534+
/* On error disable mem range */
535+
conf->membase = cpu_to_le16(le16_to_cpu(conf->membase) & ~0xfff0);
536+
conf->memlimit = cpu_to_le16(le16_to_cpu(conf->memlimit) & ~0xfff0);
537+
conf->membase = cpu_to_le16(le16_to_cpu(conf->membase) | 0xfff0);
538+
}
519539
break;
520540

521541
case PCI_IO_BASE_UPPER16:
522-
mvebu_pcie_handle_iobase_change(port);
542+
if (mvebu_pcie_handle_iobase_change(port)) {
543+
/* On error disable IO range */
544+
conf->iobase &= ~0xf0;
545+
conf->iolimit &= ~0xf0;
546+
conf->iobaseupper = cpu_to_le16(0x0000);
547+
conf->iolimitupper = cpu_to_le16(0x0000);
548+
if (mvebu_has_ioport(port))
549+
conf->iobase |= 0xf0;
550+
}
523551
break;
524552

525553
case PCI_PRIMARY_BUS:

0 commit comments

Comments
 (0)