Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

FDDI: defxx: Bail out gracefully with unassigned PCI resource for CSR

Recent versions of the PCI Express specification have deprecated support
for I/O transactions and actually some PCIe host bridges, such as Power
Systems Host Bridge 4 (PHB4), do not implement them.

For those systems the PCI BARs that request a mapping in the I/O space
have the length recorded in the corresponding PCI resource set to zero,
which makes it unassigned:

# lspci -s 0031:02:04.0 -v
0031:02:04.0 FDDI network controller: Digital Equipment Corporation PCI-to-PDQ Interface Chip [PFI] FDDI (DEFPA) (rev 02)
Subsystem: Digital Equipment Corporation FDDIcontroller/PCI (DEFPA)
Flags: bus master, medium devsel, latency 136, IRQ 57, NUMA node 8
Memory at 620c080020000 (32-bit, non-prefetchable) [size=128]
I/O ports at <unassigned> [disabled]
Memory at 620c080030000 (32-bit, non-prefetchable) [size=64K]
Capabilities: [50] Power Management version 2
Kernel driver in use: defxx
Kernel modules: defxx

#

Regardless the driver goes ahead and requests it (here observed with a
Raptor Talos II POWER9 system), resulting in an odd /proc/ioport entry:

# cat /proc/ioports
00000000-ffffffffffffffff : 0031:02:04.0
#

Furthermore, the system gets confused as the driver actually continues
and pokes at those locations, causing a flood of messages being output
to the system console by the underlying system firmware, like:

defxx: v1.11 2014/07/01 Lawrence V. Stefani and others
defxx 0031:02:04.0: enabling device (0140 -> 0142)
LPC[000]: Got SYNC no-response error. Error address reg: 0xd0010000
IPMI: dropping non severe PEL event
LPC[000]: Got SYNC no-response error. Error address reg: 0xd0010014
IPMI: dropping non severe PEL event
LPC[000]: Got SYNC no-response error. Error address reg: 0xd0010014
IPMI: dropping non severe PEL event

and so on and so on (possibly intermixed actually, as there's no locking
between the kernel and the firmware in console port access with this
particular system, but cleaned up above for clarity), and once some 10k
of such pairs of the latter two messages have been produced an interace
eventually shows up in a useless state:

0031:02:04.0: DEFPA at I/O addr = 0x0, IRQ = 57, Hardware addr = 00-00-00-00-00-00

This was not expected to happen as resource handling was added to the
driver a while ago, because it was not known at that time that a PCI
system would be possible that cannot assign port I/O resources, and
oddly enough `request_region' does not fail, which would have caught it.

Correct the problem then by checking for the length of zero for the CSR
resource and bail out gracefully refusing to register an interface if
that turns out to be the case, producing messages like:

defxx: v1.11 2014/07/01 Lawrence V. Stefani and others
0031:02:04.0: Cannot use I/O, no address set, aborting
0031:02:04.0: Recompile driver with "CONFIG_DEFXX_MMIO=y"

Keep the original check for the EISA MMIO resource as implemented,
because in that case the length is hardwired to 0x400 as a consequence
of how the compare/mask address decoding works in the ESIC chip and it
is only the base address that is set to zero if MMIO has been disabled
for the adapter in EISA configuration, which in turn could be a valid
bus address in a legacy-free system implementing PCI, especially for
port I/O.

Where the EISA MMIO resource has been disabled for the adapter in EISA
configuration this arrangement keeps producing messages like:

eisa 00:05: EISA: slot 5: DEC3002 detected
defxx: v1.11 2014/07/01 Lawrence V. Stefani and others
00:05: Cannot use MMIO, no address set, aborting
00:05: Recompile driver with "CONFIG_DEFXX_MMIO=n"
00:05: Or run ECU and set adapter's MMIO location

with the last two lines now swapped for easier handling in the driver.

There is no need to check for and catch the case of a port I/O resource
not having been assigned for EISA as the adapter uses the slot-specific
I/O space, which gets assigned by how EISA has been specified and maps
directly to the particular slot an option card has been placed in. And
the EISA variant of the adapter has additional registers that are only
accessible via the port I/O space anyway.

While at it factor out the error message calls into helpers and fix an
argument order bug with the `pr_err' call now in `dfx_register_res_err'.

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Fixes: 4d0438e56a8f ("defxx: Clean up DEFEA resource management")
Cc: stable@vger.kernel.org # v3.19+
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Maciej W. Rozycki and committed by
David S. Miller
f626ca68 a3c39230

