mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/6] PCI patches
@ 2023-12-19 12:56 Sascha Hauer
  2023-12-19 12:56 ` [PATCH 1/6] pci: remove duplicate definition of pci_resource_start Sascha Hauer
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Sascha Hauer @ 2023-12-19 12:56 UTC (permalink / raw)
  To: Barebox List

These patches will be needed for upcoming Layerscape LS1028a support.
This SoC has the Ethernet Complex in an Integrated Endpoint Root
Complex.

Sascha Hauer (6):
  pci: remove duplicate definition of pci_resource_start
  pci: Do not register device tree disabled devices
  pci: layerscape: limit fixup to layerscape controllers
  pci: fix __pci_bus_find_cap_start
  pci: implement Enhanced Allocation support
  pci: implement function level reset

 drivers/pci/bus.c            |   3 +
 drivers/pci/pci-layerscape.c |   3 +
 drivers/pci/pci.c            | 222 ++++++++++++++++++++++++++++++++++-
 include/linux/pci.h          |   6 +-
 include/linux/pci_regs.h     |  50 +++++++-
 5 files changed, 277 insertions(+), 7 deletions(-)

-- 
2.39.2




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/6] pci: remove duplicate definition of pci_resource_start
  2023-12-19 12:56 [PATCH 0/6] PCI patches Sascha Hauer
@ 2023-12-19 12:56 ` Sascha Hauer
  2023-12-19 12:56 ` [PATCH 2/6] pci: Do not register device tree disabled devices Sascha Hauer
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Sascha Hauer @ 2023-12-19 12:56 UTC (permalink / raw)
  To: Barebox List

pci_resource_start is defined twice. Remove the duplicate.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/linux/pci.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/include/linux/pci.h b/include/linux/pci.h
index 98d056624f..0e907209a7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -201,10 +201,6 @@ struct pci_driver {
 
 #define	to_pci_driver(drv) container_of(drv, struct pci_driver, driver)
 
-/* these helpers provide future and backwards compatibility
- * for accessing popular PCI BAR info */
-#define pci_resource_start(dev, bar)    ((dev)->resource[(bar)].start)
-
 /**
  * DEFINE_PCI_DEVICE_TABLE - macro used to describe a pci device table
  * @_table: device table name
-- 
2.39.2




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/6] pci: Do not register device tree disabled devices
  2023-12-19 12:56 [PATCH 0/6] PCI patches Sascha Hauer
  2023-12-19 12:56 ` [PATCH 1/6] pci: remove duplicate definition of pci_resource_start Sascha Hauer
@ 2023-12-19 12:56 ` Sascha Hauer
  2023-12-19 12:56 ` [PATCH 3/6] pci: layerscape: limit fixup to layerscape controllers Sascha Hauer
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Sascha Hauer @ 2023-12-19 12:56 UTC (permalink / raw)
  To: Barebox List

Some PCI devices have device nodes associated with them. Do not register
these devices when they are disabled in the device tree.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/pci/bus.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index fdd012733a..b6eab56d87 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -114,6 +114,9 @@ int pci_register_device(struct pci_dev *pdev)
 	struct device *dev = &pdev->dev;
 	int ret;
 
+	if (!of_device_is_available(pdev->dev.of_node))
+		return 0;
+
 	dev_set_name(dev, "pci-%04x:%04x.", pdev->vendor, pdev->device);
 	dev->bus = &pci_bus;
 	dev->id = DEVICE_ID_DYNAMIC;
-- 
2.39.2




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 3/6] pci: layerscape: limit fixup to layerscape controllers
  2023-12-19 12:56 [PATCH 0/6] PCI patches Sascha Hauer
  2023-12-19 12:56 ` [PATCH 1/6] pci: remove duplicate definition of pci_resource_start Sascha Hauer
  2023-12-19 12:56 ` [PATCH 2/6] pci: Do not register device tree disabled devices Sascha Hauer
