Merge branches 'pci/iommu' and 'pci/resource' into next

* pci/iommu:
  of: Calculate device DMA masks based on DT dma-range size
  arm: dma-mapping: limit IOMMU mapping size
  PCI: Update DMA configuration from DT
  of/pci: Add of_pci_dma_configure() to update DMA configuration
  PCI: Add helper functions pci_get[put]_host_bridge_device()
  of: Fix size when dma-range is not used
  of: Move of_dma_configure() to device.c to help re-use
  of: iommu: Add ptr to OF node arg to of_iommu_configure()

* pci/resource:
  PCI: Fail pci_ioremap_bar() on unassigned resources
  PCI: Show driver, BAR#, and resource on pci_ioremap_bar() failure
  PCI: Mark invalid BARs as unassigned
  PNP: Don't check for overlaps with unassigned PCI BARs
This commit is contained in:
Bjorn Helgaas 2015-03-19 10:56:47 -05:00
commit 85e8a0af37
14 changed files with 164 additions and 67 deletions

View File

@ -2027,6 +2027,13 @@ static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
if (!iommu)
return false;
/*
* currently arm_iommu_create_mapping() takes a max of size_t
* for size param. So check this limit for now.
*/
if (size > SIZE_MAX)
return false;
mapping = arm_iommu_create_mapping(dev->bus, dma_base, size);
if (IS_ERR(mapping)) {
pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",

View File

@ -133,19 +133,25 @@ struct iommu_ops *of_iommu_get_ops(struct device_node *np)
return ops;
}
struct iommu_ops *of_iommu_configure(struct device *dev)
struct iommu_ops *of_iommu_configure(struct device *dev,
struct device_node *master_np)
{
struct of_phandle_args iommu_spec;
struct device_node *np;
struct iommu_ops *ops = NULL;
int idx = 0;
if (dev_is_pci(dev)) {
dev_err(dev, "IOMMU is currently not supported for PCI\n");
return NULL;
}
/*
* We don't currently walk up the tree looking for a parent IOMMU.
* See the `Notes:' section of
* Documentation/devicetree/bindings/iommu/iommu.txt
*/
while (!of_parse_phandle_with_args(dev->of_node, "iommus",
while (!of_parse_phandle_with_args(master_np, "iommus",
"#iommu-cells", idx,
&iommu_spec)) {
np = iommu_spec.np;

View File

@ -2,6 +2,9 @@
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_iommu.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@ -66,6 +69,87 @@ int of_device_add(struct platform_device *ofdev)
return device_add(&ofdev->dev);
}
/**
* of_dma_configure - Setup DMA configuration
* @dev: Device to apply DMA configuration
* @np: Pointer to OF node having DMA configuration
*
* Try to get devices's DMA configuration from DT and update it
* accordingly.
*
* If platform code needs to use its own special DMA configuration, it
* can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events
* to fix up DMA configuration.
*/
void of_dma_configure(struct device *dev, struct device_node *np)
{
u64 dma_addr, paddr, size;
int ret;
bool coherent;
unsigned long offset;
struct iommu_ops *iommu;
/*
* Set default coherent_dma_mask to 32 bit. Drivers are expected to
* setup the correct supported mask.
*/
if (!dev->coherent_dma_mask)
dev->coherent_dma_mask = DMA_BIT_MASK(32);
/*
* Set it to coherent_dma_mask by default if the architecture
* code has not set it.
*/
if (!dev->dma_mask)
dev->dma_mask = &dev->coherent_dma_mask;
ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
if (ret < 0) {
dma_addr = offset = 0;
size = dev->coherent_dma_mask + 1;
} else {
offset = PFN_DOWN(paddr - dma_addr);
/*
* Add a work around to treat the size as mask + 1 in case
* it is defined in DT as a mask.
*/
if (size & 1) {
dev_warn(dev, "Invalid size 0x%llx for dma-range\n",
size);
size = size + 1;
}
if (!size) {
dev_err(dev, "Adjusted size 0x%llx invalid\n", size);
return;
}
dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
}
dev->dma_pfn_offset = offset;
/*
* Limit coherent and dma mask based on size and default mask
* set by the driver.
*/
dev->coherent_dma_mask = min(dev->coherent_dma_mask,
DMA_BIT_MASK(ilog2(dma_addr + size)));
*dev->dma_mask = min((*dev->dma_mask),
DMA_BIT_MASK(ilog2(dma_addr + size)));
coherent = of_dma_is_coherent(np);
dev_dbg(dev, "device is%sdma coherent\n",
coherent ? " " : " not ");
iommu = of_iommu_configure(dev, np);
dev_dbg(dev, "device is%sbehind an iommu\n",
iommu ? " " : " not ");
arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent);
}
EXPORT_SYMBOL_GPL(of_dma_configure);
int of_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);

View File

@ -2,6 +2,7 @@
#include <linux/export.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/slab.h>
@ -116,6 +117,26 @@ int of_get_pci_domain_nr(struct device_node *node)
}
EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
/**
* of_pci_dma_configure - Setup DMA configuration
* @dev: ptr to pci_dev struct of the PCI device
*
* Function to update PCI devices's DMA configuration using the same
* info from the OF node of host bridge's parent (if any).
*/
void of_pci_dma_configure(struct pci_dev *pci_dev)
{
struct device *dev = &pci_dev->dev;
struct device *bridge = pci_get_host_bridge_device(pci_dev);
if (!bridge->parent)
return;
of_dma_configure(dev, bridge->parent->of_node);
pci_put_host_bridge_device(bridge);
}
EXPORT_SYMBOL_GPL(of_pci_dma_configure);
#if defined(CONFIG_OF_ADDRESS)
/**
* of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT

View File

@ -19,7 +19,6 @@
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_iommu.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@ -150,59 +149,6 @@ struct platform_device *of_device_alloc(struct device_node *np,
}
EXPORT_SYMBOL(of_device_alloc);
/**
* of_dma_configure - Setup DMA configuration
* @dev: Device to apply DMA configuration
*
* Try to get devices's DMA configuration from DT and update it
* accordingly.
*
* In case if platform code need to use own special DMA configuration,it
* can use Platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE event
* to fix up DMA configuration.
*/
static void of_dma_configure(struct device *dev)
{
u64 dma_addr, paddr, size;
int ret;
bool coherent;
unsigned long offset;
struct iommu_ops *iommu;
/*
* Set default dma-mask to 32 bit. Drivers are expected to setup
* the correct supported dma_mask.
*/
dev->coherent_dma_mask = DMA_BIT_MASK(32);
/*
* Set it to coherent_dma_mask by default if the architecture
* code has not set it.
*/
if (!dev->dma_mask)
dev->dma_mask = &dev->coherent_dma_mask;
ret = of_dma_get_range(dev->of_node, &dma_addr, &paddr, &size);
if (ret < 0) {
dma_addr = offset = 0;
size = dev->coherent_dma_mask;
} else {
offset = PFN_DOWN(paddr - dma_addr);
dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
}
dev->dma_pfn_offset = offset;
coherent = of_dma_is_coherent(dev->of_node);
dev_dbg(dev, "device is%sdma coherent\n",
coherent ? " " : " not ");
iommu = of_iommu_configure(dev);
dev_dbg(dev, "device is%sbehind an iommu\n",
iommu ? " " : " not ");
arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent);
}
static void of_dma_deconfigure(struct device *dev)
{
arch_teardown_dma_ops(dev);
@ -236,7 +182,7 @@ static struct platform_device *of_platform_device_create_pdata(
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
of_dma_configure(&dev->dev);
of_dma_configure(&dev->dev, dev->dev.of_node);
if (of_device_add(dev) != 0) {
of_dma_deconfigure(&dev->dev);
@ -299,7 +245,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
dev_set_name(&dev->dev, "%s", bus_id);
else
of_device_make_bus_id(&dev->dev);
of_dma_configure(&dev->dev);
of_dma_configure(&dev->dev, dev->dev.of_node);
/* Allow the HW Peripheral ID to be overridden */
prop = of_get_property(node, "arm,primecell-periphid", NULL);

View File

@ -23,6 +23,20 @@ static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
return to_pci_host_bridge(root_bus->bridge);
}
struct device *pci_get_host_bridge_device(struct pci_dev *dev)
{
struct pci_bus *root_bus = find_pci_root_bus(dev->bus);
struct device *bridge = root_bus->bridge;
kobject_get(&bridge->kobj);
return bridge;
}
void pci_put_host_bridge_device(struct device *dev)
{
kobject_put(&dev->kobj);
}
void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
void (*release_fn)(struct pci_host_bridge *),
void *release_data)

View File

@ -126,15 +126,16 @@ EXPORT_SYMBOL_GPL(pci_bus_max_busnr);
#ifdef CONFIG_HAS_IOMEM
void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
{
struct resource *res = &pdev->resource[bar];
/*
* Make sure the BAR is actually a memory resource, not an IO resource
*/
if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
WARN_ON(1);
if (res->flags & IORESOURCE_UNSET || !(res->flags & IORESOURCE_MEM)) {
dev_warn(&pdev->dev, "can't ioremap BAR %d: %pR\n", bar, res);
return NULL;
}
return ioremap_nocache(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
return ioremap_nocache(res->start, resource_size(res));
}
EXPORT_SYMBOL_GPL(pci_ioremap_bar);
#endif

View File

@ -6,6 +6,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/of_pci.h>
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/module.h>
@ -1520,6 +1521,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.dma_parms = &dev->dma_parms;
dev->dev.coherent_dma_mask = 0xffffffffull;
of_pci_dma_configure(dev);
pci_set_dma_max_seg_size(dev, 65536);
pci_set_dma_seg_boundary(dev, 0xffffffff);

View File

@ -120,6 +120,7 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
if (!root) {
dev_info(&dev->dev, "can't claim BAR %d %pR: no compatible bridge window\n",
resource, res);
res->flags |= IORESOURCE_UNSET;
return -EINVAL;
}
@ -127,6 +128,7 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
if (conflict) {
dev_info(&dev->dev, "can't claim BAR %d %pR: address conflict with %s %pR\n",
resource, res, conflict->name, conflict);
res->flags |= IORESOURCE_UNSET;
return -EBUSY;
}

View File

@ -246,13 +246,16 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
*/
for_each_pci_dev(pdev) {
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
unsigned long type;
unsigned long flags, type;
type = pci_resource_flags(pdev, i) &
(IORESOURCE_IO | IORESOURCE_MEM);
flags = pci_resource_flags(pdev, i);
type = flags & (IORESOURCE_IO | IORESOURCE_MEM);
if (!type || pci_resource_len(pdev, i) == 0)
continue;
if (flags & IORESOURCE_UNSET)
continue;
pci_start = pci_resource_start(pdev, i);
pci_end = pci_resource_end(pdev, i);
for (j = 0;

View File

@ -53,6 +53,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
return of_node_get(cpu_dev->of_node);
}
void of_dma_configure(struct device *dev, struct device_node *np);
#else /* CONFIG_OF */
static inline int of_driver_match_device(struct device *dev,
@ -90,6 +91,8 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
{
return NULL;
}
static inline void of_dma_configure(struct device *dev, struct device_node *np)
{}
#endif /* CONFIG_OF */
#endif /* _LINUX_OF_DEVICE_H */

View File

@ -12,7 +12,8 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix,
size_t *size);
extern void of_iommu_init(void);
extern struct iommu_ops *of_iommu_configure(struct device *dev);
extern struct iommu_ops *of_iommu_configure(struct device *dev,
struct device_node *master_np);
#else
@ -24,7 +25,8 @@ static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
}
static inline void of_iommu_init(void) { }
static inline struct iommu_ops *of_iommu_configure(struct device *dev)
static inline struct iommu_ops *of_iommu_configure(struct device *dev,
struct device_node *master_np)
{
return NULL;
}

View File

@ -16,6 +16,7 @@ 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);
void of_pci_dma_configure(struct pci_dev *pci_dev);
#else
static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
{
@ -50,6 +51,8 @@ of_get_pci_domain_nr(struct device_node *node)
{
return -1;
}
static inline void of_pci_dma_configure(struct pci_dev *pci_dev) { }
#endif
#if defined(CONFIG_OF_ADDRESS)

View File

@ -510,6 +510,9 @@ static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev)
return dev->bus->self;
}
struct device *pci_get_host_bridge_device(struct pci_dev *dev);
void pci_put_host_bridge_device(struct device *dev);
#ifdef CONFIG_PCI_MSI
static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev)
{