+30 -17
+30 -17
drivers/net/fddi/defxx.c
··· 495 495 .ndo_set_mac_address = dfx_ctl_set_mac_address, 496 496 }; 497 497 498 + static void dfx_register_res_alloc_err(const char *print_name, bool mmio, 499 + bool eisa) 500 + { 501 + pr_err("%s: Cannot use %s, no address set, aborting\n", 502 + print_name, mmio ? "MMIO" : "I/O"); 503 + pr_err("%s: Recompile driver with \"CONFIG_DEFXX_MMIO=%c\"\n", 504 + print_name, mmio ? 'n' : 'y'); 505 + if (eisa && mmio) 506 + pr_err("%s: Or run ECU and set adapter's MMIO location\n", 507 + print_name); 508 + } 509 + 510 + static void dfx_register_res_err(const char *print_name, bool mmio, 511 + unsigned long start, unsigned long len) 512 + { 513 + pr_err("%s: Cannot reserve %s resource 0x%lx @ 0x%lx, aborting\n", 514 + print_name, mmio ? "MMIO" : "I/O", len, start); 515 + } 516 + 498 517 /* 499 518 * ================ 500 519 * = dfx_register = ··· 587 568 dev_set_drvdata(bdev, dev); 588 569 589 570 dfx_get_bars(bdev, bar_start, bar_len); 590 - if (dfx_bus_eisa && dfx_use_mmio && bar_start[0] == 0) { 591 - pr_err("%s: Cannot use MMIO, no address set, aborting\n", 592 - print_name); 593 - pr_err("%s: Run ECU and set adapter's MMIO location\n", 594 - print_name); 595 - pr_err("%s: Or recompile driver with \"CONFIG_DEFXX_MMIO=n\"" 596 - "\n", print_name); 571 + if (bar_len[0] == 0 || 572 + (dfx_bus_eisa && dfx_use_mmio && bar_start[0] == 0)) { 573 + dfx_register_res_alloc_err(print_name, dfx_use_mmio, 574 + dfx_bus_eisa); 597 575 err = -ENXIO; 598 - goto err_out; 576 + goto err_out_disable; 599 577 } 600 578 601 579 if (dfx_use_mmio) ··· 601 585 else 602 586 region = request_region(bar_start[0], bar_len[0], print_name); 603 587 if (!region) { 604 - pr_err("%s: Cannot reserve %s resource 0x%lx @ 0x%lx, " 605 - "aborting\n", dfx_use_mmio ? "MMIO" : "I/O", print_name, 606 - (long)bar_len[0], (long)bar_start[0]); 588 + dfx_register_res_err(print_name, dfx_use_mmio, 589 + bar_start[0], bar_len[0]); 607 590 err = -EBUSY; 608 591 goto err_out_disable; 609 592 } 610 593 if (bar_start[1] != 0) { 611 594 region = request_region(bar_start[1], bar_len[1], print_name); 612 595 if (!region) { 613 - pr_err("%s: Cannot reserve I/O resource " 614 - "0x%lx @ 0x%lx, aborting\n", print_name, 615 - (long)bar_len[1], (long)bar_start[1]); 596 + dfx_register_res_err(print_name, 0, 597 + bar_start[1], bar_len[1]); 616 598 err = -EBUSY; 617 599 goto err_out_csr_region; 618 600 } ··· 618 604 if (bar_start[2] != 0) { 619 605 region = request_region(bar_start[2], bar_len[2], print_name); 620 606 if (!region) { 621 - pr_err("%s: Cannot reserve I/O resource " 622 - "0x%lx @ 0x%lx, aborting\n", print_name, 623 - (long)bar_len[2], (long)bar_start[2]); 607 + dfx_register_res_err(print_name, 0, 608 + bar_start[2], bar_len[2]); 624 609 err = -EBUSY; 625 610 goto err_out_bh_region; 626 611 }