PCI/VPD: Add pci_read/write_vpd_any()
In certain cases we need a variant of pci_read_vpd()/pci_write_vpd() that does not check against dev->vpd.len. Such cases are: - Reading VPD if dev->vpd.len isn't set yet (in pci_vpd_size()) - Devices that map non-VPD information to arbitrary places in VPD address space (example: Chelsio T3 EEPROM write-protect flag) Therefore add pci_read_vpd_any() and pci_write_vpd_any() that check against PCI_VPD_MAX_SIZE only. Link: https://lore.kernel.org/r/93ecce28-a158-f02a-d134-8afcaced8efe@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
e4e737bb5c
commit
bf2928c7a2
|
@ -156,9 +156,10 @@ static int pci_vpd_wait(struct pci_dev *dev, bool set)
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
|
static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
|
||||||
void *arg)
|
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;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
loff_t end = pos + count;
|
loff_t end = pos + count;
|
||||||
u8 *buf = arg;
|
u8 *buf = arg;
|
||||||
|
@ -169,11 +170,11 @@ static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (pos > vpd->len)
|
if (pos >= max_len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (end > vpd->len) {
|
if (end > max_len) {
|
||||||
end = vpd->len;
|
end = max_len;
|
||||||
count = end - pos;
|
count = end - pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,9 +218,10 @@ static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
|
static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
|
||||||
const void *arg)
|
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;
|
||||||
const u8 *buf = arg;
|
const u8 *buf = arg;
|
||||||
loff_t end = pos + count;
|
loff_t end = pos + count;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -230,7 +232,7 @@ static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
|
||||||
if (pos < 0 || (pos & 3) || (count & 3))
|
if (pos < 0 || (pos & 3) || (count & 3))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (end > vpd->len)
|
if (end > max_len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (mutex_lock_killable(&vpd->lock))
|
if (mutex_lock_killable(&vpd->lock))
|
||||||
|
@ -381,6 +383,24 @@ static int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t __pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf,
|
||||||
|
bool check_size)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) {
|
||||||
|
dev = pci_get_func0_dev(dev);
|
||||||
|
if (!dev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = pci_vpd_read(dev, pos, count, buf, check_size);
|
||||||
|
pci_dev_put(dev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pci_vpd_read(dev, pos, count, buf, check_size);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_read_vpd - Read one entry from Vital Product Data
|
* pci_read_vpd - Read one entry from Vital Product Data
|
||||||
* @dev: PCI device struct
|
* @dev: PCI device struct
|
||||||
|
@ -389,6 +409,20 @@ static int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
|
||||||
* @buf: pointer to where to store result
|
* @buf: pointer to where to store result
|
||||||
*/
|
*/
|
||||||
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
|
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
|
||||||
|
{
|
||||||
|
return __pci_read_vpd(dev, pos, count, buf, true);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(pci_read_vpd);
|
||||||
|
|
||||||
|
/* Same, but allow to access any address */
|
||||||
|
ssize_t pci_read_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
|
||||||
|
{
|
||||||
|
return __pci_read_vpd(dev, pos, count, buf, false);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(pci_read_vpd_any);
|
||||||
|
|
||||||
|
static ssize_t __pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count,
|
||||||
|
const void *buf, bool check_size)
|
||||||
{
|
{
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
|
@ -397,14 +431,13 @@ ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
ret = pci_vpd_read(dev, pos, count, buf);
|
ret = pci_vpd_write(dev, pos, count, buf, check_size);
|
||||||
pci_dev_put(dev);
|
pci_dev_put(dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pci_vpd_read(dev, pos, count, buf);
|
return pci_vpd_write(dev, pos, count, buf, check_size);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pci_read_vpd);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_write_vpd - Write entry to Vital Product Data
|
* pci_write_vpd - Write entry to Vital Product Data
|
||||||
|
@ -415,22 +448,17 @@ EXPORT_SYMBOL(pci_read_vpd);
|
||||||
*/
|
*/
|
||||||
ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
|
ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
|
||||||
{
|
{
|
||||||
ssize_t ret;
|
return __pci_write_vpd(dev, pos, count, buf, true);
|
||||||
|
|
||||||
if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) {
|
|
||||||
dev = pci_get_func0_dev(dev);
|
|
||||||
if (!dev)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
ret = pci_vpd_write(dev, pos, count, buf);
|
|
||||||
pci_dev_put(dev);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pci_vpd_write(dev, pos, count, buf);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pci_write_vpd);
|
EXPORT_SYMBOL(pci_write_vpd);
|
||||||
|
|
||||||
|
/* Same, but allow to access any address */
|
||||||
|
ssize_t pci_write_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
|
||||||
|
{
|
||||||
|
return __pci_write_vpd(dev, pos, count, buf, false);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(pci_write_vpd_any);
|
||||||
|
|
||||||
int pci_vpd_find_ro_info_keyword(const void *buf, unsigned int len,
|
int pci_vpd_find_ro_info_keyword(const void *buf, unsigned int len,
|
||||||
const char *kw, unsigned int *size)
|
const char *kw, unsigned int *size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1350,6 +1350,8 @@ void pci_unlock_rescan_remove(void);
|
||||||
/* Vital Product Data routines */
|
/* Vital Product Data routines */
|
||||||
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
|
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
|
||||||
ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
|
ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
|
||||||
|
ssize_t pci_read_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
|
||||||
|
ssize_t pci_write_vpd_any(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
|
||||||
|
|
||||||
/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
|
/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
|
||||||
resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
|
resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
|
||||||
|
|
Loading…
Reference in New Issue