PCI/VPD: Use pci_read_vpd_any() in pci_vpd_size()
Use new function pci_read_vpd_any() to simplify the code. [bhelgaas: squash in fix for stack overflow reported & tested by Qian [1] and Kunihiko [2]: [1] https://lore.kernel.org/netdev/e89087c5-c495-c5ca-feb1-54cf3a8775c5@quicinc.com/ [2] https://lore.kernel.org/r/2f7e3770-ab47-42b5-719c-f7c661c07d28@socionext.com Link: https://lore.kernel.org/r/6211be8a-5d10-8f3a-6d33-af695dc35caf@gmail.com Reported-by: Qian Cai <quic_qiancai@quicinc.com> Tested-by: Qian Cai <quic_qiancai@quicinc.com> Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> Tested-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> ] Link: https://lore.kernel.org/r/049fa71c-c7af-9c69-51c0-05c1bc2bf660@gmail.com Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
bf2928c7a2
commit
3331325c63
|
@ -57,10 +57,7 @@ static size_t pci_vpd_size(struct pci_dev *dev)
|
||||||
size_t off = 0, size;
|
size_t off = 0, size;
|
||||||
unsigned char tag, header[1+2]; /* 1 byte tag, 2 bytes length */
|
unsigned char tag, header[1+2]; /* 1 byte tag, 2 bytes length */
|
||||||
|
|
||||||
/* Otherwise the following reads would fail. */
|
while (pci_read_vpd_any(dev, off, 1, header) == 1) {
|
||||||
dev->vpd.len = PCI_VPD_MAX_SIZE;
|
|
||||||
|
|
||||||
while (pci_read_vpd(dev, off, 1, header) == 1) {
|
|
||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
if (off == 0 && (header[0] == 0x00 || header[0] == 0xff))
|
if (off == 0 && (header[0] == 0x00 || header[0] == 0xff))
|
||||||
|
@ -68,7 +65,7 @@ static size_t pci_vpd_size(struct pci_dev *dev)
|
||||||
|
|
||||||
if (header[0] & PCI_VPD_LRDT) {
|
if (header[0] & PCI_VPD_LRDT) {
|
||||||
/* Large Resource Data Type Tag */
|
/* Large Resource Data Type Tag */
|
||||||
if (pci_read_vpd(dev, off + 1, 2, &header[1]) != 2) {
|
if (pci_read_vpd_any(dev, off + 1, 2, &header[1]) != 2) {
|
||||||
pci_warn(dev, "failed VPD read at offset %zu\n",
|
pci_warn(dev, "failed VPD read at offset %zu\n",
|
||||||
off + 1);
|
off + 1);
|
||||||
return off ?: PCI_VPD_SZ_INVALID;
|
return off ?: PCI_VPD_SZ_INVALID;
|
||||||
|
@ -99,14 +96,14 @@ error:
|
||||||
return off ?: PCI_VPD_SZ_INVALID;
|
return off ?: PCI_VPD_SZ_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pci_vpd_available(struct pci_dev *dev)
|
static bool pci_vpd_available(struct pci_dev *dev, bool check_size)
|
||||||
{
|
{
|
||||||
struct pci_vpd *vpd = &dev->vpd;
|
struct pci_vpd *vpd = &dev->vpd;
|
||||||
|
|
||||||
if (!vpd->cap)
|
if (!vpd->cap)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (vpd->len == 0) {
|
if (vpd->len == 0 && check_size) {
|
||||||
vpd->len = pci_vpd_size(dev);
|
vpd->len = pci_vpd_size(dev);
|
||||||
if (vpd->len == PCI_VPD_SZ_INVALID) {
|
if (vpd->len == PCI_VPD_SZ_INVALID) {
|
||||||
vpd->cap = 0;
|
vpd->cap = 0;
|
||||||
|
@ -159,17 +156,19 @@ static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
|
||||||
void *arg, bool check_size)
|
void *arg, bool check_size)
|
||||||
{
|
{
|
||||||
struct pci_vpd *vpd = &dev->vpd;
|
struct pci_vpd *vpd = &dev->vpd;
|
||||||
unsigned int max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE;
|
unsigned int max_len;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
loff_t end = pos + count;
|
loff_t end = pos + count;
|
||||||
u8 *buf = arg;
|
u8 *buf = arg;
|
||||||
|
|
||||||
if (!pci_vpd_available(dev))
|
if (!pci_vpd_available(dev, check_size))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE;
|
||||||
|
|
||||||
if (pos >= max_len)
|
if (pos >= max_len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -221,17 +220,19 @@ static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
|
||||||
const void *arg, bool check_size)
|
const void *arg, bool check_size)
|
||||||
{
|
{
|
||||||
struct pci_vpd *vpd = &dev->vpd;
|
struct pci_vpd *vpd = &dev->vpd;
|
||||||
unsigned int max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE;
|
unsigned int max_len;
|
||||||
const u8 *buf = arg;
|
const u8 *buf = arg;
|
||||||
loff_t end = pos + count;
|
loff_t end = pos + count;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!pci_vpd_available(dev))
|
if (!pci_vpd_available(dev, check_size))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (pos < 0 || (pos & 3) || (count & 3))
|
if (pos < 0 || (pos & 3) || (count & 3))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
max_len = check_size ? vpd->len : PCI_VPD_MAX_SIZE;
|
||||||
|
|
||||||
if (end > max_len)
|
if (end > max_len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -315,7 +316,7 @@ void *pci_vpd_alloc(struct pci_dev *dev, unsigned int *size)
|
||||||
void *buf;
|
void *buf;
|
||||||
int cnt;
|
int cnt;
|
||||||
|
|
||||||
if (!pci_vpd_available(dev))
|
if (!pci_vpd_available(dev, true))
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
len = dev->vpd.len;
|
len = dev->vpd.len;
|
||||||
|
|
Loading…
Reference in New Issue