123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Generic PCI host driver common code
- *
- * Copyright (C) 2014 ARM Limited
- *
- * Author: Will Deacon <[email protected]>
- */
- #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");
|