mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-23 02:54:32 +08:00
9ec37efb87
The generic PCI host driver relies on MSI domains for MSIs to be provided to its end-points. Make this dependency explicit. This cures the warnings occuring on arm/arm64 VMs when booted with PCI virtio devices and no MSI controller (no GICv3 ITS, for example). It is likely that other drivers will need to express the same dependency. Link: https://lore.kernel.org/r/20210330151145.997953-12-maz@kernel.org Signed-off-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
102 lines
2.3 KiB
C
102 lines
2.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Generic PCI host driver common code
|
|
*
|
|
* Copyright (C) 2014 ARM Limited
|
|
*
|
|
* Author: Will Deacon <will.deacon@arm.com>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/of_pci.h>
|
|
#include <linux/pci-ecam.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
static void gen_pci_unmap_cfg(void *ptr)
|
|
{
|
|
pci_ecam_free((struct pci_config_window *)ptr);
|
|
}
|
|
|
|
static struct pci_config_window *gen_pci_init(struct device *dev,
|
|
struct pci_host_bridge *bridge, const struct pci_ecam_ops *ops)
|
|
{
|
|
int err;
|
|
struct resource cfgres;
|
|
struct resource_entry *bus;
|
|
struct pci_config_window *cfg;
|
|
|
|
err = of_address_to_resource(dev->of_node, 0, &cfgres);
|
|
if (err) {
|
|
dev_err(dev, "missing \"reg\" property\n");
|
|
return ERR_PTR(err);
|
|
}
|
|
|
|
bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
|
|
if (!bus)
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
cfg = pci_ecam_create(dev, &cfgres, bus->res, ops);
|
|
if (IS_ERR(cfg))
|
|
return cfg;
|
|
|
|
err = devm_add_action_or_reset(dev, gen_pci_unmap_cfg, cfg);
|
|
if (err)
|
|
return ERR_PTR(err);
|
|
|
|
return cfg;
|
|
}
|
|
|
|
int pci_host_common_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct pci_host_bridge *bridge;
|
|
struct pci_config_window *cfg;
|
|
const struct pci_ecam_ops *ops;
|
|
|
|
ops = of_device_get_match_data(&pdev->dev);
|
|
if (!ops)
|
|
return -ENODEV;
|
|
|
|
bridge = devm_pci_alloc_host_bridge(dev, 0);
|
|
if (!bridge)
|
|
return -ENOMEM;
|
|
|
|
platform_set_drvdata(pdev, bridge);
|
|
|
|
of_pci_check_probe_only();
|
|
|
|
/* Parse and map our Configuration Space windows */
|
|
cfg = gen_pci_init(dev, bridge, ops);
|
|
if (IS_ERR(cfg))
|
|
return PTR_ERR(cfg);
|
|
|
|
/* Do not reassign resources if probe only */
|
|
if (!pci_has_flag(PCI_PROBE_ONLY))
|
|
pci_add_flags(PCI_REASSIGN_ALL_BUS);
|
|
|
|
bridge->sysdata = cfg;
|
|
bridge->ops = (struct pci_ops *)&ops->pci_ops;
|
|
bridge->msi_domain = true;
|
|
|
|
return pci_host_probe(bridge);
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_host_common_probe);
|
|
|
|
int pci_host_common_remove(struct platform_device *pdev)
|
|
{
|
|
struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
|
|
|
|
pci_lock_rescan_remove();
|
|
pci_stop_root_bus(bridge->bus);
|
|
pci_remove_root_bus(bridge->bus);
|
|
pci_unlock_rescan_remove();
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_host_common_remove);
|
|
|
|
MODULE_LICENSE("GPL v2");
|