From 296bd5aea223d1d04f4e113ceec74d1fb3e422c5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 20 Mar 2019 13:27:15 -0500 Subject: PCI: Mark expected switch fall-throughs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warnings: drivers/pci/proc.c: In function ‘proc_bus_pci_ioctl’: drivers/pci/proc.c:216:6: warning: this statement may fall through [-Wimplicit-fallthrough=] if (arch_can_pci_mmap_wc()) { ^ drivers/pci/proc.c:225:2: note: here default: ^~~~~~~ drivers/pci/xen-pcifront.c: In function ‘pcifront_backend_changed’: drivers/pci/xen-pcifront.c:1105:6: warning: this statement may fall through [-Wimplicit-fallthrough=] if (xdev->state == XenbusStateClosed) ^ drivers/pci/xen-pcifront.c:1108:2: note: here case XenbusStateClosing: ^~~~ Notice that, in this particular case, the /* fall through */ comment is placed at the very bottom of the case statement, which is what GCC is expecting to find. Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enable -Wimplicit-fallthrough. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Bjorn Helgaas --- drivers/pci/proc.c | 1 + drivers/pci/xen-pcifront.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 6fa1627ce08d..445b51db75b0 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -222,6 +222,7 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd, } /* If arch decided it can't, fall through... */ #endif /* HAVE_PCI_MMAP */ + /* fall through */ default: ret = -EINVAL; break; diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index eba6e33147a2..14cf0f41ecf0 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -1104,7 +1104,7 @@ static void __ref pcifront_backend_changed(struct xenbus_device *xdev, case XenbusStateClosed: if (xdev->state == XenbusStateClosed) break; - /* Missed the backend's CLOSING state -- fallthrough */ + /* fall through - Missed the backend's CLOSING state. */ case XenbusStateClosing: dev_warn(&xdev->dev, "backend going away!\n"); pcifront_try_disconnect(pdev); -- cgit From 1903ba82823b244e92764a9d899ebaac5ebcd5ec Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 12 Nov 2018 11:16:10 -0600 Subject: PCI/MSI: Remove unused __write_msi_msg() and write_msi_msg() Remove unused __write_msi_msg() and write_msi_msg(). These were added by 83a18912b0e8 ("PCI/MSI: Rename write_msi_msg() to pci_write_msi_msg()"), they served their purpose, and they're no longer needed. Signed-off-by: Bjorn Helgaas CC: Jiang Liu # 83a18912b0e8 author --- include/linux/msi.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/linux/msi.h b/include/linux/msi.h index 7e9b81c3b50d..f934982a0e68 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -148,15 +148,6 @@ u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag); void pci_msi_mask_irq(struct irq_data *data); void pci_msi_unmask_irq(struct irq_data *data); -/* Conversion helpers. Should be removed after merging */ -static inline void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) -{ - __pci_write_msi_msg(entry, msg); -} -static inline void write_msi_msg(int irq, struct msi_msg *msg) -{ - pci_write_msi_msg(irq, msg); -} static inline void mask_msi_irq(struct irq_data *data) { pci_msi_mask_irq(data); -- cgit From fc2786545395e0ca69f245e5617fee0639ff0d25 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 21 Mar 2019 14:39:24 -0500 Subject: PCI/MSI: Remove unused mask_msi_irq() and unmask_msi_irq() Change pcie-xilinx-nwl.c to use pci_msi_mask_irq() and pci_msi_unmask_irq() like all other PCI host controller drivers. Remove the now-unused mask_msi_irq() and unmask_msi_irq(). Signed-off-by: Bjorn Helgaas CC: Michal Simek CC: linux-arm-kernel@lists.infradead.org --- drivers/pci/controller/pcie-xilinx-nwl.c | 9 ++++----- include/linux/msi.h | 9 --------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c index 81538d77f790..3b031f00a94a 100644 --- a/drivers/pci/controller/pcie-xilinx-nwl.c +++ b/drivers/pci/controller/pcie-xilinx-nwl.c @@ -438,11 +438,10 @@ static const struct irq_domain_ops legacy_domain_ops = { #ifdef CONFIG_PCI_MSI static struct irq_chip nwl_msi_irq_chip = { .name = "nwl_pcie:msi", - .irq_enable = unmask_msi_irq, - .irq_disable = mask_msi_irq, - .irq_mask = mask_msi_irq, - .irq_unmask = unmask_msi_irq, - + .irq_enable = pci_msi_unmask_irq, + .irq_disable = pci_msi_mask_irq, + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, }; static struct msi_domain_info nwl_msi_domain_info = { diff --git a/include/linux/msi.h b/include/linux/msi.h index f934982a0e68..052f04fcf953 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -148,15 +148,6 @@ u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag); void pci_msi_mask_irq(struct irq_data *data); void pci_msi_unmask_irq(struct irq_data *data); -static inline void mask_msi_irq(struct irq_data *data) -{ - pci_msi_mask_irq(data); -} -static inline void unmask_msi_irq(struct irq_data *data) -{ - pci_msi_unmask_irq(data); -} - /* * The arch hooks to setup up msi irqs. Those functions are * implemented as weak symbols so that they /can/ be overriden by -- cgit From b71f0a0b1e3fea212a6a5042ced8b48a81738ac9 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Thu, 20 Sep 2018 17:02:53 +0200 Subject: tools: PCI: Exit with error code when test fails This makes it easier to use pcitest in automated setups. Signed-off-by: Jean-Jacques Hiblot Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- tools/pci/pcitest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c index ec4d51f3308b..310a7e4850f6 100644 --- a/tools/pci/pcitest.c +++ b/tools/pci/pcitest.c @@ -140,6 +140,7 @@ static void run_test(struct pci_test *test) } fflush(stdout); + return (ret < 0) ? ret : 1 - ret; /* return 0 if test succeeded */ } int main(int argc, char **argv) @@ -228,6 +229,5 @@ usage: return -EINVAL; } - run_test(test); - return 0; + return run_test(test); } -- cgit From 35d0a06dad2220d62042fd1a91a216d17744e724 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 4 Feb 2019 14:50:14 -0600 Subject: PCI: Cleanup register definition width and whitespace Follow the file conventions of: - register offsets not indented - fields within a register indented one space - field masks use same width as register - register field values indented an additional space No functional change intended. Signed-off-by: Bjorn Helgaas --- include/uapi/linux/pci_regs.h | 132 +++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 67 deletions(-) diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 5c98133f2c94..f7d3e7831fa8 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* - * pci_regs.h - * * PCI standard defines * Copyright 1994, Drew Eckhardt * Copyright 1997--1999 Martin Mares @@ -15,7 +13,7 @@ * PCI System Design Guide * * For HyperTransport information, please consult the following manuals - * from http://www.hypertransport.org + * from http://www.hypertransport.org : * * The HyperTransport I/O Link Specification */ @@ -301,7 +299,7 @@ #define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ #define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ -/* Message Signalled Interrupts registers */ +/* Message Signalled Interrupt registers */ #define PCI_MSI_FLAGS 2 /* Message Control */ #define PCI_MSI_FLAGS_ENABLE 0x0001 /* MSI feature enabled */ @@ -319,7 +317,7 @@ #define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ #define PCI_MSI_PENDING_64 20 /* Pending intrs for 64-bit devices */ -/* MSI-X registers */ +/* MSI-X registers (in MSI-X capability) */ #define PCI_MSIX_FLAGS 2 /* Message Control */ #define PCI_MSIX_FLAGS_QSIZE 0x07FF /* Table size */ #define PCI_MSIX_FLAGS_MASKALL 0x4000 /* Mask all vectors for this function */ @@ -333,13 +331,13 @@ #define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR /* deprecated */ #define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */ -/* MSI-X Table entry format */ +/* MSI-X Table entry format (in memory mapped by a BAR) */ #define PCI_MSIX_ENTRY_SIZE 16 -#define PCI_MSIX_ENTRY_LOWER_ADDR 0 -#define PCI_MSIX_ENTRY_UPPER_ADDR 4 -#define PCI_MSIX_ENTRY_DATA 8 -#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 -#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 +#define PCI_MSIX_ENTRY_LOWER_ADDR 0 /* Message Address */ +#define PCI_MSIX_ENTRY_UPPER_ADDR 4 /* Message Upper Address */ +#define PCI_MSIX_ENTRY_DATA 8 /* Message Data */ +#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 /* Vector Control */ +#define PCI_MSIX_ENTRY_CTRL_MASKBIT 0x00000001 /* CompactPCI Hotswap Register */ @@ -465,19 +463,19 @@ /* PCI Express capability registers */ #define PCI_EXP_FLAGS 2 /* Capabilities register */ -#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ -#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ -#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ -#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ -#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ -#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ -#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ -#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCIe to PCI/PCI-X Bridge */ -#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */ -#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ -#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ -#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ -#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ +#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ +#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ +#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ +#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ +#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ +#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ +#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ +#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCIe to PCI/PCI-X Bridge */ +#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */ +#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ +#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ +#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ +#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ #define PCI_EXP_DEVCAP 4 /* Device capabilities */ #define PCI_EXP_DEVCAP_PAYLOAD 0x00000007 /* Max_Payload_Size */ #define PCI_EXP_DEVCAP_PHANTOM 0x00000018 /* Phantom functions */ @@ -616,8 +614,8 @@ #define PCI_EXP_RTCAP 30 /* Root Capabilities */ #define PCI_EXP_RTCAP_CRSVIS 0x0001 /* CRS Software Visibility capability */ #define PCI_EXP_RTSTA 32 /* Root Status */ -#define PCI_EXP_RTSTA_PME 0x00010000 /* PME status */ -#define PCI_EXP_RTSTA_PENDING 0x00020000 /* PME pending */ +#define PCI_EXP_RTSTA_PME 0x00010000 /* PME status */ +#define PCI_EXP_RTSTA_PENDING 0x00020000 /* PME pending */ /* * The Device Capabilities 2, Device Status 2, Device Control 2, * Link Capabilities 2, Link Status 2, Link Control 2, @@ -637,13 +635,13 @@ #define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */ #define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */ #define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */ -#define PCI_EXP_DEVCAP2_EE_PREFIX 0x00200000 /* End-End TLP Prefix */ +#define PCI_EXP_DEVCAP2_EE_PREFIX 0x00200000 /* End-End TLP Prefix */ #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ #define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */ #define PCI_EXP_DEVCTL2_COMP_TMOUT_DIS 0x0010 /* Completion Timeout Disable */ #define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */ -#define PCI_EXP_DEVCTL2_ATOMIC_REQ 0x0040 /* Set Atomic requests */ -#define PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK 0x0080 /* Block atomic egress */ +#define PCI_EXP_DEVCTL2_ATOMIC_REQ 0x0040 /* Set Atomic requests */ +#define PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK 0x0080 /* Block atomic egress */ #define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x0100 /* Allow IDO for requests */ #define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x0200 /* Allow IDO for completions */ #define PCI_EXP_DEVCTL2_LTR_EN 0x0400 /* Enable LTR mechanism */ @@ -659,11 +657,11 @@ #define PCI_EXP_LNKCAP2_SLS_16_0GB 0x00000010 /* Supported Speed 16GT/s */ #define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink supported */ #define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ -#define PCI_EXP_LNKCTL2_TLS 0x000f -#define PCI_EXP_LNKCTL2_TLS_2_5GT 0x0001 /* Supported Speed 2.5GT/s */ -#define PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Supported Speed 5GT/s */ -#define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */ -#define PCI_EXP_LNKCTL2_TLS_16_0GT 0x0004 /* Supported Speed 16GT/s */ +#define PCI_EXP_LNKCTL2_TLS 0x000f +#define PCI_EXP_LNKCTL2_TLS_2_5GT 0x0001 /* Supported Speed 2.5GT/s */ +#define PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Supported Speed 5GT/s */ +#define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */ +#define PCI_EXP_LNKCTL2_TLS_16_0GT 0x0004 /* Supported Speed 16GT/s */ #define PCI_EXP_LNKSTA2 50 /* Link Status 2 */ #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 52 /* v2 endpoints with link end here */ #define PCI_EXP_SLTCAP2 52 /* Slot Capabilities 2 */ @@ -752,18 +750,18 @@ #define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ #define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ #define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ -#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 /* Correctable Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 /* Non-Fatal Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 /* Fatal Err Reporting Enable */ +#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 /* Correctable Err Reporting Enable */ +#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 /* Non-Fatal Err Reporting Enable */ +#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 /* Fatal Err Reporting Enable */ #define PCI_ERR_ROOT_STATUS 48 -#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ -#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 /* Multiple ERR_COR */ -#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 /* ERR_FATAL/NONFATAL */ -#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 /* Multiple FATAL/NONFATAL */ -#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First UNC is Fatal */ -#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ -#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ -#define PCI_ERR_ROOT_AER_IRQ 0xf8000000 /* Advanced Error Interrupt Message Number */ +#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ +#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 /* Multiple ERR_COR */ +#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 /* ERR_FATAL/NONFATAL */ +#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 /* Multiple FATAL/NONFATAL */ +#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First UNC is Fatal */ +#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ +#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ +#define PCI_ERR_ROOT_AER_IRQ 0xf8000000 /* Advanced Error Interrupt Message Number */ #define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ /* Virtual Channel */ @@ -875,12 +873,12 @@ /* Page Request Interface */ #define PCI_PRI_CTRL 0x04 /* PRI control register */ -#define PCI_PRI_CTRL_ENABLE 0x01 /* Enable */ -#define PCI_PRI_CTRL_RESET 0x02 /* Reset */ +#define PCI_PRI_CTRL_ENABLE 0x0001 /* Enable */ +#define PCI_PRI_CTRL_RESET 0x0002 /* Reset */ #define PCI_PRI_STATUS 0x06 /* PRI status register */ -#define PCI_PRI_STATUS_RF 0x001 /* Response Failure */ -#define PCI_PRI_STATUS_UPRGI 0x002 /* Unexpected PRG index */ -#define PCI_PRI_STATUS_STOPPED 0x100 /* PRI Stopped */ +#define PCI_PRI_STATUS_RF 0x0001 /* Response Failure */ +#define PCI_PRI_STATUS_UPRGI 0x0002 /* Unexpected PRG index */ +#define PCI_PRI_STATUS_STOPPED 0x0100 /* PRI Stopped */ #define PCI_PRI_STATUS_PASID 0x8000 /* PRG Response PASID Required */ #define PCI_PRI_MAX_REQ 0x08 /* PRI max reqs supported */ #define PCI_PRI_ALLOC_REQ 0x0c /* PRI max reqs allowed */ @@ -898,16 +896,16 @@ /* Single Root I/O Virtualization */ #define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ -#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ +#define PCI_SRIOV_CAP_VFM 0x00000001 /* VF Migration Capable */ #define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */ #define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ -#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */ -#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */ -#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */ -#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */ -#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */ +#define PCI_SRIOV_CTRL_VFE 0x0001 /* VF Enable */ +#define PCI_SRIOV_CTRL_VFM 0x0002 /* VF Migration Enable */ +#define PCI_SRIOV_CTRL_INTR 0x0004 /* VF Migration Interrupt Enable */ +#define PCI_SRIOV_CTRL_MSE 0x0008 /* VF Memory Space Enable */ +#define PCI_SRIOV_CTRL_ARI 0x0010 /* ARI Capable Hierarchy */ #define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */ -#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */ +#define PCI_SRIOV_STATUS_VFM 0x0001 /* VF Migration Status */ #define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */ #define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */ #define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */ @@ -937,13 +935,13 @@ /* Access Control Service */ #define PCI_ACS_CAP 0x04 /* ACS Capability Register */ -#define PCI_ACS_SV 0x01 /* Source Validation */ -#define PCI_ACS_TB 0x02 /* Translation Blocking */ -#define PCI_ACS_RR 0x04 /* P2P Request Redirect */ -#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */ -#define PCI_ACS_UF 0x10 /* Upstream Forwarding */ -#define PCI_ACS_EC 0x20 /* P2P Egress Control */ -#define PCI_ACS_DT 0x40 /* Direct Translated P2P */ +#define PCI_ACS_SV 0x0001 /* Source Validation */ +#define PCI_ACS_TB 0x0002 /* Translation Blocking */ +#define PCI_ACS_RR 0x0004 /* P2P Request Redirect */ +#define PCI_ACS_CR 0x0008 /* P2P Completion Redirect */ +#define PCI_ACS_UF 0x0010 /* Upstream Forwarding */ +#define PCI_ACS_EC 0x0020 /* P2P Egress Control */ +#define PCI_ACS_DT 0x0040 /* Direct Translated P2P */ #define PCI_ACS_EGRESS_BITS 0x05 /* ACS Egress Control Vector Size */ #define PCI_ACS_CTRL 0x06 /* ACS Control Register */ #define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ @@ -993,9 +991,9 @@ #define PCI_EXP_DPC_CAP_DL_ACTIVE 0x1000 /* ERR_COR signal on DL_Active supported */ #define PCI_EXP_DPC_CTL 6 /* DPC control */ -#define PCI_EXP_DPC_CTL_EN_FATAL 0x0001 /* Enable trigger on ERR_FATAL message */ -#define PCI_EXP_DPC_CTL_EN_NONFATAL 0x0002 /* Enable trigger on ERR_NONFATAL message */ -#define PCI_EXP_DPC_CTL_INT_EN 0x0008 /* DPC Interrupt Enable */ +#define PCI_EXP_DPC_CTL_EN_FATAL 0x0001 /* Enable trigger on ERR_FATAL message */ +#define PCI_EXP_DPC_CTL_EN_NONFATAL 0x0002 /* Enable trigger on ERR_NONFATAL message */ +#define PCI_EXP_DPC_CTL_INT_EN 0x0008 /* DPC Interrupt Enable */ #define PCI_EXP_DPC_STATUS 8 /* DPC Status */ #define PCI_EXP_DPC_STATUS_TRIGGER 0x0001 /* Trigger Status */ -- cgit From be20bbcb0a8cb5597cc62b3e28d275919f3431df Mon Sep 17 00:00:00 2001 From: Kazufumi Ikeda Date: Mon, 25 Mar 2019 20:43:19 +0100 Subject: PCI: rcar: Add the initialization of PCIe link in resume_noirq() Reestablish the PCIe link very early in the resume process in case it went down to prevent PCI accesses from hanging the bus. Such accesses can happen early in the PCI resume process, as early as the SUSPEND_RESUME_NOIRQ step, thus the link must be reestablished in the driver resume_noirq() callback. Fixes: e015f88c368d ("PCI: rcar: Add support for R-Car H3 to pcie-rcar") Signed-off-by: Kazufumi Ikeda Signed-off-by: Gaku Inami Signed-off-by: Marek Vasut [lorenzo.pieralisi@arm.com: reformatted commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Acked-by: Wolfram Sang Cc: stable@vger.kernel.org Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index c8febb009454..6a4e435bd35f 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -46,6 +46,7 @@ /* Transfer control */ #define PCIETCTLR 0x02000 +#define DL_DOWN BIT(3) #define CFINIT 1 #define PCIETSTR 0x02004 #define DATA_LINK_ACTIVE 1 @@ -94,6 +95,7 @@ #define MACCTLR 0x011058 #define SPEED_CHANGE BIT(24) #define SCRAMBLE_DISABLE BIT(27) +#define PMSR 0x01105c #define MACS2R 0x011078 #define MACCGSPSETR 0x011084 #define SPCNGRSN BIT(31) @@ -1130,6 +1132,7 @@ static int rcar_pcie_probe(struct platform_device *pdev) pcie = pci_host_bridge_priv(bridge); pcie->dev = dev; + platform_set_drvdata(pdev, pcie); err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL); if (err) @@ -1221,10 +1224,28 @@ err_free_bridge: return err; } +static int rcar_pcie_resume_noirq(struct device *dev) +{ + struct rcar_pcie *pcie = dev_get_drvdata(dev); + + if (rcar_pci_read_reg(pcie, PMSR) && + !(rcar_pci_read_reg(pcie, PCIETCTLR) & DL_DOWN)) + return 0; + + /* Re-establish the PCIe link */ + rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR); + return rcar_pcie_wait_for_dl(pcie); +} + +static const struct dev_pm_ops rcar_pcie_pm_ops = { + .resume_noirq = rcar_pcie_resume_noirq, +}; + static struct platform_driver rcar_pcie_driver = { .driver = { .name = "rcar-pcie", .of_match_table = rcar_pcie_of_match, + .pm = &rcar_pcie_pm_ops, .suppress_bind_attrs = true, }, .probe = rcar_pcie_probe, -- cgit From 05f151a73ec2b23ffbff706e5203e729a995cdc2 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 4 Mar 2019 21:34:48 +0000 Subject: PCI: hv: Fix a memory leak in hv_eject_device_work() When a device is created in new_pcichild_device(), hpdev->refs is set to 2 (i.e. the initial value of 1 plus the get_pcichild()). When we hot remove the device from the host, in a Linux VM we first call hv_pci_eject_device(), which increases hpdev->refs by get_pcichild() and then schedules a work of hv_eject_device_work(), so hpdev->refs becomes 3 (let's ignore the paired get/put_pcichild() in other places). But in hv_eject_device_work(), currently we only call put_pcichild() twice, meaning the 'hpdev' struct can't be freed in put_pcichild(). Add one put_pcichild() to fix the memory leak. The device can also be removed when we run "rmmod pci-hyperv". On this path (hv_pci_remove() -> hv_pci_bus_exit() -> hv_pci_devices_present()), hpdev->refs is 2, and we do correctly call put_pcichild() twice in pci_devices_present_work(). Fixes: 4daace0d8ce8 ("PCI: hv: Add paravirtual PCI front-end for Microsoft Hyper-V VMs") Signed-off-by: Dexuan Cui [lorenzo.pieralisi@arm.com: commit log rework] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Stephen Hemminger Reviewed-by: Michael Kelley Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-hyperv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 95441a35eceb..30f16b882746 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1900,6 +1900,9 @@ static void hv_eject_device_work(struct work_struct *work) sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt, VM_PKT_DATA_INBAND, 0); + /* For the get_pcichild() in hv_pci_eject_device() */ + put_pcichild(hpdev); + /* For the two refs got in new_pcichild_device() */ put_pcichild(hpdev); put_pcichild(hpdev); put_hvpcibus(hpdev->hbus); -- cgit From 15becc2b56c6eda3d9bf5ae993bafd5661c1fad1 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 4 Mar 2019 21:34:48 +0000 Subject: PCI: hv: Add hv_pci_remove_slots() when we unload the driver When we unload the pci-hyperv host controller driver, the host does not send us a PCI_EJECT message. In this case we also need to make sure the sysfs PCI slot directory is removed, otherwise a command on a slot file eg: "cat /sys/bus/pci/slots/2/address" will trigger a "BUG: unable to handle kernel paging request" and, if we unload/reload the driver several times we would end up with stale slot entries in PCI slot directories in /sys/bus/pci/slots/ root@localhost:~# ls -rtl /sys/bus/pci/slots/ total 0 drwxr-xr-x 2 root root 0 Feb 7 10:49 2 drwxr-xr-x 2 root root 0 Feb 7 10:49 2-1 drwxr-xr-x 2 root root 0 Feb 7 10:51 2-2 Add the missing code to remove the PCI slot and fix the current behaviour. Fixes: a15f2c08c708 ("PCI: hv: support reporting serial number as slot information") Signed-off-by: Dexuan Cui [lorenzo.pieralisi@arm.com: reformatted the log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Stephen Hemminger Reviewed-by: Michael Kelley Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-hyperv.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 30f16b882746..b489412e3502 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1486,6 +1486,21 @@ static void hv_pci_assign_slots(struct hv_pcibus_device *hbus) } } +/* + * Remove entries in sysfs pci slot directory. + */ +static void hv_pci_remove_slots(struct hv_pcibus_device *hbus) +{ + struct hv_pci_dev *hpdev; + + list_for_each_entry(hpdev, &hbus->children, list_entry) { + if (!hpdev->pci_slot) + continue; + pci_destroy_slot(hpdev->pci_slot); + hpdev->pci_slot = NULL; + } +} + /** * create_root_hv_pci_bus() - Expose a new root PCI bus * @hbus: Root PCI bus, as understood by this driver @@ -2680,6 +2695,7 @@ static int hv_pci_remove(struct hv_device *hdev) pci_lock_rescan_remove(); pci_stop_root_bus(hbus->pci_bus); pci_remove_root_bus(hbus->pci_bus); + hv_pci_remove_slots(hbus); pci_unlock_rescan_remove(); hbus->state = hv_pcibus_removed; } -- cgit From 340d455699400f2c2c0f9b3f703ade3085cdb501 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 4 Mar 2019 21:34:49 +0000 Subject: PCI: hv: Add pci_destroy_slot() in pci_devices_present_work(), if necessary When we hot-remove a device, usually the host sends us a PCI_EJECT message, and a PCI_BUS_RELATIONS message with bus_rel->device_count == 0. When we execute the quick hot-add/hot-remove test, the host may not send us the PCI_EJECT message if the guest has not fully finished the initialization by sending the PCI_RESOURCES_ASSIGNED* message to the host, so it's potentially unsafe to only depend on the pci_destroy_slot() in hv_eject_device_work() because the code path create_root_hv_pci_bus() -> hv_pci_assign_slots() is not called in this case. Note: in this case, the host still sends the guest a PCI_BUS_RELATIONS message with bus_rel->device_count == 0. In the quick hot-add/hot-remove test, we can have such a race before the code path pci_devices_present_work() -> new_pcichild_device() adds the new device into the hbus->children list, we may have already received the PCI_EJECT message, and since the tasklet handler hv_pci_onchannelcallback() may fail to find the "hpdev" by calling get_pcichild_wslot(hbus, dev_message->wslot.slot) hv_pci_eject_device() is not called; Later, by continuing execution create_root_hv_pci_bus() -> hv_pci_assign_slots() creates the slot and the PCI_BUS_RELATIONS message with bus_rel->device_count == 0 removes the device from hbus->children, and we end up being unable to remove the slot in hv_pci_remove() -> hv_pci_remove_slots() Remove the slot in pci_devices_present_work() when the device is removed to address this race. pci_devices_present_work() and hv_eject_device_work() run in the singled-threaded hbus->wq, so there is not a double-remove issue for the slot. We cannot offload hv_pci_eject_device() from hv_pci_onchannelcallback() to the workqueue, because we need the hv_pci_onchannelcallback() synchronously call hv_pci_eject_device() to poll the channel ringbuffer to work around the "hangs in hv_compose_msi_msg()" issue fixed in commit de0aa7b2f97d ("PCI: hv: Fix 2 hang issues in hv_compose_msi_msg()") Fixes: a15f2c08c708 ("PCI: hv: support reporting serial number as slot information") Signed-off-by: Dexuan Cui [lorenzo.pieralisi@arm.com: rewritten commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Stephen Hemminger Reviewed-by: Michael Kelley Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-hyperv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index b489412e3502..82acd6155adf 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1776,6 +1776,10 @@ static void pci_devices_present_work(struct work_struct *work) hpdev = list_first_entry(&removed, struct hv_pci_dev, list_entry); list_del(&hpdev->list_entry); + + if (hpdev->pci_slot) + pci_destroy_slot(hpdev->pci_slot); + put_pcichild(hpdev); } -- cgit From 699ca30162686bf305cdf94861be02eb0cf9bda2 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Mon, 25 Mar 2019 17:19:09 -0500 Subject: PCI: xilinx: Check for __get_free_pages() failure If __get_free_pages() fails, return -ENOMEM to avoid a NULL pointer dereference. Signed-off-by: Kangjie Lu Signed-off-by: Lorenzo Pieralisi Reviewed-by: Steven Price Reviewed-by: Mukesh Ojha --- drivers/pci/controller/pcie-xilinx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c index 9bd1a35cd5d8..5bf3af3b28e6 100644 --- a/drivers/pci/controller/pcie-xilinx.c +++ b/drivers/pci/controller/pcie-xilinx.c @@ -336,14 +336,19 @@ static const struct irq_domain_ops msi_domain_ops = { * xilinx_pcie_enable_msi - Enable MSI support * @port: PCIe port information */ -static void xilinx_pcie_enable_msi(struct xilinx_pcie_port *port) +static int xilinx_pcie_enable_msi(struct xilinx_pcie_port *port) { phys_addr_t msg_addr; port->msi_pages = __get_free_pages(GFP_KERNEL, 0); + if (!port->msi_pages) + return -ENOMEM; + msg_addr = virt_to_phys((void *)port->msi_pages); pcie_write(port, 0x0, XILINX_PCIE_REG_MSIBASE1); pcie_write(port, msg_addr, XILINX_PCIE_REG_MSIBASE2); + + return 0; } /* INTx Functions */ @@ -498,6 +503,7 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port) struct device *dev = port->dev; struct device_node *node = dev->of_node; struct device_node *pcie_intc_node; + int ret; /* Setup INTx */ pcie_intc_node = of_get_next_child(node, NULL); @@ -526,7 +532,9 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port) return -ENODEV; } - xilinx_pcie_enable_msi(port); + ret = xilinx_pcie_enable_msi(port); + if (ret) + return ret; } return 0; -- cgit From 91e0a58e663ffdae2c96a27541794ab5a6fefb22 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:36 +0800 Subject: PCI: dwc: pci-dra7xx: Fix a leaked reference by adding missing of_node_put() The call to of_get_next_child() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/dwc/pci-dra7xx.c:252:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 241, but without a corresponding object release within this function. ./drivers/pci/controller/dwc/pci-dra7xx.c:255:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 241, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: linux-omap@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index ae84a69ae63a..627c91da5701 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -247,6 +247,7 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp) dra7xx->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, &intx_domain_ops, pp); + of_node_put(pcie_intc_node); if (!dra7xx->irq_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); return -ENODEV; -- cgit From e12bfa013c0972dd94c2f849e05c87f5e1913e96 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:37 +0800 Subject: PCI: uniphier: Fix a leaked reference by adding missing of_node_put() The call to of_get_child_by_name() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/dwc/pcie-uniphier.c:283:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 274, but without a corresponding object release within this function. ./drivers/pci/controller/dwc/pcie-uniphier.c:290:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 274, but without a corresponding object release within this function. ./drivers/pci/controller/dwc/pcie-uniphier.c:296:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 274, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Kunihiko Hayashi Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Masahiro Yamada Cc: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/dwc/pcie-uniphier.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index d5dc40289cce..3f30ee4a00b3 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -270,6 +270,7 @@ static int uniphier_pcie_config_legacy_irq(struct pcie_port *pp) struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); struct device_node *np = pci->dev->of_node; struct device_node *np_intc; + int ret = 0; np_intc = of_get_child_by_name(np, "legacy-interrupt-controller"); if (!np_intc) { @@ -280,20 +281,24 @@ static int uniphier_pcie_config_legacy_irq(struct pcie_port *pp) pp->irq = irq_of_parse_and_map(np_intc, 0); if (!pp->irq) { dev_err(pci->dev, "Failed to get an IRQ entry in legacy-interrupt-controller\n"); - return -EINVAL; + ret = -EINVAL; + goto out_put_node; } priv->legacy_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX, &uniphier_intx_domain_ops, pp); if (!priv->legacy_irq_domain) { dev_err(pci->dev, "Failed to get INTx domain\n"); - return -ENODEV; + ret = -ENODEV; + goto out_put_node; } irq_set_chained_handler_and_data(pp->irq, uniphier_pcie_irq_handler, pp); - return 0; +out_put_node: + of_node_put(np_intc); + return ret; } static int uniphier_pcie_host_init(struct pcie_port *pp) -- cgit From b35c0e4543945fe9b21e6ed9ab72cdb5efb30718 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:38 +0800 Subject: PCI: dwc: layerscape: Fix a leaked reference by adding missing of_node_put() The call to of_parse_phandle() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. Detected by coccinelle with the following warnings: ./drivers/pci/controller/dwc/pci-layerscape.c:204:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 198, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Minghuan Lian Cc: Mingkai Hu Cc: Roy Zang Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/dwc/pci-layerscape.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index ce45bde29bf8..3a5fa26d5e56 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -201,6 +201,7 @@ static int ls_pcie_msi_host_init(struct pcie_port *pp) return -EINVAL; } + of_node_put(msi_node); return 0; } -- cgit From 69adea738eb2be70b4753dbb60eb1de9abbfb4dc Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:39 +0800 Subject: PCI: rockchip: Fix a leaked reference by adding missing of_node_put() The call to of_get_child_by_name() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/pcie-rockchip-host.c:729:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 718, but without a corresponding object release within this function. ./drivers/pci/controller/pcie-rockchip-host.c:732:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 718, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Shawn Lin Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Heiko Stuebner Cc: linux-pci@vger.kernel.org Cc: linux-rockchip@lists.infradead.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/pcie-rockchip-host.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index 1372d270764f..8d20f1793a61 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -724,6 +724,7 @@ static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip) rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX, &intx_domain_ops, rockchip); + of_node_put(intc); if (!rockchip->irq_domain) { dev_err(dev, "failed to get a INTx IRQ domain\n"); return -EINVAL; -- cgit From 3842f5166bf1ef286fe7a39f262b5c9581308366 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:40 +0800 Subject: PCI: aardvark: Fix a leaked reference by adding missing of_node_put() The call to of_get_next_child() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/pci-aardvark.c:826:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 798, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Thomas Petazzoni Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/pci-aardvark.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index eb58dfdaba1b..134e0306ff00 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -794,6 +794,7 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) struct device_node *node = dev->of_node; struct device_node *pcie_intc_node; struct irq_chip *irq_chip; + int ret = 0; pcie_intc_node = of_get_next_child(node, NULL); if (!pcie_intc_node) { @@ -806,8 +807,8 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-irq", dev_name(dev)); if (!irq_chip->name) { - of_node_put(pcie_intc_node); - return -ENOMEM; + ret = -ENOMEM; + goto out_put_node; } irq_chip->irq_mask = advk_pcie_irq_mask; @@ -819,11 +820,13 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) &advk_pcie_irq_domain_ops, pcie); if (!pcie->irq_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); - of_node_put(pcie_intc_node); - return -ENOMEM; + ret = -ENOMEM; + goto out_put_node; } - return 0; +out_put_node: + of_node_put(pcie_intc_node); + return ret; } static void advk_pcie_remove_irq_domain(struct advk_pcie *pcie) -- cgit From 8956388d3670c5050825a6410761843ffd7e4848 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:41 +0800 Subject: PCI: iproc: Fix a leaked reference by adding missing of_node_put() The call to of_parse_phandle() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. iproc_msi_init() also calls of_node_get() to increase refcount: proc_msi_init() -> iproc_msi_alloc_domains() -> pci_msi_create_irq_domain() -> msi_create_irq_domain() -> irq_domain_create_linear() -> __irq_domain_add() so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/pcie-iproc.c:1323:3-9: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 1299, but without a corresponding object release within this function. ./drivers/pci/controller/pcie-iproc.c:1330:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 1299, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Ray Jui Cc: Scott Branden Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/pcie-iproc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index c20fd6bd68fd..9998c5cb44c4 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -1320,14 +1320,18 @@ static int iproc_pcie_msi_enable(struct iproc_pcie *pcie) if (pcie->need_msi_steer) { ret = iproc_pcie_msi_steer(pcie, msi_node); if (ret) - return ret; + goto out_put_node; } /* * If another MSI controller is being used, the call below should fail * but that is okay */ - return iproc_msi_init(pcie, msi_node); + ret = iproc_msi_init(pcie, msi_node); + +out_put_node: + of_node_put(msi_node); + return ret; } static void iproc_pcie_msi_disable(struct iproc_pcie *pcie) -- cgit From ff7a5a0a8562434f114035a5a4cbbeec5cb6320c Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:42 +0800 Subject: PCI: mediatek: Fix a leaked reference by adding missing of_node_put() The call to of_get_next_child() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/pcie-mediatek.c:577:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 567, but without a corresponding object release within this function. ./drivers/pci/controller/pcie-mediatek.c:583:3-9: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 567, but without a corresponding object release within this function. ./drivers/pci/controller/pcie-mediatek.c:586:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 567, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Acked-by: Honghui Zhang Cc: Ryder Lee Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Matthias Brugger Cc: linux-pci@vger.kernel.org Cc: linux-mediatek@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org --- drivers/pci/controller/pcie-mediatek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 0b6c72804e03..5c485de60466 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -578,6 +578,7 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, port->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, &intx_domain_ops, port); + of_node_put(pcie_intc_node); if (!port->irq_domain) { dev_err(dev, "failed to get INTx IRQ domain\n"); return -ENODEV; -- cgit From 73b9e4d3309c540d9c855322e6ccedfa8ef698fc Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 1 Mar 2019 10:22:15 +0530 Subject: PCI: iproc: Add CRS check in config read The IPROC PCIe host controller implementation returns CFG_RETRY_STATUS (0xffff0001) data when it receives a CRS completion, regardless of the address of the read or the CRS Software Visibility Enable bit. As a workaround the driver retries in software any read that returns CFG_RETRY_STATUS even though, for reads of registers that are not Vendor ID, the register value can correspond to CFG_RETRY_STATUS; this situation would cause a timeout and failure of reading a valid register value. IPROC PCIe host controller PAXB v2 has a register to show config read status flags like SC, UR, CRS and CA. Using this status flag, an extra check is added to confirm the CRS using status flags before reissuing a config read, fixing the issue. Signed-off-by: Srinath Mannam [lorenzo.pieralisi@arm.com: rewrote commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Scott Branden --- drivers/pci/controller/pcie-iproc.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index c20fd6bd68fd..b88225577a8f 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -60,6 +60,10 @@ #define APB_ERR_EN_SHIFT 0 #define APB_ERR_EN BIT(APB_ERR_EN_SHIFT) +#define CFG_RD_SUCCESS 0 +#define CFG_RD_UR 1 +#define CFG_RD_CRS 2 +#define CFG_RD_CA 3 #define CFG_RETRY_STATUS 0xffff0001 #define CFG_RETRY_STATUS_TIMEOUT_US 500000 /* 500 milliseconds */ @@ -289,6 +293,9 @@ enum iproc_pcie_reg { IPROC_PCIE_IARR4, IPROC_PCIE_IMAP4, + /* config read status */ + IPROC_PCIE_CFG_RD_STATUS, + /* link status */ IPROC_PCIE_LINK_STATUS, @@ -350,6 +357,7 @@ static const u16 iproc_pcie_reg_paxb_v2[] = { [IPROC_PCIE_IMAP3] = 0xe08, [IPROC_PCIE_IARR4] = 0xe68, [IPROC_PCIE_IMAP4] = 0xe70, + [IPROC_PCIE_CFG_RD_STATUS] = 0xee0, [IPROC_PCIE_LINK_STATUS] = 0xf0c, [IPROC_PCIE_APB_ERR_EN] = 0xf40, }; @@ -474,10 +482,12 @@ static void __iomem *iproc_pcie_map_ep_cfg_reg(struct iproc_pcie *pcie, return (pcie->base + offset); } -static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p) +static unsigned int iproc_pcie_cfg_retry(struct iproc_pcie *pcie, + void __iomem *cfg_data_p) { int timeout = CFG_RETRY_STATUS_TIMEOUT_US; unsigned int data; + u32 status; /* * As per PCIe spec r3.1, sec 2.3.2, CRS Software Visibility only @@ -498,6 +508,15 @@ static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p) */ data = readl(cfg_data_p); while (data == CFG_RETRY_STATUS && timeout--) { + /* + * CRS state is set in CFG_RD status register + * This will handle the case where CFG_RETRY_STATUS is + * valid config data. + */ + status = iproc_pcie_read_reg(pcie, IPROC_PCIE_CFG_RD_STATUS); + if (status != CFG_RD_CRS) + return data; + udelay(1); data = readl(cfg_data_p); } @@ -576,7 +595,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, if (!cfg_data_p) return PCIBIOS_DEVICE_NOT_FOUND; - data = iproc_pcie_cfg_retry(cfg_data_p); + data = iproc_pcie_cfg_retry(pcie, cfg_data_p); *val = data; if (size <= 2) -- cgit From ea2df11f7221a149546e337f5404e8d1c932c104 Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 1 Mar 2019 10:22:16 +0530 Subject: PCI: iproc: Allow outbound configuration for 32-bit I/O region The IProc host controller has I/O memory windows allocated in the AXI memory map that can be used to address PCI I/O memory space. Mapping from AXI memory windows to PCI outbound memory windows is carried out in the host controller through OARR/OMAP registers pairs that permit to define power of two region size AXI<->PCI mappings, the smallest of which is 128MB. Current code enables AXI memory window to PCI outbound memory window mapping only for AXI windows matching one of the OARR/OMAP window sizes, that are SoC dependent and the smallest of which is 128MB. Some SoCs implementing the IProc host controller have a 32-bit AXI memory window into PCI I/O memory space, eg: Base address | Size ----------------------------- (1) 0x42000000 | 0x2000000 (2) 0x400000000 | 0x80000000 but its size (32MB - (1) above) is smaller than the smallest AXI<->PCI region size provided by OARR (128MB), so the current driver rejects mappings for the 32-bit region making the IProc host controller driver unusable on 32-bit systems. However, there is no reason why the 32-bit I/O memory window cannot be enabled by mapping it through an OARR/OMAP region bigger in size (ie 32-bit AXI window size is 32MB but can be mapped using a 128MB OARR/OMAP region). Allow outbound window configuration of I/O memory windows that are smaller in size than the host controller OARR/OMAP region, so that the 32-bit AXI memory window can actually be enabled, making the IProc host controller operational on 32-bit systems. Link: https://lore.kernel.org/linux-pci/1551415936-30174-3-git-send-email-srinath.mannam@broadcom.com/ Signed-off-by: Srinath Mannam Signed-off-by: Abhishek Shah Signed-off-by: Ray Jui [lorenzo.pieralisi@arm.com: rewrote the commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Scott Branden --- drivers/pci/controller/pcie-iproc.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index b88225577a8f..080f142ce24d 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -955,8 +955,25 @@ static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr, resource_size_t window_size = ob_map->window_sizes[size_idx] * SZ_1M; - if (size < window_size) - continue; + /* + * Keep iterating until we reach the last window and + * with the minimal window size at index zero. In this + * case, we take a compromise by mapping it using the + * minimum window size that can be supported + */ + if (size < window_size) { + if (size_idx > 0 || window_idx > 0) + continue; + + /* + * For the corner case of reaching the minimal + * window size that can be supported on the + * last window + */ + axi_addr = ALIGN_DOWN(axi_addr, window_size); + pci_addr = ALIGN_DOWN(pci_addr, window_size); + size = window_size; + } if (!IS_ALIGNED(axi_addr, window_size) || !IS_ALIGNED(pci_addr, window_size)) { -- cgit From b2c615457b2891931d3e1eec5edf4b8b380e48fb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:40:56 +0100 Subject: PCI: rcar: Clean up remaining macros defining bits Replace macros using constants with BIT()s instead, no functional change. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org To: linux-pci@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index c8febb009454..5b8736f0cd6b 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -46,14 +46,14 @@ /* Transfer control */ #define PCIETCTLR 0x02000 -#define CFINIT 1 +#define CFINIT BIT(0) #define PCIETSTR 0x02004 -#define DATA_LINK_ACTIVE 1 +#define DATA_LINK_ACTIVE BIT(0) #define PCIEERRFR 0x02020 #define UNSUPPORTED_REQUEST BIT(4) #define PCIEMSIFR 0x02044 #define PCIEMSIALR 0x02048 -#define MSIFE 1 +#define MSIFE BIT(0) #define PCIEMSIAUR 0x0204c #define PCIEMSIIER 0x02050 -- cgit From 7dc13a7939e09caa20ed3a0a8417f23b4ec4e6e2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:40:57 +0100 Subject: PCI: rcar: Replace unsigned long with u32/unsigned int in register accessors Replace unsigned long with u32 and unsigned int in register accessor functions, since they access 32bit registers. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 5b8736f0cd6b..3db693b4410e 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -152,14 +152,13 @@ struct rcar_pcie { struct rcar_msi msi; }; -static void rcar_pci_write_reg(struct rcar_pcie *pcie, unsigned long val, - unsigned long reg) +static void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, + unsigned int reg) { writel(val, pcie->base + reg); } -static unsigned long rcar_pci_read_reg(struct rcar_pcie *pcie, - unsigned long reg) +static u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg) { return readl(pcie->base + reg); } -- cgit From d8fa26609b91394f9f2d17ae6956a2c3e3632fbb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:40:58 +0100 Subject: PCI: rcar: Replace various variable types with unsigned ones for register values Replace various variable types with u32 or unsigned int type for variables holding register values, since the registers are 32bit. Note that rcar_pcie_msi_irq() still uses various variable types because both find_first_bit() and __fls() require various variable types as an argument. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 3db693b4410e..6699211fdc9a 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -170,7 +170,7 @@ enum { static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) { - int shift = 8 * (where & 3); + unsigned int shift = 8 * (where & 3); u32 val = rcar_pci_read_reg(pcie, where & ~3); val &= ~(mask << shift); @@ -180,7 +180,7 @@ static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) static u32 rcar_read_conf(struct rcar_pcie *pcie, int where) { - int shift = 8 * (where & 3); + unsigned int shift = 8 * (where & 3); u32 val = rcar_pci_read_reg(pcie, where & ~3); return val >> shift; @@ -191,7 +191,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie, unsigned char access_type, struct pci_bus *bus, unsigned int devfn, int where, u32 *data) { - int dev, func, reg, index; + unsigned int dev, func, reg, index; dev = PCI_SLOT(devfn); func = PCI_FUNC(devfn); @@ -295,8 +295,9 @@ static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { struct rcar_pcie *pcie = bus->sysdata; - int shift, ret; + unsigned int shift; u32 data; + int ret; ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ, bus, devfn, where, &data); @@ -506,10 +507,10 @@ static int phy_wait_for_ack(struct rcar_pcie *pcie) } static void phy_write_reg(struct rcar_pcie *pcie, - unsigned int rate, unsigned int addr, - unsigned int lane, unsigned int data) + unsigned int rate, u32 addr, + unsigned int lane, u32 data) { - unsigned long phyaddr; + u32 phyaddr; phyaddr = WRITE_CMD | ((rate & 1) << RATE_POS) | @@ -1117,7 +1118,7 @@ static int rcar_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rcar_pcie *pcie; - unsigned int data; + u32 data; int err; int (*phy_init_fn)(struct rcar_pcie *); struct pci_host_bridge *bridge; -- cgit From 29ffa6db40430e7c89fb1fc37cd78a90b27d4d2a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:40:59 +0100 Subject: PCI: rcar: Replace (8 * n) with (BITS_PER_BYTE * n) Replace (8 * n) with (BITS_PER_BYTE * n) to make bit shift operations consistent. No functional change. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 6699211fdc9a..96210768e774 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -170,7 +170,7 @@ enum { static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) { - unsigned int shift = 8 * (where & 3); + unsigned int shift = BITS_PER_BYTE * (where & 3); u32 val = rcar_pci_read_reg(pcie, where & ~3); val &= ~(mask << shift); @@ -180,7 +180,7 @@ static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) static u32 rcar_read_conf(struct rcar_pcie *pcie, int where) { - unsigned int shift = 8 * (where & 3); + unsigned int shift = BITS_PER_BYTE * (where & 3); u32 val = rcar_pci_read_reg(pcie, where & ~3); return val >> shift; @@ -280,9 +280,9 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, } if (size == 1) - *val = (*val >> (8 * (where & 3))) & 0xff; + *val = (*val >> (BITS_PER_BYTE * (where & 3))) & 0xff; else if (size == 2) - *val = (*val >> (8 * (where & 2))) & 0xffff; + *val = (*val >> (BITS_PER_BYTE * (where & 2))) & 0xffff; dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n", bus->number, devfn, where, size, (unsigned long)*val); @@ -308,11 +308,11 @@ static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, bus->number, devfn, where, size, (unsigned long)val); if (size == 1) { - shift = 8 * (where & 3); + shift = BITS_PER_BYTE * (where & 3); data &= ~(0xff << shift); data |= ((val & 0xff) << shift); } else if (size == 2) { - shift = 8 * (where & 2); + shift = BITS_PER_BYTE * (where & 2); data &= ~(0xffff << shift); data |= ((val & 0xffff) << shift); } else -- cgit From 42a58f73e9ea4002692732d45a6ea1a0df9e125b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:41:00 +0100 Subject: PCI: rcar: Clean up debug messages Drop useless casts from debug messages, they are no longer needed due to the data type cleanup. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 96210768e774..c6013f95bdb2 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -284,8 +284,8 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, else if (size == 2) *val = (*val >> (BITS_PER_BYTE * (where & 2))) & 0xffff; - dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n", - bus->number, devfn, where, size, (unsigned long)*val); + dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08x\n", + bus->number, devfn, where, size, *val); return ret; } @@ -304,8 +304,8 @@ static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, if (ret != PCIBIOS_SUCCESSFUL) return ret; - dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n", - bus->number, devfn, where, size, (unsigned long)val); + dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08x\n", + bus->number, devfn, where, size, val); if (size == 1) { shift = BITS_PER_BYTE * (where & 3); -- cgit From 954b4b752a4c4e963b017ed8cef4c453c5ed308d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:41:01 +0100 Subject: PCI: rcar: Fix 64bit MSI message address handling The MSI message address in the RC address space can be 64 bit. The R-Car PCIe RC supports such a 64bit MSI message address as well. The code currently uses virt_to_phys(__get_free_pages()) to obtain a reserved page for the MSI message address, and the return value of which can be a 64 bit physical address on 64 bit system. However, the driver only programs PCIEMSIALR register with the bottom 32 bits of the virt_to_phys(__get_free_pages()) return value and does not program the top 32 bits into PCIEMSIAUR, but rather programs the PCIEMSIAUR register with 0x0. This worked fine on older 32 bit R-Car SoCs, however may fail on new 64 bit R-Car SoCs. Since from a PCIe controller perspective, an inbound MSI is a memory write to a special address (in case of this controller, defined by the value in PCIEMSIAUR:PCIEMSIALR), which triggers an interrupt, but never hits the DRAM _and_ because allocation of an MSI by a PCIe card driver obtains the MSI message address by reading PCIEMSIAUR:PCIEMSIALR in rcar_msi_setup_irqs(), incorrectly programmed PCIEMSIAUR cannot cause memory corruption or other issues. There is however the possibility that if virt_to_phys(__get_free_pages()) returned address above the 32bit boundary _and_ PCIEMSIAUR was programmed to 0x0 _and_ if the system had physical RAM at the address matching the value of PCIEMSIALR, a PCIe card driver could allocate a buffer with a physical address matching the value of PCIEMSIALR and a remote write to such a buffer by a PCIe card would trigger a spurious MSI. Fixes: e015f88c368d ("PCI: rcar: Add support for R-Car H3 to pcie-rcar") Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index c6013f95bdb2..a25527185bf1 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -890,7 +890,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) { struct device *dev = pcie->dev; struct rcar_msi *msi = &pcie->msi; - unsigned long base; + phys_addr_t base; int err, i; mutex_init(&msi->lock); @@ -931,8 +931,8 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) msi->pages = __get_free_pages(GFP_KERNEL, 0); base = virt_to_phys((void *)msi->pages); - rcar_pci_write_reg(pcie, base | MSIFE, PCIEMSIALR); - rcar_pci_write_reg(pcie, 0, PCIEMSIAUR); + rcar_pci_write_reg(pcie, lower_32_bits(base) | MSIFE, PCIEMSIALR); + rcar_pci_write_reg(pcie, upper_32_bits(base), PCIEMSIAUR); /* enable all MSI interrupts */ rcar_pci_write_reg(pcie, 0xffffffff, PCIEMSIIER); -- cgit From f0d14edd2ba43b995bef4dd5da5ffe0ae19321a1 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Fri, 15 Mar 2019 02:29:43 -0500 Subject: PCI: rcar: Fix a potential NULL pointer dereference In case __get_free_pages() fails and returns NULL, fix the return value to -ENOMEM and release resources to avoid dereferencing a NULL pointer. Signed-off-by: Kangjie Lu Signed-off-by: Lorenzo Pieralisi Reviewed-by: Ulrich Hecht Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/pci/controller/pcie-rcar.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index a25527185bf1..0004b6457124 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -929,6 +929,10 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) /* setup MSI data target */ msi->pages = __get_free_pages(GFP_KERNEL, 0); + if (!msi->pages) { + err = -ENOMEM; + goto err; + } base = virt_to_phys((void *)msi->pages); rcar_pci_write_reg(pcie, lower_32_bits(base) | MSIFE, PCIEMSIALR); -- cgit From a27beb5820d1a52b1e2863a4ae5545a1dd4ab35a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 17 Mar 2019 10:34:45 +0100 Subject: PCI: rcar: Do not shadow the 'irq' variable The sparse tool rightfully detects: drivers/pci/controller/pcie-rcar.c:741:30: warning: symbol 'irq' shadows an earlier one Fix it now to avoid future surprises and for good coding style. No functional change intended. Signed-off-by: Wolfram Sang [lorenzo.pieralisi@arm.com: commit log refactoring] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/pci/controller/pcie-rcar.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 0004b6457124..e4cebeb18470 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -738,15 +738,15 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data) while (reg) { unsigned int index = find_first_bit(®, 32); - unsigned int irq; + unsigned int msi_irq; /* clear the interrupt */ rcar_pci_write_reg(pcie, 1 << index, PCIEMSIFR); - irq = irq_find_mapping(msi->domain, index); - if (irq) { + msi_irq = irq_find_mapping(msi->domain, index); + if (msi_irq) { if (test_bit(index, msi->used)) - generic_handle_irq(irq); + generic_handle_irq(msi_irq); else dev_info(dev, "unhandled MSI\n"); } else { -- cgit From 1beb55126937aff7601ddfca8df29870d29f2d86 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:20 +0530 Subject: PCI: keystone: Cleanup interrupt related macros No functional change. Change both MSI interrupt and legacy interrupt related macros to take an additional argument in order to return the correct register offset. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 14f2b0b4ed5e..5286a480f76b 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -52,17 +52,17 @@ /* IRQ register defines */ #define IRQ_EOI 0x050 -#define IRQ_STATUS 0x184 -#define IRQ_ENABLE_SET 0x188 -#define IRQ_ENABLE_CLR 0x18c #define MSI_IRQ 0x054 -#define MSI0_IRQ_STATUS 0x104 -#define MSI0_IRQ_ENABLE_SET 0x108 -#define MSI0_IRQ_ENABLE_CLR 0x10c -#define IRQ_STATUS 0x184 +#define MSI_IRQ_STATUS(n) (0x104 + ((n) << 4)) +#define MSI_IRQ_ENABLE_SET(n) (0x108 + ((n) << 4)) +#define MSI_IRQ_ENABLE_CLR(n) (0x10c + ((n) << 4)) #define MSI_IRQ_OFFSET 4 +#define IRQ_STATUS(n) (0x184 + ((n) << 4)) +#define IRQ_ENABLE_SET(n) (0x188 + ((n) << 4)) +#define INTx_EN BIT(0) + #define ERR_IRQ_STATUS 0x1c4 #define ERR_IRQ_ENABLE_SET 0x1c8 #define ERR_AER BIT(5) /* ECRC error */ @@ -142,7 +142,7 @@ static void ks_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) u32 pending, vector; int src, virq; - pending = ks_pcie_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4)); + pending = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset)); /* * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit @@ -169,7 +169,7 @@ static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) ks_pcie = to_keystone_pcie(pci); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_pcie_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_STATUS(reg_offset), BIT(bit_pos)); ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET); } @@ -181,7 +181,7 @@ static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq) struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset), BIT(bit_pos)); } @@ -192,7 +192,7 @@ static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq) struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset), BIT(bit_pos)); } @@ -206,7 +206,7 @@ static void ks_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) int i; for (i = 0; i < PCI_NUM_INTX; i++) - ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1); + ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), 0x1); } static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, @@ -217,7 +217,7 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, u32 pending; int virq; - pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS + (offset << 4)); + pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(offset)); if (BIT(0) & pending) { virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset); -- cgit From 1146c2953dcbd5eb01e415f528015206479e8fe3 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:21 +0530 Subject: PCI: keystone: Add separate functions for configuring MSI and legacy interrupt ks_pcie_get_irq_controller_info() is used to configure both MSI and legacy interrupt. This will prevent MSI or legacy interrupt specific intializations. Add separate functions to configure MSI and legacy interrupts. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 181 +++++++++++++++--------------- 1 file changed, 89 insertions(+), 92 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 5286a480f76b..47f0dcf638f2 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -87,11 +87,9 @@ struct keystone_pcie { struct dw_pcie *pci; /* PCI Device ID */ u32 device_id; - int num_legacy_host_irqs; int legacy_host_irqs[PCI_NUM_INTX]; struct device_node *legacy_intc_np; - int num_msi_host_irqs; int msi_host_irqs[MAX_MSI_HOST_IRQS]; int num_lanes; u32 num_viewport; @@ -201,14 +199,6 @@ static int ks_pcie_msi_host_init(struct pcie_port *pp) return dw_pcie_allocate_domains(pp); } -static void ks_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) -{ - int i; - - for (i = 0; i < PCI_NUM_INTX; i++) - ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), 0x1); -} - static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset) { @@ -495,17 +485,6 @@ static int __init ks_pcie_dw_host_init(struct keystone_pcie *ks_pcie) ks_pcie->app = *res; - /* Create legacy IRQ domain */ - ks_pcie->legacy_irq_domain = - irq_domain_add_linear(ks_pcie->legacy_intc_np, - PCI_NUM_INTX, - &ks_pcie_legacy_irq_domain_ops, - NULL); - if (!ks_pcie->legacy_irq_domain) { - dev_err(dev, "Failed to add irq domain for legacy irqs\n"); - return -EINVAL; - } - return dw_pcie_host_init(pp); } @@ -622,85 +601,109 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie, - char *controller, int *num_irqs) +static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) { - int temp, max_host_irqs, legacy = 1, *host_irqs; struct device *dev = ks_pcie->pci->dev; - struct device_node *np_pcie = dev->of_node, **np_temp; - - if (!strcmp(controller, "msi-interrupt-controller")) - legacy = 0; - - if (legacy) { - np_temp = &ks_pcie->legacy_intc_np; - max_host_irqs = PCI_NUM_INTX; - host_irqs = &ks_pcie->legacy_host_irqs[0]; - } else { - np_temp = &ks_pcie->msi_intc_np; - max_host_irqs = MAX_MSI_HOST_IRQS; - host_irqs = &ks_pcie->msi_host_irqs[0]; - } + struct device_node *np = ks_pcie->np; + struct device_node *intc_np; + int irq_count, irq, ret, i; - /* interrupt controller is in a child node */ - *np_temp = of_get_child_by_name(np_pcie, controller); - if (!(*np_temp)) { - dev_err(dev, "Node for %s is absent\n", controller); - return -EINVAL; - } + if (!IS_ENABLED(CONFIG_PCI_MSI)) + return 0; - temp = of_irq_count(*np_temp); - if (!temp) { - dev_err(dev, "No IRQ entries in %s\n", controller); - of_node_put(*np_temp); + intc_np = of_get_child_by_name(np, "msi-interrupt-controller"); + if (!intc_np) { + dev_warn(dev, "msi-interrupt-controller node is absent\n"); return -EINVAL; } - if (temp > max_host_irqs) - dev_warn(dev, "Too many %s interrupts defined %u\n", - (legacy ? "legacy" : "MSI"), temp); + irq_count = of_irq_count(intc_np); + if (!irq_count) { + dev_err(dev, "No IRQ entries in msi-interrupt-controller\n"); + ret = -EINVAL; + goto err; + } - /* - * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to - * 7 (MSI) - */ - for (temp = 0; temp < max_host_irqs; temp++) { - host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp); - if (!host_irqs[temp]) - break; + if (irq_count > MAX_MSI_HOST_IRQS) { + dev_warn(dev, "Too many MSI interrupt lines defined %u\n", + irq_count); + irq_count = MAX_MSI_HOST_IRQS; } - of_node_put(*np_temp); + for (i = 0; i < irq_count; i++) { + irq = irq_of_parse_and_map(intc_np, i); + if (!irq) { + ret = -EINVAL; + goto err; + } + ks_pcie->msi_host_irqs[i] = irq; - if (temp) { - *num_irqs = temp; - return 0; + irq_set_chained_handler_and_data(irq, ks_pcie_msi_irq_handler, + ks_pcie); } - return -EINVAL; + of_node_put(intc_np); + return 0; + +err: + of_node_put(intc_np); + return ret; } -static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) +static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie) { - int i; + struct device *dev = ks_pcie->pci->dev; + struct irq_domain *legacy_irq_domain; + struct device_node *np = ks_pcie->np; + struct device_node *intc_np; + int irq_count, irq, ret = 0, i; + + intc_np = of_get_child_by_name(np, "legacy-interrupt-controller"); + if (!intc_np) { + dev_warn(dev, "legacy-interrupt-controller node is absent\n"); + return -EINVAL; + } + + irq_count = of_irq_count(intc_np); + if (!irq_count) { + dev_err(dev, "No IRQ entries in legacy-interrupt-controller\n"); + ret = -EINVAL; + goto err; + } - /* Legacy IRQ */ - for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) { - irq_set_chained_handler_and_data(ks_pcie->legacy_host_irqs[i], + for (i = 0; i < irq_count; i++) { + irq = irq_of_parse_and_map(intc_np, i); + if (!irq) { + ret = -EINVAL; + goto err; + } + ks_pcie->legacy_host_irqs[i] = irq; + + irq_set_chained_handler_and_data(irq, ks_pcie_legacy_irq_handler, ks_pcie); } - ks_pcie_enable_legacy_irqs(ks_pcie); - - /* MSI IRQ */ - if (IS_ENABLED(CONFIG_PCI_MSI)) { - for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) { - irq_set_chained_handler_and_data(ks_pcie->msi_host_irqs[i], - ks_pcie_msi_irq_handler, - ks_pcie); - } + + legacy_irq_domain = + irq_domain_add_linear(intc_np, PCI_NUM_INTX, + &ks_pcie_legacy_irq_domain_ops, NULL); + if (!legacy_irq_domain) { + dev_err(dev, "Failed to add irq domain for legacy irqs\n"); + ret = -EINVAL; + goto err; } + ks_pcie->legacy_irq_domain = legacy_irq_domain; + + for (i = 0; i < PCI_NUM_INTX; i++) + ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), INTx_EN); + +err: + of_node_put(intc_np); + return ret; +} +static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) +{ if (ks_pcie->error_irq > 0) ks_pcie_enable_error_irq(ks_pcie); } @@ -754,6 +757,14 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); int ret; + ret = ks_pcie_config_legacy_irq(ks_pcie); + if (ret) + return ret; + + ret = ks_pcie_config_msi_irq(ks_pcie); + if (ret) + return ret; + dw_pcie_setup_rc(pp); ks_pcie_establish_link(ks_pcie); @@ -803,20 +814,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct device *dev = &pdev->dev; int ret; - ret = ks_pcie_get_irq_controller_info(ks_pcie, - "legacy-interrupt-controller", - &ks_pcie->num_legacy_host_irqs); - if (ret) - return ret; - - if (IS_ENABLED(CONFIG_PCI_MSI)) { - ret = ks_pcie_get_irq_controller_info(ks_pcie, - "msi-interrupt-controller", - &ks_pcie->num_msi_host_irqs); - if (ret) - return ret; - } - /* * Index 0 is the platform interrupt for error interrupt * from RC. This is optional. -- cgit From f6f2900ca9b7c79d304e0cc264b010ed1c86a6b1 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:22 +0530 Subject: PCI: keystone: Use hwirq to get the MSI IRQ number offset ks_pcie_msi_irq_handler() uses 'virq' to get the IRQ number offset. This offset is used to get the correct MSI_IRQ_STATUS register corresponding to the IRQ line that raised the interrupt. There is no guarantee that 'virq' assigned for consecutive hardware IRQ will be contiguous and this might get us an incorrect IRQ number offset. Fix it here by using 'hwirq' to get the IRQ number offset. Since we don't store the 'virq' numbers of all the IRQ numbers, stop checking if irq count is greater than MAX_MSI_HOST_IRQS and remove MAX_MSI_HOST_IRQS. Link: https://lkml.kernel.org/r/bb081d21-7c03-0357-4294-7e92d95d838c@arm.com Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 47f0dcf638f2..fce25a0dcd08 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -74,7 +74,6 @@ #define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \ ERR_NONFATAL | ERR_FATAL | ERR_SYS) -#define MAX_MSI_HOST_IRQS 8 /* PCIE controller device IDs */ #define PCIE_RC_K2HK 0xb008 #define PCIE_RC_K2E 0xb009 @@ -90,7 +89,7 @@ struct keystone_pcie { int legacy_host_irqs[PCI_NUM_INTX]; struct device_node *legacy_intc_np; - int msi_host_irqs[MAX_MSI_HOST_IRQS]; + int msi_host_irq; int num_lanes; u32 num_viewport; struct phy **phy; @@ -553,9 +552,9 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) static void ks_pcie_msi_irq_handler(struct irq_desc *desc) { - unsigned int irq = irq_desc_get_irq(desc); + unsigned int irq = desc->irq_data.hwirq; struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); - u32 offset = irq - ks_pcie->msi_host_irqs[0]; + u32 offset = irq - ks_pcie->msi_host_irq; struct dw_pcie *pci = ks_pcie->pci; struct device *dev = pci->dev; struct irq_chip *chip = irq_desc_get_chip(desc); @@ -606,6 +605,7 @@ static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) struct device *dev = ks_pcie->pci->dev; struct device_node *np = ks_pcie->np; struct device_node *intc_np; + struct irq_data *irq_data; int irq_count, irq, ret, i; if (!IS_ENABLED(CONFIG_PCI_MSI)) @@ -624,19 +624,21 @@ static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) goto err; } - if (irq_count > MAX_MSI_HOST_IRQS) { - dev_warn(dev, "Too many MSI interrupt lines defined %u\n", - irq_count); - irq_count = MAX_MSI_HOST_IRQS; - } - for (i = 0; i < irq_count; i++) { irq = irq_of_parse_and_map(intc_np, i); if (!irq) { ret = -EINVAL; goto err; } - ks_pcie->msi_host_irqs[i] = irq; + + if (!ks_pcie->msi_host_irq) { + irq_data = irq_get_irq_data(irq); + if (!irq_data) { + ret = -EINVAL; + goto err; + } + ks_pcie->msi_host_irq = irq_data->hwirq; + } irq_set_chained_handler_and_data(irq, ks_pcie_msi_irq_handler, ks_pcie); -- cgit From 66c10eca595293cd7a87afea112ca97179924d2a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:23 +0530 Subject: PCI: keystone: Cleanup ks_pcie_msi_irq_handler() ks_pcie_msi_irq_handler() invokes ks_pcie_handle_msi_irq() for handling the interrupts. Having two functions for handling the interrupt was used when keystone PCIe driver was implemented using two files but with commit b492aca35c98 ("PCI: keystone: Merge pci-keystone-dw.c and pci-keystone.c"), which merged the keystone PCIe driver to use a single file, two functions for handling the interrupt handler are not required. Handle MSI interrupt in a single interrupt handler here. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 64 ++++++++++++++----------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index fce25a0dcd08..39542f2c312b 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -105,13 +105,6 @@ struct keystone_pcie { struct resource app; }; -static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset, - u32 *bit_pos) -{ - *reg_offset = offset % 8; - *bit_pos = offset >> 3; -} - static phys_addr_t ks_pcie_get_msi_addr(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -131,31 +124,6 @@ static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset, writel(val, ks_pcie->va_app_base + offset); } -static void ks_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = pci->dev; - u32 pending, vector; - int src, virq; - - pending = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset)); - - /* - * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit - * shows 1, 9, 17, 25 and so forth - */ - for (src = 0; src < 4; src++) { - if (BIT(src) & pending) { - vector = offset + (src << 3); - virq = irq_linear_revmap(pp->irq_domain, vector); - dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", - src, vector, virq); - generic_handle_irq(virq); - } - } -} - static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) { u32 reg_offset, bit_pos; @@ -164,7 +132,9 @@ static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) pci = to_dw_pcie_from_pp(pp); ks_pcie = to_keystone_pcie(pci); - update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); + + reg_offset = irq % 8; + bit_pos = irq >> 3; ks_pcie_app_writel(ks_pcie, MSI_IRQ_STATUS(reg_offset), BIT(bit_pos)); @@ -177,7 +147,9 @@ static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); + reg_offset = irq % 8; + bit_pos = irq >> 3; + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset), BIT(bit_pos)); } @@ -188,7 +160,9 @@ static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); + reg_offset = irq % 8; + bit_pos = irq >> 3; + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset), BIT(bit_pos)); } @@ -556,8 +530,10 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); u32 offset = irq - ks_pcie->msi_host_irq; struct dw_pcie *pci = ks_pcie->pci; + struct pcie_port *pp = &pci->pp; struct device *dev = pci->dev; struct irq_chip *chip = irq_desc_get_chip(desc); + u32 vector, virq, reg, pos; dev_dbg(dev, "%s, irq %d\n", __func__, irq); @@ -567,7 +543,23 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) * ack operation. */ chained_irq_enter(chip, desc); - ks_pcie_handle_msi_irq(ks_pcie, offset); + + reg = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset)); + /* + * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit + * shows 1, 9, 17, 25 and so forth + */ + for (pos = 0; pos < 4; pos++) { + if (!(reg & BIT(pos))) + continue; + + vector = offset + (pos << 3); + virq = irq_linear_revmap(pp->irq_domain, vector); + dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", pos, vector, + virq); + generic_handle_irq(virq); + } + chained_irq_exit(chip, desc); } -- cgit From 9f67437b3a085865fbf5c2d0cbf60fb1b465411c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:24 +0530 Subject: PCI: dwc: Add support to use non default msi_irq_chip Platforms using DesignWare IP use dw_pci_msi_bottom_irq_chip for configuring the MSI controller logic within the DesignWare IP. However certain platforms like Keystone (K2G) which uses DesignWare IP have their own MSI controller logic. For handling such platforms, the irqchip ops use msi_irq_ack(), msi_set_irq(), msi_clear_irq() callback functions. Add support to use different msi_irq_chip with default set to dw_pci_msi_bottom_irq_chip. This is in preparation to get rid of msi_irq_ack(), msi_set_irq(), msi_clear_irq() and other Keystone specific dw_pcie_host_ops. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-host.c | 5 ++++- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 25087d3c9a82..e28cb082f50d 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -245,7 +245,7 @@ static int dw_pcie_irq_domain_alloc(struct irq_domain *domain, for (i = 0; i < nr_irqs; i++) irq_domain_set_info(domain, virq + i, bit + i, - &dw_pci_msi_bottom_irq_chip, + pp->msi_irq_chip, pp, handle_edge_irq, NULL, NULL); @@ -277,6 +277,9 @@ int dw_pcie_allocate_domains(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node); + if (!pp->msi_irq_chip) + pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip; + pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors, &dw_pcie_msi_domain_ops, pp); if (!pp->irq_domain) { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 377f4c0b52da..6b0cea473ee7 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -179,6 +179,7 @@ struct pcie_port { struct irq_domain *irq_domain; struct irq_domain *msi_domain; dma_addr_t msi_data; + struct irq_chip *msi_irq_chip; u32 num_vectors; u32 irq_mask[MAX_MSI_CTRLS]; raw_spinlock_t lock; -- cgit From 117c3b60bd5372ec23f8c1a9652ad78dc2b9982a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:25 +0530 Subject: PCI: keystone: Use Keystone specific msi_irq_chip Use Keystone specific msi_irq_chip to configure the MSI controller logic in the PCIe keystone wrapper instead of using the default Designware msi_irq chip (dw_pci_msi_bottom_irq_chip) with callback functions for configuring the Keystone MSI controller. This will help to remove Keystone specific callback functions added in dw_pcie_host_ops. Move the default msi_irq_chip assignment to dw_pcie_host_init since platforms that doesn't use the default msi_irq_chip will assign msi_irq_chip in the msi_host_init() callback. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 96 +++++++++++++++++------ drivers/pci/controller/dwc/pcie-designware-host.c | 5 +- 2 files changed, 74 insertions(+), 27 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 39542f2c312b..b757692e2848 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -105,14 +105,6 @@ struct keystone_pcie { struct resource app; }; -static phys_addr_t ks_pcie_get_msi_addr(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - - return ks_pcie->app.start + MSI_IRQ; -} - static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset) { return readl(ks_pcie->va_app_base + offset); @@ -124,11 +116,14 @@ static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset, writel(val, ks_pcie->va_app_base + offset); } -static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) +static void ks_pcie_msi_irq_ack(struct irq_data *data) { - u32 reg_offset, bit_pos; + struct pcie_port *pp = irq_data_get_irq_chip_data(data); struct keystone_pcie *ks_pcie; + u32 irq = data->hwirq; struct dw_pcie *pci; + u32 reg_offset; + u32 bit_pos; pci = to_dw_pcie_from_pp(pp); ks_pcie = to_keystone_pcie(pci); @@ -141,34 +136,91 @@ static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET); } -static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq) +static void ks_pcie_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { - u32 reg_offset, bit_pos; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + struct pcie_port *pp = irq_data_get_irq_chip_data(data); + struct keystone_pcie *ks_pcie; + struct dw_pcie *pci; + u64 msi_target; + + pci = to_dw_pcie_from_pp(pp); + ks_pcie = to_keystone_pcie(pci); + + msi_target = ks_pcie->app.start + MSI_IRQ; + msg->address_lo = lower_32_bits(msi_target); + msg->address_hi = upper_32_bits(msi_target); + msg->data = data->hwirq; + + dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n", + (int)data->hwirq, msg->address_hi, msg->address_lo); +} + +static int ks_pcie_msi_set_affinity(struct irq_data *irq_data, + const struct cpumask *mask, bool force) +{ + return -EINVAL; +} + +static void ks_pcie_msi_mask(struct irq_data *data) +{ + struct pcie_port *pp = irq_data_get_irq_chip_data(data); + struct keystone_pcie *ks_pcie; + u32 irq = data->hwirq; + struct dw_pcie *pci; + unsigned long flags; + u32 reg_offset; + u32 bit_pos; + + raw_spin_lock_irqsave(&pp->lock, flags); + + pci = to_dw_pcie_from_pp(pp); + ks_pcie = to_keystone_pcie(pci); reg_offset = irq % 8; bit_pos = irq >> 3; - ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset), BIT(bit_pos)); + + raw_spin_unlock_irqrestore(&pp->lock, flags); } -static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq) +static void ks_pcie_msi_unmask(struct irq_data *data) { - u32 reg_offset, bit_pos; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + struct pcie_port *pp = irq_data_get_irq_chip_data(data); + struct keystone_pcie *ks_pcie; + u32 irq = data->hwirq; + struct dw_pcie *pci; + unsigned long flags; + u32 reg_offset; + u32 bit_pos; + + raw_spin_lock_irqsave(&pp->lock, flags); + + pci = to_dw_pcie_from_pp(pp); + ks_pcie = to_keystone_pcie(pci); reg_offset = irq % 8; bit_pos = irq >> 3; - ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset), BIT(bit_pos)); + + raw_spin_unlock_irqrestore(&pp->lock, flags); } +static struct irq_chip ks_pcie_msi_irq_chip = { + .name = "KEYSTONE-PCI-MSI", + .irq_ack = ks_pcie_msi_irq_ack, + .irq_compose_msi_msg = ks_pcie_compose_msi_msg, + .irq_set_affinity = ks_pcie_msi_set_affinity, + .irq_mask = ks_pcie_msi_mask, + .irq_unmask = ks_pcie_msi_unmask, +}; + static int ks_pcie_msi_host_init(struct pcie_port *pp) { + pp->msi_irq_chip = &ks_pcie_msi_irq_chip; return dw_pcie_allocate_domains(pp); } @@ -785,11 +837,7 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = { .rd_other_conf = ks_pcie_rd_other_conf, .wr_other_conf = ks_pcie_wr_other_conf, .host_init = ks_pcie_host_init, - .msi_set_irq = ks_pcie_msi_set_irq, - .msi_clear_irq = ks_pcie_msi_clear_irq, - .get_msi_addr = ks_pcie_get_msi_addr, .msi_host_init = ks_pcie_msi_host_init, - .msi_irq_ack = ks_pcie_msi_irq_ack, .scan_bus = ks_pcie_v3_65_scan_bus, }; diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index e28cb082f50d..9e47bad82bbc 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -277,9 +277,6 @@ int dw_pcie_allocate_domains(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node); - if (!pp->msi_irq_chip) - pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip; - pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors, &dw_pcie_msi_domain_ops, pp); if (!pp->irq_domain) { @@ -462,6 +459,8 @@ int dw_pcie_host_init(struct pcie_port *pp) } if (!pp->ops->msi_host_init) { + pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip; + ret = dw_pcie_allocate_domains(pp); if (ret) goto error; -- cgit From dad5258999e91ba368dbdd31ecac94e095acb844 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:26 +0530 Subject: PCI: dwc: Remove Keystone specific dw_pcie_host_ops Now that Keystone started using its own msi_irq_chip, remove Keystone specific callback functions defined in dw_pcie_host_ops. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-host.c | 50 +++++++---------------- drivers/pci/controller/dwc/pcie-designware.h | 5 --- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 9e47bad82bbc..498422397609 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -126,18 +126,12 @@ static void dw_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); u64 msi_target; - if (pp->ops->get_msi_addr) - msi_target = pp->ops->get_msi_addr(pp); - else - msi_target = (u64)pp->msi_data; + msi_target = (u64)pp->msi_data; msg->address_lo = lower_32_bits(msi_target); msg->address_hi = upper_32_bits(msi_target); - if (pp->ops->get_msi_data) - msg->data = pp->ops->get_msi_data(pp, d->hwirq); - else - msg->data = d->hwirq; + msg->data = d->hwirq; dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n", (int)d->hwirq, msg->address_hi, msg->address_lo); @@ -157,17 +151,13 @@ static void dw_pci_bottom_mask(struct irq_data *d) raw_spin_lock_irqsave(&pp->lock, flags); - if (pp->ops->msi_clear_irq) { - pp->ops->msi_clear_irq(pp, d->hwirq); - } else { - ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; - res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; - bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; + ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; + res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; + bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - pp->irq_mask[ctrl] |= BIT(bit); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, - pp->irq_mask[ctrl]); - } + pp->irq_mask[ctrl] |= BIT(bit); + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, + pp->irq_mask[ctrl]); raw_spin_unlock_irqrestore(&pp->lock, flags); } @@ -180,17 +170,13 @@ static void dw_pci_bottom_unmask(struct irq_data *d) raw_spin_lock_irqsave(&pp->lock, flags); - if (pp->ops->msi_set_irq) { - pp->ops->msi_set_irq(pp, d->hwirq); - } else { - ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; - res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; - bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; + ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; + res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; + bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - pp->irq_mask[ctrl] &= ~BIT(bit); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, - pp->irq_mask[ctrl]); - } + pp->irq_mask[ctrl] &= ~BIT(bit); + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, + pp->irq_mask[ctrl]); raw_spin_unlock_irqrestore(&pp->lock, flags); } @@ -199,20 +185,12 @@ static void dw_pci_bottom_ack(struct irq_data *d) { struct pcie_port *pp = irq_data_get_irq_chip_data(d); unsigned int res, bit, ctrl; - unsigned long flags; ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - raw_spin_lock_irqsave(&pp->lock, flags); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, BIT(bit)); - - if (pp->ops->msi_irq_ack) - pp->ops->msi_irq_ack(d->hwirq, pp); - - raw_spin_unlock_irqrestore(&pp->lock, flags); } static struct irq_chip dw_pci_msi_bottom_irq_chip = { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 6b0cea473ee7..ca3a3190a6f5 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -145,14 +145,9 @@ struct dw_pcie_host_ops { int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); int (*host_init)(struct pcie_port *pp); - void (*msi_set_irq)(struct pcie_port *pp, int irq); - void (*msi_clear_irq)(struct pcie_port *pp, int irq); - phys_addr_t (*get_msi_addr)(struct pcie_port *pp); - u32 (*get_msi_data)(struct pcie_port *pp, int pos); void (*scan_bus)(struct pcie_port *pp); void (*set_num_vectors)(struct pcie_port *pp); int (*msi_host_init)(struct pcie_port *pp); - void (*msi_irq_ack)(int irq, struct pcie_port *pp); }; struct pcie_port { -- cgit From fd8a44bd5b76dc77133f814dd63d414d49dc74c0 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:27 +0530 Subject: PCI: dwc: Remove default MSI initialization for platform specific MSI chips Platforms which populate msi_host_init() have their own MSI controller logic. Writing to MSI control registers on platforms which do not use Designware's MSI controller logic might have side effects. To be safe, do not write to MSI control registers if the platform uses its own MSI controller logic instead of Designware's MSI one. Signed-off-by: Kishon Vijay Abraham I [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-host.c | 24 ++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 498422397609..7e0ff7d428a9 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -626,17 +626,19 @@ void dw_pcie_setup_rc(struct pcie_port *pp) dw_pcie_setup(pci); - num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; - - /* Initialize IRQ Status array */ - for (ctrl = 0; ctrl < num_ctrls; ctrl++) { - pp->irq_mask[ctrl] = ~0; - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + - (ctrl * MSI_REG_CTRL_BLOCK_SIZE), - 4, pp->irq_mask[ctrl]); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + - (ctrl * MSI_REG_CTRL_BLOCK_SIZE), - 4, ~0); + if (!pp->ops->msi_host_init) { + num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; + + /* Initialize IRQ Status array */ + for (ctrl = 0; ctrl < num_ctrls; ctrl++) { + pp->irq_mask[ctrl] = ~0; + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + + (ctrl * MSI_REG_CTRL_BLOCK_SIZE), + 4, pp->irq_mask[ctrl]); + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + + (ctrl * MSI_REG_CTRL_BLOCK_SIZE), + 4, ~0); + } } /* Setup RC BARs */ -- cgit From 6302bf3ef78dd210b5ff4a922afcb7d8eff8a211 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Mon, 18 Mar 2019 16:07:18 +0000 Subject: PCI: Init PCIe feature bits for managed host bridge alloc Two functions allocate a host bridge: devm_pci_alloc_host_bridge() and pci_alloc_host_bridge(). At the moment, only the unmanaged one initializes the PCIe feature bits, which prevents from using features such as hotplug or AER on some systems, when booting with device tree. Make the initialization code common. Fixes: 02bfeb484230 ("PCI/portdrv: Simplify PCIe feature permission checking") Signed-off-by: Jean-Philippe Brucker Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v4.17+ --- drivers/pci/probe.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2ec0df04e0dc..012250a78da7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -586,16 +586,9 @@ static void pci_release_host_bridge_dev(struct device *dev) kfree(to_pci_host_bridge(dev)); } -struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) +static void pci_init_host_bridge(struct pci_host_bridge *bridge) { - struct pci_host_bridge *bridge; - - bridge = kzalloc(sizeof(*bridge) + priv, GFP_KERNEL); - if (!bridge) - return NULL; - INIT_LIST_HEAD(&bridge->windows); - bridge->dev.release = pci_release_host_bridge_dev; /* * We assume we can manage these PCIe features. Some systems may @@ -608,6 +601,18 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) bridge->native_shpc_hotplug = 1; bridge->native_pme = 1; bridge->native_ltr = 1; +} + +struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) +{ + struct pci_host_bridge *bridge; + + bridge = kzalloc(sizeof(*bridge) + priv, GFP_KERNEL); + if (!bridge) + return NULL; + + pci_init_host_bridge(bridge); + bridge->dev.release = pci_release_host_bridge_dev; return bridge; } @@ -622,7 +627,7 @@ struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev, if (!bridge) return NULL; - INIT_LIST_HEAD(&bridge->windows); + pci_init_host_bridge(bridge); bridge->dev.release = devm_pci_release_host_bridge_dev; return bridge; -- cgit From 86fa6a344209d9414ea962b1f1ac6ade9dd7563a Mon Sep 17 00:00:00 2001 From: Stefan Mätje Date: Fri, 29 Mar 2019 18:07:34 +0100 Subject: PCI: Factor out pcie_retrain_link() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Factor out pcie_retrain_link() to use for Pericom Retrain Link quirk. No functional change intended. Signed-off-by: Stefan Mätje Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko CC: stable@vger.kernel.org --- drivers/pci/pcie/aspm.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 727e3c1ef9a4..4fa37622ad66 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -196,6 +196,29 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) link->clkpm_capable = (blacklist) ? 0 : capable; } +static bool pcie_retrain_link(struct pcie_link_state *link) +{ + struct pci_dev *parent = link->pdev; + unsigned long start_jiffies; + u16 reg16; + + pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); + reg16 |= PCI_EXP_LNKCTL_RL; + pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); + + /* Wait for link training end. Break out after waiting for timeout */ + start_jiffies = jiffies; + for (;;) { + pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_LT)) + break; + if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) + break; + msleep(1); + } + return !(reg16 & PCI_EXP_LNKSTA_LT); +} + /* * pcie_aspm_configure_common_clock: check if the 2 ends of a link * could use common clock. If they are, configure them to use the @@ -205,7 +228,6 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) { int same_clock = 1; u16 reg16, parent_reg, child_reg[8]; - unsigned long start_jiffies; struct pci_dev *child, *parent = link->pdev; struct pci_bus *linkbus = parent->subordinate; /* @@ -263,21 +285,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link) reg16 &= ~PCI_EXP_LNKCTL_CCC; pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); - /* Retrain link */ - reg16 |= PCI_EXP_LNKCTL_RL; - pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); - - /* Wait for link training end. Break out after waiting for timeout */ - start_jiffies = jiffies; - for (;;) { - pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); - if (!(reg16 & PCI_EXP_LNKSTA_LT)) - break; - if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) - break; - msleep(1); - } - if (!(reg16 & PCI_EXP_LNKSTA_LT)) + if (pcie_retrain_link(link)) return; /* Training failed. Restore common clock configurations */ -- cgit From 4ec73791a64bab25cabf16a6067ee478692e506d Mon Sep 17 00:00:00 2001 From: Stefan Mätje Date: Fri, 29 Mar 2019 18:07:35 +0100 Subject: PCI: Work around Pericom PCIe-to-PCI bridge Retrain Link erratum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to an erratum in some Pericom PCIe-to-PCI bridges in reverse mode (conventional PCI on primary side, PCIe on downstream side), the Retrain Link bit needs to be cleared manually to allow the link training to complete successfully. If it is not cleared manually, the link training is continuously restarted and no devices below the PCI-to-PCIe bridge can be accessed. That means drivers for devices below the bridge will be loaded but won't work and may even crash because the driver is only reading 0xffff. See the Pericom Errata Sheet PI7C9X111SLB_errata_rev1.2_102711.pdf for details. Devices known as affected so far are: PI7C9X110, PI7C9X111SL, PI7C9X130. Add a new flag, clear_retrain_link, in struct pci_dev. Quirks for affected devices set this bit. Note that pcie_retrain_link() lives in aspm.c because that's currently the only place we use it, but this erratum is not specific to ASPM, and we may retrain links for other reasons in the future. Signed-off-by: Stefan Mätje [bhelgaas: apply regardless of CONFIG_PCIEASPM] Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko CC: stable@vger.kernel.org --- drivers/pci/pcie/aspm.c | 9 +++++++++ drivers/pci/quirks.c | 17 +++++++++++++++++ include/linux/pci.h | 2 ++ 3 files changed, 28 insertions(+) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 4fa37622ad66..38e7017478b5 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -205,6 +205,15 @@ static bool pcie_retrain_link(struct pcie_link_state *link) pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); reg16 |= PCI_EXP_LNKCTL_RL; pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); + if (parent->clear_retrain_link) { + /* + * Due to an erratum in some devices the Retrain Link bit + * needs to be cleared again manually to allow the link + * training to succeed. + */ + reg16 &= ~PCI_EXP_LNKCTL_RL; + pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16); + } /* Wait for link training end. Break out after waiting for timeout */ start_jiffies = jiffies; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a59ad09ce911..6f34e17c98f4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2245,6 +2245,23 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f1, quirk_disable_aspm_l0s); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f4, quirk_disable_aspm_l0s); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1508, quirk_disable_aspm_l0s); +/* + * Some Pericom PCIe-to-PCI bridges in reverse mode need the PCIe Retrain + * Link bit cleared after starting the link retrain process to allow this + * process to finish. + * + * Affected devices: PI7C9X110, PI7C9X111SL, PI7C9X130. See also the + * Pericom Errata Sheet PI7C9X111SLB_errata_rev1.2_102711.pdf. + */ +static void quirk_enable_clear_retrain_link(struct pci_dev *dev) +{ + dev->clear_retrain_link = 1; + pci_info(dev, "Enable PCIe Retrain Link quirk\n"); +} +DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe110, quirk_enable_clear_retrain_link); +DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe111, quirk_enable_clear_retrain_link); +DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe130, quirk_enable_clear_retrain_link); + static void fixup_rev1_53c810(struct pci_dev *dev) { u32 class = dev->class; diff --git a/include/linux/pci.h b/include/linux/pci.h index 77448215ef5b..2c056a7a728a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -348,6 +348,8 @@ struct pci_dev { unsigned int hotplug_user_indicators:1; /* SlotCtl indicators controlled exclusively by user sysfs */ + unsigned int clear_retrain_link:1; /* Need to clear Retrain Link + bit manually */ unsigned int d3_delay; /* D3->D0 transition time in ms */ unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */ -- cgit From 658eec837b11fbfab9082ebf8da24d94cefa47c0 Mon Sep 17 00:00:00 2001 From: Stefan Mätje Date: Fri, 29 Mar 2019 18:07:36 +0100 Subject: PCI: Rework pcie_retrain_link() wait loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Transform wait code to a "do {} while (time_before())" loop as recommended by reviewer. No functional change intended. Signed-off-by: Stefan Mätje Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko --- drivers/pci/pcie/aspm.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 38e7017478b5..fd4cb75088f9 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -199,7 +199,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist) static bool pcie_retrain_link(struct pcie_link_state *link) { struct pci_dev *parent = link->pdev; - unsigned long start_jiffies; + unsigned long end_jiffies; u16 reg16; pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16); @@ -216,15 +216,13 @@ static bool pcie_retrain_link(struct pcie_link_state *link) } /* Wait for link training end. Break out after waiting for timeout */ - start_jiffies = jiffies; - for (;;) { + end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT; + do { pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_LT)) break; - if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT)) - break; msleep(1); - } + } while (time_before(jiffies, end_jiffies)); return !(reg16 & PCI_EXP_LNKSTA_LT); } -- cgit From fb26228bfc4ce3951544848555c0278e2832e618 Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Fri, 22 Mar 2019 13:27:21 -0500 Subject: PCI: rpadlpar: Fix leaked device_node references in add/remove paths The find_dlpar_node() helper returns a device node with its reference incremented. Both the add and remove paths use this helper for find the appropriate node, but fail to release the reference when done. Annotate the find_dlpar_node() helper with a comment about the incremented reference count and call of_node_put() on the obtained device_node in the add and remove paths. Also, fixup a reference leak in the find_vio_slot() helper where we fail to call of_node_put() on the vdevice node after we iterate over its children. Signed-off-by: Tyrel Datwyler Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/rpadlpar_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index e2356a9c7088..182f9e3443ee 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -51,6 +51,7 @@ static struct device_node *find_vio_slot_node(char *drc_name) if (rc == 0) break; } + of_node_put(parent); return dn; } @@ -71,6 +72,7 @@ static struct device_node *find_php_slot_pci_node(char *drc_name, return np; } +/* Returns a device_node with its reference count incremented */ static struct device_node *find_dlpar_node(char *drc_name, int *node_type) { struct device_node *dn; @@ -306,6 +308,7 @@ int dlpar_add_slot(char *drc_name) rc = dlpar_add_phb(drc_name, dn); break; } + of_node_put(dn); printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name); exit: @@ -439,6 +442,7 @@ int dlpar_remove_slot(char *drc_name) rc = dlpar_remove_pci_slot(drc_name, dn); break; } + of_node_put(dn); vm_unmap_aliases(); printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name); -- cgit From 91800660bbe9d4ae7791f0e646e5736180f01fc0 Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Fri, 22 Mar 2019 13:27:22 -0500 Subject: PCI: rpaphp: Get/put device node reference during slot alloc/dealloc When allocating the slot structure we store a pointer to the associated device_node. We really should be incrementing the reference count, so add an of_node_get() during slot alloc and an of_node_put() during slot dealloc. Signed-off-by: Tyrel Datwyler Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/rpaphp_slot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 5282aa3e33c5..93b4a945c55d 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -21,6 +21,7 @@ /* free up the memory used by a slot */ void dealloc_slot_struct(struct slot *slot) { + of_node_put(slot->dn); kfree(slot->name); kfree(slot); } @@ -36,7 +37,7 @@ struct slot *alloc_slot_struct(struct device_node *dn, slot->name = kstrdup(drc_name, GFP_KERNEL); if (!slot->name) goto error_slot; - slot->dn = dn; + slot->dn = of_node_get(dn); slot->index = drc_index; slot->power_domain = power_domain; slot->hotplug_slot.ops = &rpaphp_hotplug_slot_ops; -- cgit From 6be22343cc546b46402869668da453d56921c14e Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Wed, 10 Apr 2019 14:54:16 +0800 Subject: PCI: mediatek: Get optional clocks with devm_clk_get_optional() Update the driver to use devm_clk_get_optional() to claim optional clocks instead of devm_clk_get(). Signed-off-by: Chunfeng Yun Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee Acked-by: Honghui Zhang Cc: Ryder Lee Cc: Honghui Zhang --- drivers/pci/controller/pcie-mediatek.c | 50 ++++++++++------------------------ 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 0b6c72804e03..adb6cb15daa2 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -915,49 +915,29 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie, /* sys_ck might be divided into the following parts in some chips */ snprintf(name, sizeof(name), "ahb_ck%d", slot); - port->ahb_ck = devm_clk_get(dev, name); - if (IS_ERR(port->ahb_ck)) { - if (PTR_ERR(port->ahb_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->ahb_ck = NULL; - } + port->ahb_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->ahb_ck)) + return PTR_ERR(port->ahb_ck); snprintf(name, sizeof(name), "axi_ck%d", slot); - port->axi_ck = devm_clk_get(dev, name); - if (IS_ERR(port->axi_ck)) { - if (PTR_ERR(port->axi_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->axi_ck = NULL; - } + port->axi_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->axi_ck)) + return PTR_ERR(port->axi_ck); snprintf(name, sizeof(name), "aux_ck%d", slot); - port->aux_ck = devm_clk_get(dev, name); - if (IS_ERR(port->aux_ck)) { - if (PTR_ERR(port->aux_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->aux_ck = NULL; - } + port->aux_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->aux_ck)) + return PTR_ERR(port->aux_ck); snprintf(name, sizeof(name), "obff_ck%d", slot); - port->obff_ck = devm_clk_get(dev, name); - if (IS_ERR(port->obff_ck)) { - if (PTR_ERR(port->obff_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->obff_ck = NULL; - } + port->obff_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->obff_ck)) + return PTR_ERR(port->obff_ck); snprintf(name, sizeof(name), "pipe_ck%d", slot); - port->pipe_ck = devm_clk_get(dev, name); - if (IS_ERR(port->pipe_ck)) { - if (PTR_ERR(port->pipe_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->pipe_ck = NULL; - } + port->pipe_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->pipe_ck)) + return PTR_ERR(port->pipe_ck); snprintf(name, sizeof(name), "pcie-rst%d", slot); port->reset = devm_reset_control_get_optional_exclusive(dev, name); -- cgit From fbca0b284bd02bf83c9813168d1a58b6ec54d1ca Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 4 Apr 2019 16:36:08 +0530 Subject: tools: PCI: Add 'h' in optstring of getopt() 'h' is a valid option character for the pcitest tool used to print the pcitest usage. Add 'h' in optstring of getopt() in order to get rid of "pcitest: invalid option -- 'h'" warning. While at that remove unncessary case '?'. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Sekhar Nori Signed-off-by: Lorenzo Pieralisi --- tools/pci/pcitest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c index 310a7e4850f6..5fa5c2bdd427 100644 --- a/tools/pci/pcitest.c +++ b/tools/pci/pcitest.c @@ -163,7 +163,7 @@ int main(int argc, char **argv) /* set default endpoint device */ test->device = "/dev/pci-endpoint-test.0"; - while ((c = getopt(argc, argv, "D:b:m:x:i:Ilrwcs:")) != EOF) + while ((c = getopt(argc, argv, "D:b:m:x:i:Ilhrwcs:")) != EOF) switch (c) { case 'D': test->device = optarg; @@ -207,7 +207,6 @@ int main(int argc, char **argv) case 's': test->size = strtoul(optarg, NULL, 0); continue; - case '?': case 'h': default: usage: @@ -225,6 +224,7 @@ usage: "\t-w Write buffer test\n" "\t-c Copy buffer test\n" "\t-s Size of buffer {default: 100KB}\n", + "\t-h Print this help message\n", argv[0]); return -EINVAL; } -- cgit From 993d5fe31c7b7cf7f480c6b4bec3ed23a3a24690 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 4 Apr 2019 16:36:09 +0530 Subject: tools: PCI: Handle pcitest.sh independently from pcitest Handling pcitest.sh along with pcitest (obtained by compiling pcitest.c) results in pcitest.sh getting removed inadvertently while "make -C tools/pci clean". Fix it by handling pcitest.sh independently of pcitest. Fixes: 1ce78ce09430 ("tools: PCI: Change pcitest compiling process") Reported-by: Adrian Hunter Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi Cc: Gustavo Pimentel --- tools/pci/Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/pci/Makefile b/tools/pci/Makefile index 46e4c2f318c9..9b7534457060 100644 --- a/tools/pci/Makefile +++ b/tools/pci/Makefile @@ -14,9 +14,12 @@ MAKEFLAGS += -r CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -ALL_TARGETS := pcitest pcitest.sh +ALL_TARGETS := pcitest ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) +SCRIPTS := pcitest.sh +ALL_SCRIPTS := $(patsubst %,$(OUTPUT)%,$(SCRIPTS)) + all: $(ALL_PROGRAMS) export srctree OUTPUT CC LD CFLAGS @@ -46,6 +49,9 @@ install: $(ALL_PROGRAMS) install -d -m 755 $(DESTDIR)$(bindir); \ for program in $(ALL_PROGRAMS); do \ install $$program $(DESTDIR)$(bindir); \ + done; \ + for script in $(ALL_SCRIPTS); do \ + install $$script $(DESTDIR)$(bindir); \ done FORCE: -- cgit From 9afb20d600da83639ad800f113884fadb78a43ae Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:22 +0530 Subject: PCI: keystone: Add start_link()/stop_link() dw_pcie_ops Add start_link()/stop_link() dw_pcie_ops and invoke ks_pcie_start_link() directly from host_init. start_link()/stop_link() ops are required for adding EP mode support. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index b757692e2848..07f55b355d75 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -460,18 +460,33 @@ static int ks_pcie_link_up(struct dw_pcie *pci) return (val == PORT_LOGIC_LTSSM_STATE_L0); } -static void ks_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) +static void ks_pcie_stop_link(struct dw_pcie *pci) { + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); u32 val; /* Disable Link training */ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); val &= ~LTSSM_EN_VAL; ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); +} + +static int ks_pcie_start_link(struct dw_pcie *pci) +{ + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + struct device *dev = pci->dev; + u32 val; + + if (dw_pcie_link_up(pci)) { + dev_dbg(dev, "link is already up\n"); + return 0; + } /* Initiate Link Training */ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); + + return 0; } /** @@ -556,26 +571,6 @@ static void ks_pcie_quirk(struct pci_dev *dev) } DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, ks_pcie_quirk); -static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct device *dev = pci->dev; - - if (dw_pcie_link_up(pci)) { - dev_info(dev, "Link already up\n"); - return 0; - } - - ks_pcie_initiate_link_train(ks_pcie); - - /* check if the link is up or not */ - if (!dw_pcie_wait_for_link(pci)) - return 0; - - dev_err(dev, "phy link never came up\n"); - return -ETIMEDOUT; -} - static void ks_pcie_msi_irq_handler(struct irq_desc *desc) { unsigned int irq = desc->irq_data.hwirq; @@ -813,7 +808,7 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); - ks_pcie_establish_link(ks_pcie); + ks_pcie_stop_link(pci); ks_pcie_setup_rc_app_regs(ks_pcie); ks_pcie_setup_interrupts(ks_pcie); writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), @@ -830,6 +825,9 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) hook_fault_code(17, ks_pcie_fault, SIGBUS, 0, "Asynchronous external abort"); + ks_pcie_start_link(pci); + dw_pcie_wait_for_link(pci); + return 0; } @@ -892,6 +890,8 @@ static const struct of_device_id ks_pcie_of_match[] = { }; static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { + .start_link = ks_pcie_start_link, + .stop_link = ks_pcie_stop_link, .link_up = ks_pcie_link_up, }; -- cgit From 0790eb175ee0d8979a6db6bf2ad81e7c83d616df Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:23 +0530 Subject: PCI: keystone: Cleanup error_irq configuration pci-keystone driver uses irq_of_parse_and_map() to get irq number of error_irq. Use platform_get_irq() instead and move platform_get_irq() and request_irq() of error_irq from ks_pcie_add_pcie_port to ks_pcie_probe since error_irq is common to both RC mode and EP mode. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 43 ++++++++++++------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 07f55b355d75..e50f8773e768 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -98,8 +98,6 @@ struct keystone_pcie { struct irq_domain *legacy_irq_domain; struct device_node *np; - int error_irq; - /* Application register space */ void __iomem *va_app_base; /* DT 1st resource */ struct resource app; @@ -743,12 +741,6 @@ err: return ret; } -static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) -{ - if (ks_pcie->error_irq > 0) - ks_pcie_enable_error_irq(ks_pcie); -} - /* * When a PCI device does not exist during config cycles, keystone host gets a * bus error instead of returning 0xffffffff. This handler always returns 0 @@ -810,7 +802,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) ks_pcie_stop_link(pci); ks_pcie_setup_rc_app_regs(ks_pcie); - ks_pcie_setup_interrupts(ks_pcie); writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), pci->dbi_base + PCI_IO_BASE); @@ -854,23 +845,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct device *dev = &pdev->dev; int ret; - /* - * Index 0 is the platform interrupt for error interrupt - * from RC. This is optional. - */ - ks_pcie->error_irq = irq_of_parse_and_map(ks_pcie->np, 0); - if (ks_pcie->error_irq <= 0) - dev_info(dev, "no error IRQ defined\n"); - else { - ret = request_irq(ks_pcie->error_irq, ks_pcie_err_irq_handler, - IRQF_SHARED, "pcie-error-irq", ks_pcie); - if (ret < 0) { - dev_err(dev, "failed to request error IRQ %d\n", - ks_pcie->error_irq); - return ret; - } - } - pp->ops = &ks_pcie_host_ops; ret = ks_pcie_dw_host_init(ks_pcie); if (ret) { @@ -946,6 +920,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) u32 num_lanes; char name[10]; int ret; + int irq; int i; ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); @@ -965,6 +940,20 @@ static int __init ks_pcie_probe(struct platform_device *pdev) return ret; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "missing IRQ resource: %d\n", irq); + return irq; + } + + ret = request_irq(irq, ks_pcie_err_irq_handler, IRQF_SHARED, + "ks-pcie-error-irq", ks_pcie); + if (ret < 0) { + dev_err(dev, "failed to request error IRQ %d\n", + irq); + return ret; + } + ret = of_property_read_u32(np, "num-lanes", &num_lanes); if (ret) num_lanes = 1; @@ -1020,6 +1009,8 @@ static int __init ks_pcie_probe(struct platform_device *pdev) if (ret < 0) goto err_get_sync; + ks_pcie_enable_error_irq(ks_pcie); + return 0; err_get_sync: -- cgit From 47fe944138a6e34697e1778a74eff00ed9472b2a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:24 +0530 Subject: dt-bindings: PCI: keystone: Add "reg-names" binding information Add "reg-names" binding information in order for device tree node to be populated with the correct register strings. This will break old DT compatibility. However Keystone PCI has never worked in upstream kernel due to lack of SERDES support, so, before SERDES support is added, cleanup the Keystone PCI dt-bindings. This new binding will also be used by PCI in AM654 platform. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/pci/pci-keystone.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt index 2030ee0dc4f9..3a551687cfa2 100644 --- a/Documentation/devicetree/bindings/pci/pci-keystone.txt +++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt @@ -12,8 +12,10 @@ described here as well as properties that are not applicable. Required Properties:- compatibility: "ti,keystone-pcie" -reg: index 1 is the base address and length of DW application registers. - index 2 is the base address and length of PCI device ID register. +reg: Three register ranges as listed in the reg-names property +reg-names: "dbics" for the DesignWare PCIe registers, "app" for the + TI specific application registers, "config" for the + configuration space address pcie_msi_intc : Interrupt controller device node for MSI IRQ chip interrupt-cells: should be set to 1 -- cgit From f3560a9f88ae3aa2b2976a1a0175478f6fd32fe8 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:25 +0530 Subject: PCI: keystone: Perform host initialization in a single function No functional change. Instead of having two functions ks_pcie_add_pcie_port() and ks_pcie_dw_host_init() for initializing host, have a single function to perform all the host initialization. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 63 +++++++++++-------------------- 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e50f8773e768..566718ea7ebf 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -487,45 +487,6 @@ static int ks_pcie_start_link(struct dw_pcie *pci) return 0; } -/** - * ks_pcie_dw_host_init() - initialize host for v3_65 dw hardware - * - * Ioremap the register resources, initialize legacy irq domain - * and call dw_pcie_v3_65_host_init() API to initialize the Keystone - * PCI host controller. - */ -static int __init ks_pcie_dw_host_init(struct keystone_pcie *ks_pcie) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = pci->dev; - struct platform_device *pdev = to_platform_device(dev); - struct resource *res; - - /* Index 0 is the config reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - - /* - * We set these same and is used in pcie rd/wr_other_conf - * functions - */ - pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET; - pp->va_cfg1_base = pp->va_cfg0_base; - - /* Index 1 is the application reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - ks_pcie->va_app_base = devm_ioremap_resource(dev, res); - if (IS_ERR(ks_pcie->va_app_base)) - return PTR_ERR(ks_pcie->va_app_base); - - ks_pcie->app = *res; - - return dw_pcie_host_init(pp); -} - static void ks_pcie_quirk(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; @@ -843,10 +804,32 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; struct device *dev = &pdev->dev; + struct resource *res; int ret; + /* Index 0 is the config reg. space address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(pci->dbi_base)) + return PTR_ERR(pci->dbi_base); + + /* + * We set these same and is used in pcie rd/wr_other_conf + * functions + */ + pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET; + pp->va_cfg1_base = pp->va_cfg0_base; + + /* Index 1 is the application reg. space address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ks_pcie->va_app_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ks_pcie->va_app_base)) + return PTR_ERR(ks_pcie->va_app_base); + + ks_pcie->app = *res; + pp->ops = &ks_pcie_host_ops; - ret = ks_pcie_dw_host_init(ks_pcie); + ret = dw_pcie_host_init(pp); if (ret) { dev_err(dev, "failed to initialize host\n"); return ret; -- cgit From 2341ab4fd5d7ee3db5c67e8ff8506722910df8e9 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:26 +0530 Subject: PCI: keystone: Use platform_get_resource_byname() to get memory resources Use platform_get_resource_byname() instead of platform_get_resource() which uses an index to get memory resources. While at that get the memory resource defined specifically for configuration space instead of deriving the configuration space address from dbics address space. Since the pci-keystone driver has never worked in the mainline kernel, DT backward compatibility is not an issue. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 566718ea7ebf..5eebef9b9ada 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -44,7 +44,6 @@ #define CFG_TYPE1 BIT(24) #define OB_SIZE 0x030 -#define SPACE0_REMOTE_CFG_OFFSET 0x1000 #define OB_OFFSET_INDEX(n) (0x200 + (8 * (n))) #define OB_OFFSET_HI(n) (0x204 + (8 * (n))) #define OB_ENABLEN BIT(0) @@ -807,21 +806,19 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct resource *res; int ret; - /* Index 0 is the config reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbics"); pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); if (IS_ERR(pci->dbi_base)) return PTR_ERR(pci->dbi_base); - /* - * We set these same and is used in pcie rd/wr_other_conf - * functions - */ - pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); + pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(pp->va_cfg0_base)) + return PTR_ERR(pp->va_cfg0_base); + pp->va_cfg1_base = pp->va_cfg0_base; - /* Index 1 is the application reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app"); ks_pcie->va_app_base = devm_ioremap_resource(dev, res); if (IS_ERR(ks_pcie->va_app_base)) return PTR_ERR(ks_pcie->va_app_base); -- cgit From d28ca864c493637f3c957f4ed9348a94fca6de60 Mon Sep 17 00:00:00 2001 From: Nikolai Kostrigin Date: Mon, 8 Apr 2019 13:37:25 +0300 Subject: PCI: Mark AMD Stoney Radeon R7 GPU ATS as broken ATS is broken on the Radeon R7 GPU (at least for Stoney Ridge based laptop) and causes IOMMU stalls and system failure. Disable ATS on these devices to make them usable again with IOMMU enabled. Thanks to Joerg Roedel for help. [bhelgaas: In the email thread mentioned below, Alex suspects the real problem is in sbios or iommu, so it may affect only certain systems, and it may affect other devices in those systems as well. However, per Joerg we lack the ability to debug further, so this quirk is the best we can do for now.] Link: https://bugzilla.kernel.org/show_bug.cgi?id=194521 Link: https://lore.kernel.org/lkml/20190408103725.30426-1-nickel@altlinux.org Fixes: 9b44b0b09dec ("PCI: Mark AMD Stoney GPU ATS as broken") Signed-off-by: Nikolai Kostrigin Signed-off-by: Bjorn Helgaas Acked-by: Joerg Roedel CC: stable@vger.kernel.org --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a59ad09ce911..68bee35fcafa 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4903,6 +4903,7 @@ static void quirk_no_ats(struct pci_dev *pdev) /* AMD Stoney platform GPU */ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x98e4, quirk_no_ats); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6900, quirk_no_ats); #endif /* CONFIG_PCI_ATS */ /* Freescale PCIe doesn't support MSI in RC mode */ -- cgit From badd9f19f1992218b771c72e0cdc8825dd45938c Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Thu, 11 Apr 2019 13:40:26 +0100 Subject: dt-bindings: Add "external-facing" PCIe port property Provide a way for the firmware to tell the OS which devices are external to the machine and therefore untrusted. The property can describe for example Thunderbolt and other user-accessible ports, which should always have the strongest IOMMU protection. Signed-off-by: Jean-Philippe Brucker Signed-off-by: Bjorn Helgaas Reviewed-by: Grant Likely Reviewed-by: Rob Herring Reviewed-by: Robin Murphy --- Documentation/devicetree/bindings/pci/pci.txt | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt index c77981c5dd18..92c01db610df 100644 --- a/Documentation/devicetree/bindings/pci/pci.txt +++ b/Documentation/devicetree/bindings/pci/pci.txt @@ -24,3 +24,53 @@ driver implementation may support the following properties: unsupported link speed, for instance, trying to do training for unsupported link speed, etc. Must be '4' for gen4, '3' for gen3, '2' for gen2, and '1' for gen1. Any other values are invalid. + +PCI-PCI Bridge properties +------------------------- + +PCIe root ports and switch ports may be described explicitly in the device +tree, as children of the host bridge node. Even though those devices are +discoverable by probing, it might be necessary to describe properties that +aren't provided by standard PCIe capabilities. + +Required properties: + +- reg: + Identifies the PCI-PCI bridge. As defined in the IEEE Std 1275-1994 + document, it is a five-cell address encoded as (phys.hi phys.mid + phys.lo size.hi size.lo). phys.hi should contain the device's BDF as + 0b00000000 bbbbbbbb dddddfff 00000000. The other cells should be zero. + + The bus number is defined by firmware, through the standard bridge + configuration mechanism. If this port is a switch port, then firmware + allocates the bus number and writes it into the Secondary Bus Number + register of the bridge directly above this port. Otherwise, the bus + number of a root port is the first number in the bus-range property, + defaulting to zero. + + If firmware leaves the ARI Forwarding Enable bit set in the bridge + above this port, then phys.hi contains the 8-bit function number as + 0b00000000 bbbbbbbb ffffffff 00000000. Note that the PCIe specification + recommends that firmware only leaves ARI enabled when it knows that the + OS is ARI-aware. + +Optional properties: + +- external-facing: + When present, the port is external-facing. All bridges and endpoints + downstream of this port are external to the machine. The OS can, for + example, use this information to identify devices that cannot be + trusted with relaxed DMA protection, as users could easily attach + malicious devices to this port. + +Example: + +pcie@10000000 { + compatible = "pci-host-ecam-generic"; + ... + pcie@0008 { + /* Root port 00:01.0 is external-facing */ + reg = <0x00000800 0 0 0 0>; + external-facing; + }; +}; -- cgit From 9cb30a71acd45d65321c73160626f15fcdceba7a Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Thu, 11 Apr 2019 13:40:27 +0100 Subject: PCI: OF: Support "external-facing" property Set the "untrusted" attribute to any PCIe port that has an "external-facing" device tree property. Any device downstream of this port will inherit the attribute and have only the strictest IOMMU protection. Signed-off-by: Jean-Philippe Brucker Signed-off-by: Bjorn Helgaas --- drivers/pci/of.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 3d32da15c215..67376cf45880 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -31,10 +31,16 @@ void pci_release_of_node(struct pci_dev *dev) void pci_set_bus_of_node(struct pci_bus *bus) { - if (bus->self == NULL) - bus->dev.of_node = pcibios_get_phb_of_node(bus); - else - bus->dev.of_node = of_node_get(bus->self->dev.of_node); + struct device_node *node; + + if (bus->self == NULL) { + node = pcibios_get_phb_of_node(bus); + } else { + node = of_node_get(bus->self->dev.of_node); + if (node && of_property_read_bool(node, "external-facing")) + bus->self->untrusted = true; + } + bus->dev.of_node = node; } void pci_release_bus_of_node(struct pci_bus *bus) -- cgit From 258f250fc5f7f11dec00fc267a0424dd2a0fa8f4 Mon Sep 17 00:00:00 2001 From: Honghui Zhang Date: Mon, 18 Mar 2019 16:27:55 +0800 Subject: arm64: dts: mt2712: Remove un-used property for PCIe The "num-lanes" property for PCIe is not used, remove it. Signed-off-by: Honghui Zhang Signed-off-by: Lorenzo Pieralisi --- arch/arm64/boot/dts/mediatek/mt2712e.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi index 976d92a94738..43307bad3f0d 100644 --- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi @@ -819,7 +819,6 @@ #size-cells = <2>; #interrupt-cells = <1>; ranges; - num-lanes = <1>; interrupt-map-mask = <0 0 0 7>; interrupt-map = <0 0 0 1 &pcie_intc0 0>, <0 0 0 2 &pcie_intc0 1>, @@ -840,7 +839,6 @@ #size-cells = <2>; #interrupt-cells = <1>; ranges; - num-lanes = <1>; interrupt-map-mask = <0 0 0 7>; interrupt-map = <0 0 0 1 &pcie_intc1 0>, <0 0 0 2 &pcie_intc1 1>, -- cgit From 31f996efbd5a7825f4d30150469e9d110aea00e8 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 12 Apr 2019 06:43:06 +0000 Subject: PCI/AER: Change pci_aer_init() stub to return void Commit 60ed982a4e78 ("PCI/AER: Move internal declarations to drivers/pci/pci.h") changed pci_aer_init() to return "void", but didn't change the stub for when CONFIG_PCIEAER isn't enabled. Change the stub to match. Fixes: 60ed982a4e78 ("PCI/AER: Move internal declarations to drivers/pci/pci.h") Signed-off-by: Jisheng Zhang Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v4.19+ --- drivers/pci/pci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 224d88634115..17c4ed2021de 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -596,7 +596,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev); void pci_aer_clear_device_status(struct pci_dev *dev); #else static inline void pci_no_aer(void) { } -static inline int pci_aer_init(struct pci_dev *d) { return -ENODEV; } +static inline void pci_aer_init(struct pci_dev *d) { } static inline void pci_aer_exit(struct pci_dev *d) { } static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { } static inline void pci_aer_clear_device_status(struct pci_dev *dev) { } -- cgit From 507b820009a457afa78202da337bcb56791fbb12 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Fri, 15 Mar 2019 00:07:10 -0500 Subject: PCI: endpoint: Fix a potential NULL pointer dereference In case alloc_workqueue() fails, return -ENOMEM to avoid potential NULL pointer dereferences. Signed-off-by: Kangjie Lu [lorenzo.pieralisi@arm.com: commit log and code update] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/endpoint/functions/pci-epf-test.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index d0b91da49bf4..ed5cd28b9572 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -591,6 +591,11 @@ static int __init pci_epf_test_init(void) kpcitest_workqueue = alloc_workqueue("kpcitest", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + if (!kpcitest_workqueue) { + pr_err("Failed to allocate the kpcitest work queue\n"); + return -ENOMEM; + } + ret = pci_epf_register_driver(&test_driver); if (ret) { pr_err("Failed to register pci epf test driver --> %d\n", ret); -- cgit From 74356addc0b32e891327bcb1e36d7f798f7b1c7d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 9 Jan 2019 14:14:42 -0600 Subject: PCI: Fix comment typos Fix spelling errors and format function comments consistently. Changes whitespace and comments only; no functional change intended. Signed-off-by: Bjorn Helgaas Reviewed-by: Mukesh Ojha --- drivers/pci/controller/pci-host-generic.c | 2 +- drivers/pci/controller/pcie-iproc-msi.c | 2 +- drivers/pci/pci.c | 328 ++++++++++++++++-------------- 3 files changed, 172 insertions(+), 160 deletions(-) diff --git a/drivers/pci/controller/pci-host-generic.c b/drivers/pci/controller/pci-host-generic.c index dea3ec7592a2..75a2fb930d4b 100644 --- a/drivers/pci/controller/pci-host-generic.c +++ b/drivers/pci/controller/pci-host-generic.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Simple, generic PCI host controller driver targetting firmware-initialised + * Simple, generic PCI host controller driver targeting firmware-initialised * systems and virtual machines (e.g. the PCI emulation provided by kvmtool). * * Copyright (C) 2014 ARM Limited diff --git a/drivers/pci/controller/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c index cb3401a931f8..0a3f61be5625 100644 --- a/drivers/pci/controller/pcie-iproc-msi.c +++ b/drivers/pci/controller/pcie-iproc-msi.c @@ -367,7 +367,7 @@ static void iproc_msi_handler(struct irq_desc *desc) /* * Now go read the tail pointer again to see if there are new - * oustanding events that came in during the above window. + * outstanding events that came in during the above window. */ } while (true); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7c1b362f599a..530eec3191e7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -197,8 +197,8 @@ EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar); /** * pci_dev_str_match_path - test if a path string matches a device - * @dev: the PCI device to test - * @path: string to match the device against + * @dev: the PCI device to test + * @path: string to match the device against * @endptr: pointer to the string after the match * * Test if a string (typically from a kernel parameter) formatted as a @@ -280,8 +280,8 @@ free_and_exit: /** * pci_dev_str_match - test if a string matches a device - * @dev: the PCI device to test - * @p: string to match the device against + * @dev: the PCI device to test + * @p: string to match the device against * @endptr: pointer to the string after the match * * Test if a string (typically from a kernel parameter) matches a specified @@ -341,7 +341,7 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p, } else { /* * PCI Bus, Device, Function IDs are specified - * (optionally, may include a path of devfns following it) + * (optionally, may include a path of devfns following it) */ ret = pci_dev_str_match_path(dev, p, &p); if (ret < 0) @@ -425,7 +425,7 @@ static int __pci_bus_find_cap_start(struct pci_bus *bus, * Tell if a device supports a given PCI capability. * Returns the address of the requested capability structure within the * device's PCI configuration space or 0 in case the device does not - * support it. Possible values for @cap: + * support it. Possible values for @cap include: * * %PCI_CAP_ID_PM Power Management * %PCI_CAP_ID_AGP Accelerated Graphics Port @@ -450,11 +450,11 @@ EXPORT_SYMBOL(pci_find_capability); /** * pci_bus_find_capability - query for devices' capabilities - * @bus: the PCI bus to query + * @bus: the PCI bus to query * @devfn: PCI device to query - * @cap: capability code + * @cap: capability code * - * Like pci_find_capability() but works for pci devices that do not have a + * Like pci_find_capability() but works for PCI devices that do not have a * pci_dev structure set up yet. * * Returns the address of the requested capability structure within the @@ -535,7 +535,7 @@ EXPORT_SYMBOL_GPL(pci_find_next_ext_capability); * * Returns the address of the requested extended capability structure * within the device's PCI configuration space or 0 if the device does - * not support it. Possible values for @cap: + * not support it. Possible values for @cap include: * * %PCI_EXT_CAP_ID_ERR Advanced Error Reporting * %PCI_EXT_CAP_ID_VC Virtual Channel @@ -618,12 +618,13 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) EXPORT_SYMBOL_GPL(pci_find_ht_capability); /** - * pci_find_parent_resource - return resource region of parent bus of given region + * pci_find_parent_resource - return resource region of parent bus of given + * region * @dev: PCI device structure contains resources to be searched * @res: child resource record for which parent is sought * - * For given resource region of given device, return the resource - * region of parent bus the given region is contained in. + * For given resource region of given device, return the resource region of + * parent bus the given region is contained in. */ struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) @@ -800,7 +801,7 @@ static inline bool platform_pci_bridge_d3(struct pci_dev *dev) /** * pci_raw_set_power_state - Use PCI PM registers to set the power state of - * given PCI device + * given PCI device * @dev: PCI device to handle. * @state: PCI power state (D0, D1, D2, D3hot) to put the device into. * @@ -826,7 +827,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) if (state < PCI_D0 || state > PCI_D3hot) return -EINVAL; - /* Validate current state: + /* + * Validate current state: * Can enter D0 from any state, but if we can only go deeper * to sleep if we're already in a low power state */ @@ -837,14 +839,15 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) return -EINVAL; } - /* check if this device supports the desired state */ + /* Check if this device supports the desired state */ if ((state == PCI_D1 && !dev->d1_support) || (state == PCI_D2 && !dev->d2_support)) return -EIO; pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); - /* If we're (effectively) in D3, force entire word to 0. + /* + * If we're (effectively) in D3, force entire word to 0. * This doesn't affect PME_Status, disables PME_En, and * sets PowerState to 0. */ @@ -867,11 +870,13 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) break; } - /* enter specified state */ + /* Enter specified state */ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); - /* Mandatory power management transition delays */ - /* see PCI PM 1.1 5.6.1 table 18 */ + /* + * Mandatory power management transition delays; see PCI PM 1.1 + * 5.6.1 table 18 + */ if (state == PCI_D3hot || dev->current_state == PCI_D3hot) pci_dev_d3_sleep(dev); else if (state == PCI_D2 || dev->current_state == PCI_D2) @@ -1085,16 +1090,18 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { int error; - /* bound the state we're entering */ + /* Bound the state we're entering */ if (state > PCI_D3cold) state = PCI_D3cold; else if (state < PCI_D0) state = PCI_D0; else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) + /* - * If the device or the parent bridge do not support PCI PM, - * ignore the request if we're doing anything other than putting - * it into D0 (which would only happen on boot). + * If the device or the parent bridge do not support PCI + * PM, ignore the request if we're doing anything other + * than putting it into D0 (which would only happen on + * boot). */ return 0; @@ -1104,8 +1111,10 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) __pci_start_power_transition(dev, state); - /* This device is quirked not to be put into D3, so - don't put it in D3 */ + /* + * This device is quirked not to be put into D3, so don't put it in + * D3 + */ if (state >= PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3)) return 0; @@ -1127,12 +1136,11 @@ EXPORT_SYMBOL(pci_set_power_state); * pci_choose_state - Choose the power state of a PCI device * @dev: PCI device to be suspended * @state: target sleep state for the whole system. This is the value - * that is passed to suspend() function. + * that is passed to suspend() function. * * Returns PCI power state suitable for given device and given system * message. */ - pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { pci_power_t ret; @@ -1310,8 +1318,9 @@ static void pci_restore_ltr_state(struct pci_dev *dev) } /** - * pci_save_state - save the PCI configuration space of a device before suspending - * @dev: - PCI device that we're dealing with + * pci_save_state - save the PCI configuration space of a device before + * suspending + * @dev: PCI device that we're dealing with */ int pci_save_state(struct pci_dev *dev) { @@ -1422,7 +1431,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev) /** * pci_restore_state - Restore the saved state of a PCI device - * @dev: - PCI device that we're dealing with + * @dev: PCI device that we're dealing with */ void pci_restore_state(struct pci_dev *dev) { @@ -1599,8 +1608,8 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars) * pci_reenable_device - Resume abandoned device * @dev: PCI device to be resumed * - * Note this function is a backend of pci_default_resume and is not supposed - * to be called by normal code, write proper resume handler and use it instead. + * NOTE: This function is a backend of pci_default_resume() and is not supposed + * to be called by normal code, write proper resume handler and use it instead. */ int pci_reenable_device(struct pci_dev *dev) { @@ -1675,9 +1684,9 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) * pci_enable_device_io - Initialize a device for use with IO space * @dev: PCI device to be initialized * - * Initialize device before it's used by a driver. Ask low-level code - * to enable I/O resources. Wake up the device if it was suspended. - * Beware, this function can fail. + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O resources. Wake up the device if it was suspended. + * Beware, this function can fail. */ int pci_enable_device_io(struct pci_dev *dev) { @@ -1689,9 +1698,9 @@ EXPORT_SYMBOL(pci_enable_device_io); * pci_enable_device_mem - Initialize a device for use with Memory space * @dev: PCI device to be initialized * - * Initialize device before it's used by a driver. Ask low-level code - * to enable Memory resources. Wake up the device if it was suspended. - * Beware, this function can fail. + * Initialize device before it's used by a driver. Ask low-level code + * to enable Memory resources. Wake up the device if it was suspended. + * Beware, this function can fail. */ int pci_enable_device_mem(struct pci_dev *dev) { @@ -1703,12 +1712,12 @@ EXPORT_SYMBOL(pci_enable_device_mem); * pci_enable_device - Initialize device before it's used by a driver. * @dev: PCI device to be initialized * - * Initialize device before it's used by a driver. Ask low-level code - * to enable I/O and memory. Wake up the device if it was suspended. - * Beware, this function can fail. + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O and memory. Wake up the device if it was suspended. + * Beware, this function can fail. * - * Note we don't actually enable the device many times if we call - * this function repeatedly (we just increment the count). + * Note we don't actually enable the device many times if we call + * this function repeatedly (we just increment the count). */ int pci_enable_device(struct pci_dev *dev) { @@ -1717,8 +1726,8 @@ int pci_enable_device(struct pci_dev *dev) EXPORT_SYMBOL(pci_enable_device); /* - * Managed PCI resources. This manages device on/off, intx/msi/msix - * on/off and BAR regions. pci_dev itself records msi/msix status, so + * Managed PCI resources. This manages device on/off, INTx/MSI/MSI-X + * on/off and BAR regions. pci_dev itself records MSI/MSI-X status, so * there's no need to track it separately. pci_devres is initialized * when a device is enabled using managed PCI device enable interface. */ @@ -1836,7 +1845,8 @@ int __weak pcibios_add_device(struct pci_dev *dev) } /** - * pcibios_release_device - provide arch specific hooks when releasing device dev + * pcibios_release_device - provide arch specific hooks when releasing + * device dev * @dev: the PCI device being released * * Permits the platform to provide architecture specific functionality when @@ -1927,8 +1937,7 @@ EXPORT_SYMBOL(pci_disable_device); * @dev: the PCIe device reset * @state: Reset state to enter into * - * - * Sets the PCIe reset state for the device. This is the default + * Set the PCIe reset state for the device. This is the default * implementation. Architecture implementations can override this. */ int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev, @@ -1942,7 +1951,6 @@ int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev, * @dev: the PCIe device reset * @state: Reset state to enter into * - * * Sets the PCI reset state for the device. */ int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) @@ -2339,7 +2347,8 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup) } /** - * pci_prepare_to_sleep - prepare PCI device for system-wide transition into a sleep state + * pci_prepare_to_sleep - prepare PCI device for system-wide transition + * into a sleep state * @dev: Device to handle. * * Choose the power state appropriate for the device depending on whether @@ -2367,7 +2376,8 @@ int pci_prepare_to_sleep(struct pci_dev *dev) EXPORT_SYMBOL(pci_prepare_to_sleep); /** - * pci_back_from_sleep - turn PCI device on during system-wide transition into working state + * pci_back_from_sleep - turn PCI device on during system-wide transition + * into working state * @dev: Device to handle. * * Disable device's system wake-up capability and put it into D0. @@ -3005,7 +3015,7 @@ static void pci_add_saved_cap(struct pci_dev *pci_dev, /** * _pci_add_cap_save_buffer - allocate buffer for saving given - * capability registers + * capability registers * @dev: the PCI device * @cap: the capability to allocate the buffer for * @extended: Standard or Extended capability ID @@ -3186,7 +3196,7 @@ static void pci_disable_acs_redir(struct pci_dev *dev) } /** - * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites + * pci_std_enable_acs - enable ACS on devices using standard ACS capabilities * @dev: the PCI device */ static void pci_std_enable_acs(struct pci_dev *dev) @@ -3609,13 +3619,14 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) EXPORT_SYMBOL_GPL(pci_common_swizzle); /** - * pci_release_region - Release a PCI bar - * @pdev: PCI device whose resources were previously reserved by pci_request_region - * @bar: BAR to release + * pci_release_region - Release a PCI bar + * @pdev: PCI device whose resources were previously reserved by + * pci_request_region() + * @bar: BAR to release * - * Releases the PCI I/O and memory resources previously reserved by a - * successful call to pci_request_region. Call this function only - * after all use of the PCI regions has ceased. + * Releases the PCI I/O and memory resources previously reserved by a + * successful call to pci_request_region(). Call this function only + * after all use of the PCI regions has ceased. */ void pci_release_region(struct pci_dev *pdev, int bar) { @@ -3637,23 +3648,23 @@ void pci_release_region(struct pci_dev *pdev, int bar) EXPORT_SYMBOL(pci_release_region); /** - * __pci_request_region - Reserved PCI I/O and memory resource - * @pdev: PCI device whose resources are to be reserved - * @bar: BAR to be reserved - * @res_name: Name to be associated with resource. - * @exclusive: whether the region access is exclusive or not + * __pci_request_region - Reserved PCI I/O and memory resource + * @pdev: PCI device whose resources are to be reserved + * @bar: BAR to be reserved + * @res_name: Name to be associated with resource. + * @exclusive: whether the region access is exclusive or not * - * Mark the PCI region associated with PCI device @pdev BR @bar as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark the PCI region associated with PCI device @pdev BAR @bar as + * being reserved by owner @res_name. Do not access any + * address inside the PCI regions unless this call returns + * successfully. * - * If @exclusive is set, then the region is marked so that userspace - * is explicitly not allowed to map the resource via /dev/mem or - * sysfs MMIO access. + * If @exclusive is set, then the region is marked so that userspace + * is explicitly not allowed to map the resource via /dev/mem or + * sysfs MMIO access. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning + * message is also printed on failure. */ static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_name, int exclusive) @@ -3687,18 +3698,18 @@ err_out: } /** - * pci_request_region - Reserve PCI I/O and memory resource - * @pdev: PCI device whose resources are to be reserved - * @bar: BAR to be reserved - * @res_name: Name to be associated with resource + * pci_request_region - Reserve PCI I/O and memory resource + * @pdev: PCI device whose resources are to be reserved + * @bar: BAR to be reserved + * @res_name: Name to be associated with resource * - * Mark the PCI region associated with PCI device @pdev BAR @bar as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark the PCI region associated with PCI device @pdev BAR @bar as + * being reserved by owner @res_name. Do not access any + * address inside the PCI regions unless this call returns + * successfully. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning + * message is also printed on failure. */ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) { @@ -3707,22 +3718,22 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) EXPORT_SYMBOL(pci_request_region); /** - * pci_request_region_exclusive - Reserved PCI I/O and memory resource - * @pdev: PCI device whose resources are to be reserved - * @bar: BAR to be reserved - * @res_name: Name to be associated with resource. + * pci_request_region_exclusive - Reserved PCI I/O and memory resource + * @pdev: PCI device whose resources are to be reserved + * @bar: BAR to be reserved + * @res_name: Name to be associated with resource. * - * Mark the PCI region associated with PCI device @pdev BR @bar as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark the PCI region associated with PCI device @pdev BAR @bar as + * being reserved by owner @res_name. Do not access any + * address inside the PCI regions unless this call returns + * successfully. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning + * message is also printed on failure. * - * The key difference that _exclusive makes it that userspace is - * explicitly not allowed to map the resource via /dev/mem or - * sysfs. + * The key difference that _exclusive makes it that userspace is + * explicitly not allowed to map the resource via /dev/mem or + * sysfs. */ int pci_request_region_exclusive(struct pci_dev *pdev, int bar, const char *res_name) @@ -3791,12 +3802,13 @@ int pci_request_selected_regions_exclusive(struct pci_dev *pdev, int bars, EXPORT_SYMBOL(pci_request_selected_regions_exclusive); /** - * pci_release_regions - Release reserved PCI I/O and memory resources - * @pdev: PCI device whose resources were previously reserved by pci_request_regions + * pci_release_regions - Release reserved PCI I/O and memory resources + * @pdev: PCI device whose resources were previously reserved by + * pci_request_regions() * - * Releases all PCI I/O and memory resources previously reserved by a - * successful call to pci_request_regions. Call this function only - * after all use of the PCI regions has ceased. + * Releases all PCI I/O and memory resources previously reserved by a + * successful call to pci_request_regions(). Call this function only + * after all use of the PCI regions has ceased. */ void pci_release_regions(struct pci_dev *pdev) @@ -3806,17 +3818,17 @@ void pci_release_regions(struct pci_dev *pdev) EXPORT_SYMBOL(pci_release_regions); /** - * pci_request_regions - Reserved PCI I/O and memory resources - * @pdev: PCI device whose resources are to be reserved - * @res_name: Name to be associated with resource. + * pci_request_regions - Reserve PCI I/O and memory resources + * @pdev: PCI device whose resources are to be reserved + * @res_name: Name to be associated with resource. * - * Mark all PCI regions associated with PCI device @pdev as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark all PCI regions associated with PCI device @pdev as + * being reserved by owner @res_name. Do not access any + * address inside the PCI regions unless this call returns + * successfully. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning + * message is also printed on failure. */ int pci_request_regions(struct pci_dev *pdev, const char *res_name) { @@ -3825,20 +3837,19 @@ int pci_request_regions(struct pci_dev *pdev, const char *res_name) EXPORT_SYMBOL(pci_request_regions); /** - * pci_request_regions_exclusive - Reserved PCI I/O and memory resources - * @pdev: PCI device whose resources are to be reserved - * @res_name: Name to be associated with resource. + * pci_request_regions_exclusive - Reserve PCI I/O and memory resources + * @pdev: PCI device whose resources are to be reserved + * @res_name: Name to be associated with resource. * - * Mark all PCI regions associated with PCI device @pdev as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark all PCI regions associated with PCI device @pdev as being reserved + * by owner @res_name. Do not access any address inside the PCI regions + * unless this call returns successfully. * - * pci_request_regions_exclusive() will mark the region so that - * /dev/mem and the sysfs MMIO access will not be allowed. + * pci_request_regions_exclusive() will mark the region so that /dev/mem + * and the sysfs MMIO access will not be allowed. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning message is also + * printed on failure. */ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name) { @@ -3849,7 +3860,7 @@ EXPORT_SYMBOL(pci_request_regions_exclusive); /* * Record the PCI IO range (expressed as CPU physical address + size). - * Return a negative value if an error has occured, zero otherwise + * Return a negative value if an error has occurred, zero otherwise */ int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr, resource_size_t size) @@ -3905,14 +3916,14 @@ unsigned long __weak pci_address_to_pio(phys_addr_t address) } /** - * pci_remap_iospace - Remap the memory mapped I/O space - * @res: Resource describing the I/O space - * @phys_addr: physical address of range to be mapped + * pci_remap_iospace - Remap the memory mapped I/O space + * @res: Resource describing the I/O space + * @phys_addr: physical address of range to be mapped * - * Remap the memory mapped I/O space described by the @res - * and the CPU physical address @phys_addr into virtual address space. - * Only architectures that have memory mapped IO functions defined - * (and the PCI_IOBASE value defined) should call this function. + * Remap the memory mapped I/O space described by the @res and the CPU + * physical address @phys_addr into virtual address space. Only + * architectures that have memory mapped IO functions defined (and the + * PCI_IOBASE value defined) should call this function. */ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) { @@ -3928,8 +3939,10 @@ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) return ioremap_page_range(vaddr, vaddr + resource_size(res), phys_addr, pgprot_device(PAGE_KERNEL)); #else - /* this architecture does not have memory mapped I/O space, - so this function should never be called */ + /* + * This architecture does not have memory mapped I/O space, + * so this function should never be called + */ WARN_ONCE(1, "This architecture does not support memory mapped I/O\n"); return -ENODEV; #endif @@ -3937,12 +3950,12 @@ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) EXPORT_SYMBOL(pci_remap_iospace); /** - * pci_unmap_iospace - Unmap the memory mapped I/O space - * @res: resource to be unmapped + * pci_unmap_iospace - Unmap the memory mapped I/O space + * @res: resource to be unmapped * - * Unmap the CPU virtual address @res from virtual address space. - * Only architectures that have memory mapped IO functions defined - * (and the PCI_IOBASE value defined) should call this function. + * Unmap the CPU virtual address @res from virtual address space. Only + * architectures that have memory mapped IO functions defined (and the + * PCI_IOBASE value defined) should call this function. */ void pci_unmap_iospace(struct resource *res) { @@ -4288,7 +4301,7 @@ EXPORT_SYMBOL(pci_clear_mwi); * @pdev: the PCI device to operate on * @enable: boolean: whether to enable or disable PCI INTx * - * Enables/disables PCI INTx for device dev + * Enables/disables PCI INTx for device @pdev */ void pci_intx(struct pci_dev *pdev, int enable) { @@ -4364,9 +4377,8 @@ done: * pci_check_and_mask_intx - mask INTx on pending interrupt * @dev: the PCI device to operate on * - * Check if the device dev has its INTx line asserted, mask it and - * return true in that case. False is returned if no interrupt was - * pending. + * Check if the device dev has its INTx line asserted, mask it and return + * true in that case. False is returned if no interrupt was pending. */ bool pci_check_and_mask_intx(struct pci_dev *dev) { @@ -4378,9 +4390,9 @@ EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending * @dev: the PCI device to operate on * - * Check if the device dev has its INTx line asserted, unmask it if not - * and return true. False is returned and the mask remains active if - * there was still an interrupt pending. + * Check if the device dev has its INTx line asserted, unmask it if not and + * return true. False is returned and the mask remains active if there was + * still an interrupt pending. */ bool pci_check_and_unmask_intx(struct pci_dev *dev) { @@ -4389,7 +4401,7 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev) EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); /** - * pci_wait_for_pending_transaction - waits for pending transaction + * pci_wait_for_pending_transaction - wait for pending transaction * @dev: the PCI device to operate on * * Return 0 if transaction is pending 1 otherwise. @@ -4447,7 +4459,7 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) /** * pcie_has_flr - check if a device supports function level resets - * @dev: device to check + * @dev: device to check * * Returns true if the device advertises support for PCIe function level * resets. @@ -4466,7 +4478,7 @@ EXPORT_SYMBOL_GPL(pcie_has_flr); /** * pcie_flr - initiate a PCIe function level reset - * @dev: device to reset + * @dev: device to reset * * Initiate a function level reset on @dev. The caller should ensure the * device supports FLR before calling this function, e.g. by using the @@ -4810,6 +4822,7 @@ static void pci_dev_restore(struct pci_dev *dev) * * The device function is presumed to be unused and the caller is holding * the device mutex lock when this function is called. + * * Resetting the device will make the contents of PCI configuration space * random, so any caller of this must be prepared to reinitialise the * device including MSI, bus mastering, BARs, decoding IO and memory spaces, @@ -5373,8 +5386,8 @@ EXPORT_SYMBOL_GPL(pci_reset_bus); * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count * @dev: PCI device to query * - * Returns mmrbc: maximum designed memory read count in bytes - * or appropriate error value. + * Returns mmrbc: maximum designed memory read count in bytes or + * appropriate error value. */ int pcix_get_max_mmrbc(struct pci_dev *dev) { @@ -5396,8 +5409,8 @@ EXPORT_SYMBOL(pcix_get_max_mmrbc); * pcix_get_mmrbc - get PCI-X maximum memory read byte count * @dev: PCI device to query * - * Returns mmrbc: maximum memory read count in bytes - * or appropriate error value. + * Returns mmrbc: maximum memory read count in bytes or appropriate error + * value. */ int pcix_get_mmrbc(struct pci_dev *dev) { @@ -5421,7 +5434,7 @@ EXPORT_SYMBOL(pcix_get_mmrbc); * @mmrbc: maximum memory read count in bytes * valid values are 512, 1024, 2048, 4096 * - * If possible sets maximum memory read byte count, some bridges have erratas + * If possible sets maximum memory read byte count, some bridges have errata * that prevent this. */ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) @@ -5466,8 +5479,7 @@ EXPORT_SYMBOL(pcix_set_mmrbc); * pcie_get_readrq - get PCI Express read request size * @dev: PCI device to query * - * Returns maximum memory read request in bytes - * or appropriate error value. + * Returns maximum memory read request in bytes or appropriate error value. */ int pcie_get_readrq(struct pci_dev *dev) { @@ -5495,10 +5507,9 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) return -EINVAL; /* - * If using the "performance" PCIe config, we clamp the - * read rq size to the max packet size to prevent the - * host bridge generating requests larger than we can - * cope with + * If using the "performance" PCIe config, we clamp the read rq + * size to the max packet size to keep the host bridge from + * generating requests larger than we can cope with. */ if (pcie_bus_config == PCIE_BUS_PERFORMANCE) { int mps = pcie_get_mps(dev); @@ -6144,6 +6155,7 @@ static int of_pci_bus_find_domain_nr(struct device *parent) if (parent) domain = of_get_pci_domain_nr(parent->of_node); + /* * Check DT domain and use_dt_domains values. * -- cgit From 12fa4f47924c9e0638869c2315dda29d50a94446 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 1 Sep 2017 18:14:04 -0500 Subject: CPER: Add UEFI spec references Add UEFI spec references for CPER UUIDs and structures, fix a few typos, and remove some useless comments. No functional change intended. Link: http://www.uefi.org/specifications Signed-off-by: Bjorn Helgaas --- include/linux/cper.h | 54 +++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/include/linux/cper.h b/include/linux/cper.h index 9c703a0abe6e..2f361a96dc76 100644 --- a/include/linux/cper.h +++ b/include/linux/cper.h @@ -44,7 +44,7 @@ */ #define CPER_REC_LEN 256 /* - * Severity difinition for error_severity in struct cper_record_header + * Severity definition for error_severity in struct cper_record_header * and section_severity in struct cper_section_descriptor */ enum { @@ -55,24 +55,21 @@ enum { }; /* - * Validation bits difinition for validation_bits in struct + * Validation bits definition for validation_bits in struct * cper_record_header. If set, corresponding fields in struct * cper_record_header contain valid information. - * - * corresponds platform_id */ #define CPER_VALID_PLATFORM_ID 0x0001 -/* corresponds timestamp */ #define CPER_VALID_TIMESTAMP 0x0002 -/* corresponds partition_id */ #define CPER_VALID_PARTITION_ID 0x0004 /* * Notification type used to generate error record, used in - * notification_type in struct cper_record_header - * - * Corrected Machine Check + * notification_type in struct cper_record_header. These UUIDs are defined + * in the UEFI spec v2.7, sec N.2.1. */ + +/* Corrected Machine Check */ #define CPER_NOTIFY_CMC \ GUID_INIT(0x2DCE8BB1, 0xBDD7, 0x450e, 0xB9, 0xAD, 0x9C, 0xF4, \ 0xEB, 0xD4, 0xF8, 0x90) @@ -122,14 +119,11 @@ enum { #define CPER_SEC_REV 0x0100 /* - * Validation bits difinition for validation_bits in struct + * Validation bits definition for validation_bits in struct * cper_section_descriptor. If set, corresponding fields in struct * cper_section_descriptor contain valid information. - * - * corresponds fru_id */ #define CPER_SEC_VALID_FRU_ID 0x1 -/* corresponds fru_text */ #define CPER_SEC_VALID_FRU_TEXT 0x2 /* @@ -165,10 +159,11 @@ enum { /* * Section type definitions, used in section_type field in struct - * cper_section_descriptor - * - * Processor Generic + * cper_section_descriptor. These UUIDs are defined in the UEFI spec + * v2.7, sec N.2.2. */ + +/* Processor Generic */ #define CPER_SEC_PROC_GENERIC \ GUID_INIT(0x9876CCAD, 0x47B4, 0x4bdb, 0xB6, 0x5E, 0x16, 0xF1, \ 0x93, 0xC4, 0xF3, 0xDB) @@ -325,6 +320,7 @@ enum { */ #pragma pack(1) +/* Record Header, UEFI v2.7 sec N.2.1 */ struct cper_record_header { char signature[CPER_SIG_SIZE]; /* must be CPER_SIG_RECORD */ __u16 revision; /* must be CPER_RECORD_REV */ @@ -344,6 +340,7 @@ struct cper_record_header { __u8 reserved[12]; /* must be zero */ }; +/* Section Descriptor, UEFI v2.7 sec N.2.2 */ struct cper_section_descriptor { __u32 section_offset; /* Offset in bytes of the * section body from the base @@ -359,7 +356,7 @@ struct cper_section_descriptor { __u8 fru_text[20]; }; -/* Generic Processor Error Section */ +/* Generic Processor Error Section, UEFI v2.7 sec N.2.4.1 */ struct cper_sec_proc_generic { __u64 validation_bits; __u8 proc_type; @@ -378,14 +375,14 @@ struct cper_sec_proc_generic { __u64 ip; }; -/* IA32/X64 Processor Error Section */ +/* IA32/X64 Processor Error Section, UEFI v2.7 sec N.2.4.2 */ struct cper_sec_proc_ia { __u64 validation_bits; __u64 lapic_id; __u8 cpuid[48]; }; -/* IA32/X64 Processor Error Information Structure */ +/* IA32/X64 Processor Error Information Structure, UEFI v2.7 sec N.2.4.2.1 */ struct cper_ia_err_info { guid_t err_type; __u64 validation_bits; @@ -396,7 +393,7 @@ struct cper_ia_err_info { __u64 ip; }; -/* IA32/X64 Processor Context Information Structure */ +/* IA32/X64 Processor Context Information Structure, UEFI v2.7 sec N.2.4.2.2 */ struct cper_ia_proc_ctx { __u16 reg_ctx_type; __u16 reg_arr_size; @@ -404,7 +401,7 @@ struct cper_ia_proc_ctx { __u64 mm_reg_addr; }; -/* ARM Processor Error Section */ +/* ARM Processor Error Section, UEFI v2.7 sec N.2.4.4 */ struct cper_sec_proc_arm { __u32 validation_bits; __u16 err_info_num; /* Number of Processor Error Info */ @@ -418,7 +415,7 @@ struct cper_sec_proc_arm { __u32 psci_state; }; -/* ARM Processor Error Information Structure */ +/* ARM Processor Error Information Structure, UEFI v2.7 sec N.2.4.4.1 */ struct cper_arm_err_info { __u8 version; __u8 length; @@ -431,14 +428,14 @@ struct cper_arm_err_info { __u64 physical_fault_addr; }; -/* ARM Processor Context Information Structure */ +/* ARM Processor Context Information Structure, UEFI v2.7 sec N.2.4.4.2 */ struct cper_arm_ctx_info { __u16 version; __u16 type; __u32 size; }; -/* Old Memory Error Section UEFI 2.1, 2.2 */ +/* Old Memory Error Section, UEFI v2.1, v2.2 */ struct cper_sec_mem_err_old { __u64 validation_bits; __u64 error_status; @@ -458,7 +455,7 @@ struct cper_sec_mem_err_old { __u8 error_type; }; -/* Memory Error Section UEFI >= 2.3 */ +/* Memory Error Section (UEFI >= v2.3), UEFI v2.7 sec N.2.5 */ struct cper_sec_mem_err { __u64 validation_bits; __u64 error_status; @@ -478,8 +475,8 @@ struct cper_sec_mem_err { __u8 error_type; __u8 reserved; __u16 rank; - __u16 mem_array_handle; /* card handle in UEFI 2.4 */ - __u16 mem_dev_handle; /* module handle in UEFI 2.4 */ + __u16 mem_array_handle; /* "card handle" in UEFI 2.4 */ + __u16 mem_dev_handle; /* "module handle" in UEFI 2.4 */ }; struct cper_mem_err_compact { @@ -500,6 +497,7 @@ struct cper_mem_err_compact { __u16 mem_dev_handle; }; +/* PCI Express Error Section, UEFI v2.7 sec N.2.7 */ struct cper_sec_pcie { __u64 validation_bits; __u32 port_type; @@ -538,7 +536,7 @@ struct cper_sec_pcie { /* Reset to default packing */ #pragma pack() -extern const char * const cper_proc_error_type_strs[4]; +extern const char *const cper_proc_error_type_strs[4]; u64 cper_next_record_id(void); const char *cper_severity_str(unsigned int); -- cgit From 113fb03ed1d4c1877cc8817e500867616b222380 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 22 Mar 2019 13:06:40 -0500 Subject: CPER: Remove unnecessary use of user-space types "__u32" and similar types are intended for things exported to user-space, including structs used in ioctls; see include/uapi/asm-generic/int-l64.h. They are not needed for the CPER struct definitions, which not exported to user-space and not used in ioctls. Replace them with the typical "u32" and similar types. No functional change intended. The reason for changing this is to remove the question of "why do we use __u32 here instead of u32?" We should use __u32 when there's a reason for it; otherwise, we should prefer u32 for consistency. Reference: Documentation/process/coding-style.rst Signed-off-by: Bjorn Helgaas CC: Masahiro Yamada CC: Greg Kroah-Hartman CC: Andrew Morton --- include/linux/cper.h | 286 +++++++++++++++++++++++++-------------------------- 1 file changed, 143 insertions(+), 143 deletions(-) diff --git a/include/linux/cper.h b/include/linux/cper.h index 2f361a96dc76..cc4980bb0f65 100644 --- a/include/linux/cper.h +++ b/include/linux/cper.h @@ -323,214 +323,214 @@ enum { /* Record Header, UEFI v2.7 sec N.2.1 */ struct cper_record_header { char signature[CPER_SIG_SIZE]; /* must be CPER_SIG_RECORD */ - __u16 revision; /* must be CPER_RECORD_REV */ - __u32 signature_end; /* must be CPER_SIG_END */ - __u16 section_count; - __u32 error_severity; - __u32 validation_bits; - __u32 record_length; - __u64 timestamp; + u16 revision; /* must be CPER_RECORD_REV */ + u32 signature_end; /* must be CPER_SIG_END */ + u16 section_count; + u32 error_severity; + u32 validation_bits; + u32 record_length; + u64 timestamp; guid_t platform_id; guid_t partition_id; guid_t creator_id; guid_t notification_type; - __u64 record_id; - __u32 flags; - __u64 persistence_information; - __u8 reserved[12]; /* must be zero */ + u64 record_id; + u32 flags; + u64 persistence_information; + u8 reserved[12]; /* must be zero */ }; /* Section Descriptor, UEFI v2.7 sec N.2.2 */ struct cper_section_descriptor { - __u32 section_offset; /* Offset in bytes of the + u32 section_offset; /* Offset in bytes of the * section body from the base * of the record header */ - __u32 section_length; - __u16 revision; /* must be CPER_RECORD_REV */ - __u8 validation_bits; - __u8 reserved; /* must be zero */ - __u32 flags; + u32 section_length; + u16 revision; /* must be CPER_RECORD_REV */ + u8 validation_bits; + u8 reserved; /* must be zero */ + u32 flags; guid_t section_type; guid_t fru_id; - __u32 section_severity; - __u8 fru_text[20]; + u32 section_severity; + u8 fru_text[20]; }; /* Generic Processor Error Section, UEFI v2.7 sec N.2.4.1 */ struct cper_sec_proc_generic { - __u64 validation_bits; - __u8 proc_type; - __u8 proc_isa; - __u8 proc_error_type; - __u8 operation; - __u8 flags; - __u8 level; - __u16 reserved; - __u64 cpu_version; + u64 validation_bits; + u8 proc_type; + u8 proc_isa; + u8 proc_error_type; + u8 operation; + u8 flags; + u8 level; + u16 reserved; + u64 cpu_version; char cpu_brand[128]; - __u64 proc_id; - __u64 target_addr; - __u64 requestor_id; - __u64 responder_id; - __u64 ip; + u64 proc_id; + u64 target_addr; + u64 requestor_id; + u64 responder_id; + u64 ip; }; /* IA32/X64 Processor Error Section, UEFI v2.7 sec N.2.4.2 */ struct cper_sec_proc_ia { - __u64 validation_bits; - __u64 lapic_id; - __u8 cpuid[48]; + u64 validation_bits; + u64 lapic_id; + u8 cpuid[48]; }; /* IA32/X64 Processor Error Information Structure, UEFI v2.7 sec N.2.4.2.1 */ struct cper_ia_err_info { guid_t err_type; - __u64 validation_bits; - __u64 check_info; - __u64 target_id; - __u64 requestor_id; - __u64 responder_id; - __u64 ip; + u64 validation_bits; + u64 check_info; + u64 target_id; + u64 requestor_id; + u64 responder_id; + u64 ip; }; /* IA32/X64 Processor Context Information Structure, UEFI v2.7 sec N.2.4.2.2 */ struct cper_ia_proc_ctx { - __u16 reg_ctx_type; - __u16 reg_arr_size; - __u32 msr_addr; - __u64 mm_reg_addr; + u16 reg_ctx_type; + u16 reg_arr_size; + u32 msr_addr; + u64 mm_reg_addr; }; /* ARM Processor Error Section, UEFI v2.7 sec N.2.4.4 */ struct cper_sec_proc_arm { - __u32 validation_bits; - __u16 err_info_num; /* Number of Processor Error Info */ - __u16 context_info_num; /* Number of Processor Context Info Records*/ - __u32 section_length; - __u8 affinity_level; - __u8 reserved[3]; /* must be zero */ - __u64 mpidr; - __u64 midr; - __u32 running_state; /* Bit 0 set - Processor running. PSCI = 0 */ - __u32 psci_state; + u32 validation_bits; + u16 err_info_num; /* Number of Processor Error Info */ + u16 context_info_num; /* Number of Processor Context Info Records*/ + u32 section_length; + u8 affinity_level; + u8 reserved[3]; /* must be zero */ + u64 mpidr; + u64 midr; + u32 running_state; /* Bit 0 set - Processor running. PSCI = 0 */ + u32 psci_state; }; /* ARM Processor Error Information Structure, UEFI v2.7 sec N.2.4.4.1 */ struct cper_arm_err_info { - __u8 version; - __u8 length; - __u16 validation_bits; - __u8 type; - __u16 multiple_error; - __u8 flags; - __u64 error_info; - __u64 virt_fault_addr; - __u64 physical_fault_addr; + u8 version; + u8 length; + u16 validation_bits; + u8 type; + u16 multiple_error; + u8 flags; + u64 error_info; + u64 virt_fault_addr; + u64 physical_fault_addr; }; /* ARM Processor Context Information Structure, UEFI v2.7 sec N.2.4.4.2 */ struct cper_arm_ctx_info { - __u16 version; - __u16 type; - __u32 size; + u16 version; + u16 type; + u32 size; }; /* Old Memory Error Section, UEFI v2.1, v2.2 */ struct cper_sec_mem_err_old { - __u64 validation_bits; - __u64 error_status; - __u64 physical_addr; - __u64 physical_addr_mask; - __u16 node; - __u16 card; - __u16 module; - __u16 bank; - __u16 device; - __u16 row; - __u16 column; - __u16 bit_pos; - __u64 requestor_id; - __u64 responder_id; - __u64 target_id; - __u8 error_type; + u64 validation_bits; + u64 error_status; + u64 physical_addr; + u64 physical_addr_mask; + u16 node; + u16 card; + u16 module; + u16 bank; + u16 device; + u16 row; + u16 column; + u16 bit_pos; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u8 error_type; }; /* Memory Error Section (UEFI >= v2.3), UEFI v2.7 sec N.2.5 */ struct cper_sec_mem_err { - __u64 validation_bits; - __u64 error_status; - __u64 physical_addr; - __u64 physical_addr_mask; - __u16 node; - __u16 card; - __u16 module; - __u16 bank; - __u16 device; - __u16 row; - __u16 column; - __u16 bit_pos; - __u64 requestor_id; - __u64 responder_id; - __u64 target_id; - __u8 error_type; - __u8 reserved; - __u16 rank; - __u16 mem_array_handle; /* "card handle" in UEFI 2.4 */ - __u16 mem_dev_handle; /* "module handle" in UEFI 2.4 */ + u64 validation_bits; + u64 error_status; + u64 physical_addr; + u64 physical_addr_mask; + u16 node; + u16 card; + u16 module; + u16 bank; + u16 device; + u16 row; + u16 column; + u16 bit_pos; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u8 error_type; + u8 reserved; + u16 rank; + u16 mem_array_handle; /* "card handle" in UEFI 2.4 */ + u16 mem_dev_handle; /* "module handle" in UEFI 2.4 */ }; struct cper_mem_err_compact { - __u64 validation_bits; - __u16 node; - __u16 card; - __u16 module; - __u16 bank; - __u16 device; - __u16 row; - __u16 column; - __u16 bit_pos; - __u64 requestor_id; - __u64 responder_id; - __u64 target_id; - __u16 rank; - __u16 mem_array_handle; - __u16 mem_dev_handle; + u64 validation_bits; + u16 node; + u16 card; + u16 module; + u16 bank; + u16 device; + u16 row; + u16 column; + u16 bit_pos; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u16 rank; + u16 mem_array_handle; + u16 mem_dev_handle; }; /* PCI Express Error Section, UEFI v2.7 sec N.2.7 */ struct cper_sec_pcie { - __u64 validation_bits; - __u32 port_type; + u64 validation_bits; + u32 port_type; struct { - __u8 minor; - __u8 major; - __u8 reserved[2]; + u8 minor; + u8 major; + u8 reserved[2]; } version; - __u16 command; - __u16 status; - __u32 reserved; + u16 command; + u16 status; + u32 reserved; struct { - __u16 vendor_id; - __u16 device_id; - __u8 class_code[3]; - __u8 function; - __u8 device; - __u16 segment; - __u8 bus; - __u8 secondary_bus; - __u16 slot; - __u8 reserved; + u16 vendor_id; + u16 device_id; + u8 class_code[3]; + u8 function; + u8 device; + u16 segment; + u8 bus; + u8 secondary_bus; + u16 slot; + u8 reserved; } device_id; struct { - __u32 lower; - __u32 upper; + u32 lower; + u32 upper; } serial_number; struct { - __u16 secondary_status; - __u16 control; + u16 secondary_status; + u16 control; } bridge; - __u8 capability[60]; - __u8 aer_info[96]; + u8 capability[60]; + u8 aer_info[96]; }; /* Reset to default packing */ -- cgit From c577f4a5a08bb9677e12ddafb62e2f3a901de87f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 30 Mar 2019 15:09:10 +0000 Subject: PCI: rockchip: Fix rockchip_pcie_ep_assert_intx() bitwise operations Currently the bitwise operations on the u16 variable 'status' with the setting ROCKCHIP_PCIE_EP_CMD_STATUS_IS are incorrect because ROCKCHIP_PCIE_EP_CMD_STATUS_IS is 1UL<<19 which is wider than the u16 variable. Fix this by making status a u32. Fixes: cf590b078391 ("PCI: rockchip: Add EP driver for Rockchip PCIe controller") Signed-off-by: Colin Ian King Signed-off-by: Lorenzo Pieralisi Reviewed-by: Mukesh Ojha Acked-by: Shawn Lin --- drivers/pci/controller/pcie-rockchip-ep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index a5d799e2dff2..d743b0a48988 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -350,7 +350,7 @@ static void rockchip_pcie_ep_assert_intx(struct rockchip_pcie_ep *ep, u8 fn, struct rockchip_pcie *rockchip = &ep->rockchip; u32 r = ep->max_regions - 1; u32 offset; - u16 status; + u32 status; u8 msg_code; if (unlikely(ep->irq_pci_addr != ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR || -- cgit From b1dee41b76927747c1c63c5196ce9eaec6d0e81a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:27 +0530 Subject: PCI: keystone: Move resources initialization to prepare for EP support Move platform_get_resource() calls for resources that are applicable to both host and endpoint mode (ie "dbics" and "app") from ks_add_pcie_port() to the probe() callback, in preparation for adding endpoint support to pci-keystone driver. No functional change intended. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 5eebef9b9ada..95997885a05c 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -806,11 +806,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct resource *res; int ret; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbics"); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res); if (IS_ERR(pp->va_cfg0_base)) @@ -818,13 +813,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, pp->va_cfg1_base = pp->va_cfg0_base; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app"); - ks_pcie->va_app_base = devm_ioremap_resource(dev, res); - if (IS_ERR(ks_pcie->va_app_base)) - return PTR_ERR(ks_pcie->va_app_base); - - ks_pcie->app = *res; - pp->ops = &ks_pcie_host_ops; ret = dw_pcie_host_init(pp); if (ret) { @@ -895,6 +883,8 @@ static int __init ks_pcie_probe(struct platform_device *pdev) struct dw_pcie *pci; struct keystone_pcie *ks_pcie; struct device_link **link; + struct resource *res; + void __iomem *base; u32 num_viewport; struct phy **phy; u32 num_lanes; @@ -911,6 +901,19 @@ static int __init ks_pcie_probe(struct platform_device *pdev) if (!pci) return -ENOMEM; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app"); + ks_pcie->va_app_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ks_pcie->va_app_base)) + return PTR_ERR(ks_pcie->va_app_base); + + ks_pcie->app = *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbics"); + base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + pci->dbi_base = base; pci->dev = dev; pci->ops = &ks_pcie_dw_pcie_ops; -- cgit From 1c55c4263fe76f1a65b198787495c7f5f9e48002 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:28 +0530 Subject: dt-bindings: PCI: Add dt-binding to configure PCIe mode Add "ti,syscon-pcie-mode" dt-binding to hold phandle to the syscon register that should be used to configure PCIe in RC mode or EP mode. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/pci/pci-keystone.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt index 3a551687cfa2..8ee07197a063 100644 --- a/Documentation/devicetree/bindings/pci/pci-keystone.txt +++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt @@ -23,6 +23,8 @@ pcie_msi_intc : Interrupt controller device node for MSI IRQ chip ti,syscon-pcie-id : phandle to the device control module required to set device id and vendor id. +ti,syscon-pcie-mode : phandle to the device control module required to configure + PCI in either RC mode or EP mode. Example: pcie_msi_intc: msi-interrupt-controller { -- cgit From 156c6fef75a41bc463cc1e3c1b45de140443ae31 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:29 +0530 Subject: PCI: keystone: Explicitly set the PCIe mode Explicitly set the PCIe mode to BOOTCFG_DEVCFG instead of always relying on the default values. This is required when EP mode has to be explicitly written to BOOTCFG_DEVCFG register. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 95997885a05c..dfe54553d832 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -79,6 +79,15 @@ #define PCIE_RC_K2L 0xb00a #define PCIE_RC_K2G 0xb00b +#define KS_PCIE_DEV_TYPE_MASK (0x3 << 1) +#define KS_PCIE_DEV_TYPE(mode) ((mode) << 1) + +#define EP 0x0 +#define LEG_EP 0x1 +#define RC 0x2 + +#define KS_PCIE_SYSCLOCKOUTEN BIT(0) + #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) struct keystone_pcie { @@ -876,6 +885,30 @@ err_phy: return ret; } +static int ks_pcie_set_mode(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct regmap *syscon; + u32 val; + u32 mask; + int ret = 0; + + syscon = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pcie-mode"); + if (IS_ERR(syscon)) + return 0; + + mask = KS_PCIE_DEV_TYPE_MASK | KS_PCIE_SYSCLOCKOUTEN; + val = KS_PCIE_DEV_TYPE(RC) | KS_PCIE_SYSCLOCKOUTEN; + + ret = regmap_update_bits(syscon, 0, mask, val); + if (ret) { + dev_err(dev, "failed to set pcie mode\n"); + return ret; + } + + return 0; +} + static int __init ks_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -988,6 +1021,10 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } + ret = ks_pcie_set_mode(dev); + if (ret < 0) + goto err_get_sync; + ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) goto err_get_sync; -- cgit From 26f51e85b3b61106ea8b9e1c0a277aa3851f7433 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:30 +0530 Subject: dt-bindings: PCI: Document "atu" reg-names Document "atu" reg-names required to get the register space for ATU in Synopsys designware core version >= 4.80. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- Documentation/devicetree/bindings/pci/designware-pcie.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt index c124f9bc11f3..5561a1c060d0 100644 --- a/Documentation/devicetree/bindings/pci/designware-pcie.txt +++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt @@ -4,8 +4,11 @@ Required properties: - compatible: "snps,dw-pcie" for RC mode; "snps,dw-pcie-ep" for EP mode; -- reg: Should contain the configuration address space. -- reg-names: Must be "config" for the PCIe configuration space. +- reg: For designware cores version < 4.80 contains the configuration + address space. For designware core version >= 4.80, contains + the configuration and ATU address space +- reg-names: Must be "config" for the PCIe configuration space and "atu" for + the ATU address space. (The old way of getting the configuration address space from "ranges" is deprecated and should be avoided.) - num-lanes: number of lanes to use -- cgit From a9f4c2d2f99ec85ebc734a5bfb21a2cf93c169ad Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:31 +0530 Subject: PCI: dwc: Enable iATU unroll for endpoint too iatu_unroll_enabled flag is set only for Designware in host mode. However iATU unroll can be applicable for endpoint mode too. Set iatu_unroll_enabled flag in dw_pcie_setup() which is common for both host mode and endpoint mode. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-ep.c | 4 ---- drivers/pci/controller/dwc/pcie-designware-host.c | 19 ------------------- drivers/pci/controller/dwc/pcie-designware.c | 19 +++++++++++++++++++ 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 24f5a775ad34..dc6a4bbd3ace 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -517,10 +517,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) dev_err(dev, "dbi_base/dbi_base2 is not populated\n"); return -EINVAL; } - if (pci->iatu_unroll_enabled && !pci->atu_base) { - dev_err(dev, "atu_base is not populated\n"); - return -EINVAL; - } ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows); if (ret < 0) { diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 7e0ff7d428a9..7bf6558341b6 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -608,17 +608,6 @@ static struct pci_ops dw_pcie_ops = { .write = dw_pcie_wr_conf, }; -static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) -{ - u32 val; - - val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT); - if (val == 0xffffffff) - return 1; - - return 0; -} - void dw_pcie_setup_rc(struct pcie_port *pp) { u32 val, ctrl, num_ctrls; @@ -672,14 +661,6 @@ void dw_pcie_setup_rc(struct pcie_port *pp) * we should not program the ATU here. */ if (!pp->ops->rd_other_conf) { - /* Get iATU unroll support */ - pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci); - dev_dbg(pci->dev, "iATU unroll: %s\n", - pci->iatu_unroll_enabled ? "enabled" : "disabled"); - - if (pci->iatu_unroll_enabled && !pci->atu_base) - pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, PCIE_ATU_TYPE_MEM, pp->mem_base, pp->mem_bus_addr, pp->mem_size); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 31f6331ca46f..a14ca00f72aa 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -339,6 +339,17 @@ int dw_pcie_link_up(struct dw_pcie *pci) (!(val & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING))); } +static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) +{ + u32 val; + + val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT); + if (val == 0xffffffff) + return 1; + + return 0; +} + void dw_pcie_setup(struct dw_pcie *pci) { int ret; @@ -347,6 +358,14 @@ void dw_pcie_setup(struct dw_pcie *pci) struct device *dev = pci->dev; struct device_node *np = dev->of_node; + /* Get iATU unroll support */ + pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci); + dev_dbg(pci->dev, "iATU unroll: %s\n", + pci->iatu_unroll_enabled ? "enabled" : "disabled"); + + if (pci->iatu_unroll_enabled && !pci->atu_base) + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + ret = of_property_read_u32(np, "num-lanes", &lanes); if (ret) lanes = 0; -- cgit From 2aadcb0cd39198833fabe1c45084f78686e71a6c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:32 +0530 Subject: PCI: dwc: Fix ATU identification for designware version >= 4.80 Synopsys designware version >= 4.80 uses a separate register space for programming ATU. The current code identifies if there exists a separate register space by accessing the register address of ATUs in designware version < 4.80. Accessing this address results in abort in the case of K2G. Fix it here by adding "version" member to struct dw_pcie. This should be set by platform specific drivers and designware core will use it to identify if the platform has a separate ATU space. For platforms which have not populated the version member, the old method of identification will still be used. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware.c | 14 ++++++++------ drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index a14ca00f72aa..4e2f7946da89 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -358,13 +358,15 @@ void dw_pcie_setup(struct dw_pcie *pci) struct device *dev = pci->dev; struct device_node *np = dev->of_node; - /* Get iATU unroll support */ - pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci); - dev_dbg(pci->dev, "iATU unroll: %s\n", - pci->iatu_unroll_enabled ? "enabled" : "disabled"); + if (pci->version >= 0x480A || (!pci->version && + dw_pcie_iatu_unroll_enabled(pci))) { + pci->iatu_unroll_enabled = true; + if (!pci->atu_base) + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + } + dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? + "enabled" : "disabled"); - if (pci->iatu_unroll_enabled && !pci->atu_base) - pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; ret = of_property_read_u32(np, "num-lanes", &lanes); if (ret) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index ca3a3190a6f5..90a5b1215344 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -234,6 +234,7 @@ struct dw_pcie { struct pcie_port pp; struct dw_pcie_ep ep; const struct dw_pcie_ops *ops; + unsigned int version; }; #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) -- cgit From f316a2b53cd7f37963ae20ec7072eb27a349a4ce Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:33 +0530 Subject: PCI: keystone: Prevent ARM32 specific code to be compiled for ARM64 hook_fault_code() is an ARM32 specific API for hooking into data abort. AM65X platforms (that integrate ARM v8 cores and select CONFIG_ARM64 as arch) rely on pci-keystone.c but on them the enumeration of a non-present BDF does not trigger a bus error, so the fixup exception provided by calling hook_fault_code() is not needed and can be guarded with CONFIG_ARM. Signed-off-by: Kishon Vijay Abraham I [lorenzo.pieralisi@arm.com: commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index dfe54553d832..93296d434f40 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -710,6 +710,7 @@ err: return ret; } +#ifdef CONFIG_ARM /* * When a PCI device does not exist during config cycles, keystone host gets a * bus error instead of returning 0xffffffff. This handler always returns 0 @@ -729,6 +730,7 @@ static int ks_pcie_fault(unsigned long addr, unsigned int fsr, return 0; } +#endif static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie) { @@ -778,12 +780,14 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) if (ret < 0) return ret; +#ifdef CONFIG_ARM /* * PCIe access errors that result into OCP errors are caught by ARM as * "External aborts" */ hook_fault_code(17, ks_pcie_fault, SIGBUS, 0, "Asynchronous external abort"); +#endif ks_pcie_start_link(pci); dw_pcie_wait_for_link(pci); -- cgit From 162aaa3b6cc151720392adbdf7c6db9a7e06c769 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:34 +0530 Subject: dt-bindings: PCI: Add PCI RC DT binding documentation for AM654 Add devicetree binding documentation for PCIe in RC mode present in AM654 SoC. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/pci/pci-keystone.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt index 8ee07197a063..5c60e911b8b1 100644 --- a/Documentation/devicetree/bindings/pci/pci-keystone.txt +++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt @@ -11,7 +11,8 @@ described here as well as properties that are not applicable. Required Properties:- -compatibility: "ti,keystone-pcie" +compatibility: Should be "ti,keystone-pcie" for RC on Keystone2 SoC + Should be "ti,am654-pcie-rc" for RC on AM654x SoC reg: Three register ranges as listed in the reg-names property reg-names: "dbics" for the DesignWare PCIe registers, "app" for the TI specific application registers, "config" for the @@ -20,6 +21,9 @@ reg-names: "dbics" for the DesignWare PCIe registers, "app" for the pcie_msi_intc : Interrupt controller device node for MSI IRQ chip interrupt-cells: should be set to 1 interrupts: GIC interrupt lines connected to PCI MSI interrupt lines + (required if the compatible is "ti,keystone-pcie") +msi-map: As specified in Documentation/devicetree/bindings/pci/pci-msi.txt + (required if the compatible is "ti,am654-pcie-rc". ti,syscon-pcie-id : phandle to the device control module required to set device id and vendor id. -- cgit From 18b0415bc802a8bab5dedba5ae2757e83259e6ee Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:35 +0530 Subject: PCI: keystone: Add support for PCIe RC in AM654x Platforms Add PCIe RC support for AM654x Platforms in pci-keystone.c Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/Kconfig | 2 +- drivers/pci/controller/dwc/pci-keystone.c | 161 +++++++++++++++++++++++++++--- 2 files changed, 148 insertions(+), 15 deletions(-) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 6ea74b1c0d94..d1d00833e0b3 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -104,7 +104,7 @@ config PCIE_SPEAR13XX config PCI_KEYSTONE bool "TI Keystone PCIe controller" - depends on ARCH_KEYSTONE || (ARM && COMPILE_TEST) + depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST) depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST help diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 93296d434f40..a6a482bd648f 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +67,7 @@ #define ERR_IRQ_STATUS 0x1c4 #define ERR_IRQ_ENABLE_SET 0x1c8 #define ERR_AER BIT(5) /* ECRC error */ +#define AM6_ERR_AER BIT(4) /* AM6 ECRC error */ #define ERR_AXI BIT(4) /* AXI tag lookup fatal error */ #define ERR_CORR BIT(3) /* Correctable error */ #define ERR_NONFATAL BIT(2) /* Non-fatal error */ @@ -88,8 +91,15 @@ #define KS_PCIE_SYSCLOCKOUTEN BIT(0) +#define AM654_PCIE_DEV_TYPE_MASK 0x3 + #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) +struct ks_pcie_of_data { + const struct dw_pcie_host_ops *host_ops; + unsigned int version; +}; + struct keystone_pcie { struct dw_pcie *pci; /* PCI Device ID */ @@ -109,6 +119,7 @@ struct keystone_pcie { /* Application register space */ void __iomem *va_app_base; /* DT 1st resource */ struct resource app; + bool is_am6; }; static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset) @@ -250,6 +261,16 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset); } +static int ks_pcie_am654_msi_host_init(struct pcie_port *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct device *dev = pci->dev; + + dev_vdbg(dev, "dummy function so that DW core doesn't configure MSI\n"); + + return 0; +} + static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) { ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); @@ -276,10 +297,10 @@ static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) if (reg & ERR_CORR) dev_dbg(dev, "Correctable Error\n"); - if (reg & ERR_AXI) + if (!ks_pcie->is_am6 && (reg & ERR_AXI)) dev_err(dev, "AXI tag lookup fatal Error\n"); - if (reg & ERR_AER) + if (reg & ERR_AER || (ks_pcie->is_am6 && (reg & AM6_ERR_AER))) dev_err(dev, "ECRC Error\n"); ks_pcie_app_writel(ks_pcie, ERR_IRQ_STATUS, reg); @@ -377,6 +398,9 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0); ks_pcie_clear_dbi_mode(ks_pcie); + if (ks_pcie->is_am6) + return; + val = ilog2(OB_WIN_SIZE); ks_pcie_app_writel(ks_pcie, OB_SIZE, val); @@ -619,6 +643,8 @@ static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) intc_np = of_get_child_by_name(np, "msi-interrupt-controller"); if (!intc_np) { + if (ks_pcie->is_am6) + return 0; dev_warn(dev, "msi-interrupt-controller node is absent\n"); return -EINVAL; } @@ -668,6 +694,12 @@ static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie) intc_np = of_get_child_by_name(np, "legacy-interrupt-controller"); if (!intc_np) { + /* + * Since legacy interrupts are modeled as edge-interrupts in + * AM6, keep it disabled for now. + */ + if (ks_pcie->is_am6) + return 0; dev_warn(dev, "legacy-interrupt-controller node is absent\n"); return -EINVAL; } @@ -749,8 +781,10 @@ static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie) if (ret) return ret; + dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, id & PCIE_VENDORID_MASK); dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, id >> PCIE_DEVICEID_SHIFT); + dw_pcie_dbi_ro_wr_dis(pci); return 0; } @@ -803,6 +837,11 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = { .scan_bus = ks_pcie_v3_65_scan_bus, }; +static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = { + .host_init = ks_pcie_host_init, + .msi_host_init = ks_pcie_am654_msi_host_init, +}; + static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv) { struct keystone_pcie *ks_pcie = priv; @@ -826,7 +865,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, pp->va_cfg1_base = pp->va_cfg0_base; - pp->ops = &ks_pcie_host_ops; ret = dw_pcie_host_init(pp); if (ret) { dev_err(dev, "failed to initialize host\n"); @@ -836,14 +874,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, return 0; } -static const struct of_device_id ks_pcie_of_match[] = { - { - .type = "pci", - .compatible = "ti,keystone-pcie", - }, - { }, -}; - static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { .start_link = ks_pcie_start_link, .stop_link = ks_pcie_stop_link, @@ -913,14 +943,67 @@ static int ks_pcie_set_mode(struct device *dev) return 0; } +static int ks_pcie_am654_set_mode(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct regmap *syscon; + u32 val; + u32 mask; + int ret = 0; + + syscon = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pcie-mode"); + if (IS_ERR(syscon)) + return 0; + + mask = AM654_PCIE_DEV_TYPE_MASK; + val = RC; + + ret = regmap_update_bits(syscon, 0, mask, val); + if (ret) { + dev_err(dev, "failed to set pcie mode\n"); + return ret; + } + + return 0; +} + +static const struct ks_pcie_of_data ks_pcie_rc_of_data = { + .host_ops = &ks_pcie_host_ops, + .version = 0x365A, +}; + +static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = { + .host_ops = &ks_pcie_am654_host_ops, + .version = 0x490A, +}; + +static const struct of_device_id ks_pcie_of_match[] = { + { + .type = "pci", + .data = &ks_pcie_rc_of_data, + .compatible = "ti,keystone-pcie", + }, + { + .data = &ks_pcie_am654_rc_of_data, + .compatible = "ti,am654-pcie-rc", + }, + { }, +}; + static int __init ks_pcie_probe(struct platform_device *pdev) { + const struct dw_pcie_host_ops *host_ops; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; + const struct ks_pcie_of_data *data; + const struct of_device_id *match; struct dw_pcie *pci; struct keystone_pcie *ks_pcie; struct device_link **link; + struct gpio_desc *gpiod; + void __iomem *atu_base; struct resource *res; + unsigned int version; void __iomem *base; u32 num_viewport; struct phy **phy; @@ -930,6 +1013,14 @@ static int __init ks_pcie_probe(struct platform_device *pdev) int irq; int i; + match = of_match_device(of_match_ptr(ks_pcie_of_match), dev); + data = (struct ks_pcie_of_data *)match->data; + if (!data) + return -EINVAL; + + version = data->version; + host_ops = data->host_ops; + ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); if (!ks_pcie) return -ENOMEM; @@ -950,9 +1041,13 @@ static int __init ks_pcie_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + if (of_device_is_compatible(np, "ti,am654-pcie-rc")) + ks_pcie->is_am6 = true; + pci->dbi_base = base; pci->dev = dev; pci->ops = &ks_pcie_dw_pcie_ops; + pci->version = version; ret = of_property_read_u32(np, "num-viewport", &num_viewport); if (ret < 0) { @@ -1011,6 +1106,15 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ks_pcie->num_viewport = num_viewport; ks_pcie->phy = phy; + gpiod = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + ret = PTR_ERR(gpiod); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get reset GPIO\n"); + goto err_link; + } + ret = ks_pcie_enable_phy(ks_pcie); if (ret) { dev_err(dev, "failed to enable phy\n"); @@ -1025,10 +1129,39 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } - ret = ks_pcie_set_mode(dev); - if (ret < 0) - goto err_get_sync; + if (pci->version >= 0x480A) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu"); + atu_base = devm_ioremap_resource(dev, res); + if (IS_ERR(atu_base)) { + ret = PTR_ERR(atu_base); + goto err_get_sync; + } + + pci->atu_base = atu_base; + + ret = ks_pcie_am654_set_mode(dev); + if (ret < 0) + goto err_get_sync; + } else { + ret = ks_pcie_set_mode(dev); + if (ret < 0) + goto err_get_sync; + } + + /* + * "Power Sequencing and Reset Signal Timings" table in + * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0 + * indicates PERST# should be deasserted after minimum of 100us + * once REFCLK is stable. The REFCLK to the connector in RC + * mode is selected while enabling the PHY. So deassert PERST# + * after 100 us. + */ + if (gpiod) { + usleep_range(100, 200); + gpiod_set_value_cansleep(gpiod, 1); + } + pci->pp.ops = host_ops; ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) goto err_get_sync; -- cgit From b22af42b3e57c3a49a4c4a54c7d8a1363af75e90 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:36 +0530 Subject: PCI: keystone: Invoke phy_reset() API before enabling PHY SERDES connected to the PCIe controller in AM654 requires power on reset enable (POR_EN) to be set in the SERDES. The SERDES driver sets POR_EN in the reset ops and it has to be invoked before init or enable ops. In order for SERDES driver to set POR_EN, invoke the phy_reset() API in pci-keystone driver. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index a6a482bd648f..e4a816f53b8e 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -897,6 +897,10 @@ static int ks_pcie_enable_phy(struct keystone_pcie *ks_pcie) int num_lanes = ks_pcie->num_lanes; for (i = 0; i < num_lanes; i++) { + ret = phy_reset(ks_pcie->phy[i]); + if (ret < 0) + goto err_phy; + ret = phy_init(ks_pcie->phy[i]); if (ret < 0) goto err_phy; -- cgit From 40e5d614a0cdbf50dc3caa7eb10bd838edcb3ba5 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:37 +0530 Subject: PCI: OF: Allow of_pci_get_max_link_speed() to be used by PCI Endpoint drivers of_pci_get_max_link_speed() is built only if CONFIG_PCI is enabled. Make of_pci_get_max_link_speed() to be also used by PCI Endpoint controllers with just CONFIG_PCI_ENDPOINT enabled. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Sekhar Nori Signed-off-by: Lorenzo Pieralisi Acked-by: Bjorn Helgaas --- drivers/pci/Makefile | 2 +- drivers/pci/of.c | 44 +++++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 657d642fcc67..28cdd8c0213a 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -10,10 +10,10 @@ obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \ ifdef CONFIG_PCI obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSFS) += slot.o -obj-$(CONFIG_OF) += of.o obj-$(CONFIG_ACPI) += pci-acpi.o endif +obj-$(CONFIG_OF) += of.o obj-$(CONFIG_PCI_QUIRKS) += quirks.o obj-$(CONFIG_PCIEPORTBUS) += pcie/ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 3d32da15c215..8095933f8452 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -15,6 +15,7 @@ #include #include "pci.h" +#ifdef CONFIG_PCI void pci_set_of_node(struct pci_dev *dev) { if (!dev->bus->dev.of_node) @@ -196,27 +197,6 @@ int of_get_pci_domain_nr(struct device_node *node) } EXPORT_SYMBOL_GPL(of_get_pci_domain_nr); -/** - * This function will try to find the limitation of link speed by finding - * a property called "max-link-speed" of the given device node. - * - * @node: device tree node with the max link speed information - * - * Returns the associated max link speed from DT, or a negative value if the - * required property is not found or is invalid. - */ -int of_pci_get_max_link_speed(struct device_node *node) -{ - u32 max_link_speed; - - if (of_property_read_u32(node, "max-link-speed", &max_link_speed) || - max_link_speed > 4) - return -EINVAL; - - return max_link_speed; -} -EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed); - /** * of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only * is present and valid @@ -537,3 +517,25 @@ int pci_parse_request_of_pci_ranges(struct device *dev, return err; } +#endif /* CONFIG_PCI */ + +/** + * This function will try to find the limitation of link speed by finding + * a property called "max-link-speed" of the given device node. + * + * @node: device tree node with the max link speed information + * + * Returns the associated max link speed from DT, or a negative value if the + * required property is not found or is invalid. + */ +int of_pci_get_max_link_speed(struct device_node *node) +{ + u32 max_link_speed; + + if (of_property_read_u32(node, "max-link-speed", &max_link_speed) || + max_link_speed > 4) + return -EINVAL; + + return max_link_speed; +} +EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed); -- cgit From fbb2de891cc4d69c0c80c4116cf870a99235cfe8 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:38 +0530 Subject: PCI: keystone: Add support to set the max link speed from DT PCIe in TI's AM654 devices is by default configured to work in GEN3 mode. However PCIe does not work reliably in GEN3 mode because of SERDES configuration. Add support to set the link speed to GEN1, GEN2 or GEN3 based on "max-link-speed" DT property with GEN2 as the default speed if "max-link-speed" is absent. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e4a816f53b8e..312fd0c49bbb 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -28,6 +28,7 @@ #include #include +#include "../../pci.h" #include "pcie-designware.h" #define PCIE_VENDORID_MASK 0xffff @@ -89,6 +90,8 @@ #define LEG_EP 0x1 #define RC 0x2 +#define EXP_CAP_ID_OFFSET 0x70 + #define KS_PCIE_SYSCLOCKOUTEN BIT(0) #define AM654_PCIE_DEV_TYPE_MASK 0x3 @@ -971,6 +974,31 @@ static int ks_pcie_am654_set_mode(struct device *dev) return 0; } +static void ks_pcie_set_link_speed(struct dw_pcie *pci, int link_speed) +{ + u32 val; + + dw_pcie_dbi_ro_wr_en(pci); + + val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP); + if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { + val &= ~((u32)PCI_EXP_LNKCAP_SLS); + val |= link_speed; + dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP, + val); + } + + val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2); + if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { + val &= ~((u32)PCI_EXP_LNKCAP_SLS); + val |= link_speed; + dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2, + val); + } + + dw_pcie_dbi_ro_wr_dis(pci); +} + static const struct ks_pcie_of_data ks_pcie_rc_of_data = { .host_ops = &ks_pcie_host_ops, .version = 0x365A, @@ -1011,6 +1039,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) void __iomem *base; u32 num_viewport; struct phy **phy; + int link_speed; u32 num_lanes; char name[10]; int ret; @@ -1165,6 +1194,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev) gpiod_set_value_cansleep(gpiod, 1); } + link_speed = of_pci_get_max_link_speed(np); + if (link_speed < 0) + link_speed = 2; + + ks_pcie_set_link_speed(pci, link_speed); + pci->pp.ops = host_ops; ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) -- cgit From 2a9a801620efac92885fc9cd53594c0b9aba87a4 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:39 +0530 Subject: PCI: endpoint: Add support to specify alignment for buffers allocated to BARs The address that is allocated using pci_epf_alloc_space() is directly written to the target address of the Inbound Address Translation unit (ie the HW component implementing inbound address decoding) on endpoint controllers. Designware IP [1] has a configuration parameter (CX_ATU_MIN_REGION_SIZE [2]) which has 64KB as default value and the lower 16 bits of the Base, Limit and Target registers of the Inbound ATU are fixed to zero. If the programmed memory address is not aligned to 64 KB boundary this causes memory corruption. Modify pci_epf_alloc_space() API to take alignment size as argument in order to allocate buffers to be mapped to BARs with an alignment that suits the platform where they are used. Add an 'align' parameter to epc_features which can be used by platform drivers to specify the BAR allocation alignment requirements and use this while invoking pci_epf_alloc_space(). [1] "I/O and MEM Match Modes" section in DesignWare Cores PCI Express Controller Databook version 4.90a [2] http://www.ti.com/lit/ug/spruid7c/spruid7c.pdf Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/endpoint/functions/pci-epf-test.c | 5 +++-- drivers/pci/endpoint/pci-epf-core.c | 10 ++++++++-- include/linux/pci-epc.h | 2 ++ include/linux/pci-epf.h | 3 ++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index d0b91da49bf4..c0786ca74312 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -438,7 +438,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) epc_features = epf_test->epc_features; base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg), - test_reg_bar); + test_reg_bar, epc_features->align); if (!base) { dev_err(dev, "Failed to allocated register space\n"); return -ENOMEM; @@ -453,7 +453,8 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf) if (!!(epc_features->reserved_bar & (1 << bar))) continue; - base = pci_epf_alloc_space(epf, bar_size[bar], bar); + base = pci_epf_alloc_space(epf, bar_size[bar], bar, + epc_features->align); if (!base) dev_err(dev, "Failed to allocate space for BAR%d\n", bar); diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c index 8bfdcd291196..fb1306de8f40 100644 --- a/drivers/pci/endpoint/pci-epf-core.c +++ b/drivers/pci/endpoint/pci-epf-core.c @@ -109,10 +109,12 @@ EXPORT_SYMBOL_GPL(pci_epf_free_space); * pci_epf_alloc_space() - allocate memory for the PCI EPF register space * @size: the size of the memory that has to be allocated * @bar: the BAR number corresponding to the allocated register space + * @align: alignment size for the allocation region * * Invoke to allocate memory for the PCI EPF register space. */ -void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar) +void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, + size_t align) { void *space; struct device *dev = epf->epc->dev.parent; @@ -120,7 +122,11 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar) if (size < 128) size = 128; - size = roundup_pow_of_two(size); + + if (align) + size = ALIGN(size, align); + else + size = roundup_pow_of_two(size); space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); if (!space) { diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index c3ffa3917f88..f641badc2c61 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -109,6 +109,7 @@ struct pci_epc { * @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver * @bar_fixed_64bit: bitmap to indicate fixed 64bit BARs * @bar_fixed_size: Array specifying the size supported by each BAR + * @align: alignment size required for BAR buffer allocation */ struct pci_epc_features { unsigned int linkup_notifier : 1; @@ -117,6 +118,7 @@ struct pci_epc_features { u8 reserved_bar; u8 bar_fixed_64bit; u64 bar_fixed_size[BAR_5 + 1]; + size_t align; }; #define to_pci_epc(device) container_of((device), struct pci_epc, dev) diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h index ec02f58758c8..2d6f07556682 100644 --- a/include/linux/pci-epf.h +++ b/include/linux/pci-epf.h @@ -149,7 +149,8 @@ void pci_epf_destroy(struct pci_epf *epf); int __pci_epf_register_driver(struct pci_epf_driver *driver, struct module *owner); void pci_epf_unregister_driver(struct pci_epf_driver *driver); -void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar); +void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, + size_t align); void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar); int pci_epf_bind(struct pci_epf *epf); void pci_epf_unbind(struct pci_epf *epf); -- cgit From 626961dd6d32edcdbea1ebc488305533960b5d08 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:40 +0530 Subject: PCI: dwc: Add const qualifier to struct dw_pcie_ep_ops Add const qualifier to struct dw_pcie_ep_ops member of struct dw_pcie_ep. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-dra7xx.c | 2 +- drivers/pci/controller/dwc/pci-layerscape-ep.c | 2 +- drivers/pci/controller/dwc/pcie-artpec6.c | 2 +- drivers/pci/controller/dwc/pcie-designware-plat.c | 2 +- drivers/pci/controller/dwc/pcie-designware.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index ae84a69ae63a..b287dbf6914c 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -406,7 +406,7 @@ dra7xx_pcie_get_features(struct dw_pcie_ep *ep) return &dra7xx_pcie_epc_features; } -static struct dw_pcie_ep_ops pcie_ep_ops = { +static const struct dw_pcie_ep_ops pcie_ep_ops = { .ep_init = dra7xx_pcie_ep_init, .raise_irq = dra7xx_pcie_raise_irq, .get_features = dra7xx_pcie_get_features, diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index a42c9c3ae1cc..be61d96cc95e 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -79,7 +79,7 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } } -static struct dw_pcie_ep_ops pcie_ep_ops = { +static const struct dw_pcie_ep_ops pcie_ep_ops = { .ep_init = ls_pcie_ep_init, .raise_irq = ls_pcie_ep_raise_irq, .get_features = ls_pcie_ep_get_features, diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index dba83abfe764..d00252bd8fae 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -444,7 +444,7 @@ static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } -static struct dw_pcie_ep_ops pcie_ep_ops = { +static const struct dw_pcie_ep_ops pcie_ep_ops = { .ep_init = artpec6_pcie_ep_init, .raise_irq = artpec6_pcie_raise_irq, }; diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 932dbd0b34b6..b58fdcbc664b 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -106,7 +106,7 @@ dw_plat_pcie_get_features(struct dw_pcie_ep *ep) return &dw_plat_pcie_epc_features; } -static struct dw_pcie_ep_ops pcie_ep_ops = { +static const struct dw_pcie_ep_ops pcie_ep_ops = { .ep_init = dw_plat_pcie_ep_init, .raise_irq = dw_plat_pcie_ep_raise_irq, .get_features = dw_plat_pcie_get_features, diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 90a5b1215344..e36941ff7cf6 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -196,7 +196,7 @@ struct dw_pcie_ep_ops { struct dw_pcie_ep { struct pci_epc *epc; - struct dw_pcie_ep_ops *ops; + const struct dw_pcie_ep_ops *ops; phys_addr_t phys_base; size_t addr_size; size_t page_size; -- cgit From 421db1ab287eebe80fd203eb009ae92836c586ad Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:41 +0530 Subject: PCI: dwc: Fix dw_pcie_ep_find_capability() to return correct capability offset commit beb4641a787d ("PCI: dwc: Add MSI-X callbacks handler") while adding MSI-X callback handler, introduced dw_pcie_ep_find_capability() and __dw_pcie_ep_find_next_cap() for finding the MSI and MSIX capability. However if MSI or MSIX capability is the last capability (i.e there are no additional items in the capabilities list and the Next Capability Pointer is set to '0'), __dw_pcie_ep_find_next_cap will return '0' even though MSI or MSIX capability may be present because of incorrect ordering of the "next_cap_ptr" check. Fix it. Fixes: beb4641a787d ("PCI: dwc: Add MSI-X callbacks handler") Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-ep.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index dc6a4bbd3ace..74477ad7467f 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -46,16 +46,19 @@ static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr, u8 cap_id, next_cap_ptr; u16 reg; + if (!cap_ptr) + return 0; + reg = dw_pcie_readw_dbi(pci, cap_ptr); - next_cap_ptr = (reg & 0xff00) >> 8; cap_id = (reg & 0x00ff); - if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX) + if (cap_id > PCI_CAP_ID_MAX) return 0; if (cap_id == cap) return cap_ptr; + next_cap_ptr = (reg & 0xff00) >> 8; return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); } @@ -67,9 +70,6 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap) reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST); next_cap_ptr = (reg & 0x00ff); - if (!next_cap_ptr) - return 0; - return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); } -- cgit From ddf567e3d9949aeb7992fb48a8663c81a15e7d81 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:42 +0530 Subject: PCI: dwc: Add callbacks for accessing dbi2 address space Certain platforms like TI's AM654 do not have aseparate address space for dbi2 instead they are accessed using the same address space as dbi with some configuration bit set. In order to support such platforms, add callbacks for accessing dbi2 address space. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware.c | 31 ++++++++++++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 12 +++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 4e2f7946da89..d7cc1a0c1de6 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -89,6 +89,37 @@ void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, dev_err(pci->dev, "Write DBI address failed\n"); } +u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, + size_t size) +{ + int ret; + u32 val; + + if (pci->ops->read_dbi2) + return pci->ops->read_dbi2(pci, base, reg, size); + + ret = dw_pcie_read(base + reg, size, &val); + if (ret) + dev_err(pci->dev, "read DBI address failed\n"); + + return val; +} + +void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, + size_t size, u32 val) +{ + int ret; + + if (pci->ops->write_dbi2) { + pci->ops->write_dbi2(pci, base, reg, size, val); + return; + } + + ret = dw_pcie_write(base + reg, size, val); + if (ret) + dev_err(pci->dev, "write DBI address failed\n"); +} + static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg) { u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index e36941ff7cf6..7abca9eb00bf 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -218,6 +218,10 @@ struct dw_pcie_ops { size_t size); void (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg, size_t size, u32 val); + u32 (*read_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg, + size_t size); + void (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg, + size_t size, u32 val); int (*link_up)(struct dw_pcie *pcie); int (*start_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie); @@ -249,6 +253,10 @@ u32 __dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size); void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size, u32 val); +u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, + size_t size); +void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, + size_t size, u32 val); int dw_pcie_link_up(struct dw_pcie *pci); int dw_pcie_wait_for_link(struct dw_pcie *pci); void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, @@ -292,12 +300,12 @@ static inline u8 dw_pcie_readb_dbi(struct dw_pcie *pci, u32 reg) static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val) { - __dw_pcie_write_dbi(pci, pci->dbi_base2, reg, 0x4, val); + __dw_pcie_write_dbi2(pci, pci->dbi_base2, reg, 0x4, val); } static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg) { - return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4); + return __dw_pcie_read_dbi2(pci, pci->dbi_base2, reg, 0x4); } static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) -- cgit From 21e2079fe4938e84c0c5c0996cc03d63d5f9cacc Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Tue, 16 Apr 2019 16:21:44 +0530 Subject: PCI: tegra: Use the DMA-API to get the MSI address Since the upstream MSI memory writes are generated by downstream devices, it is logically correct to have MSI target memory coming from the DMA pool reserved for PCIe than from the general memory pool reserved for CPU access to avoid PCIe DMA addresses coinciding with MSI target address thereby raising unwanted MSI interrupts. Enforce this behaviour by retrieving the MSI address through the DMA API. Limit the MSI target address to 32-bits to make it work for PCIe endpoints that support only 32-bit MSI target address; endpoints that support 64-bit MSI target address work with 32-bit MSI target address too. Signed-off-by: Vidya Sagar [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Robin Murphy Reviewed-by: Thierry Reding Acked-by: Thierry Reding --- drivers/pci/controller/pci-tegra.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index f4f53d092e00..464ba2538d52 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -231,9 +231,9 @@ struct tegra_msi { struct msi_controller chip; DECLARE_BITMAP(used, INT_PCI_MSI_NR); struct irq_domain *domain; - unsigned long pages; struct mutex lock; - u64 phys; + void *virt; + dma_addr_t phys; int irq; }; @@ -1536,7 +1536,7 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie) err = platform_get_irq_byname(pdev, "msi"); if (err < 0) { dev_err(dev, "failed to get IRQ: %d\n", err); - goto err; + goto free_irq_domain; } msi->irq = err; @@ -1545,17 +1545,35 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie) tegra_msi_irq_chip.name, pcie); if (err < 0) { dev_err(dev, "failed to request IRQ: %d\n", err); - goto err; + goto free_irq_domain; + } + + /* Though the PCIe controller can address >32-bit address space, to + * facilitate endpoints that support only 32-bit MSI target address, + * the mask is set to 32-bit to make sure that MSI target address is + * always a 32-bit address + */ + err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); + if (err < 0) { + dev_err(dev, "failed to set DMA coherent mask: %d\n", err); + goto free_irq; + } + + msi->virt = dma_alloc_attrs(dev, PAGE_SIZE, &msi->phys, GFP_KERNEL, + DMA_ATTR_NO_KERNEL_MAPPING); + if (!msi->virt) { + dev_err(dev, "failed to allocate DMA memory for MSI\n"); + err = -ENOMEM; + goto free_irq; } - /* setup AFI/FPCI range */ - msi->pages = __get_free_pages(GFP_KERNEL, 0); - msi->phys = virt_to_phys((void *)msi->pages); host->msi = &msi->chip; return 0; -err: +free_irq: + free_irq(msi->irq, pcie); +free_irq_domain: irq_domain_remove(msi->domain); return err; } @@ -1592,7 +1610,8 @@ static void tegra_pcie_msi_teardown(struct tegra_pcie *pcie) struct tegra_msi *msi = &pcie->msi; unsigned int i, irq; - free_pages(msi->pages, 0); + dma_free_attrs(pcie->dev, PAGE_SIZE, msi->virt, msi->phys, + DMA_ATTR_NO_KERNEL_MAPPING); if (msi->irq > 0) free_irq(msi->irq, pcie); -- cgit From 2dbce590117981196fe355efc0569bc6f949ae9b Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Mon, 19 Nov 2018 18:44:32 +0530 Subject: PCI: Assign bus numbers present in EA capability for bridges The "Enhanced Allocation (EA) for Memory and I/O Resources" ECN, approved 23 October 2014, sec 6.9.1.2, specifies a second DW in the capability for type 1 (bridge) functions to describe fixed secondary and subordinate bus numbers. This ECN was included in the PCIe r4.0 spec, but sec 6.9.1.2 was omitted, presumably by mistake. Read fixed bus numbers from the EA capability for bridges. Signed-off-by: Subbaraya Sundeep [bhelgaas: add pci_ea_fixed_busnrs() return value] Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 54 +++++++++++++++++++++++++++++++++++++++---- include/uapi/linux/pci_regs.h | 6 +++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 012250a78da7..a6874c306908 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1086,6 +1086,36 @@ static void pci_enable_crs(struct pci_dev *pdev) static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus, unsigned int available_buses); +/** + * pci_ea_fixed_busnrs() - Read fixed Secondary and Subordinate bus + * numbers from EA capability. + * @dev: Bridge + * @sec: updated with secondary bus number from EA + * @sub: updated with subordinate bus number from EA + * + * If @dev is a bridge with EA capability, update @sec and @sub with + * fixed bus numbers from the capability and return true. Otherwise, + * return false. + */ +static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub) +{ + int ea, offset; + u32 dw; + + if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) + return false; + + /* find PCI EA capability in list */ + ea = pci_find_capability(dev, PCI_CAP_ID_EA); + if (!ea) + return false; + + offset = ea + PCI_EA_FIRST_ENT; + pci_read_config_dword(dev, offset, &dw); + *sec = dw & PCI_EA_SEC_BUS_MASK; + *sub = (dw & PCI_EA_SUB_BUS_MASK) >> PCI_EA_SUB_BUS_SHIFT; + return true; +} /* * pci_scan_bridge_extend() - Scan buses behind a bridge @@ -1120,6 +1150,9 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, u16 bctl; u8 primary, secondary, subordinate; int broken = 0; + bool fixed_buses; + u8 fixed_sec, fixed_sub; + int next_busnr; /* * Make sure the bridge is powered on to be able to access config @@ -1219,17 +1252,24 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, /* Clear errors */ pci_write_config_word(dev, PCI_STATUS, 0xffff); + /* Read bus numbers from EA Capability (if present) */ + fixed_buses = pci_ea_fixed_busnrs(dev, &fixed_sec, &fixed_sub); + if (fixed_buses) + next_busnr = fixed_sec; + else + next_busnr = max + 1; + /* * Prevent assigning a bus number that already exists. * This can happen when a bridge is hot-plugged, so in this * case we only re-scan this bus. */ - child = pci_find_bus(pci_domain_nr(bus), max+1); + child = pci_find_bus(pci_domain_nr(bus), next_busnr); if (!child) { - child = pci_add_new_bus(bus, dev, max+1); + child = pci_add_new_bus(bus, dev, next_busnr); if (!child) goto out; - pci_bus_insert_busn_res(child, max+1, + pci_bus_insert_busn_res(child, next_busnr, bus->busn_res.end); } max++; @@ -1290,7 +1330,13 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, max += i; } - /* Set subordinate bus number to its real value */ + /* + * Set subordinate bus number to its real value. + * If fixed subordinate bus number exists from EA + * capability then use it. + */ + if (fixed_buses) + max = fixed_sub; pci_bus_update_busn_res_end(child, max); pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); } diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 5c98133f2c94..c51e0066de8b 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -372,6 +372,12 @@ #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 -- cgit From 804ee5be633f051f85270ae3f4770a5fc6cd92d5 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 17 Apr 2019 10:23:56 +0200 Subject: PCI: Remove unused pci_request_region_exclusive() pci_request_region_exclusive() was introduced with commit e8de1481fd71 ("resource: allow MMIO exclusivity for device drivers") in 2.6.29 which was released 2008. It never had an in tree user since then, so after 11 years later let's remove it. Signed-off-by: Johannes Thumshirn Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 25 ------------------------- include/linux/pci.h | 1 - 2 files changed, 26 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7c1b362f599a..d185b49e105a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3706,31 +3706,6 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) } EXPORT_SYMBOL(pci_request_region); -/** - * pci_request_region_exclusive - Reserved PCI I/O and memory resource - * @pdev: PCI device whose resources are to be reserved - * @bar: BAR to be reserved - * @res_name: Name to be associated with resource. - * - * Mark the PCI region associated with PCI device @pdev BR @bar as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. - * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. - * - * The key difference that _exclusive makes it that userspace is - * explicitly not allowed to map the resource via /dev/mem or - * sysfs. - */ -int pci_request_region_exclusive(struct pci_dev *pdev, int bar, - const char *res_name) -{ - return __pci_request_region(pdev, bar, res_name, IORESOURCE_EXCLUSIVE); -} -EXPORT_SYMBOL(pci_request_region_exclusive); - /** * pci_release_selected_regions - Release selected PCI I/O and memory resources * @pdev: PCI device whose resources were previously reserved diff --git a/include/linux/pci.h b/include/linux/pci.h index 77448215ef5b..5f32275358cf 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1233,7 +1233,6 @@ int __must_check pci_request_regions(struct pci_dev *, const char *); int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *); void pci_release_regions(struct pci_dev *); int __must_check pci_request_region(struct pci_dev *, int, const char *); -int __must_check pci_request_region_exclusive(struct pci_dev *, int, const char *); void pci_release_region(struct pci_dev *, int); int pci_request_selected_regions(struct pci_dev *, int, const char *); int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *); -- cgit From ea094d53580f40c2124cef3d072b73b2425e7bfd Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Wed, 17 Apr 2019 09:18:50 -0500 Subject: x86/PCI: Fix PCI IRQ routing table memory leak In pcibios_irq_init(), the PCI IRQ routing table 'pirq_table' is first found through pirq_find_routing_table(). If the table is not found and CONFIG_PCI_BIOS is defined, the table is then allocated in pcibios_get_irq_routing_table() using kmalloc(). Later, if the I/O APIC is used, this table is actually not used. In that case, the allocated table is not freed, which is a memory leak. Free the allocated table if it is not used. Signed-off-by: Wenwen Wang [bhelgaas: added Ingo's reviewed-by, since the only change since v1 was to use the irq_routing_table local variable name he suggested] Signed-off-by: Bjorn Helgaas Reviewed-by: Ingo Molnar Acked-by: Thomas Gleixner --- arch/x86/pci/irq.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 52e55108404e..d3a73f9335e1 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -1119,6 +1119,8 @@ static const struct dmi_system_id pciirq_dmi_table[] __initconst = { void __init pcibios_irq_init(void) { + struct irq_routing_table *rtable = NULL; + DBG(KERN_DEBUG "PCI: IRQ init\n"); if (raw_pci_ops == NULL) @@ -1129,8 +1131,10 @@ void __init pcibios_irq_init(void) pirq_table = pirq_find_routing_table(); #ifdef CONFIG_PCI_BIOS - if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN)) + if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN)) { pirq_table = pcibios_get_irq_routing_table(); + rtable = pirq_table; + } #endif if (pirq_table) { pirq_peer_trick(); @@ -1145,8 +1149,10 @@ void __init pcibios_irq_init(void) * If we're using the I/O APIC, avoid using the PCI IRQ * routing table */ - if (io_apic_assign_pci_irqs) + if (io_apic_assign_pci_irqs) { + kfree(rtable); pirq_table = NULL; + } } x86_init.pci.fixup_irqs(); -- cgit From ba8a39820d4614b2b04ac74a48d1f8de677de750 Mon Sep 17 00:00:00 2001 From: Wesley Sheng Date: Mon, 15 Apr 2019 22:41:41 +0800 Subject: switchtec: Increase PFF limit from 48 to 255 The Switchtec devices supports two PCIe Function Frameworks (PFFs) per upstream port (one for the port itself and one for the management endoint), and each PFF may have up to 255 ports. Previously the driver only supported 48 of those ports, and the SWITCHTEC_IOCTL_EVENT_SUMMARY ioctl only returned information about those 48. Increase SWITCHTEC_MAX_PFF_CSR from 48 to 255 so the driver supports all 255 possible ports. Rename SWITCHTEC_IOCTL_EVENT_SUMMARY and associated struct switchtec_ioctl_event_summary to SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY and switchtec_ioctl_event_summary_legacy with so existing applications work unchanged, supporting up to 48 ports. Add replacement SWITCHTEC_IOCTL_EVENT_SUMMARY and struct switchtec_ioctl_event_summary that new and recompiled applications support up to 255 ports. Signed-off-by: Wesley Sheng [bhelgaas: changelog] Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe --- drivers/pci/switch/switchtec.c | 39 +++++++++++++++++++++++++----------- include/linux/switchtec.h | 2 +- include/uapi/linux/switchtec_ioctl.h | 13 +++++++++++- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index e22766c79fe9..7df9a69f7d93 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -658,19 +658,25 @@ static int ioctl_flash_part_info(struct switchtec_dev *stdev, static int ioctl_event_summary(struct switchtec_dev *stdev, struct switchtec_user *stuser, - struct switchtec_ioctl_event_summary __user *usum) + struct switchtec_ioctl_event_summary __user *usum, + size_t size) { - struct switchtec_ioctl_event_summary s = {0}; + struct switchtec_ioctl_event_summary *s; int i; u32 reg; + int ret = 0; - s.global = ioread32(&stdev->mmio_sw_event->global_summary); - s.part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap); - s.local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary); + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + s->global = ioread32(&stdev->mmio_sw_event->global_summary); + s->part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap); + s->local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary); for (i = 0; i < stdev->partition_count; i++) { reg = ioread32(&stdev->mmio_part_cfg_all[i].part_event_summary); - s.part[i] = reg; + s->part[i] = reg; } for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { @@ -679,15 +685,19 @@ static int ioctl_event_summary(struct switchtec_dev *stdev, break; reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary); - s.pff[i] = reg; + s->pff[i] = reg; } - if (copy_to_user(usum, &s, sizeof(s))) - return -EFAULT; + if (copy_to_user(usum, s, size)) { + ret = -EFAULT; + goto error_case; + } stuser->event_cnt = atomic_read(&stdev->event_cnt); - return 0; +error_case: + kfree(s); + return ret; } static u32 __iomem *global_ev_reg(struct switchtec_dev *stdev, @@ -977,8 +987,9 @@ static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd, case SWITCHTEC_IOCTL_FLASH_PART_INFO: rc = ioctl_flash_part_info(stdev, argp); break; - case SWITCHTEC_IOCTL_EVENT_SUMMARY: - rc = ioctl_event_summary(stdev, stuser, argp); + case SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY: + rc = ioctl_event_summary(stdev, stuser, argp, + sizeof(struct switchtec_ioctl_event_summary_legacy)); break; case SWITCHTEC_IOCTL_EVENT_CTL: rc = ioctl_event_ctl(stdev, argp); @@ -989,6 +1000,10 @@ static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd, case SWITCHTEC_IOCTL_PORT_TO_PFF: rc = ioctl_port_to_pff(stdev, argp); break; + case SWITCHTEC_IOCTL_EVENT_SUMMARY: + rc = ioctl_event_summary(stdev, stuser, argp, + sizeof(struct switchtec_ioctl_event_summary)); + break; default: rc = -ENOTTY; break; diff --git a/include/linux/switchtec.h b/include/linux/switchtec.h index 52a079b3a9a6..0cfc34ac37fb 100644 --- a/include/linux/switchtec.h +++ b/include/linux/switchtec.h @@ -20,7 +20,7 @@ #include #define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024 -#define SWITCHTEC_MAX_PFF_CSR 48 +#define SWITCHTEC_MAX_PFF_CSR 255 #define SWITCHTEC_EVENT_OCCURRED BIT(0) #define SWITCHTEC_EVENT_CLEAR BIT(0) diff --git a/include/uapi/linux/switchtec_ioctl.h b/include/uapi/linux/switchtec_ioctl.h index 4f4daf8db954..c912b5a678e4 100644 --- a/include/uapi/linux/switchtec_ioctl.h +++ b/include/uapi/linux/switchtec_ioctl.h @@ -50,7 +50,7 @@ struct switchtec_ioctl_flash_part_info { __u32 active; }; -struct switchtec_ioctl_event_summary { +struct switchtec_ioctl_event_summary_legacy { __u64 global; __u64 part_bitmap; __u32 local_part; @@ -59,6 +59,15 @@ struct switchtec_ioctl_event_summary { __u32 pff[48]; }; +struct switchtec_ioctl_event_summary { + __u64 global; + __u64 part_bitmap; + __u32 local_part; + __u32 padding; + __u32 part[48]; + __u32 pff[255]; +}; + #define SWITCHTEC_IOCTL_EVENT_STACK_ERROR 0 #define SWITCHTEC_IOCTL_EVENT_PPU_ERROR 1 #define SWITCHTEC_IOCTL_EVENT_ISP_ERROR 2 @@ -127,6 +136,8 @@ struct switchtec_ioctl_pff_port { _IOWR('W', 0x41, struct switchtec_ioctl_flash_part_info) #define SWITCHTEC_IOCTL_EVENT_SUMMARY \ _IOR('W', 0x42, struct switchtec_ioctl_event_summary) +#define SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY \ + _IOR('W', 0x42, struct switchtec_ioctl_event_summary_legacy) #define SWITCHTEC_IOCTL_EVENT_CTL \ _IOWR('W', 0x43, struct switchtec_ioctl_event_ctl) #define SWITCHTEC_IOCTL_PFF_TO_PORT \ -- cgit From 083c1b5e50b701899dc32445efa8b153685260d5 Mon Sep 17 00:00:00 2001 From: Wesley Sheng Date: Mon, 15 Apr 2019 22:41:42 +0800 Subject: switchtec: Fix unintended mask of MRPC event When running application tool switchtec-user's `firmware update` and `event wait` commands concurrently, sometimes the firmware update speed reduced significantly. It is because when the MRPC event happened after MRPC event occurrence check but before the event mask loop reaches its header register in event ISR, the MRPC event would be masked unintentionally. Since there's no chance to enable it again except for a module reload, all the following MRPC execution completion checks time out. Fix this bug by skipping the mask operation for MRPC event in event ISR, same as what we already do for LINK event. Fixes: 52eabba5bcdb ("switchtec: Add IOCTLs to the Switchtec driver") Signed-off-by: Wesley Sheng Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe --- drivers/pci/switch/switchtec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 7df9a69f7d93..30f6e080bad8 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1177,7 +1177,8 @@ static int mask_event(struct switchtec_dev *stdev, int eid, int idx) if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ)) return 0; - if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE) + if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE || + eid == SWITCHTEC_IOCTL_EVENT_MRPC_COMP) return 0; dev_dbg(&stdev->dev, "%s: %d %d %x\n", __func__, eid, idx, hdr); -- cgit From 6056bed93b4f93707b0564aa418b9c06b613ff04 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 15 Apr 2019 11:41:42 +0300 Subject: PCI/LINK: Disable bandwidth notification interrupt during suspend If the bandwidth notification interrupt is left unmasked when entering suspend to idle, it triggers immediately bringing the system back to working state. To keep that from happening, disable the interrupt when entering system sleep and enable it again during resume. Reported-by: Imre Deak Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/bw_notification.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/pci/pcie/bw_notification.c b/drivers/pci/pcie/bw_notification.c index d2eae3b7cc0f..971eb7e90fb0 100644 --- a/drivers/pci/pcie/bw_notification.c +++ b/drivers/pci/pcie/bw_notification.c @@ -96,11 +96,25 @@ static void pcie_bandwidth_notification_remove(struct pcie_device *srv) free_irq(srv->irq, srv); } +static int pcie_bandwidth_notification_suspend(struct pcie_device *srv) +{ + pcie_disable_link_bandwidth_notification(srv->port); + return 0; +} + +static int pcie_bandwidth_notification_resume(struct pcie_device *srv) +{ + pcie_enable_link_bandwidth_notification(srv->port); + return 0; +} + static struct pcie_port_service_driver pcie_bandwidth_notification_driver = { .name = "pcie_bw_notification", .port_type = PCIE_ANY_PORT, .service = PCIE_PORT_SERVICE_BWNOTIF, .probe = pcie_bandwidth_notification_probe, + .suspend = pcie_bandwidth_notification_suspend, + .resume = pcie_bandwidth_notification_resume, .remove = pcie_bandwidth_notification_remove, }; -- cgit From 6afb7e26978da5e86e57e540fdce65c8b04f398a Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Mon, 7 Jan 2019 13:32:48 -0800 Subject: PCI: Mark Atheros AR9462 to avoid bus reset When using PCI passthrough with this device, the host machine locks up completely when starting the VM, requiring a hard reboot. Add a quirk to avoid bus resets on this device. Fixes: c3e59ee4e766 ("PCI: Mark Atheros AR93xx to avoid bus reset") Link: https://lore.kernel.org/linux-pci/20190107213248.3034-1-james.prestwood@linux.intel.com Signed-off-by: James Prestwood Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v3.14+ --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 68bee35fcafa..9b9e28854a58 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3408,6 +3408,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset); /* * Root port on some Cavium CN8xxx chips do not successfully complete a bus -- cgit From e77704501ca00ecb3f2f6439b3eb0d8afbe3a1bf Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Fri, 8 Feb 2019 10:24:11 -0600 Subject: PCI/ACPI: Do not export pci_get_hp_params() pci_get_hp_params() is only used within drivers/pci, and there is no reason to make it available outside of the PCI core, so stop exporting it. Link: https://lore.kernel.org/lkml/20190208162414.3996-2-mr.nuke.me@gmail.com Signed-off-by: Alexandru Gagniuc Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index e1949f7efd9c..b25e5fa9d1c9 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -366,7 +366,6 @@ int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp) } return -ENODEV; } -EXPORT_SYMBOL_GPL(pci_get_hp_params); /** * pciehp_is_native - Check whether a hotplug port is handled by the OS -- cgit From 87fcf12e846a5028c14d21a94a0712fd1ad5bad0 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Fri, 19 Apr 2019 14:27:36 -0500 Subject: PCI/ACPI: Remove the need for 'struct hotplug_params' We used to first parse all the _HPP and _HPX tables before using the information to program registers of PCIe devices. Up through HPX Type 2, there was only one structure of each type, so we could cheat and store it on the stack. With HPX Type 3 we get an arbitrary number of entries, so the above model doesn't scale that well. Instead of parsing all tables at once, parse and program each entry separately. For _HPP and _HPX Types 0 through 2, this is functionally equivalent. The change enables the upcoming _HPX Type 3 to integrate more easily. Link: https://lore.kernel.org/lkml/20190208162414.3996-3-mr.nuke.me@gmail.com Signed-off-by: Alexandru Gagniuc [bhelgaas: fix build errors] Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 108 ++++++++++++++++++++++++-------------------- drivers/pci/probe.c | 16 +++---- include/linux/pci_hotplug.h | 18 ++++---- 3 files changed, 72 insertions(+), 70 deletions(-) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index b25e5fa9d1c9..95f4f86d2f34 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -119,7 +119,7 @@ phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) } static acpi_status decode_type0_hpx_record(union acpi_object *record, - struct hotplug_params *hpx) + struct hpp_type0 *hpx0) { int i; union acpi_object *fields = record->package.elements; @@ -132,12 +132,11 @@ static acpi_status decode_type0_hpx_record(union acpi_object *record, for (i = 2; i < 6; i++) if (fields[i].type != ACPI_TYPE_INTEGER) return AE_ERROR; - hpx->t0 = &hpx->type0_data; - hpx->t0->revision = revision; - hpx->t0->cache_line_size = fields[2].integer.value; - hpx->t0->latency_timer = fields[3].integer.value; - hpx->t0->enable_serr = fields[4].integer.value; - hpx->t0->enable_perr = fields[5].integer.value; + hpx0->revision = revision; + hpx0->cache_line_size = fields[2].integer.value; + hpx0->latency_timer = fields[3].integer.value; + hpx0->enable_serr = fields[4].integer.value; + hpx0->enable_perr = fields[5].integer.value; break; default: printk(KERN_WARNING @@ -149,7 +148,7 @@ static acpi_status decode_type0_hpx_record(union acpi_object *record, } static acpi_status decode_type1_hpx_record(union acpi_object *record, - struct hotplug_params *hpx) + struct hpp_type1 *hpx1) { int i; union acpi_object *fields = record->package.elements; @@ -162,11 +161,10 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record, for (i = 2; i < 5; i++) if (fields[i].type != ACPI_TYPE_INTEGER) return AE_ERROR; - hpx->t1 = &hpx->type1_data; - hpx->t1->revision = revision; - hpx->t1->max_mem_read = fields[2].integer.value; - hpx->t1->avg_max_split = fields[3].integer.value; - hpx->t1->tot_max_split = fields[4].integer.value; + hpx1->revision = revision; + hpx1->max_mem_read = fields[2].integer.value; + hpx1->avg_max_split = fields[3].integer.value; + hpx1->tot_max_split = fields[4].integer.value; break; default: printk(KERN_WARNING @@ -178,7 +176,7 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record, } static acpi_status decode_type2_hpx_record(union acpi_object *record, - struct hotplug_params *hpx) + struct hpp_type2 *hpx2) { int i; union acpi_object *fields = record->package.elements; @@ -191,24 +189,23 @@ static acpi_status decode_type2_hpx_record(union acpi_object *record, for (i = 2; i < 18; i++) if (fields[i].type != ACPI_TYPE_INTEGER) return AE_ERROR; - hpx->t2 = &hpx->type2_data; - hpx->t2->revision = revision; - hpx->t2->unc_err_mask_and = fields[2].integer.value; - hpx->t2->unc_err_mask_or = fields[3].integer.value; - hpx->t2->unc_err_sever_and = fields[4].integer.value; - hpx->t2->unc_err_sever_or = fields[5].integer.value; - hpx->t2->cor_err_mask_and = fields[6].integer.value; - hpx->t2->cor_err_mask_or = fields[7].integer.value; - hpx->t2->adv_err_cap_and = fields[8].integer.value; - hpx->t2->adv_err_cap_or = fields[9].integer.value; - hpx->t2->pci_exp_devctl_and = fields[10].integer.value; - hpx->t2->pci_exp_devctl_or = fields[11].integer.value; - hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value; - hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value; - hpx->t2->sec_unc_err_sever_and = fields[14].integer.value; - hpx->t2->sec_unc_err_sever_or = fields[15].integer.value; - hpx->t2->sec_unc_err_mask_and = fields[16].integer.value; - hpx->t2->sec_unc_err_mask_or = fields[17].integer.value; + hpx2->revision = revision; + hpx2->unc_err_mask_and = fields[2].integer.value; + hpx2->unc_err_mask_or = fields[3].integer.value; + hpx2->unc_err_sever_and = fields[4].integer.value; + hpx2->unc_err_sever_or = fields[5].integer.value; + hpx2->cor_err_mask_and = fields[6].integer.value; + hpx2->cor_err_mask_or = fields[7].integer.value; + hpx2->adv_err_cap_and = fields[8].integer.value; + hpx2->adv_err_cap_or = fields[9].integer.value; + hpx2->pci_exp_devctl_and = fields[10].integer.value; + hpx2->pci_exp_devctl_or = fields[11].integer.value; + hpx2->pci_exp_lnkctl_and = fields[12].integer.value; + hpx2->pci_exp_lnkctl_or = fields[13].integer.value; + hpx2->sec_unc_err_sever_and = fields[14].integer.value; + hpx2->sec_unc_err_sever_or = fields[15].integer.value; + hpx2->sec_unc_err_mask_and = fields[16].integer.value; + hpx2->sec_unc_err_mask_or = fields[17].integer.value; break; default: printk(KERN_WARNING @@ -219,17 +216,18 @@ static acpi_status decode_type2_hpx_record(union acpi_object *record, return AE_OK; } -static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) +static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle, + const struct hotplug_program_ops *hp_ops) { acpi_status status; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *package, *record, *fields; + struct hpp_type0 hpx0; + struct hpp_type1 hpx1; + struct hpp_type2 hpx2; u32 type; int i; - /* Clear the return buffer with zeros */ - memset(hpx, 0, sizeof(struct hotplug_params)); - status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer); if (ACPI_FAILURE(status)) return status; @@ -257,19 +255,25 @@ static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) type = fields[0].integer.value; switch (type) { case 0: - status = decode_type0_hpx_record(record, hpx); + memset(&hpx0, 0, sizeof(hpx0)); + status = decode_type0_hpx_record(record, &hpx0); if (ACPI_FAILURE(status)) goto exit; + hp_ops->program_type0(dev, &hpx0); break; case 1: - status = decode_type1_hpx_record(record, hpx); + memset(&hpx1, 0, sizeof(hpx1)); + status = decode_type1_hpx_record(record, &hpx1); if (ACPI_FAILURE(status)) goto exit; + hp_ops->program_type1(dev, &hpx1); break; case 2: - status = decode_type2_hpx_record(record, hpx); + memset(&hpx2, 0, sizeof(hpx2)); + status = decode_type2_hpx_record(record, &hpx2); if (ACPI_FAILURE(status)) goto exit; + hp_ops->program_type2(dev, &hpx2); break; default: printk(KERN_ERR "%s: Type %d record not supported\n", @@ -283,14 +287,16 @@ static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) return status; } -static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) +static acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle, + const struct hotplug_program_ops *hp_ops) { acpi_status status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *package, *fields; + struct hpp_type0 hpp0; int i; - memset(hpp, 0, sizeof(struct hotplug_params)); + memset(&hpp0, 0, sizeof(hpp0)); status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer); if (ACPI_FAILURE(status)) @@ -311,12 +317,13 @@ static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) } } - hpp->t0 = &hpp->type0_data; - hpp->t0->revision = 1; - hpp->t0->cache_line_size = fields[0].integer.value; - hpp->t0->latency_timer = fields[1].integer.value; - hpp->t0->enable_serr = fields[2].integer.value; - hpp->t0->enable_perr = fields[3].integer.value; + hpp0.revision = 1; + hpp0.cache_line_size = fields[0].integer.value; + hpp0.latency_timer = fields[1].integer.value; + hpp0.enable_serr = fields[2].integer.value; + hpp0.enable_perr = fields[3].integer.value; + + hp_ops->program_type0(dev, &hpp0); exit: kfree(buffer.pointer); @@ -328,7 +335,8 @@ exit: * @dev - the pci_dev for which we want parameters * @hpp - allocated by the caller */ -int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp) +int pci_acpi_program_hp_params(struct pci_dev *dev, + const struct hotplug_program_ops *hp_ops) { acpi_status status; acpi_handle handle, phandle; @@ -351,10 +359,10 @@ int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp) * this pci dev. */ while (handle) { - status = acpi_run_hpx(handle, hpp); + status = acpi_run_hpx(dev, handle, hp_ops); if (ACPI_SUCCESS(status)) return 0; - status = acpi_run_hpp(handle, hpp); + status = acpi_run_hpp(dev, handle, hp_ops); if (ACPI_SUCCESS(status)) return 0; if (acpi_is_root_bridge(handle)) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2ec0df04e0dc..dce5ae39d0d8 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2206,8 +2206,11 @@ static void pci_configure_serr(struct pci_dev *dev) static void pci_configure_device(struct pci_dev *dev) { - struct hotplug_params hpp; - int ret; + static const struct hotplug_program_ops hp_ops = { + .program_type0 = program_hpp_type0, + .program_type1 = program_hpp_type1, + .program_type2 = program_hpp_type2, + }; pci_configure_mps(dev); pci_configure_extended_tags(dev, NULL); @@ -2216,14 +2219,7 @@ static void pci_configure_device(struct pci_dev *dev) pci_configure_eetlp_prefix(dev); pci_configure_serr(dev); - memset(&hpp, 0, sizeof(hpp)); - ret = pci_get_hp_params(dev, &hpp); - if (ret) - return; - - program_hpp_type2(dev, hpp.t2); - program_hpp_type1(dev, hpp.t1); - program_hpp_type0(dev, hpp.t0); + pci_acpi_program_hp_params(dev, &hp_ops); } static void pci_release_capabilities(struct pci_dev *dev) diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 7acc9f91e72b..2c1e12b7ac00 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -124,26 +124,24 @@ struct hpp_type2 { u32 sec_unc_err_mask_or; }; -struct hotplug_params { - struct hpp_type0 *t0; /* Type0: NULL if not available */ - struct hpp_type1 *t1; /* Type1: NULL if not available */ - struct hpp_type2 *t2; /* Type2: NULL if not available */ - struct hpp_type0 type0_data; - struct hpp_type1 type1_data; - struct hpp_type2 type2_data; +struct hotplug_program_ops { + void (*program_type0)(struct pci_dev *dev, struct hpp_type0 *hpp); + void (*program_type1)(struct pci_dev *dev, struct hpp_type1 *hpp); + void (*program_type2)(struct pci_dev *dev, struct hpp_type2 *hpp); }; #ifdef CONFIG_ACPI #include -int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp); +int pci_acpi_program_hp_params(struct pci_dev *dev, + const struct hotplug_program_ops *hp_ops); bool pciehp_is_native(struct pci_dev *bridge); int acpi_get_hp_hw_control_from_firmware(struct pci_dev *bridge); bool shpchp_is_native(struct pci_dev *bridge); int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle); int acpi_pci_detect_ejectable(acpi_handle handle); #else -static inline int pci_get_hp_params(struct pci_dev *dev, - struct hotplug_params *hpp) +static inline int pci_acpi_program_hp_params(struct pci_dev *dev, + const struct hotplug_program_ops *hp_ops) { return -ENODEV; } -- cgit From f873c51a155aaa6dafdc00fa7fda3754f2f9f794 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Fri, 8 Feb 2019 10:24:13 -0600 Subject: PCI/ACPI: Implement _HPX Type 3 Setting Record The _HPX Type 3 Setting Record is intended to be more generic and allow configuration of settings not possible with Type 2 records. For example, firmware could ensure that the completion timeout value is set accordingly throughout the PCI tree. Implement support for _HPX Type 3 Setting Records, which were added in the ACPI 6.3 spec. Link: https://lore.kernel.org/lkml/20190208162414.3996-4-mr.nuke.me@gmail.com Signed-off-by: Alexandru Gagniuc Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 63 ++++++++++++++++++++++++ drivers/pci/probe.c | 114 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci_hotplug.h | 48 +++++++++++++++++++ 3 files changed, 225 insertions(+) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 95f4f86d2f34..03e02dd6c1d9 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -216,6 +216,64 @@ static acpi_status decode_type2_hpx_record(union acpi_object *record, return AE_OK; } +static void parse_hpx3_register(struct hpx_type3 *hpx3_reg, + union acpi_object *reg_fields) +{ + hpx3_reg->device_type = reg_fields[0].integer.value; + hpx3_reg->function_type = reg_fields[1].integer.value; + hpx3_reg->config_space_location = reg_fields[2].integer.value; + hpx3_reg->pci_exp_cap_id = reg_fields[3].integer.value; + hpx3_reg->pci_exp_cap_ver = reg_fields[4].integer.value; + hpx3_reg->pci_exp_vendor_id = reg_fields[5].integer.value; + hpx3_reg->dvsec_id = reg_fields[6].integer.value; + hpx3_reg->dvsec_rev = reg_fields[7].integer.value; + hpx3_reg->match_offset = reg_fields[8].integer.value; + hpx3_reg->match_mask_and = reg_fields[9].integer.value; + hpx3_reg->match_value = reg_fields[10].integer.value; + hpx3_reg->reg_offset = reg_fields[11].integer.value; + hpx3_reg->reg_mask_and = reg_fields[12].integer.value; + hpx3_reg->reg_mask_or = reg_fields[13].integer.value; +} + +static acpi_status program_type3_hpx_record(struct pci_dev *dev, + union acpi_object *record, + const struct hotplug_program_ops *hp_ops) +{ + union acpi_object *fields = record->package.elements; + u32 desc_count, expected_length, revision; + union acpi_object *reg_fields; + struct hpx_type3 hpx3; + int i; + + revision = fields[1].integer.value; + switch (revision) { + case 1: + desc_count = fields[2].integer.value; + expected_length = 3 + desc_count * 14; + + if (record->package.count != expected_length) + return AE_ERROR; + + for (i = 2; i < expected_length; i++) + if (fields[i].type != ACPI_TYPE_INTEGER) + return AE_ERROR; + + for (i = 0; i < desc_count; i++) { + reg_fields = fields + 3 + i * 14; + parse_hpx3_register(&hpx3, reg_fields); + hp_ops->program_type3(dev, &hpx3); + } + + break; + default: + printk(KERN_WARNING + "%s: Type 3 Revision %d record not supported\n", + __func__, revision); + return AE_ERROR; + } + return AE_OK; +} + static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle, const struct hotplug_program_ops *hp_ops) { @@ -275,6 +333,11 @@ static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle, goto exit; hp_ops->program_type2(dev, &hpx2); break; + case 3: + status = program_type3_hpx_record(dev, record, hp_ops); + if (ACPI_FAILURE(status)) + goto exit; + break; default: printk(KERN_ERR "%s: Type %d record not supported\n", __func__, type); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index dce5ae39d0d8..ea6c1762d5c8 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2026,6 +2026,119 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) */ } +static u16 hpx3_device_type(struct pci_dev *dev) +{ + u16 pcie_type = pci_pcie_type(dev); + const int pcie_to_hpx3_type[] = { + [PCI_EXP_TYPE_ENDPOINT] = HPX_TYPE_ENDPOINT, + [PCI_EXP_TYPE_LEG_END] = HPX_TYPE_LEG_END, + [PCI_EXP_TYPE_RC_END] = HPX_TYPE_RC_END, + [PCI_EXP_TYPE_RC_EC] = HPX_TYPE_RC_EC, + [PCI_EXP_TYPE_ROOT_PORT] = HPX_TYPE_ROOT_PORT, + [PCI_EXP_TYPE_UPSTREAM] = HPX_TYPE_UPSTREAM, + [PCI_EXP_TYPE_DOWNSTREAM] = HPX_TYPE_DOWNSTREAM, + [PCI_EXP_TYPE_PCI_BRIDGE] = HPX_TYPE_PCI_BRIDGE, + [PCI_EXP_TYPE_PCIE_BRIDGE] = HPX_TYPE_PCIE_BRIDGE, + }; + + if (pcie_type >= ARRAY_SIZE(pcie_to_hpx3_type)) + return 0; + + return pcie_to_hpx3_type[pcie_type]; +} + +static u8 hpx3_function_type(struct pci_dev *dev) +{ + if (dev->is_virtfn) + return HPX_FN_SRIOV_VIRT; + else if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV) > 0) + return HPX_FN_SRIOV_PHYS; + else + return HPX_FN_NORMAL; +} + +static bool hpx3_cap_ver_matches(u8 pcie_cap_id, u8 hpx3_cap_id) +{ + u8 cap_ver = hpx3_cap_id & 0xf; + + if ((hpx3_cap_id & BIT(4)) && cap_ver >= pcie_cap_id) + return true; + else if (cap_ver == pcie_cap_id) + return true; + + return false; +} + +static void program_hpx_type3_register(struct pci_dev *dev, + const struct hpx_type3 *reg) +{ + u32 match_reg, write_reg, header, orig_value; + u16 pos; + + if (!(hpx3_device_type(dev) & reg->device_type)) + return; + + if (!(hpx3_function_type(dev) & reg->function_type)) + return; + + switch (reg->config_space_location) { + case HPX_CFG_PCICFG: + pos = 0; + break; + case HPX_CFG_PCIE_CAP: + pos = pci_find_capability(dev, reg->pci_exp_cap_id); + if (pos == 0) + return; + + break; + case HPX_CFG_PCIE_CAP_EXT: + pos = pci_find_ext_capability(dev, reg->pci_exp_cap_id); + if (pos == 0) + return; + + pci_read_config_dword(dev, pos, &header); + if (!hpx3_cap_ver_matches(PCI_EXT_CAP_VER(header), + reg->pci_exp_cap_ver)) + return; + + break; + case HPX_CFG_VEND_CAP: /* Fall through */ + case HPX_CFG_DVSEC: /* Fall through */ + default: + pci_warn(dev, "Encountered _HPX type 3 with unsupported config space location"); + return; + } + + pci_read_config_dword(dev, pos + reg->match_offset, &match_reg); + + if ((match_reg & reg->match_mask_and) != reg->match_value) + return; + + pci_read_config_dword(dev, pos + reg->reg_offset, &write_reg); + orig_value = write_reg; + write_reg &= reg->reg_mask_and; + write_reg |= reg->reg_mask_or; + + if (orig_value == write_reg) + return; + + pci_write_config_dword(dev, pos + reg->reg_offset, write_reg); + + pci_dbg(dev, "Applied _HPX3 at [0x%x]: 0x%08x -> 0x%08x", + pos, orig_value, write_reg); +} + +static void program_hpx_type3(struct pci_dev *dev, struct hpx_type3 *hpx3) +{ + if (!hpx3) + return; + + if (!pci_is_pcie(dev)) + return; + + program_hpx_type3_register(dev, hpx3); +} + int pci_configure_extended_tags(struct pci_dev *dev, void *ign) { struct pci_host_bridge *host; @@ -2210,6 +2323,7 @@ static void pci_configure_device(struct pci_dev *dev) .program_type0 = program_hpp_type0, .program_type1 = program_hpp_type1, .program_type2 = program_hpp_type2, + .program_type3 = program_hpx_type3, }; pci_configure_mps(dev); diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 2c1e12b7ac00..f694eb2ca978 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -124,10 +124,58 @@ struct hpp_type2 { u32 sec_unc_err_mask_or; }; +/* + * _HPX PCI Express Setting Record (Type 3) + */ +struct hpx_type3 { + u16 device_type; + u16 function_type; + u16 config_space_location; + u16 pci_exp_cap_id; + u16 pci_exp_cap_ver; + u16 pci_exp_vendor_id; + u16 dvsec_id; + u16 dvsec_rev; + u16 match_offset; + u32 match_mask_and; + u32 match_value; + u16 reg_offset; + u32 reg_mask_and; + u32 reg_mask_or; +}; + struct hotplug_program_ops { void (*program_type0)(struct pci_dev *dev, struct hpp_type0 *hpp); void (*program_type1)(struct pci_dev *dev, struct hpp_type1 *hpp); void (*program_type2)(struct pci_dev *dev, struct hpp_type2 *hpp); + void (*program_type3)(struct pci_dev *dev, struct hpx_type3 *hpp); +}; + +enum hpx_type3_dev_type { + HPX_TYPE_ENDPOINT = BIT(0), + HPX_TYPE_LEG_END = BIT(1), + HPX_TYPE_RC_END = BIT(2), + HPX_TYPE_RC_EC = BIT(3), + HPX_TYPE_ROOT_PORT = BIT(4), + HPX_TYPE_UPSTREAM = BIT(5), + HPX_TYPE_DOWNSTREAM = BIT(6), + HPX_TYPE_PCI_BRIDGE = BIT(7), + HPX_TYPE_PCIE_BRIDGE = BIT(8), +}; + +enum hpx_type3_fn_type { + HPX_FN_NORMAL = BIT(0), + HPX_FN_SRIOV_PHYS = BIT(1), + HPX_FN_SRIOV_VIRT = BIT(2), +}; + +enum hpx_type3_cfg_loc { + HPX_CFG_PCICFG = 0, + HPX_CFG_PCIE_CAP = 1, + HPX_CFG_PCIE_CAP_EXT = 2, + HPX_CFG_VEND_CAP = 3, + HPX_CFG_DVSEC = 4, + HPX_CFG_MAX, }; #ifdef CONFIG_ACPI -- cgit From ba11edc65065ffe38508aa76fdf7a7db15ad8161 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Fri, 15 Mar 2019 14:29:40 -0500 Subject: PCI/ACPI: Advertise _HPX Type 3 support via _OSC _OSC now has a way to inform firmware that OS has the capability to interpret _HPX Type 3 setting records. This was added by the following PCI Firmware Specification ECN: ECN: _HPX and PCIe Completion Timeout related _OSC Enhancements Date: September 12, 2018 Affected Document: PCI Firmware Specification, Rev. 3.2 Signed-off-by: Alexandru Gagniuc Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 2 ++ include/linux/acpi.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 707aafc7c2aa..c36781a9b493 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -145,6 +145,7 @@ static struct pci_osc_bit_struct pci_osc_support_bit[] = { { OSC_PCI_CLOCK_PM_SUPPORT, "ClockPM" }, { OSC_PCI_SEGMENT_GROUPS_SUPPORT, "Segments" }, { OSC_PCI_MSI_SUPPORT, "MSI" }, + { OSC_PCI_HPX_TYPE_3_SUPPORT, "HPX-Type3" }, }; static struct pci_osc_bit_struct pci_osc_control_bit[] = { @@ -446,6 +447,7 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, * PCI domains, so we indicate this in _OSC support capabilities. */ support = OSC_PCI_SEGMENT_GROUPS_SUPPORT; + support |= OSC_PCI_HPX_TYPE_3_SUPPORT; if (pci_ext_cfg_avail()) support |= OSC_PCI_EXT_CONFIG_SUPPORT; if (pcie_aspm_support_enabled()) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d5dcebd7aad3..b84bcd705fe1 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -513,7 +513,8 @@ extern bool osc_pc_lpi_support_confirmed; #define OSC_PCI_CLOCK_PM_SUPPORT 0x00000004 #define OSC_PCI_SEGMENT_GROUPS_SUPPORT 0x00000008 #define OSC_PCI_MSI_SUPPORT 0x00000010 -#define OSC_PCI_SUPPORT_MASKS 0x0000001f +#define OSC_PCI_HPX_TYPE_3_SUPPORT 0x00000100 +#define OSC_PCI_SUPPORT_MASKS 0x0000011f /* PCI Host Bridge _OSC: Capabilities DWORD 3: Control Field */ #define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 0x00000001 -- cgit From e0547c81bfcfad01cbbfa93a5e66bb98ab932f80 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 12 Feb 2019 17:02:30 -0500 Subject: PCI: Reset Lenovo ThinkPad P50 nvgpu at boot if necessary On ThinkPad P50 SKUs with an Nvidia Quadro M1000M instead of the M2000M variant, the BIOS does not always reset the secondary Nvidia GPU during reboot if the laptop is configured in Hybrid Graphics mode. The reason is unknown, but the following steps and possibly a good bit of patience will reproduce the issue: 1. Boot up the laptop normally in Hybrid Graphics mode 2. Make sure nouveau is loaded and that the GPU is awake 3. Allow the Nvidia GPU to runtime suspend itself after being idle 4. Reboot the machine, the more sudden the better (e.g. sysrq-b may help) 5. If nouveau loads up properly, reboot the machine again and go back to step 2 until you reproduce the issue This results in some very strange behavior: the GPU will be left in exactly the same state it was in when the previously booted kernel started the reboot. This has all sorts of bad side effects: for starters, this completely breaks nouveau starting with a mysterious EVO channel failure that happens well before we've actually used the EVO channel for anything: nouveau 0000:01:00.0: disp: chid 0 mthd 0000 data 00000400 00001000 00000002 This causes a timeout trying to bring up the GR ctx: nouveau 0000:01:00.0: timeout WARNING: CPU: 0 PID: 12 at drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c:1547 gf100_grctx_generate+0x7b2/0x850 [nouveau] Hardware name: LENOVO 20EQS64N0B/20EQS64N0B, BIOS N1EET82W (1.55 ) 12/18/2018 Workqueue: events_long drm_dp_mst_link_probe_work [drm_kms_helper] ... nouveau 0000:01:00.0: gr: wait for idle timeout (en: 1, ctxsw: 0, busy: 1) nouveau 0000:01:00.0: gr: wait for idle timeout (en: 1, ctxsw: 0, busy: 1) nouveau 0000:01:00.0: fifo: fault 01 [WRITE] at 0000000000008000 engine 00 [GR] client 15 [HUB/SCC_NB] reason c4 [] on channel -1 [0000000000 unknown] The GPU never manages to recover. Booting without loading nouveau causes issues as well, since the GPU starts sending spurious interrupts that cause other device's IRQs to get disabled by the kernel: irq 16: nobody cared (try booting with the "irqpoll" option) ... handlers: [<000000007faa9e99>] i801_isr [i2c_i801] Disabling IRQ #16 ... serio: RMI4 PS/2 pass-through port at rmi4-00.fn03 i801_smbus 0000:00:1f.4: Timeout waiting for interrupt! i801_smbus 0000:00:1f.4: Transaction timeout rmi4_f03 rmi4-00.fn03: rmi_f03_pt_write: Failed to write to F03 TX register (-110). i801_smbus 0000:00:1f.4: Timeout waiting for interrupt! i801_smbus 0000:00:1f.4: Transaction timeout rmi4_physical rmi4-00: rmi_driver_set_irq_bits: Failed to change enabled interrupts! This causes the touchpad and sometimes other things to get disabled. Since this happens without nouveau, we can't fix this problem from nouveau itself. Add a PCI quirk for the specific P50 variant of this GPU. Make sure the GPU is advertising NoReset- so we don't reset the GPU when the machine is in Dedicated graphics mode (where the GPU being initialized by the BIOS is normal and expected). Map the GPU MMIO space and read the magic 0x2240c register, which will have bit 1 set if the device was POSTed during a previous boot. Once we've confirmed all of this, reset the GPU and re-disable it - bringing it back to a healthy state. Link: https://bugzilla.kernel.org/show_bug.cgi?id=203003 Link: https://lore.kernel.org/lkml/20190212220230.1568-1-lyude@redhat.com Signed-off-by: Lyude Paul Signed-off-by: Bjorn Helgaas Cc: nouveau@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Cc: Karol Herbst Cc: Ben Skeggs Cc: stable@vger.kernel.org --- drivers/pci/quirks.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a59ad09ce911..819a595b0b1d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -5120,3 +5120,61 @@ SWITCHTEC_QUIRK(0x8573); /* PFXI 48XG3 */ SWITCHTEC_QUIRK(0x8574); /* PFXI 64XG3 */ SWITCHTEC_QUIRK(0x8575); /* PFXI 80XG3 */ SWITCHTEC_QUIRK(0x8576); /* PFXI 96XG3 */ + +/* + * On Lenovo Thinkpad P50 SKUs with a Nvidia Quadro M1000M, the BIOS does + * not always reset the secondary Nvidia GPU between reboots if the system + * is configured to use Hybrid Graphics mode. This results in the GPU + * being left in whatever state it was in during the *previous* boot, which + * causes spurious interrupts from the GPU, which in turn causes us to + * disable the wrong IRQ and end up breaking the touchpad. Unsurprisingly, + * this also completely breaks nouveau. + * + * Luckily, it seems a simple reset of the Nvidia GPU brings it back to a + * clean state and fixes all these issues. + * + * When the machine is configured in Dedicated display mode, the issue + * doesn't occur. Fortunately the GPU advertises NoReset+ when in this + * mode, so we can detect that and avoid resetting it. + */ +static void quirk_reset_lenovo_thinkpad_p50_nvgpu(struct pci_dev *pdev) +{ + void __iomem *map; + int ret; + + if (pdev->subsystem_vendor != PCI_VENDOR_ID_LENOVO || + pdev->subsystem_device != 0x222e || + !pdev->reset_fn) + return; + + if (pci_enable_device_mem(pdev)) + return; + + /* + * Based on nvkm_device_ctor() in + * drivers/gpu/drm/nouveau/nvkm/engine/device/base.c + */ + map = pci_iomap(pdev, 0, 0x23000); + if (!map) { + pci_err(pdev, "Can't map MMIO space\n"); + goto out_disable; + } + + /* + * Make sure the GPU looks like it's been POSTed before resetting + * it. + */ + if (ioread32(map + 0x2240c) & 0x2) { + pci_info(pdev, FW_BUG "GPU left initialized by EFI, resetting\n"); + ret = pci_reset_function(pdev); + if (ret < 0) + pci_err(pdev, "Failed to reset GPU: %d\n", ret); + } + + iounmap(map); +out_disable: + pci_disable_device(pdev); +} +DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, 0x13b1, + PCI_CLASS_DISPLAY_VGA, 8, + quirk_reset_lenovo_thinkpad_p50_nvgpu); -- cgit From 4166bfe53093b687a0b1b22e5d943e143b8089b2 Mon Sep 17 00:00:00 2001 From: Jonathan Chocron Date: Thu, 28 Mar 2019 13:57:56 +0200 Subject: PCI: al: Add Amazon Annapurna Labs PCIe host controller driver Add driver for Amazon's Annapurna Labs PCIe host controller. The controller is based on DesignWare's IP. The controller doesn't support accessing the Root Port's config space via ECAM, so we obtain its base address via an AMZN0001 device. Furthermore, the DesignWare PCIe controller doesn't filter out config transactions sent to devices 1 and up on its bus, so they are filtered by the driver. All subordinate buses do support ECAM access. Implementing specific PCI config access functions involves: - Adding an init function to obtain the Root Port's base address from an AMZN0001 device. - Adding a new entry in the MCFG quirk array. [bhelgaas: Note that there is no Kconfig option for this driver because it is only intended for use with the generic ACPI host bridge driver. This driver is only needed because the DesignWare IP doesn't completely support ECAM access to the root bus.] Link: https://lore.kernel.org/lkml/1553774276-24675-1-git-send-email-jonnyc@amazon.com Co-developed-by: Vladimir Aerov Signed-off-by: Jonathan Chocron Signed-off-by: Vladimir Aerov Signed-off-by: Bjorn Helgaas Reviewed-by: David Woodhouse Reviewed-by: Benjamin Herrenschmidt Acked-by: Lorenzo Pieralisi --- MAINTAINERS | 6 +++ drivers/acpi/pci_mcfg.c | 12 +++++ drivers/pci/controller/dwc/Makefile | 1 + drivers/pci/controller/dwc/pcie-al.c | 93 ++++++++++++++++++++++++++++++++++++ include/linux/pci-ecam.h | 1 + 5 files changed, 113 insertions(+) create mode 100644 drivers/pci/controller/dwc/pcie-al.c diff --git a/MAINTAINERS b/MAINTAINERS index e17ebf70b548..8b18d02a50cb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12014,6 +12014,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/ S: Supported F: drivers/pci/controller/ +PCIE DRIVER FOR ANNAPURNA LABS +M: Jonathan Chocron +L: linux-pci@vger.kernel.org +S: Maintained +F: drivers/pci/controller/dwc/pcie-al.c + PCIE DRIVER FOR AMLOGIC MESON M: Yue Wang L: linux-pci@vger.kernel.org diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index a4e8432fc2fb..b42be067fb83 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -52,6 +52,18 @@ struct mcfg_fixup { static struct mcfg_fixup mcfg_quirks[] = { /* { OEM_ID, OEM_TABLE_ID, REV, SEGMENT, BUS_RANGE, ops, cfgres }, */ +#define AL_ECAM(table_id, rev, seg, ops) \ + { "AMAZON", table_id, rev, seg, MCFG_BUS_ANY, ops } + + AL_ECAM("GRAVITON", 0, 0, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 1, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 2, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 3, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 4, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 5, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 6, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 7, &al_pcie_ops), + #define QCOM_ECAM32(seg) \ { "QCOM ", "QDF2432 ", 1, seg, MCFG_BUS_ANY, &pci_32b_ops } diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile index b5f3b83cc2b3..b085dfd4fab7 100644 --- a/drivers/pci/controller/dwc/Makefile +++ b/drivers/pci/controller/dwc/Makefile @@ -28,5 +28,6 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o # depending on whether ACPI, the DT driver, or both are enabled. ifdef CONFIG_PCI +obj-$(CONFIG_ARM64) += pcie-al.o obj-$(CONFIG_ARM64) += pcie-hisi.o endif diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c new file mode 100644 index 000000000000..3ab58f0584a8 --- /dev/null +++ b/drivers/pci/controller/dwc/pcie-al.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCIe host controller driver for Amazon's Annapurna Labs IP (used in chips + * such as Graviton and Alpine) + * + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Author: Jonathan Chocron + */ + +#include +#include +#include +#include "../../pci.h" + +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) + +struct al_pcie_acpi { + void __iomem *dbi_base; +}; + +static void __iomem *al_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, + int where) +{ + struct pci_config_window *cfg = bus->sysdata; + struct al_pcie_acpi *pcie = cfg->priv; + void __iomem *dbi_base = pcie->dbi_base; + + if (bus->number == cfg->busr.start) { + /* + * The DW PCIe core doesn't filter out transactions to other + * devices/functions on the root bus num, so we do this here. + */ + if (PCI_SLOT(devfn) > 0) + return NULL; + else + return dbi_base + where; + } + + return pci_ecam_map_bus(bus, devfn, where); +} + +static int al_pcie_init(struct pci_config_window *cfg) +{ + struct device *dev = cfg->parent; + struct acpi_device *adev = to_acpi_device(dev); + struct acpi_pci_root *root = acpi_driver_data(adev); + struct al_pcie_acpi *al_pcie; + struct resource *res; + int ret; + + al_pcie = devm_kzalloc(dev, sizeof(*al_pcie), GFP_KERNEL); + if (!al_pcie) + return -ENOMEM; + + res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; + + ret = acpi_get_rc_resources(dev, "AMZN0001", root->segment, res); + if (ret) { + dev_err(dev, "can't get rc dbi base address for SEG %d\n", + root->segment); + return ret; + } + + dev_dbg(dev, "Root port dbi res: %pR\n", res); + + al_pcie->dbi_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(al_pcie->dbi_base)) { + long err = PTR_ERR(al_pcie->dbi_base); + + dev_err(dev, "couldn't remap dbi base %pR (err:%ld)\n", + res, err); + return err; + } + + cfg->priv = al_pcie; + + return 0; +} + +struct pci_ecam_ops al_pcie_ops = { + .bus_shift = 20, + .init = al_pcie_init, + .pci_ops = { + .map_bus = al_pcie_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, + } +}; + +#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */ diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 29efa09d686b..a73164c85e78 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -56,6 +56,7 @@ extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */ extern struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */ extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops; /* APM X-Gene PCIe v1 */ extern struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */ +extern struct pci_ecam_ops al_pcie_ops; /* Amazon Annapurna Labs PCIe */ #endif #ifdef CONFIG_PCI_HOST_COMMON -- cgit From 4e544bac8267f65a0bf06aed1bde9964da4812ed Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 24 Apr 2019 21:11:58 +0200 Subject: PCI: Add pci_dev_id() helper In several places in the kernel we find PCI_DEVID used like this: PCI_DEVID(dev->bus->number, dev->devfn) Add a "pci_dev_id(struct pci_dev *dev)" helper to simplify callers. Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas --- drivers/pci/msi.c | 6 +++--- drivers/pci/search.c | 10 +++------- include/linux/pci.h | 5 +++++ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 73986825d221..e039b740fe74 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1338,7 +1338,7 @@ irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev, struct msi_desc *desc) { return (irq_hw_number_t)desc->msi_attrib.entry_nr | - PCI_DEVID(dev->bus->number, dev->devfn) << 11 | + pci_dev_id(dev) << 11 | (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27; } @@ -1508,7 +1508,7 @@ static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data) u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev) { struct device_node *of_node; - u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn); + u32 rid = pci_dev_id(pdev); pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid); @@ -1531,7 +1531,7 @@ u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev) struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev) { struct irq_domain *dom; - u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn); + u32 rid = pci_dev_id(pdev); pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid); dom = of_msi_map_get_device_domain(&pdev->dev, rid); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 2b5f720862d3..5c7922612733 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -33,7 +33,7 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, struct pci_bus *bus; int ret; - ret = fn(pdev, PCI_DEVID(pdev->bus->number, pdev->devfn), data); + ret = fn(pdev, pci_dev_id(pdev), data); if (ret) return ret; @@ -88,9 +88,7 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, return ret; continue; case PCI_EXP_TYPE_PCIE_BRIDGE: - ret = fn(tmp, - PCI_DEVID(tmp->bus->number, - tmp->devfn), data); + ret = fn(tmp, pci_dev_id(tmp), data); if (ret) return ret; continue; @@ -101,9 +99,7 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, PCI_DEVID(tmp->subordinate->number, PCI_DEVFN(0, 0)), data); else - ret = fn(tmp, - PCI_DEVID(tmp->bus->number, - tmp->devfn), data); + ret = fn(tmp, pci_dev_id(tmp), data); if (ret) return ret; } diff --git a/include/linux/pci.h b/include/linux/pci.h index 5f32275358cf..26fa6d143dfe 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -596,6 +596,11 @@ struct pci_bus { #define to_pci_bus(n) container_of(n, struct pci_bus, dev) +static inline u16 pci_dev_id(struct pci_dev *dev) +{ + return PCI_DEVID(dev->bus->number, dev->devfn); +} + /* * Returns true if the PCI bus is root (behind host-PCI bridge), * false otherwise -- cgit From a195016a5981376721a7770e1d01be676540ead8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 24 Apr 2019 21:13:25 +0200 Subject: r8169: use pci_dev_id() helper Use new helper pci_dev_id() to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas Acked-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index c29dde064078..65eb095f94b8 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -7182,8 +7182,7 @@ static int r8169_mdio_register(struct rtl8169_private *tp) new_bus->priv = tp; new_bus->parent = &pdev->dev; new_bus->irq[0] = PHY_IGNORE_INTERRUPT; - snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x", - PCI_DEVID(pdev->bus->number, pdev->devfn)); + snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x", pci_dev_id(pdev)); new_bus->read = r8169_mdio_read_reg; new_bus->write = r8169_mdio_write_reg; -- cgit From 51c51a48de4bfda78d381616e553445a76b1d407 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 24 Apr 2019 21:14:25 +0200 Subject: powerpc/powernv/npu: Use pci_dev_id() helper Use new helper pci_dev_id() to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas Reviewed-by: Alexey Kardashevskiy --- arch/powerpc/platforms/powernv/npu-dma.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c index dc23d9d2a7d9..495550432f3d 100644 --- a/arch/powerpc/platforms/powernv/npu-dma.c +++ b/arch/powerpc/platforms/powernv/npu-dma.c @@ -1213,9 +1213,8 @@ int pnv_npu2_map_lpar_dev(struct pci_dev *gpdev, unsigned int lparid, * Currently we only support radix and non-zero LPCR only makes sense * for hash tables so skiboot expects the LPCR parameter to be a zero. */ - ret = opal_npu_map_lpar(nphb->opal_id, - PCI_DEVID(gpdev->bus->number, gpdev->devfn), lparid, - 0 /* LPCR bits */); + ret = opal_npu_map_lpar(nphb->opal_id, pci_dev_id(gpdev), lparid, + 0 /* LPCR bits */); if (ret) { dev_err(&gpdev->dev, "Error %d mapping device to LPAR\n", ret); return ret; @@ -1224,7 +1223,7 @@ int pnv_npu2_map_lpar_dev(struct pci_dev *gpdev, unsigned int lparid, dev_dbg(&gpdev->dev, "init context opalid=%llu msr=%lx\n", nphb->opal_id, msr); ret = opal_npu_init_context(nphb->opal_id, 0/*__unused*/, msr, - PCI_DEVID(gpdev->bus->number, gpdev->devfn)); + pci_dev_id(gpdev)); if (ret < 0) dev_err(&gpdev->dev, "Failed to init context: %d\n", ret); else @@ -1258,7 +1257,7 @@ int pnv_npu2_unmap_lpar_dev(struct pci_dev *gpdev) dev_dbg(&gpdev->dev, "destroy context opalid=%llu\n", nphb->opal_id); ret = opal_npu_destroy_context(nphb->opal_id, 0/*__unused*/, - PCI_DEVID(gpdev->bus->number, gpdev->devfn)); + pci_dev_id(gpdev)); if (ret < 0) { dev_err(&gpdev->dev, "Failed to destroy context: %d\n", ret); return ret; @@ -1266,9 +1265,8 @@ int pnv_npu2_unmap_lpar_dev(struct pci_dev *gpdev) /* Set LPID to 0 anyway, just to be safe */ dev_dbg(&gpdev->dev, "Map LPAR opalid=%llu lparid=0\n", nphb->opal_id); - ret = opal_npu_map_lpar(nphb->opal_id, - PCI_DEVID(gpdev->bus->number, gpdev->devfn), 0 /*LPID*/, - 0 /* LPCR bits */); + ret = opal_npu_map_lpar(nphb->opal_id, pci_dev_id(gpdev), 0 /*LPID*/, + 0 /* LPCR bits */); if (ret) dev_err(&gpdev->dev, "Error %d mapping device to LPAR\n", ret); -- cgit From babe2ef342c4829c3875a03a6ecb9716813cbe21 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 24 Apr 2019 21:14:55 +0200 Subject: drm/amdkfd: Use pci_dev_id() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use new helper pci_dev_id() to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas Acked-by: Christian König --- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 09da91644f9f..b0c59a313049 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1270,8 +1270,7 @@ int kfd_topology_add_device(struct kfd_dev *gpu) dev->node_props.vendor_id = gpu->pdev->vendor; dev->node_props.device_id = gpu->pdev->device; - dev->node_props.location_id = PCI_DEVID(gpu->pdev->bus->number, - gpu->pdev->devfn); + dev->node_props.location_id = pci_dev_id(gpu->pdev); dev->node_props.max_engine_clk_fcompute = amdgpu_amdkfd_get_max_engine_clock_in_mhz(dev->gpu->kgd); dev->node_props.max_engine_clk_ccompute = -- cgit From 775c068c6aae6f1ce16bcb3443998ab40500496c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 24 Apr 2019 21:15:25 +0200 Subject: iommu/amd: Use pci_dev_id() helper Use new helper pci_dev_id() to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas Reviewed-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index b319e51c379b..8e8121b14c36 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -165,7 +165,7 @@ static inline u16 get_pci_device_id(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - return PCI_DEVID(pdev->bus->number, pdev->devfn); + return pci_dev_id(pdev); } static inline int get_acpihid_device_id(struct device *dev, -- cgit From cc49baa9a202373b59aad8aca2e5285b9b9eda77 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 24 Apr 2019 21:16:10 +0200 Subject: iommu/vt-d: Use pci_dev_id() helper Use new helper pci_dev_id() to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas Reviewed-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 2 +- drivers/iommu/intel_irq_remapping.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 87274b54febd..a772dedb05b9 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1391,7 +1391,7 @@ static void iommu_enable_dev_iotlb(struct device_domain_info *info) /* pdev will be returned if device is not a vf */ pf_pdev = pci_physfn(pdev); - info->pfsid = PCI_DEVID(pf_pdev->bus->number, pf_pdev->devfn); + info->pfsid = pci_dev_id(pf_pdev); } #ifdef CONFIG_INTEL_IOMMU_SVM diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 2d74641b7f7b..871458b873be 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -424,7 +424,7 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, data.alias); else set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, - PCI_DEVID(dev->bus->number, dev->devfn)); + pci_dev_id(dev)); return 0; } -- cgit From d4a62ea411f98be6f7ffdeb339eca901f3d6472b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 24 Apr 2019 21:16:41 +0200 Subject: stmmac: pci: Use pci_dev_id() helper Use new helper pci_dev_id() to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index d819e8eaba12..5cdc17381c80 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -204,7 +204,7 @@ static int quark_default_data(struct pci_dev *pdev, ret = 1; } - plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn); + plat->bus_id = pci_dev_id(pdev); plat->phy_addr = ret; plat->interface = PHY_INTERFACE_MODE_RMII; -- cgit From 3b9f900fa0636b7b530e517b4fbefa6cc5819f52 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 24 Apr 2019 21:17:19 +0200 Subject: platform/chrome: chromeos_laptop: use pci_dev_id() helper Use new helper pci_dev_id() to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas Acked-By: Benson Leung --- drivers/platform/chrome/chromeos_laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index 24326eecd787..7abbb6167766 100644 --- a/drivers/platform/chrome/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c @@ -125,7 +125,7 @@ static bool chromeos_laptop_match_adapter_devid(struct device *dev, u32 devid) return false; pdev = to_pci_dev(dev); - return devid == PCI_DEVID(pdev->bus->number, pdev->devfn); + return devid == pci_dev_id(pdev); } static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter) -- cgit From 8cff995405eb0b563e7a0d2c49838611ea3f2692 Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 26 Apr 2019 14:50:04 +0530 Subject: PCI: iproc: Enable iProc config read for PAXBv2 iProc config read flag has to be enabled for PAXBv2 instead of PAXB. Fixes: f78e60a29d4f ("PCI: iproc: Reject unconfigured physical functions from PAXC") Signed-off-by: Srinath Mannam Signed-off-by: Lorenzo Pieralisi Reviewed-by: Ray Jui --- drivers/pci/controller/pcie-iproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 080f142ce24d..dd11d0226ff0 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -1383,7 +1383,6 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) break; case IPROC_PCIE_PAXB: regs = iproc_pcie_reg_paxb; - pcie->iproc_cfg_read = true; pcie->has_apb_err_disable = true; if (pcie->need_ob_cfg) { pcie->ob_map = paxb_ob_map; @@ -1392,6 +1391,7 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) break; case IPROC_PCIE_PAXB_V2: regs = iproc_pcie_reg_paxb_v2; + pcie->iproc_cfg_read = true; pcie->has_apb_err_disable = true; if (pcie->need_ob_cfg) { pcie->ob_map = paxb_v2_ob_map; -- cgit From 9e303be2e5d0705f3fc51c4c854e5d94e1b943c4 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:22 -0700 Subject: PCI: imx6: Simplify imx7d_pcie_wait_for_phy_pll_lock() Make use of regmap_read_poll_timeout() to simplify imx7d_pcie_wait_for_phy_pll_lock(). No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 3d627f94a166..ea2617712a3b 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -89,9 +89,8 @@ struct imx6_pcie { }; /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ -#define PHY_PLL_LOCK_WAIT_MAX_RETRIES 2000 -#define PHY_PLL_LOCK_WAIT_USLEEP_MIN 50 #define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 +#define PHY_PLL_LOCK_WAIT_TIMEOUT (2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX) /* PCIe Root Complex registers (memory-mapped) */ #define PCIE_RC_IMX6_MSI_CAP 0x50 @@ -488,20 +487,14 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) { u32 val; - unsigned int retries; struct device *dev = imx6_pcie->pci->dev; - for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES; retries++) { - regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR22, &val); - - if (val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED) - return; - - usleep_range(PHY_PLL_LOCK_WAIT_USLEEP_MIN, - PHY_PLL_LOCK_WAIT_USLEEP_MAX); - } - - dev_err(dev, "PCIe PLL lock timeout\n"); + if (regmap_read_poll_timeout(imx6_pcie->iomuxc_gpr, + IOMUXC_GPR22, val, + val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED, + PHY_PLL_LOCK_WAIT_USLEEP_MAX, + PHY_PLL_LOCK_WAIT_TIMEOUT)) + dev_err(dev, "PCIe PLL lock timeout\n"); } static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) -- cgit From ee6f37175b3f7ae1c3bc147d4779c6043ce25461 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:23 -0700 Subject: PCI: imx6: Drop imx6_pcie_wait_for_link() All calls to imx6_pcie_wait_for_link() share the same error path and the state of PHY debug registers will already be printed there, so there's no real reason we can't just use dw_pcie_wait_for_link(). Drop imx6_pcie_wait_for_link() and replace it with dw_pcie_wait_for_link(). Suggested-by: Lucas Stach Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index ea2617712a3b..bb3dcfdbf697 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -723,21 +723,6 @@ static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) return 0; } -static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie) -{ - struct dw_pcie *pci = imx6_pcie->pci; - struct device *dev = pci->dev; - - /* check if the link is up or not */ - if (!dw_pcie_wait_for_link(pci)) - return 0; - - dev_dbg(dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", - dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0), - dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1)); - return -ETIMEDOUT; -} - static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -796,7 +781,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); - ret = imx6_pcie_wait_for_link(imx6_pcie); + ret = dw_pcie_wait_for_link(pci); if (ret) goto err_reset_phy; @@ -834,7 +819,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) } /* Make sure link training is finished as well! */ - ret = imx6_pcie_wait_for_link(imx6_pcie); + ret = dw_pcie_wait_for_link(pci); if (ret) { dev_err(dev, "Failed to bring link up!\n"); goto err_reset_phy; -- cgit From c377690cffaf6a497b81304a83d3b2a2dad2942a Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:24 -0700 Subject: PCI: imx6: Return -ETIMEOUT from imx6_pcie_wait_for_speed_change() Change error code from -EINVAL to -ETIMEDOUT in imx6_pcie_wait_for_speed_change() since that error code seems more appropriate. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index bb3dcfdbf697..021ef121a058 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -739,7 +739,7 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) } dev_err(dev, "Speed change timeout\n"); - return -EINVAL; + return -ETIMEDOUT; } static void imx6_pcie_ltssm_enable(struct device *dev) -- cgit From 680728e4cbee8ede008373c56fe6978946080008 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:25 -0700 Subject: PCI: imx6: Remove PCIE_PL_PFLR_* constants Code using these constants was removed in commit a71280722eeb ("PCI: imx6: Remove LTSSM disable workaround"). No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 021ef121a058..c0867df090f5 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -103,9 +103,6 @@ struct imx6_pcie { /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 -#define PCIE_PL_PFLR (PL_OFFSET + 0x08) -#define PCIE_PL_PFLR_LINK_STATE_MASK (0x3f << 16) -#define PCIE_PL_PFLR_FORCE_LINK (1 << 15) #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) #define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c) -- cgit From 60ef4b072ba089440531287f72740d94ed1e8dd1 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:26 -0700 Subject: PCI: dwc: imx6: Share PHY debug register definitions Both pcie-designware.c and pci-imx6.c contain custom definitions for PHY debug registers R0/R1 and on top of that there's already a definition for R0 in pcie-designware.h. Move all of the definitions to pcie-designware.h. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 6 ++---- drivers/pci/controller/dwc/pcie-designware.c | 12 +++--------- drivers/pci/controller/dwc/pcie-designware.h | 3 +++ 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index c0867df090f5..eeacdebd9b50 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -103,8 +103,6 @@ struct imx6_pcie { /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 -#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) -#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c) #define PCIE_PHY_CTRL (PL_OFFSET + 0x114) #define PCIE_PHY_CTRL_DATA_LOC 0 @@ -831,8 +829,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) err_reset_phy: dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n", - dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0), - dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1)); + dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0), + dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1)); imx6_pcie_reset_phy(imx6_pcie); return ret; } diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 31f6331ca46f..086e87a40316 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -14,12 +14,6 @@ #include "pcie-designware.h" -/* PCIe Port Logic registers */ -#define PLR_OFFSET 0x700 -#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c) -#define PCIE_PHY_DEBUG_R1_LINK_UP (0x1 << 4) -#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (0x1 << 29) - int dw_pcie_read(void __iomem *addr, int size, u32 *val) { if (!IS_ALIGNED((uintptr_t)addr, size)) { @@ -334,9 +328,9 @@ int dw_pcie_link_up(struct dw_pcie *pci) if (pci->ops->link_up) return pci->ops->link_up(pci); - val = readl(pci->dbi_base + PCIE_PHY_DEBUG_R1); - return ((val & PCIE_PHY_DEBUG_R1_LINK_UP) && - (!(val & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING))); + val = readl(pci->dbi_base + PCIE_PORT_DEBUG1); + return ((val & PCIE_PORT_DEBUG1_LINK_UP) && + (!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING))); } void dw_pcie_setup(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 377f4c0b52da..b33ae13194be 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -41,6 +41,9 @@ #define PCIE_PORT_DEBUG0 0x728 #define PORT_LOGIC_LTSSM_STATE_MASK 0x1f #define PORT_LOGIC_LTSSM_STATE_L0 0x11 +#define PCIE_PORT_DEBUG1 0x72C +#define PCIE_PORT_DEBUG1_LINK_UP BIT(4) +#define PCIE_PORT_DEBUG1_LINK_IN_TRAINING BIT(29) #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C #define PORT_LOGIC_SPEED_CHANGE BIT(17) -- cgit From 276c76d7a15ada363b8efab7b50a52aeaf3b3fd5 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:27 -0700 Subject: PCI: imx6: Make use of BIT() in constant definitions Avoid using explicit left shifts and convert various definitions to use BIT() instead. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index eeacdebd9b50..5650642ab248 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -118,14 +118,14 @@ struct imx6_pcie { /* PHY registers (not memory-mapped) */ #define PCIE_PHY_ATEOVRD 0x10 -#define PCIE_PHY_ATEOVRD_EN (0x1 << 2) +#define PCIE_PHY_ATEOVRD_EN BIT(2) #define PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT 0 #define PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK 0x1 #define PCIE_PHY_MPLL_OVRD_IN_LO 0x11 #define PCIE_PHY_MPLL_MULTIPLIER_SHIFT 2 #define PCIE_PHY_MPLL_MULTIPLIER_MASK 0x7f -#define PCIE_PHY_MPLL_MULTIPLIER_OVRD (0x1 << 9) +#define PCIE_PHY_MPLL_MULTIPLIER_OVRD BIT(9) #define PCIE_PHY_RX_ASIC_OUT 0x100D #define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0) @@ -148,8 +148,8 @@ struct imx6_pcie { #define PCIE_PHY_CMN_REG26_ATT_MODE 0xBC #define PHY_RX_OVRD_IN_LO 0x1005 -#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5) -#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3) +#define PHY_RX_OVRD_IN_LO_RX_DATA_EN BIT(5) +#define PHY_RX_OVRD_IN_LO_RX_PLL_EN BIT(3) static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val) { -- cgit From 3ca4133253a7ff37e56b3b00f1e03c3e7d20ea89 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:28 -0700 Subject: PCI: imx6: Simplify bit operations in PHY functions Simplify the code by incorporating left shifts into constant definitions as well as using FIELD_PREP/GENMASK. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 5650642ab248..669e01353026 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -105,11 +105,11 @@ struct imx6_pcie { #define PL_OFFSET 0x700 #define PCIE_PHY_CTRL (PL_OFFSET + 0x114) -#define PCIE_PHY_CTRL_DATA_LOC 0 -#define PCIE_PHY_CTRL_CAP_ADR_LOC 16 -#define PCIE_PHY_CTRL_CAP_DAT_LOC 17 -#define PCIE_PHY_CTRL_WR_LOC 18 -#define PCIE_PHY_CTRL_RD_LOC 19 +#define PCIE_PHY_CTRL_DATA(x) FIELD_PREP(GENMASK(15, 0), (x)) +#define PCIE_PHY_CTRL_CAP_ADR BIT(16) +#define PCIE_PHY_CTRL_CAP_DAT BIT(17) +#define PCIE_PHY_CTRL_WR BIT(18) +#define PCIE_PHY_CTRL_RD BIT(19) #define PCIE_PHY_STAT (PL_OFFSET + 0x110) #define PCIE_PHY_STAT_ACK_LOC 16 @@ -178,17 +178,17 @@ static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr) u32 val; int ret; - val = addr << PCIE_PHY_CTRL_DATA_LOC; + val = PCIE_PHY_CTRL_DATA(addr); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); - val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC); + val |= PCIE_PHY_CTRL_CAP_ADR; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); ret = pcie_phy_poll_ack(imx6_pcie, 1); if (ret) return ret; - val = addr << PCIE_PHY_CTRL_DATA_LOC; + val = PCIE_PHY_CTRL_DATA(addr); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); return pcie_phy_poll_ack(imx6_pcie, 0); @@ -206,7 +206,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) return ret; /* assert Read signal */ - phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC; + phy_ctl = PCIE_PHY_CTRL_RD; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, phy_ctl); ret = pcie_phy_poll_ack(imx6_pcie, 1); @@ -234,11 +234,11 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) if (ret) return ret; - var = data << PCIE_PHY_CTRL_DATA_LOC; + var = PCIE_PHY_CTRL_DATA(data); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* capture data */ - var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC); + var |= PCIE_PHY_CTRL_CAP_DAT; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); ret = pcie_phy_poll_ack(imx6_pcie, 1); @@ -246,7 +246,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) return ret; /* deassert cap data */ - var = data << PCIE_PHY_CTRL_DATA_LOC; + var = PCIE_PHY_CTRL_DATA(data); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ @@ -255,7 +255,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) return ret; /* assert wr signal */ - var = 0x1 << PCIE_PHY_CTRL_WR_LOC; + var = PCIE_PHY_CTRL_WR; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack */ @@ -264,7 +264,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) return ret; /* deassert wr signal */ - var = data << PCIE_PHY_CTRL_DATA_LOC; + var = PCIE_PHY_CTRL_DATA(data); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ -- cgit From c2c708bc1dbf9655211d3843e2f36c7951059cf0 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:29 -0700 Subject: PCI: imx6: Simplify pcie_phy_poll_ack() Simplify pcie_phy_poll_ack() by incorporating shifting into constant definition and convert the code to use 'bool'. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 669e01353026..3fd084357488 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -112,7 +112,7 @@ struct imx6_pcie { #define PCIE_PHY_CTRL_RD BIT(19) #define PCIE_PHY_STAT (PL_OFFSET + 0x110) -#define PCIE_PHY_STAT_ACK_LOC 16 +#define PCIE_PHY_STAT_ACK BIT(16) #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C @@ -151,16 +151,16 @@ struct imx6_pcie { #define PHY_RX_OVRD_IN_LO_RX_DATA_EN BIT(5) #define PHY_RX_OVRD_IN_LO_RX_PLL_EN BIT(3) -static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val) +static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, bool exp_val) { struct dw_pcie *pci = imx6_pcie->pci; - u32 val; + bool val; u32 max_iterations = 10; u32 wait_counter = 0; do { - val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT); - val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1; + val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT) & + PCIE_PHY_STAT_ACK; wait_counter++; if (val == exp_val) @@ -184,14 +184,14 @@ static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr) val |= PCIE_PHY_CTRL_CAP_ADR; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); - ret = pcie_phy_poll_ack(imx6_pcie, 1); + ret = pcie_phy_poll_ack(imx6_pcie, true); if (ret) return ret; val = PCIE_PHY_CTRL_DATA(addr); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); - return pcie_phy_poll_ack(imx6_pcie, 0); + return pcie_phy_poll_ack(imx6_pcie, false); } /* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */ @@ -209,7 +209,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) phy_ctl = PCIE_PHY_CTRL_RD; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, phy_ctl); - ret = pcie_phy_poll_ack(imx6_pcie, 1); + ret = pcie_phy_poll_ack(imx6_pcie, true); if (ret) return ret; @@ -219,7 +219,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) /* deassert Read signal */ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, 0x00); - return pcie_phy_poll_ack(imx6_pcie, 0); + return pcie_phy_poll_ack(imx6_pcie, false); } static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) @@ -241,7 +241,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) var |= PCIE_PHY_CTRL_CAP_DAT; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); - ret = pcie_phy_poll_ack(imx6_pcie, 1); + ret = pcie_phy_poll_ack(imx6_pcie, true); if (ret) return ret; @@ -250,7 +250,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ - ret = pcie_phy_poll_ack(imx6_pcie, 0); + ret = pcie_phy_poll_ack(imx6_pcie, false); if (ret) return ret; @@ -259,7 +259,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack */ - ret = pcie_phy_poll_ack(imx6_pcie, 1); + ret = pcie_phy_poll_ack(imx6_pcie, true); if (ret) return ret; @@ -268,7 +268,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ - ret = pcie_phy_poll_ack(imx6_pcie, 0); + ret = pcie_phy_poll_ack(imx6_pcie, false); if (ret) return ret; -- cgit From 37d5d32ae091c7acff23a080e3c179977fb943cd Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:30 -0700 Subject: PCI: imx6: Restrict PHY register data to 16-bit PHY registers on i.MX6 are 16-bit wide, so we can get rid of explicit masking if we restrict pcie_phy_read()/pcie_phy_write() to use 'u16' instead of 'int'. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 3fd084357488..30e764b6cbcc 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -195,10 +195,10 @@ static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr) } /* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */ -static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) +static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, u16 *data) { struct dw_pcie *pci = imx6_pcie->pci; - u32 val, phy_ctl; + u32 phy_ctl; int ret; ret = pcie_phy_wait_ack(imx6_pcie, addr); @@ -213,8 +213,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) if (ret) return ret; - val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT); - *data = val & 0xffff; + *data = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT); /* deassert Read signal */ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, 0x00); @@ -222,7 +221,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) return pcie_phy_poll_ack(imx6_pcie, false); } -static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) +static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, u16 data) { struct dw_pcie *pci = imx6_pcie->pci; u32 var; @@ -279,7 +278,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie) { - u32 tmp; + u16 tmp; if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY)) return; @@ -675,7 +674,7 @@ static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) { unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy); int mult, div; - u32 val; + u16 val; if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY)) return 0; -- cgit From 76d6dc26331dfe3c275b16ac28f8b92f9614cd7e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:31 -0700 Subject: PCI: imx6: Use flags to indicate support for suspend Now that driver data has flags variable that can be used to indicate quirks/features supported we can switch the code to use it instead of having a special function that does so based on variant alone. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 30e764b6cbcc..3e45f49b8a4f 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -52,6 +52,7 @@ enum imx6_pcie_variants { #define IMX6_PCIE_FLAG_IMX6_PHY BIT(0) #define IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE BIT(1) +#define IMX6_PCIE_FLAG_SUPPORTS_SUSPEND BIT(2) struct imx6_pcie_drvdata { enum imx6_pcie_variants variant; @@ -965,17 +966,11 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) } } -static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie) -{ - return (imx6_pcie->drvdata->variant == IMX7D || - imx6_pcie->drvdata->variant == IMX6SX); -} - static int imx6_pcie_suspend_noirq(struct device *dev) { struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); - if (!imx6_pcie_supports_suspend(imx6_pcie)) + if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND)) return 0; imx6_pcie_pm_turnoff(imx6_pcie); @@ -991,7 +986,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); struct pcie_port *pp = &imx6_pcie->pci->pp; - if (!imx6_pcie_supports_suspend(imx6_pcie)) + if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND)) return 0; imx6_pcie_assert_core_reset(imx6_pcie); @@ -1221,7 +1216,8 @@ static const struct imx6_pcie_drvdata drvdata[] = { [IMX6SX] = { .variant = IMX6SX, .flags = IMX6_PCIE_FLAG_IMX6_PHY | - IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE, + IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE | + IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, }, [IMX6QP] = { .variant = IMX6QP, @@ -1230,6 +1226,7 @@ static const struct imx6_pcie_drvdata drvdata[] = { }, [IMX7D] = { .variant = IMX7D, + .flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, }, [IMX8MQ] = { .variant = IMX8MQ, -- cgit From 87cb312777b5dc5eece8e1c58d4e0040eeea39fa Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:32 -0700 Subject: PCI: imx6: Use usleep_range() in imx6_pcie_enable_ref_clk() imx6_pcie_enable_ref_clk() is never called in atomic context, so there's no need to use udelay(). Replace it with usleep_range(). Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 3e45f49b8a4f..c6d6bde4d860 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -449,7 +449,7 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) * reset time is too short, cannot meet the requirement. * add one ~10us delay here. */ - udelay(10); + usleep_range(10, 100); regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); break; -- cgit From 9bc755d2cf54510629bfb9ef591a4af10343699e Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 26 Apr 2019 18:16:20 +0530 Subject: dt-bindings: PCI: Add PCI EP DT binding documentation for AM654 Add devicetree binding documentation for PCIe in EP mode present in AM654 SoC. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- .../devicetree/bindings/pci/pci-keystone.txt | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/pci-keystone.txt b/Documentation/devicetree/bindings/pci/pci-keystone.txt index 5c60e911b8b1..47202a2938f2 100644 --- a/Documentation/devicetree/bindings/pci/pci-keystone.txt +++ b/Documentation/devicetree/bindings/pci/pci-keystone.txt @@ -69,3 +69,47 @@ Optional properties:- DesignWare DT Properties not applicable for Keystone PCI 1. pcie_bus clock-names not used. Instead, a phandle to phys is used. + +AM654 PCIe Endpoint +=================== + +Required Properties:- + +compatibility: Should be "ti,am654-pcie-ep" for EP on AM654x SoC +reg: Four register ranges as listed in the reg-names property +reg-names: "dbics" for the DesignWare PCIe registers, "app" for the + TI specific application registers, "atu" for the + Address Translation Unit configuration registers and + "addr_space" used to map remote RC address space +num-ib-windows: As specified in + Documentation/devicetree/bindings/pci/designware-pcie.txt +num-ob-windows: As specified in + Documentation/devicetree/bindings/pci/designware-pcie.txt +num-lanes: As specified in + Documentation/devicetree/bindings/pci/designware-pcie.txt +power-domains: As documented by the generic PM domain bindings in + Documentation/devicetree/bindings/power/power_domain.txt. +ti,syscon-pcie-mode: phandle to the device control module required to configure + PCI in either RC mode or EP mode. + +Optional properties:- + +phys: list of PHY specifiers (used by generic PHY framework) +phy-names: must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the + number of lanes as specified in *num-lanes* property. +("phys" and "phy-names" DT bindings are specified in +Documentation/devicetree/bindings/phy/phy-bindings.txt) +interrupts: platform interrupt for error interrupts. + +pcie-ep { + compatible = "ti,am654-pcie-ep"; + reg = <0x5500000 0x1000>, <0x5501000 0x1000>, + <0x10000000 0x8000000>, <0x5506000 0x1000>; + reg-names = "app", "dbics", "addr_space", "atu"; + power-domains = <&k3_pds 120>; + ti,syscon-pcie-mode = <&pcie0_mode>; + num-lanes = <1>; + num-ib-windows = <16>; + num-ob-windows = <16>; + interrupts = ; +}; -- cgit From 23284ad677a94f26afc92017d540ccaf26c1a581 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:43 +0530 Subject: PCI: keystone: Add support for PCIe EP in AM654x Platforms Add PCIe EP support for AM654x Platforms in pci-keystone.c Link: https://lore.kernel.org/linux-pci/20190325093947.32633-15-kishon@ti.com/ Signed-off-by: Kishon Vijay Abraham I [lorenzo.pieralisi@arm.com: made dev_vdbg() call a comment] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/Kconfig | 27 +++- drivers/pci/controller/dwc/pci-keystone.c | 250 ++++++++++++++++++++++++++---- 2 files changed, 240 insertions(+), 37 deletions(-) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index d1d00833e0b3..a6ce1ee51b4c 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -103,15 +103,32 @@ config PCIE_SPEAR13XX Say Y here if you want PCIe support on SPEAr13XX SoCs. config PCI_KEYSTONE - bool "TI Keystone PCIe controller" + bool + +config PCI_KEYSTONE_HOST + bool "PCI Keystone Host Mode" depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST) depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST + select PCI_KEYSTONE + default y help - Say Y here if you want to enable PCI controller support on Keystone - SoCs. The PCI controller on Keystone is based on DesignWare hardware - and therefore the driver re-uses the DesignWare core functions to - implement the driver. + Enables support for the PCIe controller in the Keystone SoC to + work in host mode. The PCI controller on Keystone is based on + DesignWare hardware and therefore the driver re-uses the + DesignWare core functions to implement the driver. + +config PCI_KEYSTONE_EP + bool "PCI Keystone Endpoint Mode" + depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST) + depends on PCI_ENDPOINT + select PCIE_DW_EP + select PCI_KEYSTONE + help + Enables support for the PCIe controller in the Keystone SoC to + work in endpoint mode. The PCI controller on Keystone is based + on DesignWare hardware and therefore the driver re-uses the + DesignWare core functions to implement the driver. config PCI_LAYERSCAPE bool "Freescale Layerscape PCIe controller" diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 312fd0c49bbb..af677254a072 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -52,6 +52,12 @@ #define OB_ENABLEN BIT(0) #define OB_WIN_SIZE 8 /* 8MB */ +#define PCIE_LEGACY_IRQ_ENABLE_SET(n) (0x188 + (0x10 * ((n) - 1))) +#define PCIE_LEGACY_IRQ_ENABLE_CLR(n) (0x18c + (0x10 * ((n) - 1))) +#define PCIE_EP_IRQ_SET 0x64 +#define PCIE_EP_IRQ_CLR 0x68 +#define INT_ENABLE BIT(0) + /* IRQ register defines */ #define IRQ_EOI 0x050 @@ -95,11 +101,16 @@ #define KS_PCIE_SYSCLOCKOUTEN BIT(0) #define AM654_PCIE_DEV_TYPE_MASK 0x3 +#define AM654_WIN_SIZE SZ_64K + +#define APP_ADDR_SPACE_0 (16 * SZ_1K) #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) struct ks_pcie_of_data { + enum dw_pcie_device_mode mode; const struct dw_pcie_host_ops *host_ops; + const struct dw_pcie_ep_ops *ep_ops; unsigned int version; }; @@ -264,13 +275,11 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset); } +/* + * Dummy function so that DW core doesn't configure MSI + */ static int ks_pcie_am654_msi_host_init(struct pcie_port *pp) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct device *dev = pci->dev; - - dev_vdbg(dev, "dummy function so that DW core doesn't configure MSI\n"); - return 0; } @@ -877,12 +886,139 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, return 0; } +static u32 ks_pcie_am654_read_dbi2(struct dw_pcie *pci, void __iomem *base, + u32 reg, size_t size) +{ + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + u32 val; + + ks_pcie_set_dbi_mode(ks_pcie); + dw_pcie_read(base + reg, size, &val); + ks_pcie_clear_dbi_mode(ks_pcie); + return val; +} + +static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base, + u32 reg, size_t size, u32 val) +{ + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + + ks_pcie_set_dbi_mode(ks_pcie); + dw_pcie_write(base + reg, size, val); + ks_pcie_clear_dbi_mode(ks_pcie); +} + static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { .start_link = ks_pcie_start_link, .stop_link = ks_pcie_stop_link, .link_up = ks_pcie_link_up, + .read_dbi2 = ks_pcie_am654_read_dbi2, + .write_dbi2 = ks_pcie_am654_write_dbi2, +}; + +static void ks_pcie_am654_ep_init(struct dw_pcie_ep *ep) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + int flags; + + ep->page_size = AM654_WIN_SIZE; + flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32; + dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, APP_ADDR_SPACE_0 - 1); + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, flags); +} + +static void ks_pcie_am654_raise_legacy_irq(struct keystone_pcie *ks_pcie) +{ + struct dw_pcie *pci = ks_pcie->pci; + u8 int_pin; + + int_pin = dw_pcie_readb_dbi(pci, PCI_INTERRUPT_PIN); + if (int_pin == 0 || int_pin > 4) + return; + + ks_pcie_app_writel(ks_pcie, PCIE_LEGACY_IRQ_ENABLE_SET(int_pin), + INT_ENABLE); + ks_pcie_app_writel(ks_pcie, PCIE_EP_IRQ_SET, INT_ENABLE); + mdelay(1); + ks_pcie_app_writel(ks_pcie, PCIE_EP_IRQ_CLR, INT_ENABLE); + ks_pcie_app_writel(ks_pcie, PCIE_LEGACY_IRQ_ENABLE_CLR(int_pin), + INT_ENABLE); +} + +static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + enum pci_epc_irq_type type, + u16 interrupt_num) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + + switch (type) { + case PCI_EPC_IRQ_LEGACY: + ks_pcie_am654_raise_legacy_irq(ks_pcie); + break; + case PCI_EPC_IRQ_MSI: + dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); + break; + default: + dev_err(pci->dev, "UNKNOWN IRQ type\n"); + return -EINVAL; + } + + return 0; +} + +static const struct pci_epc_features ks_pcie_am654_epc_features = { + .linkup_notifier = false, + .msi_capable = true, + .msix_capable = false, + .reserved_bar = 1 << BAR_0 | 1 << BAR_1, + .bar_fixed_64bit = 1 << BAR_0, + .bar_fixed_size[2] = SZ_1M, + .bar_fixed_size[3] = SZ_64K, + .bar_fixed_size[4] = 256, + .bar_fixed_size[5] = SZ_1M, + .align = SZ_1M, }; +static const struct pci_epc_features* +ks_pcie_am654_get_features(struct dw_pcie_ep *ep) +{ + return &ks_pcie_am654_epc_features; +} + +static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = { + .ep_init = ks_pcie_am654_ep_init, + .raise_irq = ks_pcie_am654_raise_irq, + .get_features = &ks_pcie_am654_get_features, +}; + +static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie, + struct platform_device *pdev) +{ + int ret; + struct dw_pcie_ep *ep; + struct resource *res; + struct device *dev = &pdev->dev; + struct dw_pcie *pci = ks_pcie->pci; + + ep = &pci->ep; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); + if (!res) + return -EINVAL; + + ep->phys_base = res->start; + ep->addr_size = resource_size(res); + + ret = dw_pcie_ep_init(ep); + if (ret) { + dev_err(dev, "failed to initialize endpoint\n"); + return ret; + } + + return 0; +} + static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie) { int num_lanes = ks_pcie->num_lanes; @@ -950,7 +1086,8 @@ static int ks_pcie_set_mode(struct device *dev) return 0; } -static int ks_pcie_am654_set_mode(struct device *dev) +static int ks_pcie_am654_set_mode(struct device *dev, + enum dw_pcie_device_mode mode) { struct device_node *np = dev->of_node; struct regmap *syscon; @@ -963,7 +1100,18 @@ static int ks_pcie_am654_set_mode(struct device *dev) return 0; mask = AM654_PCIE_DEV_TYPE_MASK; - val = RC; + + switch (mode) { + case DW_PCIE_RC_TYPE: + val = RC; + break; + case DW_PCIE_EP_TYPE: + val = EP; + break; + default: + dev_err(dev, "INVALID device type %d\n", mode); + return -EINVAL; + } ret = regmap_update_bits(syscon, 0, mask, val); if (ret) { @@ -1006,6 +1154,13 @@ static const struct ks_pcie_of_data ks_pcie_rc_of_data = { static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = { .host_ops = &ks_pcie_am654_host_ops, + .mode = DW_PCIE_RC_TYPE, + .version = 0x490A, +}; + +static const struct ks_pcie_of_data ks_pcie_am654_ep_of_data = { + .ep_ops = &ks_pcie_am654_ep_ops, + .mode = DW_PCIE_EP_TYPE, .version = 0x490A, }; @@ -1019,16 +1174,22 @@ static const struct of_device_id ks_pcie_of_match[] = { .data = &ks_pcie_am654_rc_of_data, .compatible = "ti,am654-pcie-rc", }, + { + .data = &ks_pcie_am654_ep_of_data, + .compatible = "ti,am654-pcie-ep", + }, { }, }; static int __init ks_pcie_probe(struct platform_device *pdev) { const struct dw_pcie_host_ops *host_ops; + const struct dw_pcie_ep_ops *ep_ops; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; const struct ks_pcie_of_data *data; const struct of_device_id *match; + enum dw_pcie_device_mode mode; struct dw_pcie *pci; struct keystone_pcie *ks_pcie; struct device_link **link; @@ -1053,6 +1214,8 @@ static int __init ks_pcie_probe(struct platform_device *pdev) version = data->version; host_ops = data->host_ops; + ep_ops = data->ep_ops; + mode = data->mode; ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); if (!ks_pcie) @@ -1078,16 +1241,11 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ks_pcie->is_am6 = true; pci->dbi_base = base; + pci->dbi_base2 = base; pci->dev = dev; pci->ops = &ks_pcie_dw_pcie_ops; pci->version = version; - ret = of_property_read_u32(np, "num-viewport", &num_viewport); - if (ret < 0) { - dev_err(dev, "unable to read *num-viewport* property\n"); - return ret; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "missing IRQ resource: %d\n", irq); @@ -1136,7 +1294,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ks_pcie->pci = pci; ks_pcie->link = link; ks_pcie->num_lanes = num_lanes; - ks_pcie->num_viewport = num_viewport; ks_pcie->phy = phy; gpiod = devm_gpiod_get_optional(dev, "reset", @@ -1172,7 +1329,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) pci->atu_base = atu_base; - ret = ks_pcie_am654_set_mode(dev); + ret = ks_pcie_am654_set_mode(dev, mode); if (ret < 0) goto err_get_sync; } else { @@ -1181,29 +1338,58 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } - /* - * "Power Sequencing and Reset Signal Timings" table in - * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0 - * indicates PERST# should be deasserted after minimum of 100us - * once REFCLK is stable. The REFCLK to the connector in RC - * mode is selected while enabling the PHY. So deassert PERST# - * after 100 us. - */ - if (gpiod) { - usleep_range(100, 200); - gpiod_set_value_cansleep(gpiod, 1); - } - link_speed = of_pci_get_max_link_speed(np); if (link_speed < 0) link_speed = 2; ks_pcie_set_link_speed(pci, link_speed); - pci->pp.ops = host_ops; - ret = ks_pcie_add_pcie_port(ks_pcie, pdev); - if (ret < 0) - goto err_get_sync; + switch (mode) { + case DW_PCIE_RC_TYPE: + if (!IS_ENABLED(CONFIG_PCI_KEYSTONE_HOST)) { + ret = -ENODEV; + goto err_get_sync; + } + + ret = of_property_read_u32(np, "num-viewport", &num_viewport); + if (ret < 0) { + dev_err(dev, "unable to read *num-viewport* property\n"); + return ret; + } + + /* + * "Power Sequencing and Reset Signal Timings" table in + * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0 + * indicates PERST# should be deasserted after minimum of 100us + * once REFCLK is stable. The REFCLK to the connector in RC + * mode is selected while enabling the PHY. So deassert PERST# + * after 100 us. + */ + if (gpiod) { + usleep_range(100, 200); + gpiod_set_value_cansleep(gpiod, 1); + } + + ks_pcie->num_viewport = num_viewport; + pci->pp.ops = host_ops; + ret = ks_pcie_add_pcie_port(ks_pcie, pdev); + if (ret < 0) + goto err_get_sync; + break; + case DW_PCIE_EP_TYPE: + if (!IS_ENABLED(CONFIG_PCI_KEYSTONE_EP)) { + ret = -ENODEV; + goto err_get_sync; + } + + pci->ep.ops = ep_ops; + ret = ks_pcie_add_pcie_ep(ks_pcie, pdev); + if (ret < 0) + goto err_get_sync; + break; + default: + dev_err(dev, "INVALID device type %d\n", mode); + } ks_pcie_enable_error_irq(ks_pcie); -- cgit From fc9a77040b04c05f036515f40aa7cf4b9c91defd Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:44 +0530 Subject: PCI: designware-ep: Configure Resizable BAR cap to advertise the smallest size Configure the Resizable BAR capability to advertise the smallest size (1MB) for a couple of reasons: - Host side resource allocation of BAR fails for larger sizes - Endpoint function driver does not allocate memory for all supported sizes in the Resizable BAR capability. If and when there is a usecase required to add more flexibility using the Resizable BAR capability, this can be revisited. Signed-off-by: Kishon Vijay Abraham I [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-ep.c | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 74477ad7467f..0c208b9bda43 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -504,10 +504,32 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep) pci_epc_mem_exit(epc); } +static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap) +{ + u32 header; + int pos = PCI_CFG_SPACE_SIZE; + + while (pos) { + header = dw_pcie_readl_dbi(pci, pos); + if (PCI_EXT_CAP_ID(header) == cap) + return pos; + + pos = PCI_EXT_CAP_NEXT(header); + if (!pos) + break; + } + + return 0; +} + int dw_pcie_ep_init(struct dw_pcie_ep *ep) { + int i; int ret; + u32 reg; void *addr; + unsigned int nbars; + unsigned int offset; struct pci_epc *epc; struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct device *dev = pci->dev; @@ -591,6 +613,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX); + offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); + if (offset) { + reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); + nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> + PCI_REBAR_CTRL_NBAR_SHIFT; + + dw_pcie_dbi_ro_wr_en(pci); + for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) + dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0); + dw_pcie_dbi_ro_wr_dis(pci); + } + dw_pcie_setup(pci); return 0; -- cgit From 6b7330303a8186fb211357e6d379237fe9d2ece1 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:45 +0530 Subject: PCI: designware-ep: Use aligned ATU window for raising MSI interrupts Certain platforms like K2G reguires the outbound ATU window to be aligned. The alignment size is already present in mem->page_size. Use the alignment size present in mem->page_size to configure an aligned ATU window. In order to raise an interrupt, CPU has to write to address offset from the start of the window unlike before where writes were always to the beginning of the ATU window. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-ep.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 0c208b9bda43..2bf5a35c0570 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -397,6 +397,7 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct pci_epc *epc = ep->epc; + unsigned int aligned_offset; u16 msg_ctrl, msg_data; u32 msg_addr_lower, msg_addr_upper, reg; u64 msg_addr; @@ -422,13 +423,15 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, reg = ep->msi_cap + PCI_MSI_DATA_32; msg_data = dw_pcie_readw_dbi(pci, reg); } - msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; + aligned_offset = msg_addr_lower & (epc->mem->page_size - 1); + msg_addr = ((u64)msg_addr_upper) << 32 | + (msg_addr_lower & ~aligned_offset); ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, epc->mem->page_size); if (ret) return ret; - writel(msg_data | (interrupt_num - 1), ep->msi_mem); + writel(msg_data | (interrupt_num - 1), ep->msi_mem + aligned_offset); dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys); -- cgit From 5bb04b19230c02cc1b450b029856cbe093e09908 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:46 +0530 Subject: misc: pci_endpoint_test: Add support to test PCI EP in AM654x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TI's AM654x PCIe EP has a restriction that BAR_0 is mapped to application registers. "PCIe Inbound Address Translation" section in AM65x Sitara Processors TRM (SPRUID7 – April 2018) describes BAR0 as reserved. Configure pci_endpoint_test to use BAR_2 instead. Also set alignment to 64K since "PCIe Subsystem Address Translation" section in TRM indicates minimum ATU window size is 64K. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/misc/pci_endpoint_test.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 29582fe57151..e015e8fa9bd3 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -75,6 +75,11 @@ #define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24 #define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28 +#define PCI_DEVICE_ID_TI_AM654 0xb00c + +#define is_am654_pci_dev(pdev) \ + ((pdev)->device == PCI_DEVICE_ID_TI_AM654) + static DEFINE_IDA(pci_endpoint_test_ida); #define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \ @@ -588,6 +593,7 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, int ret = -EINVAL; enum pci_barno bar; struct pci_endpoint_test *test = to_endpoint_test(file->private_data); + struct pci_dev *pdev = test->pdev; mutex_lock(&test->mutex); switch (cmd) { @@ -595,6 +601,8 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd, bar = arg; if (bar < 0 || bar > 5) goto ret; + if (is_am654_pci_dev(pdev) && bar == BAR_0) + goto ret; ret = pci_endpoint_test_bar(test, bar); break; case PCITEST_LEGACY_IRQ: @@ -785,11 +793,20 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev) pci_disable_device(pdev); } +static const struct pci_endpoint_test_data am654_data = { + .test_reg_bar = BAR_2, + .alignment = SZ_64K, + .irq_type = IRQ_TYPE_MSI, +}; + static const struct pci_device_id pci_endpoint_test_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) }, { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) }, { PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 0xedda) }, + { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654), + .driver_data = (kernel_ulong_t)&am654_data + }, { } }; MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl); -- cgit From 8f220664570e755946db1282f48e07f26e1f2cb4 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:47 +0530 Subject: misc: pci_endpoint_test: Fix test_reg_bar to be updated in pci_endpoint_test commit 834b90519925 ("misc: pci_endpoint_test: Add support for PCI_ENDPOINT_TEST regs to be mapped to any BAR") while adding test_reg_bar in order to map PCI_ENDPOINT_TEST regs to be mapped to any BAR failed to update test_reg_bar in pci_endpoint_test, resulting in test_reg_bar having invalid value when used outside probe. Fix it. Fixes: 834b90519925 ("misc: pci_endpoint_test: Add support for PCI_ENDPOINT_TEST regs to be mapped to any BAR") Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/misc/pci_endpoint_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index e015e8fa9bd3..7b015f2a1c6f 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -670,6 +670,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, data = (struct pci_endpoint_test_data *)ent->driver_data; if (data) { test_reg_bar = data->test_reg_bar; + test->test_reg_bar = test_reg_bar; test->alignment = data->alignment; irq_type = data->irq_type; } -- cgit From 0f97da83102610db886e8b688b9029e080e6d511 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 18 Apr 2019 13:58:59 +0200 Subject: PCI/P2PDMA: Allow P2P DMA between any devices under AMD ZEN Root Complex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI specs say that peer-to-peer DMA should be supported between any two devices that have a common upstream PCI-to-PCI bridge. But devices under different Root Ports don't share a common upstream bridge, and PCIe r4.0, sec 1.3.1, says routing peer-to-peer transactions between Root Ports in the same Root Complex is optional. Many Root Complexes, including AMD ZEN, *do* support peer-to-peer DMA even between Root Ports. Add a whitelist and allow peer-to-peer DMA if both participants are attached to a Root Complex known to support it. Link: https://lore.kernel.org/linux-pci/20190418115859.2394-1-christian.koenig@amd.com Signed-off-by: Christian König [bhelgaas: changelog] Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe --- drivers/pci/p2pdma.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index c52298d76e64..742928d0053e 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -274,6 +274,30 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev) seq_buf_printf(buf, "%s;", pci_name(pdev)); } +/* + * If we can't find a common upstream bridge take a look at the root + * complex and compare it to a whitelist of known good hardware. + */ +static bool root_complex_whitelist(struct pci_dev *dev) +{ + struct pci_host_bridge *host = pci_find_host_bridge(dev->bus); + struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0)); + unsigned short vendor, device; + + if (!root) + return false; + + vendor = root->vendor; + device = root->device; + pci_dev_put(root); + + /* AMD ZEN host bridges can do peer to peer */ + if (vendor == PCI_VENDOR_ID_AMD && device == 0x1450) + return true; + + return false; +} + /* * Find the distance through the nearest common upstream bridge between * two PCI devices. @@ -317,13 +341,13 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev) * In this case, a list of all infringing bridge addresses will be * populated in acs_list (assuming it's non-null) for printk purposes. */ -static int upstream_bridge_distance(struct pci_dev *a, - struct pci_dev *b, +static int upstream_bridge_distance(struct pci_dev *provider, + struct pci_dev *client, struct seq_buf *acs_list) { + struct pci_dev *a = provider, *b = client, *bb; int dist_a = 0; int dist_b = 0; - struct pci_dev *bb = NULL; int acs_cnt = 0; /* @@ -354,6 +378,14 @@ static int upstream_bridge_distance(struct pci_dev *a, dist_a++; } + /* + * Allow the connection if both devices are on a whitelisted root + * complex, but add an arbitary large value to the distance. + */ + if (root_complex_whitelist(provider) && + root_complex_whitelist(client)) + return 0x1000 + dist_a + dist_b; + return -1; check_b_path_acs: -- cgit From e80a91ad302b3b66822756afc61f9f9c1658b9c9 Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 3 May 2019 19:35:32 +0530 Subject: PCI: Add dma_ranges window list Add a dma_ranges field in PCI host bridge structure to hold resource entries list of memory regions in sorted order representing memory ranges that can be accessed through DMA transactions. Based-on-a-patch-by: Oza Pawandeep Signed-off-by: Srinath Mannam [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Oza Pawandeep Acked-by: Bjorn Helgaas --- drivers/pci/probe.c | 3 +++ include/linux/pci.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2ec0df04e0dc..2a651089a606 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -595,6 +595,7 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) return NULL; INIT_LIST_HEAD(&bridge->windows); + INIT_LIST_HEAD(&bridge->dma_ranges); bridge->dev.release = pci_release_host_bridge_dev; /* @@ -623,6 +624,7 @@ struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev, return NULL; INIT_LIST_HEAD(&bridge->windows); + INIT_LIST_HEAD(&bridge->dma_ranges); bridge->dev.release = devm_pci_release_host_bridge_dev; return bridge; @@ -632,6 +634,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge); void pci_free_host_bridge(struct pci_host_bridge *bridge) { pci_free_resource_list(&bridge->windows); + pci_free_resource_list(&bridge->dma_ranges); kfree(bridge); } diff --git a/include/linux/pci.h b/include/linux/pci.h index 77448215ef5b..bba0a29a5066 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -490,6 +490,7 @@ struct pci_host_bridge { void *sysdata; int busnr; struct list_head windows; /* resource_entry */ + struct list_head dma_ranges; /* dma ranges resource list */ u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* Platform IRQ swizzler */ int (*map_irq)(const struct pci_dev *, u8, u8); void (*release_fn)(struct pci_host_bridge *); -- cgit From aadad097cd46f783b75c235cffa5c21fcffbf189 Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 3 May 2019 19:35:33 +0530 Subject: iommu/dma: Reserve IOVA for PCIe inaccessible DMA address The dma_ranges list field of PCI host bridge structure has resource entries in sorted order representing address ranges allowed for DMA transfers. Process the list and reserve IOVA addresses that are not present in its resource entries (ie DMA memory holes) to prevent allocating IOVA addresses that cannot be accessed by PCI devices. Based-on-a-patch-by: Oza Pawandeep Signed-off-by: Srinath Mannam Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Oza Pawandeep Acked-by: Robin Murphy --- drivers/iommu/dma-iommu.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 77aabe637a60..954ae11461a3 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -206,12 +206,13 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie, return 0; } -static void iova_reserve_pci_windows(struct pci_dev *dev, +static int iova_reserve_pci_windows(struct pci_dev *dev, struct iova_domain *iovad) { struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus); struct resource_entry *window; unsigned long lo, hi; + phys_addr_t start = 0, end; resource_list_for_each_entry(window, &bridge->windows) { if (resource_type(window->res) != IORESOURCE_MEM) @@ -221,6 +222,31 @@ static void iova_reserve_pci_windows(struct pci_dev *dev, hi = iova_pfn(iovad, window->res->end - window->offset); reserve_iova(iovad, lo, hi); } + + /* Get reserved DMA windows from host bridge */ + resource_list_for_each_entry(window, &bridge->dma_ranges) { + end = window->res->start - window->offset; +resv_iova: + if (end > start) { + lo = iova_pfn(iovad, start); + hi = iova_pfn(iovad, end); + reserve_iova(iovad, lo, hi); + } else { + /* dma_ranges list should be sorted */ + dev_err(&dev->dev, "Failed to reserve IOVA\n"); + return -EINVAL; + } + + start = window->res->end - window->offset + 1; + /* If window is last entry */ + if (window->node.next == &bridge->dma_ranges && + end != ~(dma_addr_t)0) { + end = ~(dma_addr_t)0; + goto resv_iova; + } + } + + return 0; } static int iova_reserve_iommu_regions(struct device *dev, @@ -232,8 +258,11 @@ static int iova_reserve_iommu_regions(struct device *dev, LIST_HEAD(resv_regions); int ret = 0; - if (dev_is_pci(dev)) - iova_reserve_pci_windows(to_pci_dev(dev), iovad); + if (dev_is_pci(dev)) { + ret = iova_reserve_pci_windows(to_pci_dev(dev), iovad); + if (ret) + return ret; + } iommu_get_resv_regions(dev, &resv_regions); list_for_each_entry(region, &resv_regions, list) { -- cgit From 90199c951bd2a6248e55a8db3368a2568e3b3edc Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 3 May 2019 19:35:34 +0530 Subject: PCI: iproc: Add sorted dma ranges resource entries to host bridge The iProc host controller allows only a subset of physical address space as target of inbound PCI memory transaction addresses. PCI device memory transactions targeting memory regions that are not allowed for inbound transactions in the host controller are rejected by the host controller and cannot reach the upstream buses. The firmware device tree description defines the DMA ranges that are addressable by devices DMA transactions; parse the device tree dma-ranges property and add its ranges to the PCI host bridge dma_ranges list; the iova_reserve_pci_windows() call executed at iommu_dma_init_domain() will reserve the IOVA address ranges that are not addressable (ie memory holes in the dma-ranges set) so that they are not allocated to PCI devices for DMA transfers. All allowed address ranges are listed in the dma-ranges DT parameter. For example: dma-ranges = < \ 0x43000000 0x00 0x80000000 0x00 0x80000000 0x00 0x80000000 \ 0x43000000 0x08 0x00000000 0x08 0x00000000 0x08 0x00000000 \ 0x43000000 0x80 0x00000000 0x80 0x00000000 0x40 0x00000000> In the above example of dma-ranges, memory address from 0x0 - 0x80000000, 0x100000000 - 0x800000000, 0x1000000000 - 0x8000000000 and 0x10000000000 - 0xffffffffffffffff. are not allowed to be used as inbound addresses. Based-on-a-patch-by: Oza Pawandeep Signed-off-by: Srinath Mannam [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi [bhelgaas: fix function prototype style] Signed-off-by: Bjorn Helgaas Reviewed-by: Oza Pawandeep Reviewed-by: Eric Auger --- drivers/pci/controller/pcie-iproc.c | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index c20fd6bd68fd..f76a75bb7ae4 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -1146,11 +1146,43 @@ err_ib: return ret; } +static int iproc_pcie_add_dma_range(struct device *dev, + struct list_head *resources, + struct of_pci_range *range) +{ + struct resource *res; + struct resource_entry *entry, *tmp; + struct list_head *head = resources; + + res = devm_kzalloc(dev, sizeof(struct resource), GFP_KERNEL); + if (!res) + return -ENOMEM; + + resource_list_for_each_entry(tmp, resources) { + if (tmp->res->start < range->cpu_addr) + head = &tmp->node; + } + + res->start = range->cpu_addr; + res->end = res->start + range->size - 1; + + entry = resource_list_create_entry(res, 0); + if (!entry) + return -ENOMEM; + + entry->offset = res->start - range->cpu_addr; + resource_list_add(entry, head); + + return 0; +} + static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) { + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); struct of_pci_range range; struct of_pci_range_parser parser; int ret; + LIST_HEAD(resources); /* Get the dma-ranges from DT */ ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node); @@ -1158,13 +1190,23 @@ static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) return ret; for_each_of_pci_range(&parser, &range) { + ret = iproc_pcie_add_dma_range(pcie->dev, + &resources, + &range); + if (ret) + goto out; /* Each range entry corresponds to an inbound mapping region */ ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_MEM); if (ret) - return ret; + goto out; } + list_splice_init(&resources, &host->dma_ranges); + return 0; +out: + pci_free_resource_list(&resources); + return ret; } static int iproce_pcie_get_msi(struct iproc_pcie *pcie, -- cgit From 322f03436692481993d389f539c016d20bb0fa1d Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Mon, 25 Mar 2019 16:42:55 +0100 Subject: PCI: qcom: Use default config space read function Move the device class fudge to a proper fixup function, and remove qcom_pcie_rd_own_conf() which has become useless. dw_pcie_setup_rc() already did the right thing, but it's broken on older qcom chips, such as 8064. Signed-off-by: Marc Gonzalez Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Stanimir Varbanov --- drivers/pci/controller/dwc/pcie-qcom.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index a7f703556790..0ed235d560e3 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1129,25 +1129,8 @@ err_deinit: return ret; } -static int qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, - u32 *val) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - - /* the device class is not reported correctly from the register */ - if (where == PCI_CLASS_REVISION && size == 4) { - *val = readl(pci->dbi_base + PCI_CLASS_REVISION); - *val &= 0xff; /* keep revision id */ - *val |= PCI_CLASS_BRIDGE_PCI << 16; - return PCIBIOS_SUCCESSFUL; - } - - return dw_pcie_read(pci->dbi_base + where, size, val); -} - static const struct dw_pcie_host_ops qcom_pcie_dw_ops = { .host_init = qcom_pcie_host_init, - .rd_own_conf = qcom_pcie_rd_own_conf, }; /* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */ @@ -1309,6 +1292,12 @@ static const struct of_device_id qcom_pcie_match[] = { { } }; +static void qcom_fixup_class(struct pci_dev *dev) +{ + dev->class = PCI_CLASS_BRIDGE_PCI << 8; +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, PCI_ANY_ID, qcom_fixup_class); + static struct platform_driver qcom_pcie_driver = { .probe = qcom_pcie_probe, .driver = { -- cgit From 3ebc269c197ee6a9788aeb76ebcc9132814a75e5 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:56:25 +0000 Subject: PCI: dwc: Fix dw_pcie_free_msi() if msi_irq is invalid Check msi_irq variable before calling irq_set_chained_handler() and irq_set_handler_data(), lest we call those functions for an invalid MSI IRQ. Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-host.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 25087d3c9a82..1040939f45b4 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -298,8 +298,10 @@ int dw_pcie_allocate_domains(struct pcie_port *pp) void dw_pcie_free_msi(struct pcie_port *pp) { - irq_set_chained_handler(pp->msi_irq, NULL); - irq_set_handler_data(pp->msi_irq, NULL); + if (pp->msi_irq) { + irq_set_chained_handler(pp->msi_irq, NULL); + irq_set_handler_data(pp->msi_irq, NULL); + } irq_domain_remove(pp->msi_domain); irq_domain_remove(pp->irq_domain); -- cgit From dc69a3d567941784c3d00e1d0834582b42b0b3e7 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:57:17 +0000 Subject: PCI: dwc: Free MSI IRQ page in dw_pcie_free_msi() To avoid a memory leak, free the page allocated for MSI IRQ in dw_pcie_free_msi(). Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-host.c | 12 ++++++++---- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 1040939f45b4..a71b874ae3c0 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -305,20 +305,24 @@ void dw_pcie_free_msi(struct pcie_port *pp) irq_domain_remove(pp->msi_domain); irq_domain_remove(pp->irq_domain); + + if (pp->msi_page) + __free_page(pp->msi_page); } void dw_pcie_msi_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct device *dev = pci->dev; - struct page *page; u64 msi_target; - page = alloc_page(GFP_KERNEL); - pp->msi_data = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); + pp->msi_page = alloc_page(GFP_KERNEL); + pp->msi_data = dma_map_page(dev, pp->msi_page, 0, PAGE_SIZE, + DMA_FROM_DEVICE); if (dma_mapping_error(dev, pp->msi_data)) { dev_err(dev, "Failed to map MSI data\n"); - __free_page(page); + __free_page(pp->msi_page); + pp->msi_page = NULL; return; } msi_target = (u64)pp->msi_data; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 377f4c0b52da..6fb0a1879932 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -179,6 +179,7 @@ struct pcie_port { struct irq_domain *irq_domain; struct irq_domain *msi_domain; dma_addr_t msi_data; + struct page *msi_page; u32 num_vectors; u32 irq_mask[MAX_MSI_CTRLS]; raw_spinlock_t lock; -- cgit From 9e2b5de5604a6ff2626c51e77014d92c9299722c Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:57:54 +0000 Subject: PCI: dwc: Free MSI in dw_pcie_host_init() error path If we ever did MSI-related initializations, we need to call dw_pcie_free_msi() in the error code path. Remove the IS_ENABLED(CONFIG_PCI_MSI) check for MSI init because pci_msi_enabled() already has a stub for !CONFIG_PCI_MSI. Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-host.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index a71b874ae3c0..acc9be5cf34a 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -445,7 +445,7 @@ int dw_pcie_host_init(struct pcie_port *pp) if (ret) pci->num_viewport = 2; - if (IS_ENABLED(CONFIG_PCI_MSI) && pci_msi_enabled()) { + if (pci_msi_enabled()) { /* * If a specific SoC driver needs to change the * default number of vectors, it needs to implement @@ -483,7 +483,7 @@ int dw_pcie_host_init(struct pcie_port *pp) if (pp->ops->host_init) { ret = pp->ops->host_init(pp); if (ret) - goto error; + goto err_free_msi; } pp->root_bus_nr = pp->busn->start; @@ -497,7 +497,7 @@ int dw_pcie_host_init(struct pcie_port *pp) ret = pci_scan_root_bus_bridge(bridge); if (ret) - goto error; + goto err_free_msi; bus = bridge->bus; @@ -513,6 +513,9 @@ int dw_pcie_host_init(struct pcie_port *pp) pci_bus_add_devices(bus); return 0; +err_free_msi: + if (pci_msi_enabled() && !pp->ops->msi_host_init) + dw_pcie_free_msi(pp); error: pci_free_host_bridge(bridge); return ret; -- cgit From e6fdd3bf5aecd8615f31a5128775b9abcf3e0d86 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:58:53 +0000 Subject: PCI: dwc: Use devm_pci_alloc_host_bridge() to simplify code Use devm_pci_alloc_host_bridge() to simplify the error code path. This also fixes a leak in the dw_pcie_host_init() error path. Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel CC: stable@vger.kernel.org # v4.13+ --- drivers/pci/controller/dwc/pcie-designware-host.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index acc9be5cf34a..dcc7405aff9a 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -358,7 +358,7 @@ int dw_pcie_host_init(struct pcie_port *pp) dev_err(dev, "Missing *config* reg space\n"); } - bridge = pci_alloc_host_bridge(0); + bridge = devm_pci_alloc_host_bridge(dev, 0); if (!bridge) return -ENOMEM; @@ -369,7 +369,7 @@ int dw_pcie_host_init(struct pcie_port *pp) ret = devm_request_pci_bus_resources(dev, &bridge->windows); if (ret) - goto error; + return ret; /* Get the I/O and memory ranges from DT */ resource_list_for_each_entry_safe(win, tmp, &bridge->windows) { @@ -413,8 +413,7 @@ int dw_pcie_host_init(struct pcie_port *pp) resource_size(pp->cfg)); if (!pci->dbi_base) { dev_err(dev, "Error with ioremap\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } } @@ -425,8 +424,7 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->cfg0_base, pp->cfg0_size); if (!pp->va_cfg0_base) { dev_err(dev, "Error with ioremap in function\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } } @@ -436,8 +434,7 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->cfg1_size); if (!pp->va_cfg1_base) { dev_err(dev, "Error with ioremap\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } } @@ -460,14 +457,14 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->num_vectors == 0) { dev_err(dev, "Invalid number of vectors\n"); - goto error; + return -EINVAL; } } if (!pp->ops->msi_host_init) { ret = dw_pcie_allocate_domains(pp); if (ret) - goto error; + return ret; if (pp->msi_irq) irq_set_chained_handler_and_data(pp->msi_irq, @@ -476,7 +473,7 @@ int dw_pcie_host_init(struct pcie_port *pp) } else { ret = pp->ops->msi_host_init(pp); if (ret < 0) - goto error; + return ret; } } @@ -516,8 +513,6 @@ int dw_pcie_host_init(struct pcie_port *pp) err_free_msi: if (pci_msi_enabled() && !pp->ops->msi_host_init) dw_pcie_free_msi(pp); -error: - pci_free_host_bridge(bridge); return ret; } -- cgit From fe23274f72f4e3be93134aac0ae1e1fd522f438a Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:59:26 +0000 Subject: PCI: dwc: Save root bus for driver remove hooks Currently DWC host does not support the remove callback, but nothing prevents us from supporting it. Save the root bus for clean up work in driver remove code paths to allow DWC host drivers to implement their remove hook as, eg: static int foo_pcie_remove(struct platform_device *pdev) { ... pci_stop_root_bus(pp->root_bus); pci_remove_root_bus(pp->root_bus); dw_pcie_free_msi(pp); ... } Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-host.c | 12 ++++++------ drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index dcc7405aff9a..3e4169e738a5 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -341,7 +341,7 @@ int dw_pcie_host_init(struct pcie_port *pp) struct device_node *np = dev->of_node; struct platform_device *pdev = to_platform_device(dev); struct resource_entry *win, *tmp; - struct pci_bus *bus, *child; + struct pci_bus *child; struct pci_host_bridge *bridge; struct resource *cfg_res; int ret; @@ -496,18 +496,18 @@ int dw_pcie_host_init(struct pcie_port *pp) if (ret) goto err_free_msi; - bus = bridge->bus; + pp->root_bus = bridge->bus; if (pp->ops->scan_bus) pp->ops->scan_bus(pp); - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); + pci_bus_size_bridges(pp->root_bus); + pci_bus_assign_resources(pp->root_bus); - list_for_each_entry(child, &bus->children, node) + list_for_each_entry(child, &pp->root_bus->children, node) pcie_bus_configure_settings(child); - pci_bus_add_devices(bus); + pci_bus_add_devices(pp->root_bus); return 0; err_free_msi: diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 6fb0a1879932..adff0c713665 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -182,6 +182,7 @@ struct pcie_port { struct page *msi_page; u32 num_vectors; u32 irq_mask[MAX_MSI_CTRLS]; + struct pci_bus *root_bus; raw_spinlock_t lock; DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); }; -- cgit From 1b8df7aa78748ddafc6f3b16a6328a3c500087b3 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 4 Apr 2019 18:45:17 +0200 Subject: PCI: imx6: Allow asynchronous probing Establishing a PCIe link can take a while; allow asynchronous probing so that link establishment can happen in the background while other devices are being probed. Signed-off-by: Lucas Stach Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Fabio Estevam --- drivers/pci/controller/dwc/pci-imx6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 3d627f94a166..2eb39d5de4f6 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1279,6 +1279,7 @@ static struct platform_driver imx6_pcie_driver = { .of_match_table = imx6_pcie_of_match, .suppress_bind_attrs = true, .pm = &imx6_pcie_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = imx6_pcie_probe, .shutdown = imx6_pcie_shutdown, -- cgit From 0d6076184aecb97cc583bc7f9e125518d6c24404 Mon Sep 17 00:00:00 2001 From: Nicholas Johnson Date: Tue, 7 May 2019 14:51:24 -0500 Subject: PCI: Cleanup setup-bus.c comments and whitespace Cleanup comments, kernel-doc, coding style. No functional changes intended; comment and whitespace changes only. Link: https://lore.kernel.org/lkml/PS2P216MB06427E290A68CDB921FB4B2980250@PS2P216MB0642.KORP216.PROD.OUTLOOK.COM Signed-off-by: Nicholas Johnson [bhelgaas: tidy related things throughout the file] Signed-off-by: Bjorn Helgaas --- drivers/pci/setup-bus.c | 496 ++++++++++++++++++++++++------------------------ 1 file changed, 249 insertions(+), 247 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index ec44a0f3a7ac..6728144308c0 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -49,17 +49,15 @@ static void free_list(struct list_head *head) } /** - * add_to_list() - add a new resource tracker to the list + * add_to_list() - Add a new resource tracker to the list * @head: Head of the list - * @dev: device corresponding to which the resource - * belongs - * @res: The resource to be tracked - * @add_size: additional size to be optionally added - * to the resource + * @dev: Device to which the resource belongs + * @res: Resource to be tracked + * @add_size: Additional size to be optionally added to the resource */ -static int add_to_list(struct list_head *head, - struct pci_dev *dev, struct resource *res, - resource_size_t add_size, resource_size_t min_align) +static int add_to_list(struct list_head *head, struct pci_dev *dev, + struct resource *res, resource_size_t add_size, + resource_size_t min_align) { struct pci_dev_resource *tmp; @@ -80,8 +78,7 @@ static int add_to_list(struct list_head *head, return 0; } -static void remove_from_list(struct list_head *head, - struct resource *res) +static void remove_from_list(struct list_head *head, struct resource *res) { struct pci_dev_resource *dev_res, *tmp; @@ -158,7 +155,7 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) tmp->res = r; tmp->dev = dev; - /* fallback is smallest one or list is empty*/ + /* Fallback is smallest one or list is empty */ n = head; list_for_each_entry(dev_res, head, list) { resource_size_t align; @@ -171,21 +168,20 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) break; } } - /* Insert it just before n*/ + /* Insert it just before n */ list_add_tail(&tmp->list, n); } } -static void __dev_sort_resources(struct pci_dev *dev, - struct list_head *head) +static void __dev_sort_resources(struct pci_dev *dev, struct list_head *head) { u16 class = dev->class >> 8; - /* Don't touch classless devices or host bridges or ioapics. */ + /* Don't touch classless devices or host bridges or IOAPICs */ if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST) return; - /* Don't touch ioapic devices already enabled by firmware */ + /* Don't touch IOAPIC devices already enabled by firmware */ if (class == PCI_CLASS_SYSTEM_PIC) { u16 command; pci_read_config_word(dev, PCI_COMMAND, &command); @@ -204,19 +200,18 @@ static inline void reset_resource(struct resource *res) } /** - * reassign_resources_sorted() - satisfy any additional resource requests + * reassign_resources_sorted() - Satisfy any additional resource requests * - * @realloc_head : head of the list tracking requests requiring additional - * resources - * @head : head of the list tracking requests with allocated - * resources + * @realloc_head: Head of the list tracking requests requiring + * additional resources + * @head: Head of the list tracking requests with allocated + * resources * - * Walk through each element of the realloc_head and try to procure - * additional resources for the element, provided the element - * is in the head list. + * Walk through each element of the realloc_head and try to procure additional + * resources for the element, provided the element is in the head list. */ static void reassign_resources_sorted(struct list_head *realloc_head, - struct list_head *head) + struct list_head *head) { struct resource *res; struct pci_dev_resource *add_res, *tmp; @@ -228,18 +223,18 @@ static void reassign_resources_sorted(struct list_head *realloc_head, bool found_match = false; res = add_res->res; - /* skip resource that has been reset */ + /* Skip resource that has been reset */ if (!res->flags) goto out; - /* skip this resource if not found in head list */ + /* Skip this resource if not found in head list */ list_for_each_entry(dev_res, head, list) { if (dev_res->res == res) { found_match = true; break; } } - if (!found_match)/* just skip */ + if (!found_match) /* Just skip */ continue; idx = res - &add_res->dev->resource[0]; @@ -267,14 +262,14 @@ out: } /** - * assign_requested_resources_sorted() - satisfy resource requests + * assign_requested_resources_sorted() - Satisfy resource requests * - * @head : head of the list tracking requests for resources - * @fail_head : head of the list tracking requests that could - * not be allocated + * @head: Head of the list tracking requests for resources + * @fail_head: Head of the list tracking requests that could not be + * allocated * - * Satisfy resource requests of each element in the list. Add - * requests that could not satisfied to the failed_list. + * Satisfy resource requests of each element in the list. Add requests that + * could not be satisfied to the failed_list. */ static void assign_requested_resources_sorted(struct list_head *head, struct list_head *fail_head) @@ -290,8 +285,9 @@ static void assign_requested_resources_sorted(struct list_head *head, pci_assign_resource(dev_res->dev, idx)) { if (fail_head) { /* - * if the failed res is for ROM BAR, and it will - * be enabled later, don't add it to the list + * If the failed resource is a ROM BAR and + * it will be enabled later, don't add it + * to the list. */ if (!((idx == PCI_ROM_RESOURCE) && (!(res->flags & IORESOURCE_ROM_ENABLE)))) @@ -310,15 +306,14 @@ static unsigned long pci_fail_res_type_mask(struct list_head *fail_head) struct pci_dev_resource *fail_res; unsigned long mask = 0; - /* check failed type */ + /* Check failed type */ list_for_each_entry(fail_res, fail_head, list) mask |= fail_res->flags; /* - * one pref failed resource will set IORESOURCE_MEM, - * as we can allocate pref in non-pref range. - * Will release all assigned non-pref sibling resources - * according to that bit. + * One pref failed resource will set IORESOURCE_MEM, as we can + * allocate pref in non-pref range. Will release all assigned + * non-pref sibling resources according to that bit. */ return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH); } @@ -328,11 +323,11 @@ static bool pci_need_to_release(unsigned long mask, struct resource *res) if (res->flags & IORESOURCE_IO) return !!(mask & IORESOURCE_IO); - /* check pref at first */ + /* Check pref at first */ if (res->flags & IORESOURCE_PREFETCH) { if (mask & IORESOURCE_PREFETCH) return true; - /* count pref if its parent is non-pref */ + /* Count pref if its parent is non-pref */ else if ((mask & IORESOURCE_MEM) && !(res->parent->flags & IORESOURCE_PREFETCH)) return true; @@ -343,33 +338,33 @@ static bool pci_need_to_release(unsigned long mask, struct resource *res) if (res->flags & IORESOURCE_MEM) return !!(mask & IORESOURCE_MEM); - return false; /* should not get here */ + return false; /* Should not get here */ } static void __assign_resources_sorted(struct list_head *head, - struct list_head *realloc_head, - struct list_head *fail_head) + struct list_head *realloc_head, + struct list_head *fail_head) { /* - * Should not assign requested resources at first. - * they could be adjacent, so later reassign can not reallocate - * them one by one in parent resource window. - * Try to assign requested + add_size at beginning - * if could do that, could get out early. - * if could not do that, we still try to assign requested at first, - * then try to reassign add_size for some resources. + * Should not assign requested resources at first. They could be + * adjacent, so later reassign can not reallocate them one by one in + * parent resource window. + * + * Try to assign requested + add_size at beginning. If could do that, + * could get out early. If could not do that, we still try to assign + * requested at first, then try to reassign add_size for some resources. * * Separate three resource type checking if we need to release * assigned resource after requested + add_size try. - * 1. if there is io port assign fail, will release assigned - * io port. - * 2. if there is pref mmio assign fail, release assigned - * pref mmio. - * if assigned pref mmio's parent is non-pref mmio and there - * is non-pref mmio assign fail, will release that assigned - * pref mmio. - * 3. if there is non-pref mmio assign fail or pref mmio - * assigned fail, will release assigned non-pref mmio. + * + * 1. If IO port assignment fails, will release assigned IO + * port. + * 2. If pref MMIO assignment fails, release assigned pref + * MMIO. If assigned pref MMIO's parent is non-pref MMIO + * and non-pref MMIO assignment fails, will release that + * assigned pref MMIO. + * 3. If non-pref MMIO assignment fails or pref MMIO + * assignment fails, will release assigned non-pref MMIO. */ LIST_HEAD(save_head); LIST_HEAD(local_fail_head); @@ -398,7 +393,7 @@ static void __assign_resources_sorted(struct list_head *head, /* * There are two kinds of additional resources in the list: * 1. bridge resource -- IORESOURCE_STARTALIGN - * 2. SR-IOV resource -- IORESOURCE_SIZEALIGN + * 2. SR-IOV resource -- IORESOURCE_SIZEALIGN * Here just fix the additional alignment for bridge */ if (!(dev_res->res->flags & IORESOURCE_STARTALIGN)) @@ -407,10 +402,10 @@ static void __assign_resources_sorted(struct list_head *head, add_align = get_res_add_align(realloc_head, dev_res->res); /* - * The "head" list is sorted by the alignment to make sure - * resources with bigger alignment will be assigned first. - * After we change the alignment of a dev_res in "head" list, - * we need to reorder the list by alignment to make it + * The "head" list is sorted by alignment so resources with + * bigger alignment will be assigned first. After we + * change the alignment of a dev_res in "head" list, we + * need to reorder the list by alignment to make it * consistent. */ if (add_align > dev_res->res->start) { @@ -435,7 +430,7 @@ static void __assign_resources_sorted(struct list_head *head, /* Try updated head list with add_size added */ assign_requested_resources_sorted(head, &local_fail_head); - /* all assigned with add_size ? */ + /* All assigned with add_size? */ if (list_empty(&local_fail_head)) { /* Remove head list from realloc_head list */ list_for_each_entry(dev_res, head, list) @@ -445,13 +440,13 @@ static void __assign_resources_sorted(struct list_head *head, return; } - /* check failed type */ + /* Check failed type */ fail_type = pci_fail_res_type_mask(&local_fail_head); - /* remove not need to be released assigned res from head list etc */ + /* Remove not need to be released assigned res from head list etc */ list_for_each_entry_safe(dev_res, tmp_res, head, list) if (dev_res->res->parent && !pci_need_to_release(fail_type, dev_res->res)) { - /* remove it from realloc_head list */ + /* Remove it from realloc_head list */ remove_from_list(realloc_head, dev_res->res); remove_from_list(&save_head, dev_res->res); list_del(&dev_res->list); @@ -477,16 +472,15 @@ requested_and_reassign: /* Satisfy the must-have resource requests */ assign_requested_resources_sorted(head, fail_head); - /* Try to satisfy any additional optional resource - requests */ + /* Try to satisfy any additional optional resource requests */ if (realloc_head) reassign_resources_sorted(realloc_head, head); free_list(head); } static void pdev_assign_resources_sorted(struct pci_dev *dev, - struct list_head *add_head, - struct list_head *fail_head) + struct list_head *add_head, + struct list_head *fail_head) { LIST_HEAD(head); @@ -563,17 +557,19 @@ void pci_setup_cardbus(struct pci_bus *bus) } EXPORT_SYMBOL(pci_setup_cardbus); -/* Initialize bridges with base/limit values we have collected. - PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998) - requires that if there is no I/O ports or memory behind the - bridge, corresponding range must be turned off by writing base - value greater than limit to the bridge's base/limit registers. - - Note: care must be taken when updating I/O base/limit registers - of bridges which support 32-bit I/O. This update requires two - config space writes, so it's quite possible that an I/O window of - the bridge will have some undesirable address (e.g. 0) after the - first write. Ditto 64-bit prefetchable MMIO. */ +/* + * Initialize bridges with base/limit values we have collected. PCI-to-PCI + * Bridge Architecture Specification rev. 1.1 (1998) requires that if there + * are no I/O ports or memory behind the bridge, the corresponding range + * must be turned off by writing base value greater than limit to the + * bridge's base/limit registers. + * + * Note: care must be taken when updating I/O base/limit registers of + * bridges which support 32-bit I/O. This update requires two config space + * writes, so it's quite possible that an I/O window of the bridge will + * have some undesirable address (e.g. 0) after the first write. Ditto + * 64-bit prefetchable MMIO. + */ static void pci_setup_bridge_io(struct pci_dev *bridge) { struct resource *res; @@ -587,7 +583,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge) if (bridge->io_window_1k) io_mask = PCI_IO_1K_RANGE_MASK; - /* Set up the top and bottom of the PCI I/O segment for this bus. */ + /* Set up the top and bottom of the PCI I/O segment for this bus */ res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0]; pcibios_resource_to_bus(bridge->bus, ®ion, res); if (res->flags & IORESOURCE_IO) { @@ -595,19 +591,19 @@ static void pci_setup_bridge_io(struct pci_dev *bridge) io_base_lo = (region.start >> 8) & io_mask; io_limit_lo = (region.end >> 8) & io_mask; l = ((u16) io_limit_lo << 8) | io_base_lo; - /* Set up upper 16 bits of I/O base/limit. */ + /* Set up upper 16 bits of I/O base/limit */ io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); pci_info(bridge, " bridge window %pR\n", res); } else { - /* Clear upper 16 bits of I/O base/limit. */ + /* Clear upper 16 bits of I/O base/limit */ io_upper16 = 0; l = 0x00f0; } - /* Temporarily disable the I/O range before updating PCI_IO_BASE. */ + /* Temporarily disable the I/O range before updating PCI_IO_BASE */ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); - /* Update lower 16 bits of I/O base/limit. */ + /* Update lower 16 bits of I/O base/limit */ pci_write_config_word(bridge, PCI_IO_BASE, l); - /* Update upper 16 bits of I/O base/limit. */ + /* Update upper 16 bits of I/O base/limit */ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); } @@ -617,7 +613,7 @@ static void pci_setup_bridge_mmio(struct pci_dev *bridge) struct pci_bus_region region; u32 l; - /* Set up the top and bottom of the PCI Memory segment for this bus. */ + /* Set up the top and bottom of the PCI Memory segment for this bus */ res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1]; pcibios_resource_to_bus(bridge->bus, ®ion, res); if (res->flags & IORESOURCE_MEM) { @@ -636,12 +632,14 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge) struct pci_bus_region region; u32 l, bu, lu; - /* Clear out the upper 32 bits of PREF limit. - If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily - disables PREF range, which is ok. */ + /* + * Clear out the upper 32 bits of PREF limit. If + * PCI_PREF_BASE_UPPER32 was non-zero, this temporarily disables + * PREF range, which is ok. + */ pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); - /* Set up PREF base/limit. */ + /* Set up PREF base/limit */ bu = lu = 0; res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2]; pcibios_resource_to_bus(bridge->bus, ®ion, res); @@ -658,7 +656,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge) } pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - /* Set the upper 32 bits of PREF base & limit. */ + /* Set the upper 32 bits of PREF base & limit */ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); } @@ -702,13 +700,13 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i) return 0; if (pci_claim_resource(bridge, i) == 0) - return 0; /* claimed the window */ + return 0; /* Claimed the window */ if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI) return 0; if (!pci_bus_clip_resource(bridge, i)) - return -EINVAL; /* clipping didn't change anything */ + return -EINVAL; /* Clipping didn't change anything */ switch (i - PCI_BRIDGE_RESOURCES) { case 0: @@ -725,14 +723,16 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i) } if (pci_claim_resource(bridge, i) == 0) - return 0; /* claimed a smaller window */ + return 0; /* Claimed a smaller window */ return -EINVAL; } -/* Check whether the bridge supports optional I/O and - prefetchable memory ranges. If not, the respective - base/limit registers must be read-only and read as 0. */ +/* + * Check whether the bridge supports optional I/O and prefetchable memory + * ranges. If not, the respective base/limit registers must be read-only + * and read as 0. + */ static void pci_bridge_check_ranges(struct pci_bus *bus) { struct pci_dev *bridge = bus->self; @@ -752,12 +752,14 @@ static void pci_bridge_check_ranges(struct pci_bus *bus) } } -/* Helper function for sizing routines: find first available - bus resource of a given type. Note: we intentionally skip - the bus resources which have already been assigned (that is, - have non-NULL parent resource). */ +/* + * Helper function for sizing routines: find first available bus resource + * of a given type. Note: we intentionally skip the bus resources which + * have already been assigned (that is, have non-NULL parent resource). + */ static struct resource *find_free_bus_resource(struct pci_bus *bus, - unsigned long type_mask, unsigned long type) + unsigned long type_mask, + unsigned long type) { int i; struct resource *r; @@ -772,19 +774,21 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, } static resource_size_t calculate_iosize(resource_size_t size, - resource_size_t min_size, - resource_size_t size1, - resource_size_t add_size, - resource_size_t children_add_size, - resource_size_t old_size, - resource_size_t align) + resource_size_t min_size, + resource_size_t size1, + resource_size_t add_size, + resource_size_t children_add_size, + resource_size_t old_size, + resource_size_t align) { if (size < min_size) size = min_size; if (old_size == 1) old_size = 0; - /* To be fixed in 2.5: we should have sort of HAVE_ISA - flag in the struct pci_bus. */ + /* + * To be fixed in 2.5: we should have sort of HAVE_ISA flag in the + * struct pci_bus. + */ #if defined(CONFIG_ISA) || defined(CONFIG_EISA) size = (size & 0xff) + ((size & ~0xffUL) << 2); #endif @@ -797,11 +801,11 @@ static resource_size_t calculate_iosize(resource_size_t size, } static resource_size_t calculate_memsize(resource_size_t size, - resource_size_t min_size, - resource_size_t add_size, - resource_size_t children_add_size, - resource_size_t old_size, - resource_size_t align) + resource_size_t min_size, + resource_size_t add_size, + resource_size_t children_add_size, + resource_size_t old_size, + resource_size_t align) { if (size < min_size) size = min_size; @@ -824,8 +828,7 @@ resource_size_t __weak pcibios_window_alignment(struct pci_bus *bus, #define PCI_P2P_DEFAULT_IO_ALIGN 0x1000 /* 4KiB */ #define PCI_P2P_DEFAULT_IO_ALIGN_1K 0x400 /* 1KiB */ -static resource_size_t window_alignment(struct pci_bus *bus, - unsigned long type) +static resource_size_t window_alignment(struct pci_bus *bus, unsigned long type) { resource_size_t align = 1, arch_align; @@ -833,8 +836,8 @@ static resource_size_t window_alignment(struct pci_bus *bus, align = PCI_P2P_DEFAULT_MEM_ALIGN; else if (type & IORESOURCE_IO) { /* - * Per spec, I/O windows are 4K-aligned, but some - * bridges have an extension to support 1K alignment. + * Per spec, I/O windows are 4K-aligned, but some bridges have + * an extension to support 1K alignment. */ if (bus->self->io_window_1k) align = PCI_P2P_DEFAULT_IO_ALIGN_1K; @@ -847,20 +850,21 @@ static resource_size_t window_alignment(struct pci_bus *bus, } /** - * pbus_size_io() - size the io window of a given bus + * pbus_size_io() - Size the I/O window of a given bus * - * @bus : the bus - * @min_size : the minimum io window that must to be allocated - * @add_size : additional optional io window - * @realloc_head : track the additional io window on this list + * @bus: The bus + * @min_size: The minimum I/O window that must be allocated + * @add_size: Additional optional I/O window + * @realloc_head: Track the additional I/O window on this list * - * Sizing the IO windows of the PCI-PCI bridge is trivial, - * since these windows have 1K or 4K granularity and the IO ranges - * of non-bridge PCI devices are limited to 256 bytes. - * We must be careful with the ISA aliasing though. + * Sizing the I/O windows of the PCI-PCI bridge is trivial, since these + * windows have 1K or 4K granularity and the I/O ranges of non-bridge PCI + * devices are limited to 256 bytes. We must be careful with the ISA + * aliasing though. */ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, - resource_size_t add_size, struct list_head *realloc_head) + resource_size_t add_size, + struct list_head *realloc_head) { struct pci_dev *dev; struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO, @@ -947,33 +951,33 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns, } /** - * pbus_size_mem() - size the memory window of a given bus + * pbus_size_mem() - Size the memory window of a given bus * - * @bus : the bus - * @mask: mask the resource flag, then compare it with type - * @type: the type of free resource from bridge - * @type2: second match type - * @type3: third match type - * @min_size : the minimum memory window that must to be allocated - * @add_size : additional optional memory window - * @realloc_head : track the additional memory window on this list + * @bus: The bus + * @mask: Mask the resource flag, then compare it with type + * @type: The type of free resource from bridge + * @type2: Second match type + * @type3: Third match type + * @min_size: The minimum memory window that must be allocated + * @add_size: Additional optional memory window + * @realloc_head: Track the additional memory window on this list * - * Calculate the size of the bus and minimal alignment which - * guarantees that all child resources fit in this size. + * Calculate the size of the bus and minimal alignment which guarantees + * that all child resources fit in this size. * - * Returns -ENOSPC if there's no available bus resource of the desired type. - * Otherwise, sets the bus resource start/end to indicate the required - * size, adds things to realloc_head (if supplied), and returns 0. + * Return -ENOSPC if there's no available bus resource of the desired + * type. Otherwise, set the bus resource start/end to indicate the + * required size, add things to realloc_head (if supplied), and return 0. */ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type, unsigned long type2, - unsigned long type3, - resource_size_t min_size, resource_size_t add_size, + unsigned long type3, resource_size_t min_size, + resource_size_t add_size, struct list_head *realloc_head) { struct pci_dev *dev; resource_size_t min_align, align, size, size0, size1; - resource_size_t aligns[18]; /* Alignments from 1Mb to 128Gb */ + resource_size_t aligns[18]; /* Alignments from 1MB to 128GB */ int order, max_order; struct resource *b_res = find_free_bus_resource(bus, mask | IORESOURCE_PREFETCH, type); @@ -1002,12 +1006,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, continue; r_size = resource_size(r); #ifdef CONFIG_PCI_IOV - /* put SRIOV requested res to the optional list */ + /* Put SRIOV requested res to the optional list */ if (realloc_head && i >= PCI_IOV_RESOURCES && i <= PCI_IOV_RESOURCE_END) { add_align = max(pci_resource_alignment(dev, r), add_align); r->end = r->start - 1; - add_to_list(realloc_head, dev, r, r_size, 0/* don't care */); + add_to_list(realloc_head, dev, r, r_size, 0 /* Don't care */); children_add_size += r_size; continue; } @@ -1029,8 +1033,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, continue; } size += max(r_size, align); - /* Exclude ranges with size > align from - calculation of the alignment. */ + /* + * Exclude ranges with size > align from calculation of + * the alignment. + */ if (r_size <= align) aligns[order] += align; if (order > max_order) @@ -1081,7 +1087,7 @@ unsigned long pci_cardbus_resource_alignment(struct resource *res) } static void pci_bus_size_cardbus(struct pci_bus *bus, - struct list_head *realloc_head) + struct list_head *realloc_head) { struct pci_dev *bridge = bus->self; struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; @@ -1091,8 +1097,8 @@ static void pci_bus_size_cardbus(struct pci_bus *bus, if (b_res[0].parent) goto handle_b_res_1; /* - * Reserve some resources for CardBus. We reserve - * a fixed amount of bus space for CardBus bridges. + * Reserve some resources for CardBus. We reserve a fixed amount + * of bus space for CardBus bridges. */ b_res[0].start = pci_cardbus_io_size; b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1; @@ -1116,7 +1122,7 @@ handle_b_res_1: } handle_b_res_2: - /* MEM1 must not be pref mmio */ + /* MEM1 must not be pref MMIO */ pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) { ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1; @@ -1124,10 +1130,7 @@ handle_b_res_2: pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); } - /* - * Check whether prefetchable memory is supported - * by this bridge. - */ + /* Check whether prefetchable memory is supported by this bridge. */ pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) { ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0; @@ -1138,9 +1141,8 @@ handle_b_res_2: if (b_res[2].parent) goto handle_b_res_3; /* - * If we have prefetchable memory support, allocate - * two regions. Otherwise, allocate one region of - * twice the size. + * If we have prefetchable memory support, allocate two regions. + * Otherwise, allocate one region of twice the size. */ if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { b_res[2].start = pci_cardbus_mem_size; @@ -1153,7 +1155,7 @@ handle_b_res_2: pci_cardbus_mem_size, pci_cardbus_mem_size); } - /* reduce that to half */ + /* Reduce that to half */ b_res_3_size = pci_cardbus_mem_size; } @@ -1204,7 +1206,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) switch (bus->self->hdr_type) { case PCI_HEADER_TYPE_CARDBUS: - /* don't size cardbuses yet. */ + /* Don't size CardBuses yet */ break; case PCI_HEADER_TYPE_BRIDGE: @@ -1271,18 +1273,17 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) /* * Compute the size required to put everything else in the - * non-prefetchable window. This includes: + * non-prefetchable window. This includes: * * - all non-prefetchable resources * - 32-bit prefetchable resources if there's a 64-bit * prefetchable window or no prefetchable window at all - * - 64-bit prefetchable resources if there's no - * prefetchable window at all + * - 64-bit prefetchable resources if there's no prefetchable + * window at all * - * Note that the strategy in __pci_assign_resource() must - * match that used here. Specifically, we cannot put a - * 32-bit prefetchable resource in a 64-bit prefetchable - * window. + * Note that the strategy in __pci_assign_resource() must match + * that used here. Specifically, we cannot put a 32-bit + * prefetchable resource in a 64-bit prefetchable window. */ pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3, realloc_head ? 0 : additional_mem_size, @@ -1315,8 +1316,8 @@ static void assign_fixed_resource_on_bus(struct pci_bus *b, struct resource *r) } /* - * Try to assign any resources marked as IORESOURCE_PCI_FIXED, as they - * are skipped by pbus_assign_resources_sorted(). + * Try to assign any resources marked as IORESOURCE_PCI_FIXED, as they are + * skipped by pbus_assign_resources_sorted(). */ static void pdev_assign_fixed_resources(struct pci_dev *dev) { @@ -1427,10 +1428,9 @@ static void pci_bus_allocate_resources(struct pci_bus *b) struct pci_bus *child; /* - * Carry out a depth-first search on the PCI bus - * tree to allocate bridge apertures. Read the - * programmed bridge bases and recursively claim - * the respective bridge resources. + * Carry out a depth-first search on the PCI bus tree to allocate + * bridge apertures. Read the programmed bridge bases and + * recursively claim the respective bridge resources. */ if (b->self) { pci_read_bridge_bases(b); @@ -1484,7 +1484,7 @@ static void __pci_bridge_assign_resources(const struct pci_dev *bridge, IORESOURCE_MEM_64) static void pci_bridge_release_resources(struct pci_bus *bus, - unsigned long type) + unsigned long type) { struct pci_dev *dev = bus->self; struct resource *r; @@ -1495,16 +1495,14 @@ static void pci_bridge_release_resources(struct pci_bus *bus, b_res = &dev->resource[PCI_BRIDGE_RESOURCES]; /* - * 1. if there is io port assign fail, will release bridge - * io port. - * 2. if there is non pref mmio assign fail, release bridge - * nonpref mmio. - * 3. if there is 64bit pref mmio assign fail, and bridge pref - * is 64bit, release bridge pref mmio. - * 4. if there is pref mmio assign fail, and bridge pref is - * 32bit mmio, release bridge pref mmio - * 5. if there is pref mmio assign fail, and bridge pref is not - * assigned, release bridge nonpref mmio. + * 1. If IO port assignment fails, release bridge IO port. + * 2. If non pref MMIO assignment fails, release bridge nonpref MMIO. + * 3. If 64bit pref MMIO assignment fails, and bridge pref is 64bit, + * release bridge pref MMIO. + * 4. If pref MMIO assignment fails, and bridge pref is 32bit, + * release bridge pref MMIO. + * 5. If pref MMIO assignment fails, and bridge pref is not + * assigned, release bridge nonpref MMIO. */ if (type & IORESOURCE_IO) idx = 0; @@ -1524,25 +1522,22 @@ static void pci_bridge_release_resources(struct pci_bus *bus, if (!r->parent) return; - /* - * if there are children under that, we should release them - * all - */ + /* If there are children, release them all */ release_child_resources(r); if (!release_resource(r)) { type = old_flags = r->flags & PCI_RES_TYPE_MASK; pci_printk(KERN_DEBUG, dev, "resource %d %pR released\n", PCI_BRIDGE_RESOURCES + idx, r); - /* keep the old size */ + /* Keep the old size */ r->end = resource_size(r) - 1; r->start = 0; r->flags = 0; - /* avoiding touch the one without PREF */ + /* Avoiding touch the one without PREF */ if (type & IORESOURCE_PREFETCH) type = IORESOURCE_PREFETCH; __pci_setup_bridge(bus, type); - /* for next child res under same bridge */ + /* For next child res under same bridge */ r->flags = old_flags; } } @@ -1551,9 +1546,10 @@ enum release_type { leaf_only, whole_subtree, }; + /* - * try to release pci bridge resources that is from leaf bridge, - * so we can allocate big new one later + * Try to release PCI bridge resources from leaf bridge, so we can allocate + * a larger window later. */ static void pci_bus_release_bridge_resources(struct pci_bus *bus, unsigned long type, @@ -1678,7 +1674,7 @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data) pcibios_resource_to_bus(dev->bus, ®ion, r); if (!region.start) { *unassigned = true; - return 1; /* return early from pci_walk_bus() */ + return 1; /* Return early from pci_walk_bus() */ } } @@ -1686,7 +1682,7 @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data) } static enum enable_type pci_realloc_detect(struct pci_bus *bus, - enum enable_type enable_local) + enum enable_type enable_local) { bool unassigned = false; @@ -1701,21 +1697,21 @@ static enum enable_type pci_realloc_detect(struct pci_bus *bus, } #else static enum enable_type pci_realloc_detect(struct pci_bus *bus, - enum enable_type enable_local) + enum enable_type enable_local) { return enable_local; } #endif /* - * first try will not touch pci bridge res - * second and later try will clear small leaf bridge res - * will stop till to the max depth if can not find good one + * First try will not touch PCI bridge res. + * Second and later try will clear small leaf bridge res. + * Will stop till to the max depth if can not find good one. */ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) { - LIST_HEAD(realloc_head); /* list of resources that - want additional resources */ + LIST_HEAD(realloc_head); + /* List of resources that want additional resources */ struct list_head *add_list = NULL; int tried_times = 0; enum release_type rel_type = leaf_only; @@ -1724,7 +1720,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) int pci_try_num = 1; enum enable_type enable_local; - /* don't realloc if asked to do so */ + /* Don't realloc if asked to do so */ enable_local = pci_realloc_detect(bus, pci_realloc_enable); if (pci_realloc_enabled(enable_local)) { int max_depth = pci_bus_get_depth(bus); @@ -1737,13 +1733,14 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) again: /* - * last try will use add_list, otherwise will try good to have as - * must have, so can realloc parent bridge resource + * Last try will use add_list, otherwise will try good to have as must + * have, so can realloc parent bridge resource */ if (tried_times + 1 == pci_try_num) add_list = &realloc_head; - /* Depth first, calculate sizes and alignments of all - subordinate buses. */ + /* + * Depth first, calculate sizes and alignments of all subordinate buses. + */ __pci_bus_size_bridges(bus, add_list); /* Depth last, allocate resources and update the hardware. */ @@ -1752,7 +1749,7 @@ again: BUG_ON(!list_empty(add_list)); tried_times++; - /* any device complain? */ + /* Any device complain? */ if (list_empty(&fail_head)) goto dump; @@ -1769,20 +1766,20 @@ again: dev_printk(KERN_DEBUG, &bus->dev, "No. %d try to assign unassigned res\n", tried_times + 1); - /* third times and later will not check if it is leaf */ + /* Third times and later will not check if it is leaf */ if ((tried_times + 1) > 2) rel_type = whole_subtree; /* * Try to release leaf bridge's resources that doesn't fit resource of - * child device under that bridge + * child device under that bridge. */ list_for_each_entry(fail_res, &fail_head, list) pci_bus_release_bridge_resources(fail_res->dev->bus, fail_res->flags & PCI_RES_TYPE_MASK, rel_type); - /* restore size and flags */ + /* Restore size and flags */ list_for_each_entry(fail_res, &fail_head, list) { struct resource *res = fail_res->res; @@ -1797,7 +1794,7 @@ again: goto again; dump: - /* dump the resource on buses */ + /* Dump the resource on buses */ pci_bus_dump_resources(bus); } @@ -1808,14 +1805,15 @@ void __init pci_assign_unassigned_resources(void) list_for_each_entry(root_bus, &pci_root_buses, node) { pci_assign_unassigned_root_bus_resources(root_bus); - /* Make sure the root bridge has a companion ACPI device: */ + /* Make sure the root bridge has a companion ACPI device */ if (ACPI_HANDLE(root_bus->bridge)) acpi_ioapic_add(ACPI_HANDLE(root_bus->bridge)); } } static void extend_bridge_window(struct pci_dev *bridge, struct resource *res, - struct list_head *add_list, resource_size_t available) + struct list_head *add_list, + resource_size_t available) { struct pci_dev_resource *dev_res; @@ -1839,8 +1837,10 @@ static void extend_bridge_window(struct pci_dev *bridge, struct resource *res, } static void pci_bus_distribute_available_resources(struct pci_bus *bus, - struct list_head *add_list, resource_size_t available_io, - resource_size_t available_mmio, resource_size_t available_mmio_pref) + struct list_head *add_list, + resource_size_t available_io, + resource_size_t available_mmio, + resource_size_t available_mmio_pref) { resource_size_t remaining_io, remaining_mmio, remaining_mmio_pref; unsigned int normal_bridges = 0, hotplug_bridges = 0; @@ -1864,7 +1864,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, /* * Calculate the total amount of extra resource space we can - * pass to bridges below this one. This is basically the + * pass to bridges below this one. This is basically the * extra space reduced by the minimal required space for the * non-hotplug bridges. */ @@ -1874,7 +1874,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, /* * Calculate how many hotplug bridges and normal bridges there - * are on this bus. We will distribute the additional available + * are on this bus. We will distribute the additional available * resources between hotplug bridges. */ for_each_pci_bridge(dev, bus) { @@ -1909,8 +1909,8 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, /* * There is only one bridge on the bus so it gets all available - * resources which it can then distribute to the possible - * hotplug bridges below. + * resources which it can then distribute to the possible hotplug + * bridges below. */ if (hotplug_bridges + normal_bridges == 1) { dev = list_first_entry(&bus->devices, struct pci_dev, bus_list); @@ -1961,9 +1961,8 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, } } -static void -pci_bridge_distribute_available_resources(struct pci_dev *bridge, - struct list_head *add_list) +static void pci_bridge_distribute_available_resources(struct pci_dev *bridge, + struct list_head *add_list) { resource_size_t available_io, available_mmio, available_mmio_pref; const struct resource *res; @@ -1980,14 +1979,17 @@ pci_bridge_distribute_available_resources(struct pci_dev *bridge, available_mmio_pref = resource_size(res); pci_bus_distribute_available_resources(bridge->subordinate, - add_list, available_io, available_mmio, available_mmio_pref); + add_list, available_io, + available_mmio, + available_mmio_pref); } void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) { struct pci_bus *parent = bridge->subordinate; - LIST_HEAD(add_list); /* list of resources that - want additional resources */ + /* List of resources that want additional resources */ + LIST_HEAD(add_list); + int tried_times = 0; LIST_HEAD(fail_head); struct pci_dev_resource *fail_res; @@ -1997,9 +1999,9 @@ again: __pci_bus_size_bridges(parent, &add_list); /* - * Distribute remaining resources (if any) equally between - * hotplug bridges below. This makes it possible to extend the - * hierarchy later without running out of resources. + * Distribute remaining resources (if any) equally between hotplug + * bridges below. This makes it possible to extend the hierarchy + * later without running out of resources. */ pci_bridge_distribute_available_resources(bridge, &add_list); @@ -2011,7 +2013,7 @@ again: goto enable_all; if (tried_times >= 2) { - /* still fail, don't need to try more */ + /* Still fail, don't need to try more */ free_list(&fail_head); goto enable_all; } @@ -2020,15 +2022,15 @@ again: tried_times + 1); /* - * Try to release leaf bridge's resources that doesn't fit resource of - * child device under that bridge + * Try to release leaf bridge's resources that aren't big enough + * to contain child device resources. */ list_for_each_entry(fail_res, &fail_head, list) pci_bus_release_bridge_resources(fail_res->dev->bus, fail_res->flags & PCI_RES_TYPE_MASK, whole_subtree); - /* restore size and flags */ + /* Restore size and flags */ list_for_each_entry(fail_res, &fail_head, list) { struct resource *res = fail_res->res; @@ -2107,7 +2109,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) } list_for_each_entry(dev_res, &saved, list) { - /* Skip the bridge we just assigned resources for. */ + /* Skip the bridge we just assigned resources for */ if (bridge == dev_res->dev) continue; @@ -2119,7 +2121,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) return 0; cleanup: - /* restore size and flags */ + /* Restore size and flags */ list_for_each_entry(dev_res, &failed, list) { struct resource *res = dev_res->res; @@ -2151,8 +2153,8 @@ cleanup: void pci_assign_unassigned_bus_resources(struct pci_bus *bus) { struct pci_dev *dev; - LIST_HEAD(add_list); /* list of resources that - want additional resources */ + /* List of resources that want additional resources */ + LIST_HEAD(add_list); down_read(&pci_bus_sem); for_each_pci_bridge(dev, bus) -- cgit From 7db4af43c97b68dc65394c799b86cdd0fffe5f8d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 7 May 2019 17:37:53 -0500 Subject: PCI: Use dev_printk() when possible Use dev_printk() when possible. This makes messages more consistent with other device-related messages and, in some cases, adds useful information. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 3 +-- drivers/pci/quirks.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 25794c27c7a4..6d27475e39b2 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1111,8 +1111,7 @@ legacy_io_err: kfree(b->legacy_io); b->legacy_io = NULL; kzalloc_err: - printk(KERN_WARNING "pci: warning: could not create legacy I/O port and ISA memory resources to sysfs\n"); - return; + dev_warn(&b->dev, "could not create legacy I/O port and ISA memory resources in sysfs\n"); } void pci_remove_legacy_files(struct pci_bus *b) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a59ad09ce911..0f0f73ff9ee2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -177,9 +177,9 @@ static int __init pci_apply_final_quirks(void) if (!tmp || cls == tmp) continue; - printk(KERN_DEBUG "PCI: CLS mismatch (%u != %u), using %u bytes\n", - cls << 2, tmp << 2, - pci_dfl_cache_line_size << 2); + pci_printk(KERN_DEBUG, dev, "CLS mismatch (%u != %u), using %u bytes\n", + cls << 2, tmp << 2, + pci_dfl_cache_line_size << 2); pci_cache_line_size = pci_dfl_cache_line_size; } } -- cgit From 25da8dbaaf0679b3b22c783952a8392071cfa135 Mon Sep 17 00:00:00 2001 From: Mohan Kumar Date: Sat, 20 Apr 2019 07:03:46 +0300 Subject: PCI: Replace printk(KERN_INFO) with pr_info(), etc Replace printk() with pr_*() to be more consistent with other logging and avoid checkpatch warnings. Link: https://lore.kernel.org/lkml/1555733026-19609-1-git-send-email-mohankumar718@gmail.com Link: https://lore.kernel.org/lkml/1555733130-19804-1-git-send-email-mohankumar718@gmail.com Signed-off-by: Mohan Kumar [bhelgaas: squash in similar changes from second patch in series] Signed-off-by: Bjorn Helgaas --- drivers/pci/bus.c | 2 +- drivers/pci/pci-acpi.c | 11 ++++------- drivers/pci/pci-stub.c | 10 ++++------ drivers/pci/pci.c | 3 +-- drivers/pci/quirks.c | 2 +- drivers/pci/slot.c | 2 +- 6 files changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 5cb40b2518f9..2179a8baef52 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -23,7 +23,7 @@ void pci_add_resource_offset(struct list_head *resources, struct resource *res, entry = resource_list_create_entry(res, 0); if (!entry) { - printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res); + pr_err("PCI: can't add host bridge window %pR\n", res); return; } diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index e1949f7efd9c..3ada0266974c 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -140,8 +140,7 @@ static acpi_status decode_type0_hpx_record(union acpi_object *record, hpx->t0->enable_perr = fields[5].integer.value; break; default: - printk(KERN_WARNING - "%s: Type 0 Revision %d record not supported\n", + pr_warn("%s: Type 0 Revision %d record not supported\n", __func__, revision); return AE_ERROR; } @@ -169,8 +168,7 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record, hpx->t1->tot_max_split = fields[4].integer.value; break; default: - printk(KERN_WARNING - "%s: Type 1 Revision %d record not supported\n", + pr_warn("%s: Type 1 Revision %d record not supported\n", __func__, revision); return AE_ERROR; } @@ -211,8 +209,7 @@ static acpi_status decode_type2_hpx_record(union acpi_object *record, hpx->t2->sec_unc_err_mask_or = fields[17].integer.value; break; default: - printk(KERN_WARNING - "%s: Type 2 Revision %d record not supported\n", + pr_warn("%s: Type 2 Revision %d record not supported\n", __func__, revision); return AE_ERROR; } @@ -272,7 +269,7 @@ static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) goto exit; break; default: - printk(KERN_ERR "%s: Type %d record not supported\n", + pr_err("%s: Type %d record not supported\n", __func__, type); status = AE_ERROR; goto exit; diff --git a/drivers/pci/pci-stub.c b/drivers/pci/pci-stub.c index 66f8a59fadbd..e408099fea52 100644 --- a/drivers/pci/pci-stub.c +++ b/drivers/pci/pci-stub.c @@ -66,20 +66,18 @@ static int __init pci_stub_init(void) &class, &class_mask); if (fields < 2) { - printk(KERN_WARNING - "pci-stub: invalid id string \"%s\"\n", id); + pr_warn("pci-stub: invalid ID string \"%s\"\n", id); continue; } - printk(KERN_INFO - "pci-stub: add %04X:%04X sub=%04X:%04X cls=%08X/%08X\n", + pr_info("pci-stub: add %04X:%04X sub=%04X:%04X cls=%08X/%08X\n", vendor, device, subvendor, subdevice, class, class_mask); rc = pci_add_dynid(&stub_driver, vendor, device, subvendor, subdevice, class, class_mask, 0); if (rc) - printk(KERN_WARNING - "pci-stub: failed to add dynamic id (%d)\n", rc); + pr_warn("pci-stub: failed to add dynamic ID (%d)\n", + rc); } return 0; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7c1b362f599a..225145ba4cf3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -6265,8 +6265,7 @@ static int __init pci_setup(char *str) disable_acs_redir_param = kstrdup(str + 18, GFP_KERNEL); } else { - printk(KERN_ERR "PCI: Unknown option `%s'\n", - str); + pr_err("PCI: Unknown option `%s'\n", str); } } str = k; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0f0f73ff9ee2..8d1135ca330f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2596,7 +2596,7 @@ static void nvbridge_check_legacy_irq_routing(struct pci_dev *dev) pci_read_config_dword(dev, 0x74, &cfg); if (cfg & ((1 << 2) | (1 << 15))) { - printk(KERN_INFO "Rewriting IRQ routing register on MCP55\n"); + pr_info("Rewriting IRQ routing register on MCP55\n"); cfg &= ~((1 << 2) | (1 << 15)); pci_write_config_dword(dev, 0x74, cfg); } diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index c46d5e1ff536..f4d92b1afe7b 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -403,7 +403,7 @@ static int pci_slot_init(void) pci_slots_kset = kset_create_and_add("slots", NULL, &pci_bus_kset->kobj); if (!pci_slots_kset) { - printk(KERN_ERR "PCI: Slot initialization failure\n"); + pr_err("PCI: Slot initialization failure\n"); return -ENOMEM; } return 0; -- cgit From 34c6b7105e5a11174f856483cde8ad6e61b7236a Mon Sep 17 00:00:00 2001 From: Mohan Kumar Date: Sat, 20 Apr 2019 07:07:20 +0300 Subject: PCI: Replace dev_printk(KERN_DEBUG) with dev_info(), etc Replace dev_printk(KERN_DEBUG) with dev_info(), etc to be more consistent with other logging and avoid checkpatch warnings. The KERN_DEBUG messages could be converted to dev_dbg(), but that depends on CONFIG_DYNAMIC_DEBUG and DEBUG, and we want most of these messages to *always* be in the dmesg log. Link: https://lore.kernel.org/lkml/1555733240-19875-1-git-send-email-mohankumar718@gmail.com Signed-off-by: Mohan Kumar [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas --- drivers/pci/bus.c | 3 +-- drivers/pci/pci.c | 14 +++++++------- drivers/pci/probe.c | 21 +++++++++------------ drivers/pci/quirks.c | 13 ++++++------- drivers/pci/setup-bus.c | 30 ++++++++++++++---------------- drivers/pci/xen-pcifront.c | 7 +++---- 6 files changed, 40 insertions(+), 48 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 2179a8baef52..495059d923f7 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -288,8 +288,7 @@ bool pci_bus_clip_resource(struct pci_dev *dev, int idx) res->end = end; res->flags &= ~IORESOURCE_UNSET; orig_res.flags &= ~IORESOURCE_UNSET; - pci_printk(KERN_DEBUG, dev, "%pR clipped to %pR\n", - &orig_res, res); + pci_info(dev, "%pR clipped to %pR\n", &orig_res, res); return true; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 225145ba4cf3..2d6d857a3d67 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2777,14 +2777,14 @@ void pci_pm_init(struct pci_dev *dev) dev->d2_support = true; if (dev->d1_support || dev->d2_support) - pci_printk(KERN_DEBUG, dev, "supports%s%s\n", + pci_info(dev, "supports%s%s\n", dev->d1_support ? " D1" : "", dev->d2_support ? " D2" : ""); } pmc &= PCI_PM_CAP_PME_MASK; if (pmc) { - pci_printk(KERN_DEBUG, dev, "PME# supported from%s%s%s%s%s\n", + pci_info(dev, "PME# supported from%s%s%s%s%s\n", (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "", (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "", (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "", @@ -2952,16 +2952,16 @@ static int pci_ea_read(struct pci_dev *dev, int offset) res->flags = flags; if (bei <= PCI_EA_BEI_BAR5) - pci_printk(KERN_DEBUG, dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n", + pci_info(dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n", bei, res, prop); else if (bei == PCI_EA_BEI_ROM) - pci_printk(KERN_DEBUG, dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n", + pci_info(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) - pci_printk(KERN_DEBUG, dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n", + pci_info(dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n", bei - PCI_EA_BEI_VF_BAR0, res, prop); else - pci_printk(KERN_DEBUG, dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n", + pci_info(dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n", bei, res, prop); out: @@ -4185,7 +4185,7 @@ int pci_set_cacheline_size(struct pci_dev *dev) if (cacheline_size == pci_cache_line_size) return 0; - pci_printk(KERN_DEBUG, dev, "cache line size of %d is not supported\n", + pci_info(dev, "cache line size of %d is not supported\n", pci_cache_line_size << 2); return -EINVAL; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2ec0df04e0dc..ac89f4d7a22a 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -317,7 +317,7 @@ fail: res->flags = 0; out: if (res->flags) - pci_printk(KERN_DEBUG, dev, "reg 0x%x: %pR\n", pos, res); + pci_info(dev, "reg 0x%x: %pR\n", pos, res); return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; } @@ -435,7 +435,7 @@ static void pci_read_bridge_io(struct pci_bus *child) region.start = base; region.end = limit + io_granularity - 1; pcibios_bus_to_resource(dev->bus, res, ®ion); - pci_printk(KERN_DEBUG, dev, " bridge window %pR\n", res); + pci_info(dev, " bridge window %pR\n", res); } } @@ -457,7 +457,7 @@ static void pci_read_bridge_mmio(struct pci_bus *child) region.start = base; region.end = limit + 0xfffff; pcibios_bus_to_resource(dev->bus, res, ®ion); - pci_printk(KERN_DEBUG, dev, " bridge window %pR\n", res); + pci_info(dev, " bridge window %pR\n", res); } } @@ -510,7 +510,7 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child) region.start = base; region.end = limit + 0xfffff; pcibios_bus_to_resource(dev->bus, res, ®ion); - pci_printk(KERN_DEBUG, dev, " bridge window %pR\n", res); + pci_info(dev, " bridge window %pR\n", res); } } @@ -540,8 +540,7 @@ void pci_read_bridge_bases(struct pci_bus *child) if (res && res->flags) { pci_bus_add_resource(child, res, PCI_SUBTRACTIVE_DECODE); - pci_printk(KERN_DEBUG, dev, - " bridge window %pR (subtractive decode)\n", + pci_info(dev, " bridge window %pR (subtractive decode)\n", res); } } @@ -1690,7 +1689,7 @@ int pci_setup_device(struct pci_dev *dev) dev->revision = class & 0xff; dev->class = class >> 8; /* upper 3 bytes */ - pci_printk(KERN_DEBUG, dev, "[%04x:%04x] type %02x class %#08x\n", + pci_info(dev, "[%04x:%04x] type %02x class %#08x\n", dev->vendor, dev->device, dev->hdr_type, dev->class); if (pci_early_dump) @@ -3086,7 +3085,7 @@ int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max) conflict = request_resource_conflict(parent_res, res); if (conflict) - dev_printk(KERN_DEBUG, &b->dev, + dev_info(&b->dev, "busn_res: can not insert %pR under %s%pR (conflicts with %s %pR)\n", res, pci_is_root_bus(b) ? "domain " : "", parent_res, conflict->name, conflict); @@ -3106,8 +3105,7 @@ int pci_bus_update_busn_res_end(struct pci_bus *b, int bus_max) size = bus_max - res->start + 1; ret = adjust_resource(res, res->start, size); - dev_printk(KERN_DEBUG, &b->dev, - "busn_res: %pR end %s updated to %02x\n", + dev_info(&b->dev, "busn_res: %pR end %s updated to %02x\n", &old_res, ret ? "can not be" : "is", bus_max); if (!ret && !res->parent) @@ -3125,8 +3123,7 @@ void pci_bus_release_busn_res(struct pci_bus *b) return; ret = release_resource(res); - dev_printk(KERN_DEBUG, &b->dev, - "busn_res: %pR %s released\n", + dev_info(&b->dev, "busn_res: %pR %s released\n", res, ret ? "can not be" : "is"); } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 8d1135ca330f..3f5a763addd3 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -159,8 +159,7 @@ static int __init pci_apply_final_quirks(void) u8 tmp; if (pci_cache_line_size) - printk(KERN_DEBUG "PCI: CLS %u bytes\n", - pci_cache_line_size << 2); + pr_info("PCI: CLS %u bytes\n", pci_cache_line_size << 2); pci_apply_fixup_final_quirks = true; for_each_pci_dev(dev) { @@ -177,16 +176,16 @@ static int __init pci_apply_final_quirks(void) if (!tmp || cls == tmp) continue; - pci_printk(KERN_DEBUG, dev, "CLS mismatch (%u != %u), using %u bytes\n", - cls << 2, tmp << 2, - pci_dfl_cache_line_size << 2); + pci_info(dev, "CLS mismatch (%u != %u), using %u bytes\n", + cls << 2, tmp << 2, + pci_dfl_cache_line_size << 2); pci_cache_line_size = pci_dfl_cache_line_size; } } if (!pci_cache_line_size) { - printk(KERN_DEBUG "PCI: CLS %u bytes, default %u\n", - cls << 2, pci_dfl_cache_line_size << 2); + pr_info("PCI: CLS %u bytes, default %u\n", cls << 2, + pci_dfl_cache_line_size << 2); pci_cache_line_size = cls ? cls : pci_dfl_cache_line_size; } diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index ec44a0f3a7ac..c73e66725d05 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -255,10 +255,9 @@ static void reassign_resources_sorted(struct list_head *realloc_head, (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); if (pci_reassign_resource(add_res->dev, idx, add_size, align)) - pci_printk(KERN_DEBUG, add_res->dev, - "failed to add %llx res[%d]=%pR\n", - (unsigned long long)add_size, - idx, res); + pci_info(add_res->dev, "failed to add %llx res[%d]=%pR\n", + (unsigned long long) add_size, idx, + res); } out: list_del(&add_res->list); @@ -918,9 +917,9 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, if (size1 > size0 && realloc_head) { add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); - pci_printk(KERN_DEBUG, bus->self, "bridge window %pR to %pR add_size %llx\n", - b_res, &bus->busn_res, - (unsigned long long)size1-size0); + pci_info(bus->self, "bridge window %pR to %pR add_size %llx\n", + b_res, &bus->busn_res, + (unsigned long long) size1 - size0); } } @@ -1063,7 +1062,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, b_res->flags |= IORESOURCE_STARTALIGN; if (size1 > size0 && realloc_head) { add_to_list(realloc_head, bus->self, b_res, size1-size0, add_align); - pci_printk(KERN_DEBUG, bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n", + pci_info(bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n", b_res, &bus->busn_res, (unsigned long long) (size1 - size0), (unsigned long long) add_align); @@ -1531,8 +1530,8 @@ static void pci_bridge_release_resources(struct pci_bus *bus, release_child_resources(r); if (!release_resource(r)) { type = old_flags = r->flags & PCI_RES_TYPE_MASK; - pci_printk(KERN_DEBUG, dev, "resource %d %pR released\n", - PCI_BRIDGE_RESOURCES + idx, r); + pci_info(dev, "resource %d %pR released\n", + PCI_BRIDGE_RESOURCES + idx, r); /* keep the old size */ r->end = resource_size(r) - 1; r->start = 0; @@ -1596,7 +1595,7 @@ static void pci_bus_dump_res(struct pci_bus *bus) if (!res || !res->end || !res->flags) continue; - dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res); + dev_info(&bus->dev, "resource %d %pR\n", i, res); } } @@ -1730,9 +1729,8 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) int max_depth = pci_bus_get_depth(bus); pci_try_num = max_depth + 1; - dev_printk(KERN_DEBUG, &bus->dev, - "max bus depth: %d pci_try_num: %d\n", - max_depth, pci_try_num); + dev_info(&bus->dev, "max bus depth: %d pci_try_num: %d\n", + max_depth, pci_try_num); } again: @@ -1766,8 +1764,8 @@ again: goto dump; } - dev_printk(KERN_DEBUG, &bus->dev, - "No. %d try to assign unassigned res\n", tried_times + 1); + dev_info(&bus->dev, "No. %d try to assign unassigned res\n", + tried_times + 1); /* third times and later will not check if it is leaf */ if ((tried_times + 1) > 2) diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index eba6e33147a2..fbd8d9f54d6a 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -291,8 +291,7 @@ static int pci_frontend_enable_msix(struct pci_dev *dev, vector[i] = op.msix_entries[i].vector; } } else { - printk(KERN_DEBUG "enable msix get value %x\n", - op.value); + pr_info("enable msix get value %x\n", op.value); err = op.value; } } else { @@ -364,12 +363,12 @@ static void pci_frontend_disable_msi(struct pci_dev *dev) err = do_pci_op(pdev, &op); if (err == XEN_PCI_ERR_dev_not_found) { /* XXX No response from backend, what shall we do? */ - printk(KERN_DEBUG "get no response from backend for disable MSI\n"); + pr_info("get no response from backend for disable MSI\n"); return; } if (err) /* how can pciback notify us fail? */ - printk(KERN_DEBUG "get fake response frombackend\n"); + pr_info("get fake response from backend\n"); } static struct xen_pci_frontend_ops pci_frontend_ops = { -- cgit From d55791834570e79e9a1952f5c2e73f34af890fb3 Mon Sep 17 00:00:00 2001 From: Frederick Lawler Date: Tue, 7 May 2019 18:24:46 -0500 Subject: PCI/AER: Replace dev_printk(KERN_DEBUG) with dev_info() Replace dev_printk(KERN_DEBUG) with dev_info() or dev_err() to be more consistent with other logging. These could be converted to dev_dbg(), but that depends on CONFIG_DYNAMIC_DEBUG and DEBUG, and we want most of these messages to *always* be in the dmesg log. Also remove a redundant kzalloc() failure message. Link: https://lore.kernel.org/lkml/20190509141456.223614-2-helgaas@kernel.org Signed-off-by: Frederick Lawler Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch Reviewed-by: Andy Shevchenko --- drivers/pci/pcie/aer.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index f8fc2114ad39..63a73a8c933a 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -964,8 +964,7 @@ static bool find_source_device(struct pci_dev *parent, pci_walk_bus(parent->subordinate, find_device_iter, e_info); if (!e_info->error_dev_num) { - pci_printk(KERN_DEBUG, parent, "can't find device of ID%04x\n", - e_info->id); + pci_info(parent, "can't find device of ID%04x\n", e_info->id); return false; } return true; @@ -1379,18 +1378,16 @@ static int aer_probe(struct pcie_device *dev) struct device *device = &dev->device; rpc = devm_kzalloc(device, sizeof(struct aer_rpc), GFP_KERNEL); - if (!rpc) { - dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n"); + if (!rpc) return -ENOMEM; - } + rpc->rpd = dev->port; set_service_data(dev, rpc); status = devm_request_threaded_irq(device, dev->irq, aer_irq, aer_isr, IRQF_SHARED, "aerdrv", dev); if (status) { - dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n", - dev->irq); + dev_err(device, "request AER IRQ %d failed\n", dev->irq); return status; } @@ -1419,7 +1416,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev) pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); rc = pci_bus_error_reset(dev); - pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n"); + pci_info(dev, "Root Port link has been reset\n"); /* Clear Root Error Status */ pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32); -- cgit From 00ebf1348cb332941dab52948f29480592bfbe6a Mon Sep 17 00:00:00 2001 From: Frederick Lawler Date: Tue, 7 May 2019 18:24:48 -0500 Subject: PCI/PME: Replace dev_printk(KERN_DEBUG) with dev_info() Replace dev_printk(KERN_DEBUG) with dev_info() or dev_err() to be more consistent with other logging. These could be converted to dev_dbg(), but that depends on CONFIG_DYNAMIC_DEBUG and DEBUG, and we want most of these messages to *always* be in the dmesg log. Also, use dev_fmt() to add the service name. Example output change: - pcieport 0000:80:10.0: Signaling PME with IRQ ... + pcieport 0000:80:10.0: PME: Signaling with IRQ ... Link: https://lore.kernel.org/lkml/20190509141456.223614-3-helgaas@kernel.org Signed-off-by: Frederick Lawler Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/pcie/pme.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 54d593d10396..f38e6c19dd50 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -7,6 +7,8 @@ * Copyright (C) 2009 Rafael J. Wysocki , Novell Inc. */ +#define dev_fmt(fmt) "PME: " fmt + #include #include #include @@ -194,14 +196,14 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) * assuming that the PME was reported by a PCIe-PCI bridge that * used devfn different from zero. */ - pci_dbg(port, "PME interrupt generated for non-existent device %02x:%02x.%d\n", - busnr, PCI_SLOT(devfn), PCI_FUNC(devfn)); + pci_info(port, "interrupt generated for non-existent device %02x:%02x.%d\n", + busnr, PCI_SLOT(devfn), PCI_FUNC(devfn)); found = pcie_pme_from_pci_bridge(bus, 0); } out: if (!found) - pci_dbg(port, "Spurious native PME interrupt!\n"); + pci_info(port, "Spurious native interrupt!\n"); } /** @@ -341,7 +343,7 @@ static int pcie_pme_probe(struct pcie_device *srv) return ret; } - pci_info(port, "Signaling PME with IRQ %d\n", srv->irq); + pci_info(port, "Signaling with IRQ %d\n", srv->irq); pcie_pme_mark_devices(port); pcie_pme_interrupt_enable(port, true); -- cgit From 10a9990c10447a7bfe9dc016629898814741d090 Mon Sep 17 00:00:00 2001 From: Frederick Lawler Date: Tue, 7 May 2019 18:24:47 -0500 Subject: PCI/DPC: Log messages with pci_dev, not pcie_device Log messages with pci_dev, not pcie_device. Factor out common message prefixes with dev_fmt(). Example output change: - dpc 0000:00:01.1:pcie008: DPC error containment capabilities... + pcieport 0000:00:01.1: DPC: error containment capabilities... Link: https://lore.kernel.org/lkml/20190509141456.223614-4-helgaas@kernel.org Signed-off-by: Frederick Lawler Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/pcie/dpc.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index 7b77754a82de..a32ec3487a8d 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -6,6 +6,8 @@ * Copyright (C) 2016 Intel Corp. */ +#define dev_fmt(fmt) "DPC: " fmt + #include #include #include @@ -100,7 +102,6 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc) { unsigned long timeout = jiffies + HZ; struct pci_dev *pdev = dpc->dev->port; - struct device *dev = &dpc->dev->device; u16 cap = dpc->cap_pos, status; pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); @@ -110,7 +111,7 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc) pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); } if (status & PCI_EXP_DPC_RP_BUSY) { - dev_warn(dev, "DPC root port still busy\n"); + pci_warn(pdev, "root port still busy\n"); return -EBUSY; } return 0; @@ -148,7 +149,6 @@ static pci_ers_result_t dpc_reset_link(struct pci_dev *pdev) static void dpc_process_rp_pio_error(struct dpc_dev *dpc) { - struct device *dev = &dpc->dev->device; struct pci_dev *pdev = dpc->dev->port; u16 cap = dpc->cap_pos, dpc_status, first_error; u32 status, mask, sev, syserr, exc, dw0, dw1, dw2, dw3, log, prefix; @@ -156,13 +156,13 @@ static void dpc_process_rp_pio_error(struct dpc_dev *dpc) pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, &status); pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_MASK, &mask); - dev_err(dev, "rp_pio_status: %#010x, rp_pio_mask: %#010x\n", + pci_err(pdev, "rp_pio_status: %#010x, rp_pio_mask: %#010x\n", status, mask); pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SEVERITY, &sev); pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SYSERROR, &syserr); pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_EXCEPTION, &exc); - dev_err(dev, "RP PIO severity=%#010x, syserror=%#010x, exception=%#010x\n", + pci_err(pdev, "RP PIO severity=%#010x, syserror=%#010x, exception=%#010x\n", sev, syserr, exc); /* Get First Error Pointer */ @@ -171,7 +171,7 @@ static void dpc_process_rp_pio_error(struct dpc_dev *dpc) for (i = 0; i < ARRAY_SIZE(rp_pio_error_string); i++) { if ((status & ~mask) & (1 << i)) - dev_err(dev, "[%2d] %s%s\n", i, rp_pio_error_string[i], + pci_err(pdev, "[%2d] %s%s\n", i, rp_pio_error_string[i], first_error == i ? " (First)" : ""); } @@ -185,18 +185,18 @@ static void dpc_process_rp_pio_error(struct dpc_dev *dpc) &dw2); pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12, &dw3); - dev_err(dev, "TLP Header: %#010x %#010x %#010x %#010x\n", + pci_err(pdev, "TLP Header: %#010x %#010x %#010x %#010x\n", dw0, dw1, dw2, dw3); if (dpc->rp_log_size < 5) goto clear_status; pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log); - dev_err(dev, "RP PIO ImpSpec Log %#010x\n", log); + pci_err(pdev, "RP PIO ImpSpec Log %#010x\n", log); for (i = 0; i < dpc->rp_log_size - 5; i++) { pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix); - dev_err(dev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix); + pci_err(pdev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix); } clear_status: pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, status); @@ -229,18 +229,17 @@ static irqreturn_t dpc_handler(int irq, void *context) struct aer_err_info info; struct dpc_dev *dpc = context; struct pci_dev *pdev = dpc->dev->port; - struct device *dev = &dpc->dev->device; u16 cap = dpc->cap_pos, status, source, reason, ext_reason; pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, &source); - dev_info(dev, "DPC containment event, status:%#06x source:%#06x\n", + pci_info(pdev, "containment event, status:%#06x source:%#06x\n", status, source); reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1; ext_reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT) >> 5; - dev_warn(dev, "DPC %s detected\n", + pci_warn(pdev, "%s detected\n", (reason == 0) ? "unmasked uncorrectable error" : (reason == 1) ? "ERR_NONFATAL" : (reason == 2) ? "ERR_FATAL" : @@ -307,7 +306,7 @@ static int dpc_probe(struct pcie_device *dev) dpc_handler, IRQF_SHARED, "pcie-dpc", dpc); if (status) { - dev_warn(device, "request IRQ%d failed: %d\n", dev->irq, + pci_warn(pdev, "request IRQ%d failed: %d\n", dev->irq, status); return status; } @@ -319,7 +318,7 @@ static int dpc_probe(struct pcie_device *dev) if (dpc->rp_extensions) { dpc->rp_log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8; if (dpc->rp_log_size < 4 || dpc->rp_log_size > 9) { - dev_err(device, "RP PIO log size %u is invalid\n", + pci_err(pdev, "RP PIO log size %u is invalid\n", dpc->rp_log_size); dpc->rp_log_size = 0; } @@ -328,11 +327,11 @@ static int dpc_probe(struct pcie_device *dev) ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN; pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl); - dev_info(device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n", - cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT), - FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP), - FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size, - FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE)); + pci_info(pdev, "error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n", + cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT), + FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP), + FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size, + FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE)); pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_DPC, sizeof(u16)); return status; -- cgit From 9cc6f75b27e76d38fa7c2825c4a9a64fe26e4c77 Mon Sep 17 00:00:00 2001 From: Frederick Lawler Date: Tue, 7 May 2019 18:24:50 -0500 Subject: PCI/AER: Log messages with pci_dev, not pcie_device Log messages with pci_dev, not pcie_device. Factor out common message prefixes with dev_fmt(). Example output change: - aer 0000:00:00.0:pci002: AER enabled with IRQ ... + pcieport 0000:00:00.0: AER: enabled with IRQ ... Link: https://lore.kernel.org/lkml/20190509141456.223614-5-helgaas@kernel.org Signed-off-by: Frederick Lawler Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch Reviewed-by: Andy Shevchenko --- drivers/pci/pcie/aer.c | 19 ++++++++++++------- drivers/pci/pcie/aer_inject.c | 20 ++++++++++---------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 63a73a8c933a..b45bc47d04fe 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -12,6 +12,9 @@ * Andrew Patterson */ +#define pr_fmt(fmt) "AER: " fmt +#define dev_fmt pr_fmt + #include #include #include @@ -779,10 +782,11 @@ static void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) u8 bus = info->id >> 8; u8 devfn = info->id & 0xff; - pci_info(dev, "AER: %s%s error received: %04x:%02x:%02x.%d\n", - info->multi_error_valid ? "Multiple " : "", - aer_error_severity_string[info->severity], - pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + pci_info(dev, "%s%s error received: %04x:%02x:%02x.%d\n", + info->multi_error_valid ? "Multiple " : "", + aer_error_severity_string[info->severity], + pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), + PCI_FUNC(devfn)); } #ifdef CONFIG_ACPI_APEI_PCIEAER @@ -1376,23 +1380,24 @@ static int aer_probe(struct pcie_device *dev) int status; struct aer_rpc *rpc; struct device *device = &dev->device; + struct pci_dev *port = dev->port; rpc = devm_kzalloc(device, sizeof(struct aer_rpc), GFP_KERNEL); if (!rpc) return -ENOMEM; - rpc->rpd = dev->port; + rpc->rpd = port; set_service_data(dev, rpc); status = devm_request_threaded_irq(device, dev->irq, aer_irq, aer_isr, IRQF_SHARED, "aerdrv", dev); if (status) { - dev_err(device, "request AER IRQ %d failed\n", dev->irq); + pci_err(port, "request AER IRQ %d failed\n", dev->irq); return status; } aer_enable_rootport(rpc); - dev_info(device, "AER enabled with IRQ %d\n", dev->irq); + pci_info(port, "enabled with IRQ %d\n", dev->irq); return 0; } diff --git a/drivers/pci/pcie/aer_inject.c b/drivers/pci/pcie/aer_inject.c index 95d4759664b3..043b8b0cfcc5 100644 --- a/drivers/pci/pcie/aer_inject.c +++ b/drivers/pci/pcie/aer_inject.c @@ -12,6 +12,8 @@ * Huang Ying */ +#define dev_fmt(fmt) "aer_inject: " fmt + #include #include #include @@ -332,14 +334,14 @@ static int aer_inject(struct aer_error_inj *einj) return -ENODEV; rpdev = pcie_find_root_port(dev); if (!rpdev) { - pci_err(dev, "aer_inject: Root port not found\n"); + pci_err(dev, "Root port not found\n"); ret = -ENODEV; goto out_put; } pos_cap_err = dev->aer_cap; if (!pos_cap_err) { - pci_err(dev, "aer_inject: Device doesn't support AER\n"); + pci_err(dev, "Device doesn't support AER\n"); ret = -EPROTONOSUPPORT; goto out_put; } @@ -350,7 +352,7 @@ static int aer_inject(struct aer_error_inj *einj) rp_pos_cap_err = rpdev->aer_cap; if (!rp_pos_cap_err) { - pci_err(rpdev, "aer_inject: Root port doesn't support AER\n"); + pci_err(rpdev, "Root port doesn't support AER\n"); ret = -EPROTONOSUPPORT; goto out_put; } @@ -398,14 +400,14 @@ static int aer_inject(struct aer_error_inj *einj) if (!aer_mask_override && einj->cor_status && !(einj->cor_status & ~cor_mask)) { ret = -EINVAL; - pci_warn(dev, "aer_inject: The correctable error(s) is masked by device\n"); + pci_warn(dev, "The correctable error(s) is masked by device\n"); spin_unlock_irqrestore(&inject_lock, flags); goto out_put; } if (!aer_mask_override && einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) { ret = -EINVAL; - pci_warn(dev, "aer_inject: The uncorrectable error(s) is masked by device\n"); + pci_warn(dev, "The uncorrectable error(s) is masked by device\n"); spin_unlock_irqrestore(&inject_lock, flags); goto out_put; } @@ -460,19 +462,17 @@ static int aer_inject(struct aer_error_inj *einj) if (device) { edev = to_pcie_device(device); if (!get_service_data(edev)) { - dev_warn(&edev->device, - "aer_inject: AER service is not initialized\n"); + pci_warn(edev->port, "AER service is not initialized\n"); ret = -EPROTONOSUPPORT; goto out_put; } - dev_info(&edev->device, - "aer_inject: Injecting errors %08x/%08x into device %s\n", + pci_info(edev->port, "Injecting errors %08x/%08x into device %s\n", einj->cor_status, einj->uncor_status, pci_name(dev)); local_irq_disable(); generic_handle_irq(edev->irq); local_irq_enable(); } else { - pci_err(rpdev, "aer_inject: AER device not found\n"); + pci_err(rpdev, "AER device not found\n"); ret = -ENODEV; } out_put: -- cgit From 7e696b8ae9a7f939584284a12eec3b7c62123836 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 8 May 2019 14:59:00 -0500 Subject: PCI: pciehp: Remove pciehp_debug uses We're about to convert pciehp to the dyndbg mechanism, which means we can eventually remove pciehp_debug. Replace uses of pciehp_debug with dbg() and ctrl_dbg(), which check pciehp_debug internally. Link: https://lore.kernel.org/lkml/20190509141456.223614-6-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch Reviewed-by: Andy Shevchenko --- drivers/pci/hotplug/pciehp_hpc.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 6a2365cd794e..e121f1c06c21 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -232,8 +232,8 @@ static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) delay -= step; } while (delay > 0); - if (count > 1 && pciehp_debug) - printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", + if (count > 1) + dbg("pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), count, step, l); @@ -822,14 +822,11 @@ static inline void dbg_ctrl(struct controller *ctrl) struct pci_dev *pdev = ctrl->pcie->port; u16 reg16; - if (!pciehp_debug) - return; - - ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); + ctrl_dbg(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, ®16); - ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16); + ctrl_dbg(ctrl, "Slot Status : 0x%04x\n", reg16); pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, ®16); - ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16); + ctrl_dbg(ctrl, "Slot Control : 0x%04x\n", reg16); } #define FLAG(x, y) (((x) & (y)) ? '+' : '-') -- cgit From 017124725c155a3e1b09429d27c5846b0efafa89 Mon Sep 17 00:00:00 2001 From: Frederick Lawler Date: Tue, 7 May 2019 18:24:52 -0500 Subject: PCI: pciehp: Replace pciehp_debug module param with dyndbg Previously pciehp debug messages were enabled by the pciehp_debug module parameter, e.g., by booting with this kernel command line option: pciehp.pciehp_debug=1 Convert this mechanism to use the generic dynamic debug (dyndbg) feature. After this commit, pciehp debug messages are enabled by building the kernel with CONFIG_DYNAMIC_DEBUG=y and booting with this command line option: dyndbg="file pciehp* +p" The dyndbg facility is much more flexible: messages can be enabled at boot- or run-time based on the file name, function name, line number, message test, etc. See Documentation/admin-guide/dynamic-debug-howto.rst for more details. Link: https://lore.kernel.org/lkml/20190509141456.223614-7-helgaas@kernel.org Signed-off-by: Frederick Lawler [bhelgaas: commit log, comment, remove pciehp_debug parameter] Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch Reviewed-by: Andy Shevchenko --- drivers/pci/hotplug/pciehp.h | 16 ++++++---------- drivers/pci/hotplug/pciehp_core.c | 3 --- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 506e1d923a1f..af5d9f92e6d5 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -29,13 +29,13 @@ extern bool pciehp_poll_mode; extern int pciehp_poll_time; -extern bool pciehp_debug; +/* + * Set CONFIG_DYNAMIC_DEBUG=y and boot with 'dyndbg="file pciehp* +p"' to + * enable debug messages. + */ #define dbg(format, arg...) \ -do { \ - if (pciehp_debug) \ - printk(KERN_DEBUG "%s: " format, MY_NAME, ## arg); \ -} while (0) + pr_debug("%s: " format, MY_NAME, ## arg); #define err(format, arg...) \ printk(KERN_ERR "%s: " format, MY_NAME, ## arg) #define info(format, arg...) \ @@ -44,11 +44,7 @@ do { \ printk(KERN_WARNING "%s: " format, MY_NAME, ## arg) #define ctrl_dbg(ctrl, format, arg...) \ - do { \ - if (pciehp_debug) \ - dev_printk(KERN_DEBUG, &ctrl->pcie->device, \ - format, ## arg); \ - } while (0) + dev_dbg(&ctrl->pcie->device, format, ## arg) #define ctrl_err(ctrl, format, arg...) \ dev_err(&ctrl->pcie->device, format, ## arg) #define ctrl_info(ctrl, format, arg...) \ diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index fc5366b50e95..6ff204c435bf 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -27,7 +27,6 @@ #include "../pci.h" /* Global variables */ -bool pciehp_debug; bool pciehp_poll_mode; int pciehp_poll_time; @@ -35,10 +34,8 @@ int pciehp_poll_time; * not really modular, but the easiest way to keep compat with existing * bootargs behaviour is to continue using module_param here. */ -module_param(pciehp_debug, bool, 0644); module_param(pciehp_poll_mode, bool, 0644); module_param(pciehp_poll_time, int, 0644); -MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); -- cgit From 94dbc9562edc745d0549f1744ca1bd75e644473e Mon Sep 17 00:00:00 2001 From: Frederick Lawler Date: Tue, 7 May 2019 18:24:51 -0500 Subject: PCI: pciehp: Log messages with pci_dev, not pcie_device Log messages with pci_dev, not pcie_device. Factor out common message prefixes with dev_fmt(). Example output change: - pciehp 0000:00:06.0:pcie004: Slot(0) Powering on due to button press + pcieport 0000:00:06.0: pciehp: Slot(0) Powering on due to button press Link: https://lore.kernel.org/lkml/20190509141456.223614-8-helgaas@kernel.org Signed-off-by: Frederick Lawler Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch Reviewed-by: Andy Shevchenko --- drivers/pci/hotplug/pciehp.h | 16 ++++++++-------- drivers/pci/hotplug/pciehp_core.c | 7 +++++-- drivers/pci/hotplug/pciehp_ctrl.c | 2 ++ drivers/pci/hotplug/pciehp_hpc.c | 2 ++ drivers/pci/hotplug/pciehp_pci.c | 2 ++ 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index af5d9f92e6d5..2f0295b48d5d 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -35,22 +35,22 @@ extern int pciehp_poll_time; * enable debug messages. */ #define dbg(format, arg...) \ - pr_debug("%s: " format, MY_NAME, ## arg); + pr_debug(format, ## arg); #define err(format, arg...) \ - printk(KERN_ERR "%s: " format, MY_NAME, ## arg) + pr_err(format, ## arg) #define info(format, arg...) \ - printk(KERN_INFO "%s: " format, MY_NAME, ## arg) + pr_info(format, ## arg) #define warn(format, arg...) \ - printk(KERN_WARNING "%s: " format, MY_NAME, ## arg) + pr_warn(format, ## arg) #define ctrl_dbg(ctrl, format, arg...) \ - dev_dbg(&ctrl->pcie->device, format, ## arg) + pci_dbg(ctrl->pcie->port, format, ## arg) #define ctrl_err(ctrl, format, arg...) \ - dev_err(&ctrl->pcie->device, format, ## arg) + pci_err(ctrl->pcie->port, format, ## arg) #define ctrl_info(ctrl, format, arg...) \ - dev_info(&ctrl->pcie->device, format, ## arg) + pci_info(ctrl->pcie->port, format, ## arg) #define ctrl_warn(ctrl, format, arg...) \ - dev_warn(&ctrl->pcie->device, format, ## arg) + pci_warn(ctrl->pcie->port, format, ## arg) #define SLOT_NAME_SIZE 10 diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 6ff204c435bf..b85b22880c50 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -17,6 +17,9 @@ * Dely Sy " */ +#define pr_fmt(fmt) "pciehp: " fmt +#define dev_fmt pr_fmt + #include #include #include @@ -179,14 +182,14 @@ static int pciehp_probe(struct pcie_device *dev) if (!dev->port->subordinate) { /* Can happen if we run out of bus numbers during probe */ - dev_err(&dev->device, + pci_err(dev->port, "Hotplug bridge without secondary bus, ignoring\n"); return -ENODEV; } ctrl = pcie_init(dev); if (!ctrl) { - dev_err(&dev->device, "Controller initialization failed\n"); + pci_err(dev->port, "Controller initialization failed\n"); return -ENODEV; } set_service_data(dev, ctrl); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 3f3df4c29f6e..bf81f977a751 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -13,6 +13,8 @@ * */ +#define dev_fmt(fmt) "pciehp: " fmt + #include #include #include diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index e121f1c06c21..913c7e66504f 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -12,6 +12,8 @@ * Send feedback to , */ +#define dev_fmt(fmt) "pciehp: " fmt + #include #include #include diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index b9c1396db6fe..d17f3bf36f70 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -13,6 +13,8 @@ * */ +#define dev_fmt(fmt) "pciehp: " fmt + #include #include #include -- cgit From 742ee16bc31f42b034a9b3b01731fd6dc20d0b19 Mon Sep 17 00:00:00 2001 From: Frederick Lawler Date: Tue, 7 May 2019 18:24:53 -0500 Subject: PCI: pciehp: Remove unused dbg/err/info/warn() wrappers Replace the last uses of dbg() with the equivalent pr_debug(), then remove unused dbg(), err(), info(), and warn() wrappers. Link: https://lore.kernel.org/lkml/20190509141456.223614-9-helgaas@kernel.org Signed-off-by: Frederick Lawler Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch Reviewed-by: Andy Shevchenko --- drivers/pci/hotplug/pciehp.h | 9 --------- drivers/pci/hotplug/pciehp_core.c | 4 ++-- drivers/pci/hotplug/pciehp_hpc.c | 2 +- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 2f0295b48d5d..c206fd9cd3d7 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -34,15 +34,6 @@ extern int pciehp_poll_time; * Set CONFIG_DYNAMIC_DEBUG=y and boot with 'dyndbg="file pciehp* +p"' to * enable debug messages. */ -#define dbg(format, arg...) \ - pr_debug(format, ## arg); -#define err(format, arg...) \ - pr_err(format, ## arg) -#define info(format, arg...) \ - pr_info(format, ## arg) -#define warn(format, arg...) \ - pr_warn(format, ## arg) - #define ctrl_dbg(ctrl, format, arg...) \ pci_dbg(ctrl->pcie->port, format, ## arg) #define ctrl_err(ctrl, format, arg...) \ diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index b85b22880c50..1643e9aa261c 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -328,9 +328,9 @@ int __init pcie_hp_init(void) int retval = 0; retval = pcie_port_service_register(&hpdriver_portdrv); - dbg("pcie_port_service_register = %d\n", retval); + pr_debug("pcie_port_service_register = %d\n", retval); if (retval) - dbg("Failure to register service\n"); + pr_debug("Failure to register service\n"); return retval; } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 913c7e66504f..9ce93b1034bd 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -235,7 +235,7 @@ static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) } while (delay > 0); if (count > 1) - dbg("pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", + pr_debug("pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n", pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), count, step, l); -- cgit From b498b6872da1143d67ed588d21d3c3c496a987ee Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 8 May 2019 15:23:39 -0500 Subject: PCI: pciehp: Remove pointless PCIE_MODULE_NAME definition PCIE_MODULE_NAME is only used once and offers no benefit, so remove it. Link: https://lore.kernel.org/lkml/20190509141456.223614-10-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch Reviewed-by: Andy Shevchenko --- drivers/pci/hotplug/pciehp_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 1643e9aa261c..6ad0d86762cb 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -42,8 +42,6 @@ module_param(pciehp_poll_time, int, 0644); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); -#define PCIE_MODULE_NAME "pciehp" - static int set_attention_status(struct hotplug_slot *slot, u8 value); static int get_power_status(struct hotplug_slot *slot, u8 *value); static int get_latch_status(struct hotplug_slot *slot, u8 *value); @@ -307,7 +305,7 @@ static int pciehp_runtime_resume(struct pcie_device *dev) #endif /* PM */ static struct pcie_port_service_driver hpdriver_portdrv = { - .name = PCIE_MODULE_NAME, + .name = "pciehp", .port_type = PCIE_ANY_PORT, .service = PCIE_PORT_SERVICE_HP, -- cgit From e07ca82a5fde88b5caf2b7025e97c7980c60abe1 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 8 May 2019 16:34:01 -0500 Subject: PCI: pciehp: Remove pointless MY_NAME definition MY_NAME is only used once and offers no benefit, so remove it. Link: https://lore.kernel.org/lkml/20190509141456.223614-11-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch Reviewed-by: Andy Shevchenko --- drivers/pci/hotplug/pciehp.h | 2 -- drivers/pci/hotplug/pciehp_hpc.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index c206fd9cd3d7..8c51a04b8083 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -25,8 +25,6 @@ #include "../pcie/portdrv.h" -#define MY_NAME "pciehp" - extern bool pciehp_poll_mode; extern int pciehp_poll_time; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 9ce93b1034bd..bd990e3371e3 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -48,7 +48,7 @@ static inline int pciehp_request_irq(struct controller *ctrl) /* Installs the interrupt handler */ retval = request_threaded_irq(irq, pciehp_isr, pciehp_ist, - IRQF_SHARED, MY_NAME, ctrl); + IRQF_SHARED, "pciehp", ctrl); if (retval) ctrl_err(ctrl, "Cannot get irq %d for the hotplug controller\n", irq); -- cgit From 86511dbcfb7aeee3cd4bd27b90bedf51959b7ad4 Mon Sep 17 00:00:00 2001 From: Subrahmanya Lingappa Date: Tue, 7 May 2019 07:45:16 -0400 Subject: MAINTAINERS: Add Karthikeyan Mitran and Hou Zhiqiang for Mobiveil PCI Add Karthikeyan Mitran and Hou Zhiqiang as new maintainers of Mobiveil controller driver. Link: https://lore.kernel.org/linux-pci/1557229516-6870-1-git-send-email-l.subrahmanya@mobiveil.co.in Signed-off-by: Subrahmanya Lingappa [bhelgaas: update names/email addresses to match usage in git history] Signed-off-by: Bjorn Helgaas Acked-by: Karthikeyan Mitran --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index e17ebf70b548..ebc2b758f28d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11880,7 +11880,8 @@ F: include/linux/switchtec.h F: drivers/ntb/hw/mscc/ PCI DRIVER FOR MOBIVEIL PCIE IP -M: Subrahmanya Lingappa +M: Karthikeyan Mitran +M: Hou Zhiqiang L: linux-pci@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/pci/mobiveil-pcie.txt -- cgit