@ 2023-12-19 12:56 ` Sascha Hauer
  2023-12-19 12:56 ` [PATCH 4/6] pci: fix __pci_bus_find_cap_start Sascha Hauer
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Sascha Hauer @ 2023-12-19 12:56 UTC (permalink / raw)
  To: Barebox List

ls_pcie_fixup() assumes the fixed up device is attached to the layerscape
PCI controller. This may not be true when there's another controller
active in the system, so limit the execution of the fixup to the right
controller only.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/pci/pci-layerscape.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/pci/pci-layerscape.c b/drivers/pci/pci-layerscape.c
index 0fb742af9a..12a0ec71a7 100644
--- a/drivers/pci/pci-layerscape.c
+++ b/drivers/pci/pci-layerscape.c
@@ -551,6 +551,9 @@ static void ls_pcie_fixup(struct pci_dev *pcidev)
 	uint32_t devid;
 	int base_bus_num = 0;
 
+	if (!of_match_device(ls_pcie_of_match, host->parent))
+		return;
+
 	stream_id = ls_pcie_next_streamid(lspcie);
 	index = ls_pcie_next_lut_index(lspcie);
 
-- 
2.39.2




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 4/6] pci: fix __pci_bus_find_cap_start
  2023-12-19 12:56 [PATCH 0/6] PCI patches Sascha Hauer
                   ` (2 preceding siblings ...)
  2023-12-19 12:56 ` [PATCH 3/6] pci: layerscape: limit fixup to layerscape controllers Sascha Hauer
