From 8d38821cbcf51292cd5a23469d03bd38932a3ba9 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 1 Aug 2014 14:15:10 +0200 Subject: resources: Add device-managed request/release_resource() Provide device-managed implementations of the request_resource() and release_resource() functions. Upon failure to request a resource, the new devm_request_resource() function will output an error message for consistent error reporting. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas Acked-by: Tejun Heo --- include/linux/ioport.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 142ec544167c..2c5250222278 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -215,6 +215,11 @@ static inline int __deprecated check_region(resource_size_t s, /* Wrappers for managed devices */ struct device; + +extern int devm_request_resource(struct device *dev, struct resource *root, + struct resource *new); +extern void devm_release_resource(struct device *dev, struct resource *new); + #define devm_request_region(dev,start,n,name) \ __devm_request_region(dev, &ioport_resource, (start), (n), (name)) #define devm_request_mem_region(dev,start,n,name) \ -- cgit v1.2.3 From efd01a72e7ec99ed583151fbf16b176cd2158967 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 5 Aug 2014 14:08:55 +0200 Subject: PCI/AER: Make standalone includable The header file references u16 and u32 types, but they are not defined in the header nor does the header pull in the necessary includes for them. This causes build breakage when the file is included without any of the dependencies being satisfied from somewhere else. Fix this by including linux/types.h (for u16 and u32). [bhelgaas: removed pci_dev declaration (already added by 5ccb8225abf2)] Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- include/linux/aer.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/aer.h b/include/linux/aer.h index c826d1c28f9c..4fef65e57023 100644 --- a/include/linux/aer.h +++ b/include/linux/aer.h @@ -7,6 +7,8 @@ #ifndef _AER_H_ #define _AER_H_ +#include + #define AER_NONFATAL 0 #define AER_FATAL 1 #define AER_CORRECTABLE 2 -- cgit v1.2.3 From f3dbd802b3caf8da92173870bc270dda6b3f84ba Mon Sep 17 00:00:00 2001 From: Rajat Jain Date: Tue, 2 Sep 2014 16:26:00 -0700 Subject: PCI: Enable CRS Software Visibility for root port if it is supported Per PCIe r3.0, sec 2.3.2, an endpoint may respond to a Configuration Request with a Completion with Configuration Request Retry Status (CRS). This terminates the Configuration Request. When the CRS Software Visibility feature is disabled (as it is by default), a Root Complex must handle a CRS Completion by re-issuing the Configuration Request. This is invisible to software. From the CPU's point of view, an endpoint that always responds with CRS causes a hang because the Root Complex never supplies data to complete the CPU read. When CRS Software Visibility is enabled, a Root Complex that receives a CRS Completion for a read of the Vendor ID must return data of 0x0001. The Vendor ID of 0x0001 indicates to software that the endpoint is not ready. We now have more devices that require CRS Software Visibility. For example, a PLX 8713 NT bridge may respond with CRS until it has been configured via I2C, and the I2C configuration is completely independent of PCI enumeration. Enable CRS Software Visibility if it is supported. This allows a system with such a device to work (though the PCI core times out waiting for it to become ready, and we have to rescan the bus after it is ready). This essentially reverts ad7edfe04908 ("[PCI] Do not enable CRS Software Visibility by default"). The failures that led to ad7edfe04908 should be addressed by 89665a6a7140 ("PCI: Check only the Vendor ID to identify Configuration Request Retry"). [bhelgaas: changelog] Link: http://lkml.kernel.org/r/20071029061532.5d10dfc6@snowcone Link: http://lkml.kernel.org/r/alpine.LFD.0.9999.0712271023090.21557@woody.linux-foundation.org Signed-off-by: Rajat Jain Signed-off-by: Rajat Jain Signed-off-by: Guenter Roeck Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 13 +++++++++++++ include/uapi/linux/pci_regs.h | 1 + 2 files changed, 14 insertions(+) (limited to 'include') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9c26663c91d2..e02cdaa5bf0c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -740,6 +740,17 @@ struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, } EXPORT_SYMBOL(pci_add_new_bus); +static void pci_enable_crs(struct pci_dev *pdev) +{ + u16 root_cap = 0; + + /* Enable CRS Software Visibility if supported */ + pcie_capability_read_word(pdev, PCI_EXP_RTCAP, &root_cap); + if (root_cap & PCI_EXP_RTCAP_CRSVIS) + pcie_capability_set_word(pdev, PCI_EXP_RTCTL, + PCI_EXP_RTCTL_CRSSVE); +} + /* * If it's a bridge, configure it and scan the bus behind it. * For CardBus bridges, we don't scan behind as the devices will @@ -787,6 +798,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); + pci_enable_crs(dev); + if ((secondary || subordinate) && !pcibios_assign_all_busses() && !is_cardbus && !broken) { unsigned int cmax; diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 30db069bce62..57d6e56a086a 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -552,6 +552,7 @@ #define PCI_EXP_RTCTL_PMEIE 0x0008 /* PME Interrupt Enable */ #define PCI_EXP_RTCTL_CRSSVE 0x0010 /* CRS Software Visibility Enable */ #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 */ -- cgit v1.2.3 From fbfa398b84a5fc6e085dedba5ec3e94f21815d05 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 28 Aug 2014 12:21:44 -0600 Subject: PCI: Remove unused pci_configure_slot() All pci_configure_slot() uses have been removed, so remove the definition as well. Signed-off-by: Bjorn Helgaas Acked-by: Yinghai Lu --- drivers/pci/probe.c | 28 ---------------------------- include/linux/pci_hotplug.h | 2 -- 2 files changed, 30 deletions(-) (limited to 'include') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index e9482867555b..4b3b29bc7a82 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1358,34 +1358,6 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) */ } -void pci_configure_slot(struct pci_dev *dev) -{ - struct pci_dev *cdev; - struct hotplug_params hpp; - int ret; - - if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || - (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) - return; - - pcie_bus_configure_settings(dev->bus); - - memset(&hpp, 0, sizeof(hpp)); - ret = pci_get_hp_params(dev, &hpp); - - program_hpp_type2(dev, hpp.t2); - program_hpp_type1(dev, hpp.t1); - program_hpp_type0(dev, hpp.t0); - - if (dev->subordinate) { - list_for_each_entry(cdev, &dev->subordinate->devices, - bus_list) - pci_configure_slot(cdev); - } -} -EXPORT_SYMBOL_GPL(pci_configure_slot); - static void pci_configure_device(struct pci_dev *dev) { struct hotplug_params hpp; diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 5f2e559af6b0..2706ee9a4327 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -187,6 +187,4 @@ static inline int pci_get_hp_params(struct pci_dev *dev, return -ENODEV; } #endif - -void pci_configure_slot(struct pci_dev *dev); #endif -- cgit v1.2.3 From ce0529843a505d09f5809a7db6288d2f038f64c4 Mon Sep 17 00:00:00 2001 From: Ethan Zhao Date: Tue, 9 Sep 2014 10:21:25 +0800 Subject: PCI: Add device flag helper functions Add helper functions to hide direct device flag operations: void pci_set_dev_assigned(struct pci_dev *dev); void pci_clear_dev_assigned(struct pci_dev *dev); bool pci_is_dev_assigned(struct pci_dev *dev); Signed-off-by: Ethan Zhao Signed-off-by: Bjorn Helgaas --- include/linux/pci.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include') diff --git a/include/linux/pci.h b/include/linux/pci.h index 61978a460841..92c131efec1c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1839,4 +1839,17 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, */ struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); +/* helper functions for operation of device flag */ +static inline void pci_set_dev_assigned(struct pci_dev *pdev) +{ + pdev->dev_flags |= PCI_DEV_FLAGS_ASSIGNED; +} +static inline void pci_clear_dev_assigned(struct pci_dev *pdev) +{ + pdev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; +} +static inline bool pci_is_dev_assigned(struct pci_dev *pdev) +{ + return (pdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED) == PCI_DEV_FLAGS_ASSIGNED; +} #endif /* LINUX_PCI_H */ -- cgit v1.2.3 From e0d1b6b77ced59d852d38fcf9a8a0a1c40c84cee Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 5 Aug 2014 14:08:55 +0200 Subject: PCI/AER: Make standalone includable The header file references u16 and u32 types, but they are not defined in the header nor does the header pull in the necessary includes for them. This causes build breakage when the file is included without any of the dependencies being satisfied from somewhere else. Fix this by including linux/types.h (for u16 and u32). [bhelgaas: removed pci_dev declaration (already added by 5ccb8225abf2)] Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- include/linux/aer.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/aer.h b/include/linux/aer.h index c826d1c28f9c..4fef65e57023 100644 --- a/include/linux/aer.h +++ b/include/linux/aer.h @@ -7,6 +7,8 @@ #ifndef _AER_H_ #define _AER_H_ +#include + #define AER_NONFATAL 0 #define AER_FATAL 1 #define AER_CORRECTABLE 2 -- cgit v1.2.3 From 63ddc0b8fe5ebbac88e2ac84b489470bf3a22965 Mon Sep 17 00:00:00 2001 From: Megan Kamiya Date: Fri, 5 Sep 2014 20:19:10 -0700 Subject: PCI: Parenthesize PCI_DEVID and PCI_VPD_LRDT_ID parameters Add parentheses around parameters in PCI_DEVID and PCI_VPD_LRDT_ID macros to prevent possible expansion errors as described by the CERT Secure Coding Standard: PRE01-C: Use parentheses within macros around parameter names Tested-by: Aaron Brown Signed-off-by: Megan Kamiya Signed-off-by: Jeff Kirsher Signed-off-by: Bjorn Helgaas --- include/linux/pci.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/pci.h b/include/linux/pci.h index 61978a460841..cb744f3925a4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -45,7 +45,7 @@ * In the interest of not exposing interfaces to user-space unnecessarily, * the following kernel-only defines are being added here. */ -#define PCI_DEVID(bus, devfn) ((((u16)bus) << 8) | devfn) +#define PCI_DEVID(bus, devfn) ((((u16)(bus)) << 8) | (devfn)) /* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */ #define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) @@ -1701,7 +1701,7 @@ bool pci_acs_path_enabled(struct pci_dev *start, struct pci_dev *end, u16 acs_flags); #define PCI_VPD_LRDT 0x80 /* Large Resource Data Type */ -#define PCI_VPD_LRDT_ID(x) (x | PCI_VPD_LRDT) +#define PCI_VPD_LRDT_ID(x) ((x) | PCI_VPD_LRDT) /* Large Resource Data Type Tag Item Names */ #define PCI_VPD_LTIN_ID_STRING 0x02 /* Identifier String */ -- cgit v1.2.3 From bee3f304435a9c8c70b135083e23516872a17c98 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 22 Sep 2014 14:46:13 -0600 Subject: PCI: Remove unused pci_find_upstream_pcie_bridge() pci_find_upstream_pcie_bridge() is unused, so remove it. Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas --- drivers/pci/search.c | 34 ---------------------------------- include/linux/pci.h | 11 ----------- 2 files changed, 45 deletions(-) (limited to 'include') diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 827ad831f1dd..a81f413083e4 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -103,40 +103,6 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, return ret; } -/* - * find the upstream PCIe-to-PCI bridge of a PCI device - * if the device is PCIE, return NULL - * if the device isn't connected to a PCIe bridge (that is its parent is a - * legacy PCI bridge and the bridge is directly connected to bus 0), return its - * parent - */ -struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev) -{ - struct pci_dev *tmp = NULL; - - if (pci_is_pcie(pdev)) - return NULL; - while (1) { - if (pci_is_root_bus(pdev->bus)) - break; - pdev = pdev->bus->self; - /* a p2p bridge */ - if (!pci_is_pcie(pdev)) { - tmp = pdev; - continue; - } - /* PCI device should connect to a PCIe bridge */ - if (pci_pcie_type(pdev) != PCI_EXP_TYPE_PCI_BRIDGE) { - /* Busted hardware? */ - WARN_ON_ONCE(1); - return NULL; - } - return pdev; - } - - return tmp; -} - static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) { struct pci_bus *child; diff --git a/include/linux/pci.h b/include/linux/pci.h index 92c131efec1c..bf5a47c0cb42 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1828,17 +1828,6 @@ int pci_for_each_dma_alias(struct pci_dev *pdev, int (*fn)(struct pci_dev *pdev, u16 alias, void *data), void *data); -/** - * pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device - * @pdev: the PCI device - * - * if the device is PCIE, return NULL - * if the device isn't connected to a PCIe bridge (that is its parent is a - * legacy PCI bridge and the bridge is directly connected to bus 0), return its - * parent - */ -struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); - /* helper functions for operation of device flag */ static inline void pci_set_dev_assigned(struct pci_dev *pdev) { -- cgit v1.2.3 From 5d8f4c9fdd67404c9f94683836e49ec8bded2287 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 17 Sep 2014 10:41:13 -0600 Subject: PCI: Remove unused pci_get_dma_source() pci_get_dma_source() is unused, so remove it. We now have dma_alias_devfn() to describe this. Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 51 --------------------------------------------------- include/linux/pci.h | 5 ----- 2 files changed, 56 deletions(-) (limited to 'include') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index da062d8ae36f..01c935cc38dc 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3514,57 +3514,6 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias); /* Intel 82801, https://bugzilla.kernel.org/show_bug.cgi?id=44881#c49 */ DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias); -static struct pci_dev *pci_func_0_dma_source(struct pci_dev *dev) -{ - if (!PCI_FUNC(dev->devfn)) - return pci_dev_get(dev); - - return pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); -} - -static const struct pci_dev_dma_source { - u16 vendor; - u16 device; - struct pci_dev *(*dma_source)(struct pci_dev *dev); -} pci_dev_dma_source[] = { - /* - * https://bugzilla.redhat.com/show_bug.cgi?id=605888 - * - * Some Ricoh devices use the function 0 source ID for DMA on - * other functions of a multifunction device. The DMA devices - * is therefore function 0, which will have implications of the - * iommu grouping of these devices. - */ - { PCI_VENDOR_ID_RICOH, 0xe822, pci_func_0_dma_source }, - { PCI_VENDOR_ID_RICOH, 0xe230, pci_func_0_dma_source }, - { PCI_VENDOR_ID_RICOH, 0xe832, pci_func_0_dma_source }, - { PCI_VENDOR_ID_RICOH, 0xe476, pci_func_0_dma_source }, - { 0 } -}; - -/* - * IOMMUs with isolation capabilities need to be programmed with the - * correct source ID of a device. In most cases, the source ID matches - * the device doing the DMA, but sometimes hardware is broken and will - * tag the DMA as being sourced from a different device. This function - * allows that translation. Note that the reference count of the - * returned device is incremented on all paths. - */ -struct pci_dev *pci_get_dma_source(struct pci_dev *dev) -{ - const struct pci_dev_dma_source *i; - - for (i = pci_dev_dma_source; i->dma_source; i++) { - if ((i->vendor == dev->vendor || - i->vendor == (u16)PCI_ANY_ID) && - (i->device == dev->device || - i->device == (u16)PCI_ANY_ID)) - return i->dma_source(dev); - } - - return pci_dev_get(dev); -} - /* * AMD has indicated that the devices below do not support peer-to-peer * in any system where they are found in the southbridge with an AMD diff --git a/include/linux/pci.h b/include/linux/pci.h index bf5a47c0cb42..d68d8e33c196 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1557,16 +1557,11 @@ enum pci_fixup_pass { #ifdef CONFIG_PCI_QUIRKS void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); -struct pci_dev *pci_get_dma_source(struct pci_dev *dev); int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); void pci_dev_specific_enable_acs(struct pci_dev *dev); #else static inline void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) { } -static inline struct pci_dev *pci_get_dma_source(struct pci_dev *dev) -{ - return pci_dev_get(dev); -} static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags) { -- cgit v1.2.3 From 94e57fea62020dbf6e5d0093eabcd28366e86044 Mon Sep 17 00:00:00 2001 From: Francesco Ruggeri Date: Wed, 24 Sep 2014 10:12:41 -0700 Subject: PCI: Move PCI_VENDOR_ID_VMWARE to pci_ids.h Move PCI_VENDOR_ID_VMWARE from device-specific files to pci_ids.h. It is useful to always have access to it, especially when accessing subsystem_vendor_id on emulated devices. [bhelgaas: keep pci_ids.h sorted and use lower-case hex] Signed-off-by: Francesco Ruggeri Signed-off-by: Bjorn Helgaas --- drivers/gpu/drm/vmwgfx/svga_reg.h | 1 - drivers/misc/vmw_vmci/vmci_guest.c | 1 - drivers/net/vmxnet3/vmxnet3_int.h | 1 - drivers/scsi/vmw_pvscsi.h | 1 - include/linux/pci_ids.h | 2 ++ 5 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h index 11323dd5196f..e4259c2c1acc 100644 --- a/drivers/gpu/drm/vmwgfx/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga_reg.h @@ -35,7 +35,6 @@ /* * PCI device IDs. */ -#define PCI_VENDOR_ID_VMWARE 0x15AD #define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 /* diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index 248399a881af..189b32519748 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -35,7 +35,6 @@ #include "vmci_driver.h" #include "vmci_event.h" -#define PCI_VENDOR_ID_VMWARE 0x15AD #define PCI_DEVICE_ID_VMWARE_VMCI 0x0740 #define VMCI_UTIL_NUM_RESOURCES 1 diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 29ee77f2c97f..c388ef509d66 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -117,7 +117,6 @@ enum { /* * PCI vendor and device IDs. */ -#define PCI_VENDOR_ID_VMWARE 0x15AD #define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0 #define MAX_ETHERNET_CARDS 10 #define MAX_PCI_PASSTHRU_DEVICE 6 diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h index ce4588851274..ee16f0c5c47d 100644 --- a/drivers/scsi/vmw_pvscsi.h +++ b/drivers/scsi/vmw_pvscsi.h @@ -32,7 +32,6 @@ #define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */ -#define PCI_VENDOR_ID_VMWARE 0x15AD #define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 /* diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6ed0bb73a864..da9e6f753196 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2245,6 +2245,8 @@ #define PCI_VENDOR_ID_MORETON 0x15aa #define PCI_DEVICE_ID_RASTEL_2PORT 0x2000 +#define PCI_VENDOR_ID_VMWARE 0x15ad + #define PCI_VENDOR_ID_ZOLTRIX 0x15b0 #define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0 -- cgit v1.2.3 From 99d440242c08c8a95576c0bc89278f8912f65bda Mon Sep 17 00:00:00 2001 From: "Chen, Gong" Date: Wed, 13 Aug 2014 02:22:37 -0400 Subject: trace, RAS: Replace bare numbers with #defines for PCIe AER error strings Replace bare numbers like "BIT(0)" with the existing #defines, e.g., PCI_ERR_COR_RCVR, to improve maintainability. This way grep will find more uses of the #defines. No functional change. [bhelgaas: changelog] Signed-off-by: Chen, Gong Signed-off-by: Bjorn Helgaas --- include/ras/ras_event.h | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h index 47da53c27ffa..0f2cca4ccbf0 100644 --- a/include/ras/ras_event.h +++ b/include/ras/ras_event.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -174,24 +175,24 @@ TRACE_EVENT(mc_event, */ #define aer_correctable_errors \ - {BIT(0), "Receiver Error"}, \ - {BIT(6), "Bad TLP"}, \ - {BIT(7), "Bad DLLP"}, \ - {BIT(8), "RELAY_NUM Rollover"}, \ - {BIT(12), "Replay Timer Timeout"}, \ - {BIT(13), "Advisory Non-Fatal"} + {PCI_ERR_COR_RCVR, "Receiver Error"}, \ + {PCI_ERR_COR_BAD_TLP, "Bad TLP"}, \ + {PCI_ERR_COR_BAD_DLLP, "Bad DLLP"}, \ + {PCI_ERR_COR_REP_ROLL, "RELAY_NUM Rollover"}, \ + {PCI_ERR_COR_REP_TIMER, "Replay Timer Timeout"},\ + {PCI_ERR_COR_ADV_NFAT, "Advisory Non-Fatal"} #define aer_uncorrectable_errors \ - {BIT(4), "Data Link Protocol"}, \ - {BIT(12), "Poisoned TLP"}, \ - {BIT(13), "Flow Control Protocol"}, \ - {BIT(14), "Completion Timeout"}, \ - {BIT(15), "Completer Abort"}, \ - {BIT(16), "Unexpected Completion"}, \ - {BIT(17), "Receiver Overflow"}, \ - {BIT(18), "Malformed TLP"}, \ - {BIT(19), "ECRC"}, \ - {BIT(20), "Unsupported Request"} + {PCI_ERR_UNC_DLP, "Data Link Protocol"}, \ + {PCI_ERR_UNC_POISON_TLP,"Poisoned TLP"}, \ + {PCI_ERR_UNC_FCP, "Flow Control Protocol"}, \ + {PCI_ERR_UNC_COMP_TIME, "Completion Timeout"}, \ + {PCI_ERR_UNC_COMP_ABORT,"Completer Abort"}, \ + {PCI_ERR_UNC_UNX_COMP, "Unexpected Completion"}, \ + {PCI_ERR_UNC_RX_OVER, "Receiver Overflow"}, \ + {PCI_ERR_UNC_MALF_TLP, "Malformed TLP"}, \ + {PCI_ERR_UNC_ECRC, "ECRC"}, \ + {PCI_ERR_UNC_UNSUP, "Unsupported Request"} TRACE_EVENT(aer_event, TP_PROTO(const char *dev_name, -- cgit v1.2.3 From cb9a684acb3d79a5431ac78832148817debf3a06 Mon Sep 17 00:00:00 2001 From: "Chen, Gong" Date: Wed, 13 Aug 2014 02:22:39 -0400 Subject: trace, RAS: Add additional PCIe AER error strings Add all AER error bits defined in PCIe r3.0. [bhelgaas: changelog] Signed-off-by: Chen, Gong Signed-off-by: Bjorn Helgaas --- include/ras/ras_event.h | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h index 0f2cca4ccbf0..0f04a9755d1e 100644 --- a/include/ras/ras_event.h +++ b/include/ras/ras_event.h @@ -174,25 +174,34 @@ TRACE_EVENT(mc_event, * u8 severity - error severity 0:NONFATAL 1:FATAL 2:CORRECTED */ -#define aer_correctable_errors \ - {PCI_ERR_COR_RCVR, "Receiver Error"}, \ - {PCI_ERR_COR_BAD_TLP, "Bad TLP"}, \ - {PCI_ERR_COR_BAD_DLLP, "Bad DLLP"}, \ - {PCI_ERR_COR_REP_ROLL, "RELAY_NUM Rollover"}, \ - {PCI_ERR_COR_REP_TIMER, "Replay Timer Timeout"},\ - {PCI_ERR_COR_ADV_NFAT, "Advisory Non-Fatal"} - -#define aer_uncorrectable_errors \ - {PCI_ERR_UNC_DLP, "Data Link Protocol"}, \ +#define aer_correctable_errors \ + {PCI_ERR_COR_RCVR, "Receiver Error"}, \ + {PCI_ERR_COR_BAD_TLP, "Bad TLP"}, \ + {PCI_ERR_COR_BAD_DLLP, "Bad DLLP"}, \ + {PCI_ERR_COR_REP_ROLL, "RELAY_NUM Rollover"}, \ + {PCI_ERR_COR_REP_TIMER, "Replay Timer Timeout"}, \ + {PCI_ERR_COR_ADV_NFAT, "Advisory Non-Fatal Error"}, \ + {PCI_ERR_COR_INTERNAL, "Corrected Internal Error"}, \ + {PCI_ERR_COR_LOG_OVER, "Header Log Overflow"} + +#define aer_uncorrectable_errors \ + {PCI_ERR_UNC_TRAIN, "Undefined"}, \ + {PCI_ERR_UNC_DLP, "Data Link Protocol Error"}, \ + {PCI_ERR_UNC_SURPDN, "Surprise Down Error"}, \ {PCI_ERR_UNC_POISON_TLP,"Poisoned TLP"}, \ - {PCI_ERR_UNC_FCP, "Flow Control Protocol"}, \ + {PCI_ERR_UNC_FCP, "Flow Control Protocol Error"}, \ {PCI_ERR_UNC_COMP_TIME, "Completion Timeout"}, \ {PCI_ERR_UNC_COMP_ABORT,"Completer Abort"}, \ {PCI_ERR_UNC_UNX_COMP, "Unexpected Completion"}, \ {PCI_ERR_UNC_RX_OVER, "Receiver Overflow"}, \ {PCI_ERR_UNC_MALF_TLP, "Malformed TLP"}, \ - {PCI_ERR_UNC_ECRC, "ECRC"}, \ - {PCI_ERR_UNC_UNSUP, "Unsupported Request"} + {PCI_ERR_UNC_ECRC, "ECRC Error"}, \ + {PCI_ERR_UNC_UNSUP, "Unsupported Request Error"}, \ + {PCI_ERR_UNC_ACSV, "ACS Violation"}, \ + {PCI_ERR_UNC_INTN, "Uncorrectable Internal Error"},\ + {PCI_ERR_UNC_MCBTLP, "MC Blocked TLP"}, \ + {PCI_ERR_UNC_ATOMEG, "AtomicOp Egress Blocked"}, \ + {PCI_ERR_UNC_TLPPRE, "TLP Prefix Blocked Error"} TRACE_EVENT(aer_event, TP_PROTO(const char *dev_name, -- cgit v1.2.3 From 846fc70986a65563a19ae86928c3acf34f12296d Mon Sep 17 00:00:00 2001 From: "Chen, Gong" Date: Wed, 13 Aug 2014 02:22:40 -0400 Subject: PCI/AER: Rename PCI_ERR_UNC_TRAIN to PCI_ERR_UNC_UND In PCIe r1.0, sec 5.10.2, bit 0 of the Uncorrectable Error Status, Mask, and Severity Registers was for "Training Error." In PCIe r1.1, sec 7.10.2, bit 0 was redefined to be "Undefined." Rename PCI_ERR_UNC_TRAIN to PCI_ERR_UNC_UND to reflect this change. No functional change. [bhelgaas: changelog] Signed-off-by: Chen, Gong Signed-off-by: Bjorn Helgaas --- drivers/vfio/pci/vfio_pci_config.c | 2 +- include/ras/ras_event.h | 2 +- include/uapi/linux/pci_regs.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index e50790e91f76..1de3f94aa7de 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -727,7 +727,7 @@ static int __init init_pci_ext_cap_err_perm(struct perm_bits *perm) p_setd(perm, 0, ALL_VIRT, NO_WRITE); /* Writable bits mask */ - mask = PCI_ERR_UNC_TRAIN | /* Training */ + mask = PCI_ERR_UNC_UND | /* Undefined */ PCI_ERR_UNC_DLP | /* Data Link Protocol */ PCI_ERR_UNC_SURPDN | /* Surprise Down */ PCI_ERR_UNC_POISON_TLP | /* Poisoned TLP */ diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h index 0f04a9755d1e..79abb9c71772 100644 --- a/include/ras/ras_event.h +++ b/include/ras/ras_event.h @@ -185,7 +185,7 @@ TRACE_EVENT(mc_event, {PCI_ERR_COR_LOG_OVER, "Header Log Overflow"} #define aer_uncorrectable_errors \ - {PCI_ERR_UNC_TRAIN, "Undefined"}, \ + {PCI_ERR_UNC_UND, "Undefined"}, \ {PCI_ERR_UNC_DLP, "Data Link Protocol Error"}, \ {PCI_ERR_UNC_SURPDN, "Surprise Down Error"}, \ {PCI_ERR_UNC_POISON_TLP,"Poisoned TLP"}, \ diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 30db069bce62..99e3182f2c96 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -630,7 +630,7 @@ /* Advanced Error Reporting */ #define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ -#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */ +#define PCI_ERR_UNC_UND 0x00000001 /* Undefined */ #define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ #define PCI_ERR_UNC_SURPDN 0x00000020 /* Surprise Down */ #define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ -- cgit v1.2.3 From 112eeaa7f87bbd2925e919486bb504f8954fa675 Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:20 +0100 Subject: asm-generic/io.h: Fix ioport_map() for !CONFIG_GENERIC_IOMAP The !CONFIG_GENERIC_IOMAP version of ioport_map() is wrong. It returns a mapped, i.e., virtual, address that can start from zero and completely ignores the PCI_IOBASE and IO_SPACE_LIMIT that most architectures that use !CONFIG_GENERIC_MAP define. Tested-by: Tanmay Inamdar Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas Reviewed-by: Catalin Marinas Acked-by: Arnd Bergmann --- include/asm-generic/io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index 975e1cc75edb..b8fdc57a7335 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -331,7 +331,7 @@ static inline void iounmap(void __iomem *addr) #ifndef CONFIG_GENERIC_IOMAP static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) { - return (void __iomem *) port; + return PCI_IOBASE + (port & IO_SPACE_LIMIT); } static inline void ioport_unmap(void __iomem *p) -- cgit v1.2.3 From 41f8bba7f5552d033583777dede2df7c36e7853d Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:21 +0100 Subject: of/pci: Add pci_register_io_range() and pci_pio_to_address() Some architectures do not have a simple view of the PCI I/O space and instead use a range of CPU addresses that map to bus addresses. For some architectures these ranges will be expressed by OF bindings in a device tree file. This patch introduces a pci_register_io_range() helper function with a generic implementation that can be used by such architectures to keep track of the I/O ranges described by the PCI bindings. If the PCI_IOBASE macro is not defined, that signals lack of support for PCI and we return an error. In order to retrieve the CPU address associated with an I/O port, a new helper function pci_pio_to_address() is introduced. This will search in the list of ranges registered with pci_register_io_range() and return the CPU address that corresponds to the given port. [arnd: add dummy !CONFIG_OF pci_pio_to_address() to fix build errors] Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas Reviewed-by: Catalin Marinas Acked-by: Rob Herring CC: Grant Likely --- drivers/of/address.c | 109 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/of_address.h | 7 +++ 2 files changed, 116 insertions(+) (limited to 'include') diff --git a/drivers/of/address.c b/drivers/of/address.c index e3718250d66e..758d4f04d4aa 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include /* Max address size we deal with */ @@ -601,12 +603,119 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, } EXPORT_SYMBOL(of_get_address); +#ifdef PCI_IOBASE +struct io_range { + struct list_head list; + phys_addr_t start; + resource_size_t size; +}; + +static LIST_HEAD(io_range_list); +static DEFINE_SPINLOCK(io_range_lock); +#endif + +/* + * Record the PCI IO range (expressed as CPU physical address + size). + * Return a negative value if an error has occured, zero otherwise + */ +int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size) +{ + int err = 0; + +#ifdef PCI_IOBASE + struct io_range *range; + resource_size_t allocated_size = 0; + + /* check if the range hasn't been previously recorded */ + spin_lock(&io_range_lock); + list_for_each_entry(range, &io_range_list, list) { + if (addr >= range->start && addr + size <= range->start + size) { + /* range already registered, bail out */ + goto end_register; + } + allocated_size += range->size; + } + + /* range not registed yet, check for available space */ + if (allocated_size + size - 1 > IO_SPACE_LIMIT) { + /* if it's too big check if 64K space can be reserved */ + if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) { + err = -E2BIG; + goto end_register; + } + + size = SZ_64K; + pr_warn("Requested IO range too big, new size set to 64K\n"); + } + + /* add the range to the list */ + range = kzalloc(sizeof(*range), GFP_KERNEL); + if (!range) { + err = -ENOMEM; + goto end_register; + } + + range->start = addr; + range->size = size; + + list_add_tail(&range->list, &io_range_list); + +end_register: + spin_unlock(&io_range_lock); +#endif + + return err; +} + +phys_addr_t pci_pio_to_address(unsigned long pio) +{ + phys_addr_t address = (phys_addr_t)OF_BAD_ADDR; + +#ifdef PCI_IOBASE + struct io_range *range; + resource_size_t allocated_size = 0; + + if (pio > IO_SPACE_LIMIT) + return address; + + spin_lock(&io_range_lock); + list_for_each_entry(range, &io_range_list, list) { + if (pio >= allocated_size && pio < allocated_size + range->size) { + address = range->start + pio - allocated_size; + break; + } + allocated_size += range->size; + } + spin_unlock(&io_range_lock); +#endif + + return address; +} + unsigned long __weak pci_address_to_pio(phys_addr_t address) { +#ifdef PCI_IOBASE + struct io_range *res; + resource_size_t offset = 0; + unsigned long addr = -1; + + spin_lock(&io_range_lock); + list_for_each_entry(res, &io_range_list, list) { + if (address >= res->start && address < res->start + res->size) { + addr = res->start - address + offset; + break; + } + offset += res->size; + } + spin_unlock(&io_range_lock); + + return addr; +#else if (address > IO_SPACE_LIMIT) return (unsigned long)-1; return (unsigned long) address; +#endif } static int __of_address_to_resource(struct device_node *dev, diff --git a/include/linux/of_address.h b/include/linux/of_address.h index fb7b7221e063..497a04356ff8 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -55,7 +55,9 @@ extern void __iomem *of_iomap(struct device_node *device, int index); extern const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags); +extern int pci_register_io_range(phys_addr_t addr, resource_size_t size); extern unsigned long pci_address_to_pio(phys_addr_t addr); +extern phys_addr_t pci_pio_to_address(unsigned long pio); extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, struct device_node *node); @@ -80,6 +82,11 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index, return NULL; } +static inline phys_addr_t pci_pio_to_address(unsigned long pio) +{ + return 0; +} + static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser, struct device_node *node) { -- cgit v1.2.3 From 83bbde1cc0ec9d156b9271e29ffe0dc89c687feb Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:24 +0100 Subject: of/pci: Move of_pci_range_to_resource() to of/address.c We need to enhance of_pci_range_to_resources() enough that it won't make sense for it to be inline anymore. Move it to drivers/of/address.c, under #ifdef CONFIG_PCI. of_address.h previously implemented of_pci_range_to_resources() unconditionally, regardless of any config options. The implementation in address.c is defined only when CONFIG_OF_ADDRESS=y and CONFIG_PCI=y, so add a dummy version to avoid build errors when CONFIG_OF or CONFIG_OF_ADDRESS is not defined. [bhelgaas: drop extra detail from changelog, move def under CONFIG_PCI, add dummy of_pci_range_to_resource() for build errors (from Arnd)] Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas CC: Grant Likely CC: Rob Herring CC: Arnd Bergmann CC: Catalin Marinas --- drivers/of/address.c | 9 +++++++++ include/linux/of_address.h | 20 +++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/of/address.c b/drivers/of/address.c index 758d4f04d4aa..327a57410797 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -295,6 +295,15 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, } EXPORT_SYMBOL_GPL(of_pci_range_parser_one); +void of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, struct resource *res) +{ + res->flags = range->flags; + res->start = range->cpu_addr; + res->end = range->cpu_addr + range->size - 1; + res->parent = res->child = res->sibling = NULL; + res->name = np->full_name; +} #endif /* CONFIG_PCI */ /* diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 497a04356ff8..a38e1c846c23 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -23,17 +23,6 @@ struct of_pci_range { #define for_each_of_pci_range(parser, range) \ for (; of_pci_range_parser_one(parser, range);) -static inline void of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, - struct resource *res) -{ - res->flags = range->flags; - res->start = range->cpu_addr; - res->end = range->cpu_addr + range->size - 1; - res->parent = res->child = res->sibling = NULL; - res->name = np->full_name; -} - /* Translate a DMA address from device space to CPU space */ extern u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr); @@ -145,6 +134,9 @@ extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags); extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); +extern void of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res); #else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ static inline int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r) @@ -157,6 +149,12 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev, { return NULL; } +static inline void of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res) +{ + return -ENOSYS; +} #endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */ #endif /* __OF_ADDRESS_H */ -- cgit v1.2.3 From 0b0b0893d49b34201a6c4416b1a707b580b91e3d Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:25 +0100 Subject: of/pci: Fix the conversion of IO ranges into IO resources The ranges property for a host bridge controller in DT describes the mapping between the PCI bus address and the CPU physical address. The resources framework however expects that the IO resources start at a pseudo "port" address 0 (zero) and have a maximum size of IO_SPACE_LIMIT. The conversion from PCI ranges to resources failed to take that into account, returning a CPU physical address instead of a port number. Also fix all the drivers that depend on the old behaviour by fetching the CPU physical address based on the port number where it is being needed. Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas Acked-by: Linus Walleij CC: Grant Likely CC: Rob Herring CC: Arnd Bergmann CC: Thierry Reding CC: Simon Horman CC: Catalin Marinas --- arch/arm/mach-integrator/pci_v3.c | 23 ++++++++++---------- drivers/of/address.c | 44 +++++++++++++++++++++++++++++++++++---- drivers/pci/host/pci-tegra.c | 10 ++++++--- drivers/pci/host/pcie-rcar.c | 21 +++++++++++++------ include/linux/of_address.h | 12 +++++------ 5 files changed, 80 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c index 05e1f73a1e8d..c186a17c2cff 100644 --- a/arch/arm/mach-integrator/pci_v3.c +++ b/arch/arm/mach-integrator/pci_v3.c @@ -660,6 +660,7 @@ static void __init pci_v3_preinit(void) { unsigned long flags; unsigned int temp; + phys_addr_t io_address = pci_pio_to_address(io_mem.start); pcibios_min_mem = 0x00100000; @@ -701,7 +702,7 @@ static void __init pci_v3_preinit(void) /* * Setup window 2 - PCI IO */ - v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(io_mem.start) | + v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(io_address) | V3_LB_BASE_ENABLE); v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0)); @@ -742,6 +743,7 @@ static void __init pci_v3_preinit(void) static void __init pci_v3_postinit(void) { unsigned int pci_cmd; + phys_addr_t io_address = pci_pio_to_address(io_mem.start); pci_cmd = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; @@ -758,7 +760,7 @@ static void __init pci_v3_postinit(void) "interrupt: %d\n", ret); #endif - register_isa_ports(non_mem.start, io_mem.start, 0); + register_isa_ports(non_mem.start, io_address, 0); } /* @@ -867,33 +869,32 @@ static int __init pci_v3_probe(struct platform_device *pdev) for_each_of_pci_range(&parser, &range) { if (!range.flags) { - of_pci_range_to_resource(&range, np, &conf_mem); + ret = of_pci_range_to_resource(&range, np, &conf_mem); conf_mem.name = "PCIv3 config"; } if (range.flags & IORESOURCE_IO) { - of_pci_range_to_resource(&range, np, &io_mem); + ret = of_pci_range_to_resource(&range, np, &io_mem); io_mem.name = "PCIv3 I/O"; } if ((range.flags & IORESOURCE_MEM) && !(range.flags & IORESOURCE_PREFETCH)) { non_mem_pci = range.pci_addr; non_mem_pci_sz = range.size; - of_pci_range_to_resource(&range, np, &non_mem); + ret = of_pci_range_to_resource(&range, np, &non_mem); non_mem.name = "PCIv3 non-prefetched mem"; } if ((range.flags & IORESOURCE_MEM) && (range.flags & IORESOURCE_PREFETCH)) { pre_mem_pci = range.pci_addr; pre_mem_pci_sz = range.size; - of_pci_range_to_resource(&range, np, &pre_mem); + ret = of_pci_range_to_resource(&range, np, &pre_mem); pre_mem.name = "PCIv3 prefetched mem"; } - } - if (!conf_mem.start || !io_mem.start || - !non_mem.start || !pre_mem.start) { - dev_err(&pdev->dev, "missing ranges in device node\n"); - return -EINVAL; + if (ret < 0) { + dev_err(&pdev->dev, "missing ranges in device node\n"); + return ret; + } } pci_v3.map_irq = of_irq_parse_and_map_pci; diff --git a/drivers/of/address.c b/drivers/of/address.c index 327a57410797..afdb78299f61 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -295,14 +295,50 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, } EXPORT_SYMBOL_GPL(of_pci_range_parser_one); -void of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, struct resource *res) +/* + * of_pci_range_to_resource - Create a resource from an of_pci_range + * @range: the PCI range that describes the resource + * @np: device node where the range belongs to + * @res: pointer to a valid resource that will be updated to + * reflect the values contained in the range. + * + * Returns EINVAL if the range cannot be converted to resource. + * + * Note that if the range is an IO range, the resource will be converted + * using pci_address_to_pio() which can fail if it is called too early or + * if the range cannot be matched to any host bridge IO space (our case here). + * To guard against that we try to register the IO range first. + * If that fails we know that pci_address_to_pio() will do too. + */ +int of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, struct resource *res) { + int err; res->flags = range->flags; - res->start = range->cpu_addr; - res->end = range->cpu_addr + range->size - 1; res->parent = res->child = res->sibling = NULL; res->name = np->full_name; + + if (res->flags & IORESOURCE_IO) { + unsigned long port; + err = pci_register_io_range(range->cpu_addr, range->size); + if (err) + goto invalid_range; + port = pci_address_to_pio(range->cpu_addr); + if (port == (unsigned long)-1) { + err = -EINVAL; + goto invalid_range; + } + res->start = port; + } else { + res->start = range->cpu_addr; + } + res->end = res->start + range->size - 1; + return 0; + +invalid_range: + res->start = (resource_size_t)OF_BAD_ADDR; + res->end = (resource_size_t)OF_BAD_ADDR; + return err; } #endif /* CONFIG_PCI */ diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 0fb0fdb223d5..946935db62b6 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -626,13 +626,14 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable); static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) { struct tegra_pcie *pcie = sys_to_pcie(sys); + phys_addr_t io_start = pci_pio_to_address(pcie->io.start); pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); pci_add_resource_offset(&sys->resources, &pcie->prefetch, sys->mem_offset); pci_add_resource(&sys->resources, &pcie->busn); - pci_ioremap_io(nr * SZ_64K, pcie->io.start); + pci_ioremap_io(nr * SZ_64K, io_start); return 1; } @@ -737,6 +738,7 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg) static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) { u32 fpci_bar, size, axi_address; + phys_addr_t io_start = pci_pio_to_address(pcie->io.start); /* Bar 0: type 1 extended configuration space */ fpci_bar = 0xfe100000; @@ -749,7 +751,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) /* Bar 1: downstream IO bar */ fpci_bar = 0xfdfc0000; size = resource_size(&pcie->io); - axi_address = pcie->io.start; + axi_address = io_start; afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); @@ -1520,7 +1522,9 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) } for_each_of_pci_range(&parser, &range) { - of_pci_range_to_resource(&range, np, &res); + err = of_pci_range_to_resource(&range, np, &res); + if (err < 0) + return err; switch (res.flags & IORESOURCE_TYPE_BITS) { case IORESOURCE_IO: diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 4884ee5e07d4..61158e03ab5f 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -323,6 +323,7 @@ static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie) /* Setup PCIe address space mappings for each resource */ resource_size_t size; + resource_size_t res_start; u32 mask; rcar_pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win)); @@ -335,8 +336,13 @@ static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie) mask = (roundup_pow_of_two(size) / SZ_128) - 1; rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win)); - rcar_pci_write_reg(pcie, upper_32_bits(res->start), PCIEPARH(win)); - rcar_pci_write_reg(pcie, lower_32_bits(res->start), PCIEPARL(win)); + if (res->flags & IORESOURCE_IO) + res_start = pci_pio_to_address(res->start); + else + res_start = res->start; + + rcar_pci_write_reg(pcie, upper_32_bits(res_start), PCIEPARH(win)); + rcar_pci_write_reg(pcie, lower_32_bits(res_start), PCIEPARL(win)); /* First resource is for IO */ mask = PAR_ENABLE; @@ -363,9 +369,10 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys) rcar_pcie_setup_window(i, pcie); - if (res->flags & IORESOURCE_IO) - pci_ioremap_io(nr * SZ_64K, res->start); - else + if (res->flags & IORESOURCE_IO) { + phys_addr_t io_start = pci_pio_to_address(res->start); + pci_ioremap_io(nr * SZ_64K, io_start); + } else pci_add_resource(&sys->resources, res); } pci_add_resource(&sys->resources, &pcie->busn); @@ -935,8 +942,10 @@ static int rcar_pcie_probe(struct platform_device *pdev) } for_each_of_pci_range(&parser, &range) { - of_pci_range_to_resource(&range, pdev->dev.of_node, + err = of_pci_range_to_resource(&range, pdev->dev.of_node, &pcie->res[win++]); + if (err < 0) + return err; if (win > RCAR_PCI_MAX_RESOURCES) break; diff --git a/include/linux/of_address.h b/include/linux/of_address.h index a38e1c846c23..8cb14eb393d6 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -134,9 +134,9 @@ extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags); extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); -extern void of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, - struct resource *res); +extern int of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res); #else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ static inline int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r) @@ -149,9 +149,9 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev, { return NULL; } -static inline void of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, - struct resource *res) +static inline int of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res) { return -ENOSYS; } -- cgit v1.2.3 From 670ba0c8883b576d0aec28bd7a838358a4be1406 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 29 Sep 2014 15:29:26 +0100 Subject: PCI: Add generic domain handling The handling of PCI domains (or PCI segments in ACPI speak) is usually a straightforward affair but its implementation is currently left to the architectural code, with pci_domain_nr(b) querying the value of the domain associated with bus b. This patch introduces CONFIG_PCI_DOMAINS_GENERIC as an option that can be selected if an architecture wants a simple implementation where the value of the domain associated with a bus is stored in struct pci_bus. The architectures that select CONFIG_PCI_DOMAINS_GENERIC will then have to implement pci_bus_assign_domain_nr() as a way of setting the domain number associated with a root bus. All child buses except the root bus will inherit the domain_nr value from their parent. Signed-off-by: Catalin Marinas [Renamed pci_set_domain_nr() to pci_bus_assign_domain_nr()] Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas CC: Arnd Bergmann --- drivers/pci/probe.c | 11 ++++++++--- include/linux/pci.h | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index e3cf8a2e6292..636d1c9156a9 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -485,7 +485,7 @@ void pci_read_bridge_bases(struct pci_bus *child) } } -static struct pci_bus *pci_alloc_bus(void) +static struct pci_bus *pci_alloc_bus(struct pci_bus *parent) { struct pci_bus *b; @@ -500,6 +500,10 @@ static struct pci_bus *pci_alloc_bus(void) INIT_LIST_HEAD(&b->resources); b->max_bus_speed = PCI_SPEED_UNKNOWN; b->cur_bus_speed = PCI_SPEED_UNKNOWN; +#ifdef CONFIG_PCI_DOMAINS_GENERIC + if (parent) + b->domain_nr = parent->domain_nr; +#endif return b; } @@ -671,7 +675,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, /* * Allocate a new bus, and inherit stuff from the parent.. */ - child = pci_alloc_bus(); + child = pci_alloc_bus(parent); if (!child) return NULL; @@ -1761,13 +1765,14 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, char bus_addr[64]; char *fmt; - b = pci_alloc_bus(); + b = pci_alloc_bus(NULL); if (!b) return NULL; b->sysdata = sysdata; b->ops = ops; b->number = b->busn_res.start = bus; + pci_bus_assign_domain_nr(b, parent); b2 = pci_find_bus(pci_domain_nr(b), bus); if (b2) { /* If we already got to this bus through a different bridge, ignore it */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 61978a460841..a494e5d775c3 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -456,6 +456,9 @@ struct pci_bus { unsigned char primary; /* number of primary bridge */ unsigned char max_bus_speed; /* enum pci_bus_speed */ unsigned char cur_bus_speed; /* enum pci_bus_speed */ +#ifdef CONFIG_PCI_DOMAINS_GENERIC + int domain_nr; +#endif char name[48]; @@ -1288,6 +1291,24 @@ static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } static inline int pci_proc_domain(struct pci_bus *bus) { return 0; } #endif /* CONFIG_PCI_DOMAINS */ +/* + * Generic implementation for PCI domain support. If your + * architecture does not need custom management of PCI + * domains then this implementation will be used + */ +#ifdef CONFIG_PCI_DOMAINS_GENERIC +static inline int pci_domain_nr(struct pci_bus *bus) +{ + return bus->domain_nr; +} +void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent); +#else +static inline void pci_bus_assign_domain_nr(struct pci_bus *bus, + struct device *parent) +{ +} +#endif + /* some architectures require additional setup to direct VGA traffic */ typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode, unsigned int command_bits, u32 flags); -- cgit v1.2.3 From 41e5c0f81d3e676d671d96a0a1fafb27abfbd9d7 Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:27 +0100 Subject: of/pci: Add pci_get_new_domain_nr() and of_get_pci_domain_nr() Add pci_get_new_domain_nr() to allocate a new domain number and of_get_pci_domain_nr() to retrieve the PCI domain number of a given device from DT. Host bridge drivers or architecture-specific code can choose to implement their PCI domain number policy using these two functions. Using of_get_pci_domain_nr() guarantees a stable PCI domain number on every boot provided that all host bridge controllers are assigned a number in the device tree using "linux,pci-domain" property. Mixing use of pci_get_new_domain_nr() and of_get_pci_domain_nr() is not recommended as it can lead to potentially conflicting domain numbers being assigned to root buses behind different host bridges. Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas CC: Arnd Bergmann CC: Grant Likely CC: Rob Herring CC: Catalin Marinas --- drivers/of/of_pci.c | 25 +++++++++++++++++++++++++ drivers/pci/pci.c | 9 +++++++++ include/linux/of_pci.h | 7 +++++++ include/linux/pci.h | 3 +++ 4 files changed, 44 insertions(+) (limited to 'include') diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 848199633798..82d172fa145a 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -89,6 +89,31 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res) } EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); +/** + * This function will try to obtain the host bridge domain number by + * finding a property called "linux,pci-domain" of the given device node. + * + * @node: device tree node with the domain information + * + * Returns the associated domain number from DT in the range [0-0xffff], or + * a negative value if the required property is not found. + */ +int of_get_pci_domain_nr(struct device_node *node) +{ + const __be32 *value; + int len; + u16 domain; + + value = of_get_property(node, "linux,pci-domain", &len); + if (!value || len < sizeof(*value)) + return -EINVAL; + + domain = (u16)be32_to_cpup(value); + + return domain; +} +EXPORT_SYMBOL_GPL(of_get_pci_domain_nr); + #ifdef CONFIG_PCI_MSI static LIST_HEAD(of_pci_msi_chip_list); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2c9ac70254e2..d36f35ff6c5d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4406,6 +4406,15 @@ static void pci_no_domains(void) #endif } +#ifdef CONFIG_PCI_DOMAINS +static atomic_t __domain_nr = ATOMIC_INIT(-1); + +int pci_get_new_domain_nr(void) +{ + return atomic_inc_return(&__domain_nr); +} +#endif + /** * pci_ext_cfg_avail - can we access extended PCI config space? * diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index dde3a4a0fa5d..71062e9602f5 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -15,6 +15,7 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, int of_pci_get_devfn(struct device_node *np); int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); int of_pci_parse_bus_range(struct device_node *node, struct resource *res); +int of_get_pci_domain_nr(struct device_node *node); #else static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq) { @@ -43,6 +44,12 @@ of_pci_parse_bus_range(struct device_node *node, struct resource *res) { return -EINVAL; } + +static inline int +of_get_pci_domain_nr(struct device_node *node) +{ + return -1; +} #endif #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI) diff --git a/include/linux/pci.h b/include/linux/pci.h index a494e5d775c3..150da2d644e7 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1285,10 +1285,12 @@ void pci_cfg_access_unlock(struct pci_dev *dev); */ #ifdef CONFIG_PCI_DOMAINS extern int pci_domains_supported; +int pci_get_new_domain_nr(void); #else enum { pci_domains_supported = 0 }; static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } static inline int pci_proc_domain(struct pci_bus *bus) { return 0; } +static inline int pci_get_new_domain_nr(void) { return -ENOSYS; } #endif /* CONFIG_PCI_DOMAINS */ /* @@ -1417,6 +1419,7 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; } +static inline int pci_get_new_domain_nr(void) { return -ENOSYS; } #define dev_is_pci(d) (false) #define dev_is_pf(d) (false) -- cgit v1.2.3 From cbe4097f8ae699ebbdaf8c95ecab38d47e0bd5da Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:28 +0100 Subject: of/pci: Add support for parsing PCI host bridge resources from DT Provide a function to parse the PCI DT ranges that can be used to create a pci_host_bridge structure together with its associated bus. Signed-off-by: Liviu Dudau [make io_base parameter optional] Signed-off-by: Robert Richter Signed-off-by: Bjorn Helgaas CC: Arnd Bergmann CC: Grant Likely CC: Rob Herring CC: Catalin Marinas --- drivers/of/of_pci.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/of_pci.h | 6 +++ 2 files changed, 123 insertions(+) (limited to 'include') diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 82d172fa145a..8882b467be95 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -1,7 +1,9 @@ #include #include #include +#include #include +#include static inline int __of_pci_pci_compare(struct device_node *node, unsigned int data) @@ -114,6 +116,121 @@ int of_get_pci_domain_nr(struct device_node *node) } EXPORT_SYMBOL_GPL(of_get_pci_domain_nr); +#if defined(CONFIG_OF_ADDRESS) +/** + * of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT + * @dev: device node of the host bridge having the range property + * @busno: bus number associated with the bridge root bus + * @bus_max: maximum number of buses for this bridge + * @resources: list where the range of resources will be added after DT parsing + * @io_base: pointer to a variable that will contain on return the physical + * address for the start of the I/O range. Can be NULL if the caller doesn't + * expect IO ranges to be present in the device tree. + * + * It is the caller's job to free the @resources list. + * + * This function will parse the "ranges" property of a PCI host bridge device + * node and setup the resource mapping based on its content. It is expected + * that the property conforms with the Power ePAPR document. + * + * It returns zero if the range parsing has been successful or a standard error + * value if it failed. + */ +int of_pci_get_host_bridge_resources(struct device_node *dev, + unsigned char busno, unsigned char bus_max, + struct list_head *resources, resource_size_t *io_base) +{ + struct resource *res; + struct resource *bus_range; + struct of_pci_range range; + struct of_pci_range_parser parser; + char range_type[4]; + int err; + + if (io_base) + *io_base = (resource_size_t)OF_BAD_ADDR; + + bus_range = kzalloc(sizeof(*bus_range), GFP_KERNEL); + if (!bus_range) + return -ENOMEM; + + pr_info("PCI host bridge %s ranges:\n", dev->full_name); + + err = of_pci_parse_bus_range(dev, bus_range); + if (err) { + bus_range->start = busno; + bus_range->end = bus_max; + bus_range->flags = IORESOURCE_BUS; + pr_info(" No bus range found for %s, using %pR\n", + dev->full_name, bus_range); + } else { + if (bus_range->end > bus_range->start + bus_max) + bus_range->end = bus_range->start + bus_max; + } + pci_add_resource(resources, bus_range); + + /* Check for ranges property */ + err = of_pci_range_parser_init(&parser, dev); + if (err) + goto parse_failed; + + pr_debug("Parsing ranges property...\n"); + for_each_of_pci_range(&parser, &range) { + /* Read next ranges element */ + if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) + snprintf(range_type, 4, " IO"); + else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) + snprintf(range_type, 4, "MEM"); + else + snprintf(range_type, 4, "err"); + pr_info(" %s %#010llx..%#010llx -> %#010llx\n", range_type, + range.cpu_addr, range.cpu_addr + range.size - 1, + range.pci_addr); + + /* + * If we failed translation or got a zero-sized region + * then skip this range + */ + if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) + continue; + + res = kzalloc(sizeof(struct resource), GFP_KERNEL); + if (!res) { + err = -ENOMEM; + goto parse_failed; + } + + err = of_pci_range_to_resource(&range, dev, res); + if (err) + goto conversion_failed; + + if (resource_type(res) == IORESOURCE_IO) { + if (!io_base) { + pr_err("I/O range found for %s. Please provide an io_base pointer to save CPU base address\n", + dev->full_name); + err = -EINVAL; + goto conversion_failed; + } + if (*io_base != (resource_size_t)OF_BAD_ADDR) + pr_warn("More than one I/O resource converted for %s. CPU base address for old range lost!\n", + dev->full_name); + *io_base = range.cpu_addr; + } + + pci_add_resource_offset(resources, res, res->start - range.pci_addr); + } + + return 0; + +conversion_failed: + kfree(res); +parse_failed: + pci_free_resource_list(resources); + return err; +} +EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources); +#endif /* CONFIG_OF_ADDRESS */ + #ifdef CONFIG_PCI_MSI static LIST_HEAD(of_pci_msi_chip_list); diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index 71062e9602f5..1fd207e7a847 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -52,6 +52,12 @@ of_get_pci_domain_nr(struct device_node *node) } #endif +#if defined(CONFIG_OF_ADDRESS) +int of_pci_get_host_bridge_resources(struct device_node *dev, + unsigned char busno, unsigned char bus_max, + struct list_head *resources, resource_size_t *io_base); +#endif + #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI) int of_pci_msi_chip_add(struct msi_chip *chip); void of_pci_msi_chip_remove(struct msi_chip *chip); -- cgit v1.2.3 From 8b921acfeffdb0b45085da862fc301a2d25ed2cf Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:30 +0100 Subject: PCI: Add pci_remap_iospace() to map bus I/O resources Add pci_remap_iospace() to map bus I/O resources into the CPU virtual address space. Architectures with special needs may provide their own version, but most should be able to use this one. This function is useful for PCI host bridge drivers that need to map the PCI I/O resources into virtual memory space. [bhelgaas: phys_addr description, drop temporary "err" variable] Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas Reviewed-by: Rob Herring Reviewed-by: Catalin Marinas CC: Arnd Bergmann --- drivers/pci/pci.c | 31 +++++++++++++++++++++++++++++++ include/asm-generic/pgtable.h | 4 ++++ include/linux/pci.h | 3 +++ 3 files changed, 38 insertions(+) (limited to 'include') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d36f35ff6c5d..6e994fc077f4 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2704,6 +2704,37 @@ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name) } EXPORT_SYMBOL(pci_request_regions_exclusive); +/** + * 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. + */ +int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) +{ +#if defined(PCI_IOBASE) && defined(CONFIG_MMU) + unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start; + + if (!(res->flags & IORESOURCE_IO)) + return -EINVAL; + + if (res->end > IO_SPACE_LIMIT) + return -EINVAL; + + 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 */ + WARN_ONCE(1, "This architecture does not support memory mapped I/O\n"); + return -ENODEV; +#endif +} + static void __pci_set_master(struct pci_dev *dev, bool enable) { u16 old_cmd, cmd; diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 53b2acc38213..977e545a64c3 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -249,6 +249,10 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b) #define pgprot_writecombine pgprot_noncached #endif +#ifndef pgprot_device +#define pgprot_device pgprot_noncached +#endif + /* * When walking page tables, get the address of the next boundary, * or the end address of the range if that comes earlier. Although no diff --git a/include/linux/pci.h b/include/linux/pci.h index 150da2d644e7..b4995fdfffb1 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1100,6 +1100,9 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus, resource_size_t), void *alignf_data); + +int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr); + static inline dma_addr_t pci_bus_address(struct pci_dev *pdev, int bar) { struct pci_bus_region region; -- cgit v1.2.3 From ad975ebad4c3ce8dcc7d0bb4db26ea5aca4cfc99 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 23 Sep 2014 12:39:54 -0600 Subject: PCI/MSI: Remove arch_msi_check_device() No architectures implement arch_msi_check_device() or the struct msi_chip .check_device() method, so remove them. Remove the "type" parameter to pci_msi_check_device() because it was only used to call arch_msi_check_device() and is no longer needed. [bhelgaas: changelog, split to separate patch] Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas --- drivers/pci/msi.c | 21 +++------------------ include/linux/msi.h | 3 --- 2 files changed, 3 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 5a40516444f3..db21b77a03a5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -56,16 +56,6 @@ void __weak arch_teardown_msi_irq(unsigned int irq) chip->teardown_irq(chip, irq); } -int __weak arch_msi_check_device(struct pci_dev *dev, int nvec, int type) -{ - struct msi_chip *chip = dev->bus->msi; - - if (!chip || !chip->check_device) - return 0; - - return chip->check_device(chip, dev, nvec, type); -} - int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { struct msi_desc *entry; @@ -815,10 +805,9 @@ out_free: * to determine if MSI/-X are supported for the device. If MSI/-X is * supported return 0, else return an error code. **/ -static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type) +static int pci_msi_check_device(struct pci_dev *dev, int nvec) { struct pci_bus *bus; - int ret; /* MSI must be globally enabled and supported by the device */ if (!pci_msi_enable || !dev || dev->no_msi) @@ -843,10 +832,6 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type) if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) return -EINVAL; - ret = arch_msi_check_device(dev, nvec, type); - if (ret) - return ret; - return 0; } @@ -952,7 +937,7 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) if (!entries || !dev->msix_cap || dev->current_state != PCI_D0) return -EINVAL; - status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX); + status = pci_msi_check_device(dev, nvec); if (status) return status; @@ -1086,7 +1071,7 @@ int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) nvec = maxvec; do { - rc = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSI); + rc = pci_msi_check_device(dev, nvec); if (rc < 0) { return rc; } else if (rc > 0) { diff --git a/include/linux/msi.h b/include/linux/msi.h index 8103f32f6d87..dbf7cc932444 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -60,7 +60,6 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc); void arch_teardown_msi_irq(unsigned int irq); int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); void arch_teardown_msi_irqs(struct pci_dev *dev); -int arch_msi_check_device(struct pci_dev* dev, int nvec, int type); void arch_restore_msi_irqs(struct pci_dev *dev); void default_teardown_msi_irqs(struct pci_dev *dev); @@ -77,8 +76,6 @@ struct msi_chip { int (*setup_irq)(struct msi_chip *chip, struct pci_dev *dev, struct msi_desc *desc); void (*teardown_irq)(struct msi_chip *chip, unsigned int irq); - int (*check_device)(struct msi_chip *chip, struct pci_dev *dev, - int nvec, int type); }; #endif /* LINUX_MSI_H */ -- cgit v1.2.3 From 81052769e48609525c452d8f078a5786b673e178 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 23 Sep 2014 13:27:22 +0800 Subject: PCI/MSI: Remove unused kobject from struct msi_desc After commit 1c51b50c2995 ("PCI/MSI: Export MSI mode using attributes, not kobjects"), the kobject in struct msi_desc is unused. Remove the unused struct kobject from struct msi_desc. [bhelgaas: changelog] Fixes: 1c51b50c2995 ("PCI/MSI: Export MSI mode using attributes, not kobjects") Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 11 ----------- include/linux/msi.h | 2 -- 2 files changed, 13 deletions(-) (limited to 'include') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 5f1e5dc994cf..97d6ef67a3c8 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -374,17 +374,6 @@ static void free_msi_irqs(struct pci_dev *dev) iounmap(entry->mask_base); } - /* - * Its possible that we get into this path - * When populate_msi_sysfs fails, which means the entries - * were not registered with sysfs. In that case don't - * unregister them. - */ - if (entry->kobj.parent) { - kobject_del(&entry->kobj); - kobject_put(&entry->kobj); - } - list_del(&entry->list); kfree(entry); } diff --git a/include/linux/msi.h b/include/linux/msi.h index dbf7cc932444..5a91c2d58ffd 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -47,8 +47,6 @@ struct msi_desc { /* Last set MSI message */ struct msi_msg msg; - - struct kobject kobj; }; /* -- cgit v1.2.3 From 48c3c38f003c25d50a09d3da558667c5ecd530aa Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Tue, 23 Sep 2014 11:02:42 -0600 Subject: PCI/MSI: Remove "pos" from the struct msi_desc msi_attrib "msi_attrib.pos" is only used for MSI (not MSI-X), and we already cache the MSI capability offset in "dev->msi_cap". Remove "pos" from the struct msi_attrib and use "dev->msi_cap" directly. [bhelgaas: changelog, fix whitespace] Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- arch/mips/pci/msi-octeon.c | 6 ++---- drivers/pci/host/pcie-designware.c | 5 ++--- drivers/pci/msi.c | 2 -- include/linux/msi.h | 1 - 4 files changed, 4 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index ab0c5d14c6f7..63bbe07a1ccd 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -73,8 +73,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) * wants. Most devices only want 1, which will give * configured_private_bits and request_private_bits equal 0. */ - pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, - &control); + pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); /* * If the number of private bits has been configured then use @@ -176,8 +175,7 @@ msi_irq_allocated: /* Update the number of IRQs the device has available to it */ control &= ~PCI_MSI_FLAGS_QSIZE; control |= request_private_bits << 4; - pci_write_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, - control); + pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); irq_set_msi_desc(irq, desc); write_msi_msg(irq, &msg); diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 52bd3a143563..fa2fa459ed90 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -355,9 +355,8 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, return -EINVAL; } - pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS, - &msg_ctr); - msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4; + pci_read_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, &msg_ctr); + msgvec = (msg_ctr & PCI_MSI_FLAGS_QSIZE) >> 4; if (msgvec == 0) msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1; if (msgvec > 5) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 97d6ef67a3c8..40699a2041b5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -574,7 +574,6 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev) entry->msi_attrib.entry_nr = 0; entry->msi_attrib.maskbit = !!(control & PCI_MSI_FLAGS_MASKBIT); entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ - entry->msi_attrib.pos = dev->msi_cap; entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1; if (control & PCI_MSI_FLAGS_64BIT) @@ -678,7 +677,6 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, entry->msi_attrib.is_64 = 1; entry->msi_attrib.entry_nr = entries[i].entry; entry->msi_attrib.default_irq = dev->irq; - entry->msi_attrib.pos = dev->msix_cap; entry->mask_base = base; list_add_tail(&entry->list, &dev->msi_list); diff --git a/include/linux/msi.h b/include/linux/msi.h index 5a91c2d58ffd..44f4746d033b 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -29,7 +29,6 @@ struct msi_desc { __u8 multi_cap : 3; /* log2 num of messages supported */ __u8 maskbit : 1; /* mask-pending bit supported ? */ __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ - __u8 pos; /* Location of the msi capability */ __u16 entry_nr; /* specific enabled entry */ unsigned default_irq; /* default pre-assigned irq */ } msi_attrib; -- cgit v1.2.3