Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 12566cc3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull PCI fixes from Bjorn Helgaas:
 "These are fixes for two issues:

   - The VPD parsing code we added for v4.6 keeps some devices from
     crashing, but also keeps cxgb4 from reading non-standard extra VPD
     data that is relies on.  Hariprasad added a way for the driver to
     specify how much VPD is valid.

   - The i.MX6 active-low reset GPIO support we added in v4.5 caused
     regressions on some boards, so we're reverting that.

  VPD:
    Add pci_set_vpd_size() (Hariprasad Shenai)
    cxgb4: Set VPD size so we can read both VPD structures (Hariprasad Shenai)

  Freescale i.MX6 host bridge driver:
    Revert "PCI: imx6: Add support for active-low reset GPIO" (Fabio Estevam)"

* tag 'pci-v4.6-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
  cxgb4: Set VPD size so we can read both VPD structures
  PCI: Add pci_set_vpd_size() to set VPD size
  Revert "PCI: imx6: Add support for active-low reset GPIO"
parents 95d0c427 67e65879
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -2557,6 +2557,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
}

#define EEPROM_STAT_ADDR   0x7bfc
#define VPD_SIZE           0x800
#define VPD_BASE           0x400
#define VPD_BASE_OLD       0
#define VPD_LEN            1024
@@ -2594,6 +2595,15 @@ int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p)
	if (!vpd)
		return -ENOMEM;

	/* We have two VPD data structures stored in the adapter VPD area.
	 * By default, Linux calculates the size of the VPD area by traversing
	 * the first VPD area at offset 0x0, so we need to tell the OS what
	 * our real VPD size is.
	 */
	ret = pci_set_vpd_size(adapter->pdev, VPD_SIZE);
	if (ret < 0)
		goto out;

	/* Card information normally starts at VPD_BASE but early cards had
	 * it at 0.
	 */
+42 −0
Original line number Diff line number Diff line
@@ -275,6 +275,19 @@ ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void
}
EXPORT_SYMBOL(pci_write_vpd);

/**
 * pci_set_vpd_size - Set size of Vital Product Data space
 * @dev:	pci device struct
 * @len:	size of vpd space
 */
int pci_set_vpd_size(struct pci_dev *dev, size_t len)
{
	if (!dev->vpd || !dev->vpd->ops)
		return -ENODEV;
	return dev->vpd->ops->set_size(dev, len);
}
EXPORT_SYMBOL(pci_set_vpd_size);

#define PCI_VPD_MAX_SIZE (PCI_VPD_ADDR_MASK + 1)

/**
@@ -498,9 +511,23 @@ static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
	return ret ? ret : count;
}

static int pci_vpd_set_size(struct pci_dev *dev, size_t len)
{
	struct pci_vpd *vpd = dev->vpd;

	if (len == 0 || len > PCI_VPD_MAX_SIZE)
		return -EIO;

	vpd->valid = 1;
	vpd->len = len;

	return 0;
}

static const struct pci_vpd_ops pci_vpd_ops = {
	.read = pci_vpd_read,
	.write = pci_vpd_write,
	.set_size = pci_vpd_set_size,
};

static ssize_t pci_vpd_f0_read(struct pci_dev *dev, loff_t pos, size_t count,
@@ -533,9 +560,24 @@ static ssize_t pci_vpd_f0_write(struct pci_dev *dev, loff_t pos, size_t count,
	return ret;
}

static int pci_vpd_f0_set_size(struct pci_dev *dev, size_t len)
{
	struct pci_dev *tdev = pci_get_slot(dev->bus,
					    PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
	int ret;

	if (!tdev)
		return -ENODEV;

	ret = pci_set_vpd_size(tdev, len);
	pci_dev_put(tdev);
	return ret;
}

static const struct pci_vpd_ops pci_vpd_f0_ops = {
	.read = pci_vpd_f0_read,
	.write = pci_vpd_f0_write,
	.set_size = pci_vpd_f0_set_size,
};

int pci_vpd_init(struct pci_dev *dev)
+14 −6
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@
#define to_imx6_pcie(x)	container_of(x, struct imx6_pcie, pp)

struct imx6_pcie {
	struct gpio_desc	*reset_gpio;
	int			reset_gpio;
	struct clk		*pcie_bus;
	struct clk		*pcie_phy;
	struct clk		*pcie;
@@ -309,10 +309,10 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
	usleep_range(200, 500);

	/* Some boards don't have PCIe reset GPIO. */
	if (imx6_pcie->reset_gpio) {
		gpiod_set_value_cansleep(imx6_pcie->reset_gpio, 0);
	if (gpio_is_valid(imx6_pcie->reset_gpio)) {
		gpio_set_value_cansleep(imx6_pcie->reset_gpio, 0);
		msleep(100);
		gpiod_set_value_cansleep(imx6_pcie->reset_gpio, 1);
		gpio_set_value_cansleep(imx6_pcie->reset_gpio, 1);
	}
	return 0;

@@ -523,6 +523,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
{
	struct imx6_pcie *imx6_pcie;
	struct pcie_port *pp;
	struct device_node *np = pdev->dev.of_node;
	struct resource *dbi_base;
	struct device_node *node = pdev->dev.of_node;
	int ret;
@@ -544,8 +545,15 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
		return PTR_ERR(pp->dbi_base);

	/* Fetch GPIOs */
	imx6_pcie->reset_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
							GPIOD_OUT_LOW);
	imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
	if (gpio_is_valid(imx6_pcie->reset_gpio)) {
		ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->reset_gpio,
					    GPIOF_OUT_INIT_LOW, "PCIe reset");
		if (ret) {
			dev_err(&pdev->dev, "unable to get reset gpio\n");
			return ret;
		}
	}

	/* Fetch clocks */
	imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy");
+1 −0
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ static inline bool pci_has_subordinate(struct pci_dev *pci_dev)
struct pci_vpd_ops {
	ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
	ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
	int (*set_size)(struct pci_dev *dev, size_t len);
};

struct pci_vpd {
+1 −0
Original line number Diff line number Diff line
@@ -1111,6 +1111,7 @@ void pci_unlock_rescan_remove(void);
/* Vital product data routines */
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);
int pci_set_vpd_size(struct pci_dev *dev, size_t len);

/* 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);