@ 2023-12-19 12:56 ` Sascha Hauer
  2023-12-19 12:56 ` [PATCH 5/6] pci: implement Enhanced Allocation support Sascha Hauer
  2023-12-19 12:56 ` [PATCH 6/6] pci: implement function level reset Sascha Hauer
  5 siblings, 0 replies; 7+ messages in thread
From: Sascha Hauer @ 2023-12-19 12:56 UTC (permalink / raw)
  To: Barebox List

BIT(7) of dev->hdr_type has unrelated information. Mask out the upper
bit so that the capabilities can properly be found.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/pci/pci.c        | 4 ++--
 include/linux/pci_regs.h | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 638af9722e..0211fc0081 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -428,7 +428,7 @@ static unsigned int pci_scan_bus(struct pci_bus *bus)
 		pr_debug("%02x:%02x [%04x:%04x]\n", bus->number, dev->devfn,
 		    dev->vendor, dev->device);
 
-		switch (hdr_type & 0x7f) {
+		switch (hdr_type & PCI_HEADER_TYPE_MASK) {
 		case PCI_HEADER_TYPE_NORMAL:
 			if (class == PCI_CLASS_BRIDGE_PCI)
 				goto bad;
@@ -642,7 +642,7 @@ u8 pci_find_capability(struct pci_dev *dev, int cap)
 {
 	u8 pos;
 
-	pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
+	pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type & PCI_HEADER_TYPE_MASK);
 	if (pos)
 		pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap);
 
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 2c335f5835..631f218229 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -69,6 +69,7 @@
 #define PCI_CACHE_LINE_SIZE	0x0c	/* 8 bits */
 #define PCI_LATENCY_TIMER	0x0d	/* 8 bits */
 #define PCI_HEADER_TYPE		0x0e	/* 8 bits */
+#define  PCI_HEADER_TYPE_MASK		0x7f
 #define  PCI_HEADER_TYPE_NORMAL		0
 #define  PCI_HEADER_TYPE_BRIDGE		1
 #define  PCI_HEADER_TYPE_CARDBUS	2
-- 
2.39.2




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 5/6] pci: implement Enhanced Allocation support
  2023-12-19 12:56 [PATCH 0/6] PCI patches Sascha Hauer
                   ` (3 preceding siblings ...)
  2023-12-19 12:56 ` [PATCH 4/6] pci: fix __pci_bus_find_cap_start Sascha Hauer
@ 2023-12-19 12:56 ` Sascha Hauer
  2023-12-19 12:56 ` [PATCH 6/6] pci: implement function level reset Sascha Hauer
  5 siblings, 0 replies; 7+ messages in thread
From: Sascha Hauer @ 2023-12-19 12:56 UTC (permalink / raw)
  To: Barebox List

Some PCI devices have their base addresses not defined in the BARs,
but instead have them defined in Enhanced Allocation structures.

Add support for these Enhanced Allocation structures, taken directly
from the Linux Kernel.

Motivation for adding this is the LS1028a SoC which uses Enhanced
Allocation for the Ethernet Subsystem which comes as an integrated
Endpoint Root Complex.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/pci/pci.c        | 186 +++++++++++++++++++++++++++++++++++++++
 include/linux/pci_regs.h |  49 ++++++++++-
 2 files changed, 234 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0211fc0081..a3e7e70871 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4,6 +4,7 @@
 #include <common.h>
 #include <linux/sizes.h>
 #include <linux/pci.h>
+#include <linux/bitfield.h>
 
 static unsigned int pci_scan_bus(struct pci_bus *bus);
 
@@ -152,6 +153,189 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask)
 	return size + 1;
 }
 
+static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop)
+{
+	unsigned long flags = IORESOURCE_PCI_FIXED;
+
+	switch (prop) {
+	case PCI_EA_P_MEM:
+	case PCI_EA_P_VF_MEM:
+		flags |= IORESOURCE_MEM;
+		break;
+	case PCI_EA_P_MEM_PREFETCH:
+	case PCI_EA_P_VF_MEM_PREFETCH:
+		flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+		break;
+	case PCI_EA_P_IO:
+		flags |= IORESOURCE_IO;
+		break;
+	default:
+		return 0;
+	}
+
+	return flags;
+}
+
+static struct resource *pci_ea_get_resource(struct pci_dev *dev, u8 bei,
+					    u8 prop)
+{
+	if (bei <= PCI_EA_BEI_BAR5 && prop <= PCI_EA_P_IO)
+		return &dev->resource[bei];
+	else if (bei == PCI_EA_BEI_ROM)
+		return &dev->resource[PCI_ROM_RESOURCE];
+	else
+		return NULL;
+}
+
+/* Read an Enhanced Allocation (EA) entry */
+static int pci_ea_read(struct pci_dev *dev, int offset)
+{
+	struct resource *res;
+	int ent_size, ent_offset = offset;
+	resource_size_t start, end;
+	unsigned long flags;
+	u32 dw0, bei, base, max_offset;
+	u8 prop;
+	bool support_64 = (sizeof(resource_size_t) >= 8);
+
+	pci_read_config_dword(dev, ent_offset, &dw0);
+	ent_offset += 4;
+
+	/* Entry size field indicates DWORDs after 1st */
+	ent_size = (FIELD_GET(PCI_EA_ES, dw0) + 1) << 2;
+
+	if (!(dw0 & PCI_EA_ENABLE)) /* Entry not enabled */
+		goto out;
+
+	bei = FIELD_GET(PCI_EA_BEI, dw0);
+	prop = FIELD_GET(PCI_EA_PP, dw0);
+
+	/*
+	 * If the Property is in the reserved range, try the Secondary
+	 * Property instead.
+	 */
+	if (prop > PCI_EA_P_BRIDGE_IO && prop < PCI_EA_P_MEM_RESERVED)
+		prop = FIELD_GET(PCI_EA_SP, dw0);
+	if (prop > PCI_EA_P_BRIDGE_IO)
+		goto out;
+
+	res = pci_ea_get_resource(dev, bei, prop);
+	if (!res) {
+		dev_dbg(&dev->dev, "Unsupported EA entry BEI: %u\n", bei);
+		goto out;
+	}
+
+	flags = pci_ea_flags(dev, prop);
+	if (!flags) {
+		dev_err(&dev->dev, "Unsupported EA properties: %#x\n", prop);
+		goto out;
+	}
+
+	/* Read Base */
+	pci_read_config_dword(dev, ent_offset, &base);
+	start = (base & PCI_EA_FIELD_MASK);
+	ent_offset += 4;
+
+	/* Read MaxOffset */
+	pci_read_config_dword(dev, ent_offset, &max_offset);
+	ent_offset += 4;
+
+	/* Read Base MSBs (if 64-bit entry) */
+	if (base & PCI_EA_IS_64) {
+		u32 base_upper;
+
+		pci_read_config_dword(dev, ent_offset, &base_upper);
+		ent_offset += 4;
+
+		flags |= IORESOURCE_MEM_64;
+
+		/* entry starts above 32-bit boundary, can't use */
+		if (!support_64 && base_upper)
+			goto out;
+
+		if (support_64)
+			start |= ((u64)base_upper << 32);
+	}
+
+	end = start + (max_offset | 0x03);
+
+	/* Read MaxOffset MSBs (if 64-bit entry) */
+	if (max_offset & PCI_EA_IS_64) {
+		u32 max_offset_upper;
+
+		pci_read_config_dword(dev, ent_offset, &max_offset_upper);
+		ent_offset += 4;
+
+		flags |= IORESOURCE_MEM_64;
+
+		/* entry too big, can't use */
+		if (!support_64 && max_offset_upper)
+			goto out;
+
+		if (support_64)
+			end += ((u64)max_offset_upper << 32);
+	}
+
+	if (end < start) {
+		dev_err(&dev->dev, "EA Entry crosses address boundary\n");
+		goto out;
+	}
+
+	if (ent_size != ent_offset - offset) {
+		dev_err(&dev->dev, "EA Entry Size (%d) does not match length read (%d)\n",
+			ent_size, ent_offset - offset);
+		goto out;
+	}
+
+	res->start = start;
+	res->end = end;
+	res->flags = flags;
+
+	if (bei <= PCI_EA_BEI_BAR5)
+		dev_dbg(&dev->dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
+			   bei, res, prop);
+	else if (bei == PCI_EA_BEI_ROM)
+		dev_dbg(&dev->dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n",
+			   res, prop);
+	else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5)
+		dev_dbg(&dev->dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
+			   bei - PCI_EA_BEI_VF_BAR0, res, prop);
+	else
+		dev_dbg(&dev->dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n",
+			   bei, res, prop);
+
+out:
+	return offset + ent_size;
+}
+
+/* Enhanced Allocation Initialization */
+static void pci_ea_init(struct pci_dev *dev)
+{
+	int ea;
+	u8 num_ent;
+	int offset;
+	int i;
+
+	/* find PCI EA capability in list */
+	ea = pci_find_capability(dev, PCI_CAP_ID_EA);
+	if (!ea)
+		return;
+
+	/* determine the number of entries */
+	pci_bus_read_config_byte(dev->bus, dev->devfn, ea + PCI_EA_NUM_ENT,
+					&num_ent);
+	num_ent &= PCI_EA_NUM_ENT_MASK;
+
+	offset = ea + PCI_EA_FIRST_ENT;
+
+	/* Skip DWORD 2 for type 1 functions */
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+		offset += 4;
+
+	/* parse each EA entry */
+	for (i = 0; i < num_ent; ++i)
+		offset = pci_ea_read(dev, offset);
+}
 
 static void setup_device(struct pci_dev *dev, int max_bar)
 {
@@ -251,6 +435,8 @@ static void setup_device(struct pci_dev *dev, int max_bar)
 		}
 	}
 
+	pci_ea_init(dev);
+
 	pci_fixup_device(pci_fixup_header, dev);
 
 	if (pcibios_assign_all_busses())
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 631f218229..8d71914f75 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -219,7 +219,8 @@
 #define  PCI_CAP_ID_MSIX	0x11	/* MSI-X */
 #define  PCI_CAP_ID_SATA	0x12	/* SATA Data/Index Conf. */
 #define  PCI_CAP_ID_AF		0x13	/* PCI Advanced Features */
-#define  PCI_CAP_ID_MAX		PCI_CAP_ID_AF
+#define  PCI_CAP_ID_EA		0x14	/* PCI Enhanced Allocation */
+#define  PCI_CAP_ID_MAX		PCI_CAP_ID_EA
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
 #define PCI_CAP_SIZEOF		4
@@ -355,6 +356,52 @@
 #define  PCI_AF_STATUS_TP	0x01
 #define PCI_CAP_AF_SIZEOF	6	/* size of AF registers */
 
+/* PCI Enhanced Allocation registers */
+
+#define PCI_EA_NUM_ENT		2	/* Number of Capability Entries */
+#define  PCI_EA_NUM_ENT_MASK	0x3f	/* Num Entries Mask */
+#define PCI_EA_FIRST_ENT	4	/* First EA Entry in List */
+#define PCI_EA_FIRST_ENT_BRIDGE	8	/* First EA Entry for Bridges */
+#define  PCI_EA_ES		0x00000007 /* Entry Size */
+#define  PCI_EA_BEI		0x000000f0 /* BAR Equivalent Indicator */
+
+/* EA fixed Secondary and Subordinate bus numbers for Bridge */
+#define PCI_EA_SEC_BUS_MASK	0xff
+#define PCI_EA_SUB_BUS_MASK	0xff00
+#define PCI_EA_SUB_BUS_SHIFT	8
+
+/* 0-5 map to BARs 0-5 respectively */
+#define   PCI_EA_BEI_BAR0		0
+#define   PCI_EA_BEI_BAR5		5
+#define   PCI_EA_BEI_BRIDGE		6	/* Resource behind bridge */
+#define   PCI_EA_BEI_ENI		7	/* Equivalent Not Indicated */
+#define   PCI_EA_BEI_ROM		8	/* Expansion ROM */
+/* 9-14 map to VF BARs 0-5 respectively */
+#define   PCI_EA_BEI_VF_BAR0		9
+#define   PCI_EA_BEI_VF_BAR5		14
+#define   PCI_EA_BEI_RESERVED		15	/* Reserved - Treat like ENI */
+#define  PCI_EA_PP		0x0000ff00	/* Primary Properties */
+#define  PCI_EA_SP		0x00ff0000	/* Secondary Properties */
+#define   PCI_EA_P_MEM			0x00	/* Non-Prefetch Memory */
+#define   PCI_EA_P_MEM_PREFETCH		0x01	/* Prefetchable Memory */
+#define   PCI_EA_P_IO			0x02	/* I/O Space */
+#define   PCI_EA_P_VF_MEM_PREFETCH	0x03	/* VF Prefetchable Memory */
+#define   PCI_EA_P_VF_MEM		0x04	/* VF Non-Prefetch Memory */
+#define   PCI_EA_P_BRIDGE_MEM		0x05	/* Bridge Non-Prefetch Memory */
+#define   PCI_EA_P_BRIDGE_MEM_PREFETCH	0x06	/* Bridge Prefetchable Memory */
+#define   PCI_EA_P_BRIDGE_IO		0x07	/* Bridge I/O Space */
+/* 0x08-0xfc reserved */
+#define   PCI_EA_P_MEM_RESERVED		0xfd	/* Reserved Memory */
+#define   PCI_EA_P_IO_RESERVED		0xfe	/* Reserved I/O Space */
+#define   PCI_EA_P_UNAVAILABLE		0xff	/* Entry Unavailable */
+#define  PCI_EA_WRITABLE	0x40000000	/* Writable: 1 = RW, 0 = HwInit */
+#define  PCI_EA_ENABLE		0x80000000	/* Enable for this entry */
+#define PCI_EA_BASE		4		/* Base Address Offset */
+#define PCI_EA_MAX_OFFSET	8		/* MaxOffset (resource length) */
+/* bit 0 is reserved */
+#define  PCI_EA_IS_64		0x00000002	/* 64-bit field flag */
+#define  PCI_EA_FIELD_MASK	0xfffffffc	/* For Base & Max Offset */
+
 /* PCI-X registers (Type 0 (non-bridge) devices) */
 
 #define PCI_X_CMD		2	/* Modes & Features */
-- 
2.39.2




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 6/6] pci: implement function level reset
  2023-12-19 12:56 [PATCH 0/6] PCI patches Sascha Hauer
                   ` (4 preceding siblings ...)
  2023-12-19 12:56 ` [PATCH 5/6] pci: implement Enhanced Allocation support Sascha Hauer
@ 2023-12-19 12:56 ` Sascha Hauer
  5 siblings, 0 replies; 7+ messages in thread
