* [PATCH v4 10/12] PCI/AER: Check if pcie_capability_read_*() reads ~0
[not found] <20200731114329.100848-1-refactormyself@gmail.com>
@ 2020-07-31 11:43 ` Saheed O. Bolarinwa
2020-07-31 11:43 ` [PATCH v4 12/12] PCI: Remove '*val = 0' from pcie_capability_read_*() Saheed O. Bolarinwa
1 sibling, 0 replies; 2+ messages in thread
From: Saheed O. Bolarinwa @ 2020-07-31 11:43 UTC (permalink / raw)
To: helgaas, Russell Currey, Sam Bobroff, Oliver O'Halloran
Cc: Saheed O. Bolarinwa, skhan, linux-kernel, linux-pci, bjorn,
linuxppc-dev, linux-kernel-mentees
On failure pcie_capability_read_*() sets it's last parameter, val
to 0. However, with Patch 12/12, it is possible that val is set
to ~0 on failure. This would introduce a bug because
(x & x) == (~0 & x).
Since ~0 is an invalid value in here,
Add extra check for ~0 to the if condition to confirm failure.
Suggested-by: Bjorn Helgaas <bjorn@helgaas.com>
Signed-off-by: Saheed O. Bolarinwa <refactormyself@gmail.com>
---
drivers/pci/pcie/aer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 3acf56683915..dbeabc370efc 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -829,7 +829,7 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
/* Check if AER is enabled */
pcie_capability_read_word(dev, PCI_EXP_DEVCTL, ®16);
- if (!(reg16 & PCI_EXP_AER_FLAGS))
+ if ((reg16 == (u16)~0) || !(reg16 & PCI_EXP_AER_FLAGS))
return false;
if (!aer)
--
2.18.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH v4 12/12] PCI: Remove '*val = 0' from pcie_capability_read_*()
[not found] <20200731114329.100848-1-refactormyself@gmail.com>
2020-07-31 11:43 ` [PATCH v4 10/12] PCI/AER: Check if pcie_capability_read_*() reads ~0 Saheed O. Bolarinwa
@ 2020-07-31 11:43 ` Saheed O. Bolarinwa
1 sibling, 0 replies; 2+ messages in thread
From: Saheed O. Bolarinwa @ 2020-07-31 11:43 UTC (permalink / raw)
To: helgaas
Cc: Greg Kroah-Hartman, linux-wireless, QCA ath9k Development,
Oliver O'Halloran, linux-acpi, linux-rdma, Jason Gunthorpe,
Doug Ledford, linux-pci, Jakub Kicinski, linux-kernel-mentees,
Len Brown, Arnd Bergmann, skhan, bjorn, Kalle Valo,
Mike Marciniszyn, Sam Bobroff, Saheed O. Bolarinwa,
Dennis Dalessandro, Rafael J. Wysocki, linux-kernel, netdev,
linuxppc-dev, David S. Miller
There are several reasons why a PCI capability read may fail whether the
device is present or not. If this happens, pcie_capability_read_*() will
return -EINVAL/PCIBIOS_BAD_REGISTER_NUMBER or PCIBIOS_DEVICE_NOT_FOUND
and *val is set to 0.
This behaviour if further ensured by this code inside
pcie_capability_read_*()
ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
/*
* Reset *val to 0 if pci_read_config_dword() fails, it may
* have been written as 0xFFFFFFFF if hardware error happens
* during pci_read_config_dword().
*/
if (ret)
*val = 0;
return ret;
a) Since all pci_generic_config_read() does is read a register value,
it may return success after reading a ~0 which *may* have been fabricated
by the PCI host bridge due to a read timeout. Hence pci_read_config_*()
will return success with a fabricated ~0 in *val, indicating a problem.
In this case, the assumed behaviour of pcie_capability_read_*() will be
wrong. To avoid error slipping through, more checks are necessary.
b) pci_read_config_*() will return PCIBIOS_DEVICE_NOT_FOUND only if
dev->error_state = pci_channel_io_perm_failure (i.e.
pci_dev_is_disconnected()) or if pci_generic_config_read() can't find the
device. In both cases *val is initially set to ~0 but as shown in the code
above pcie_capability_read_*() resets it back to 0. Even with this effort,
drivers still have to perform validation checks more so if 0 is a valid
value.
Most drivers only consider the case (b) and in some cases, there is the
expectation that on timeout *val has a fabricated value of ~0, which *may*
not always be true as explained in (a).
In any case, checks need to be done to validate the value read and maybe
confirm which error has occurred. It is better left to the drivers to do.
Remove the reset of *val to 0 when pci_read_config_*() fails.
Suggested-by: Bjorn Helgaas <bjorn@helgaas.com>
Signed-off-by: Saheed O. Bolarinwa <refactormyself@gmail.com>
---
drivers/pci/access.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 79c4a2ef269a..ec95edbb1ac8 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -413,13 +413,6 @@ int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
if (pcie_capability_reg_implemented(dev, pos)) {
ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
- /*
- * Reset *val to 0 if pci_read_config_word() fails, it may
- * have been written as 0xFFFF if hardware error happens
- * during pci_read_config_word().
- */
- if (ret)
- *val = 0;
return ret;
}
@@ -448,13 +441,6 @@ int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
if (pcie_capability_reg_implemented(dev, pos)) {
ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
- /*
- * Reset *val to 0 if pci_read_config_dword() fails, it may
- * have been written as 0xFFFFFFFF if hardware error happens
- * during pci_read_config_dword().
- */
- if (ret)
- *val = 0;
return ret;
}
--
2.18.4
^ permalink raw reply related [flat|nested] 2+ messages in thread