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:
commit
85e8a0af37
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user