From: Sascha Hauer @ 2023-12-19 12:56 UTC (permalink / raw)
  To: Barebox List

This will be needed for upcoming LS1028a support. The code is taken from
U-Boot which suffices for our usecase. The kernel code is much more
elaborated here.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/pci/pci.c   | 32 ++++++++++++++++++++++++++++++++
 include/linux/pci.h |  2 ++
 2 files changed, 34 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a3e7e70871..84678e40a9 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -553,6 +553,38 @@ pci_of_match_device(struct device *parent, unsigned int devfn)
 	return NULL;
 }
 
+/**
+ * pcie_flr - initiate a PCIe function level reset
+ * @dev:	device to reset
+ *
+ * Initiate a function level reset on @dev.
+ */
+int pci_flr(struct pci_dev *pdev)
+{
+	u16 val;
+	int pcie_off;
+	u32 cap;
+
+	/* look for PCI Express Capability */
+	pcie_off = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (!pcie_off)
+		return -ENOENT;
+
+	/* check FLR capability */
+	pci_read_config_dword(pdev, pcie_off + PCI_EXP_DEVCAP, &cap);
+	if (!(cap & PCI_EXP_DEVCAP_FLR))
+		return -ENOENT;
+
+	pci_read_config_word(pdev, pcie_off + PCI_EXP_DEVCTL, &val);
+	val |= PCI_EXP_DEVCTL_BCR_FLR;
+	pci_write_config_word(pdev, pcie_off + PCI_EXP_DEVCTL, val);
+
+	/* wait 100ms, per PCI spec */
+	mdelay(100);
+
+	return 0;
+}
+
 static unsigned int pci_scan_bus(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 0e907209a7..fe5285116a 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -329,6 +329,8 @@ u8 pci_find_capability(struct pci_dev *dev, int cap);
 
 extern void __iomem *pci_iomap(struct pci_dev *dev, int bar);
 
+int pci_flr(struct pci_dev *pdev);
+
 /*
  * The world is not perfect and supplies us with broken PCI devices.
  * For at least a part of these bugs we need a work-around, so both
-- 
2.39.2




^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-12-19 12:58 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-19 12:56 [PATCH 0/6] PCI patches Sascha Hauer
2023-12-19 12:56 ` [PATCH 1/6] pci: remove duplicate definition of pci_resource_start Sascha Hauer
2023-12-19 12:56 ` [PATCH 2/6] pci: Do not register device tree disabled devices Sascha Hauer
2023-12-19 12:56 ` [PATCH 3/6] pci: layerscape: limit fixup to layerscape controllers Sascha Hauer
2023-12-19 12:56 ` [PATCH 4/6] pci: fix __pci_bus_find_cap_start Sascha Hauer
2023-12-19 12:56 ` [PATCH 5/6] pci: implement Enhanced Allocation support Sascha Hauer
2023-12-19 12:56 ` [PATCH 6/6] pci: implement function level reset Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox