blob: d3924a44db02f893115214b4ab73623e1309bf83 [file] [log] [blame]
Bjorn Helgaas8cfab3c2018-01-26 12:50:27 -06001// SPDX-License-Identifier: GPL-2.0
David Daney4e64dbe2016-03-11 15:35:55 -06002/*
Paul Gortmaker4068bd12016-08-22 17:59:48 -04003 * Generic PCI host driver common code
4 *
David Daney4e64dbe2016-03-11 15:35:55 -06005 * Copyright (C) 2014 ARM Limited
6 *
7 * Author: Will Deacon <will.deacon@arm.com>
8 */
9
10#include <linux/kernel.h>
Rob Herring0c59c062020-04-09 17:49:22 -060011#include <linux/module.h>
David Daney4e64dbe2016-03-11 15:35:55 -060012#include <linux/of_address.h>
Rob Herringb2f75a42020-04-09 17:49:23 -060013#include <linux/of_device.h>
David Daney4e64dbe2016-03-11 15:35:55 -060014#include <linux/of_pci.h>
Jayachandran C80955f92016-06-10 21:55:09 +020015#include <linux/pci-ecam.h>
David Daney4e64dbe2016-03-11 15:35:55 -060016#include <linux/platform_device.h>
17
Jayachandran C1958e712016-05-11 17:34:46 -050018static void gen_pci_unmap_cfg(void *ptr)
19{
20 pci_ecam_free((struct pci_config_window *)ptr);
21}
22
23static struct pci_config_window *gen_pci_init(struct device *dev,
Rob Herringe63434f2020-05-22 17:48:20 -060024 struct pci_host_bridge *bridge, const struct pci_ecam_ops *ops)
David Daney4e64dbe2016-03-11 15:35:55 -060025{
26 int err;
Jayachandran C1958e712016-05-11 17:34:46 -050027 struct resource cfgres;
Rob Herring669cbc72020-07-21 20:25:13 -060028 struct resource_entry *bus;
Jayachandran C1958e712016-05-11 17:34:46 -050029 struct pci_config_window *cfg;
David Daney4e64dbe2016-03-11 15:35:55 -060030
Jayachandran C1958e712016-05-11 17:34:46 -050031 err = of_address_to_resource(dev->of_node, 0, &cfgres);
David Daney4e64dbe2016-03-11 15:35:55 -060032 if (err) {
33 dev_err(dev, "missing \"reg\" property\n");
Rob Herringe63434f2020-05-22 17:48:20 -060034 return ERR_PTR(err);
David Daney4e64dbe2016-03-11 15:35:55 -060035 }
36
Rob Herring669cbc72020-07-21 20:25:13 -060037 bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
38 if (!bus)
39 return ERR_PTR(-ENODEV);
40
41 cfg = pci_ecam_create(dev, &cfgres, bus->res, ops);
Rob Herringe63434f2020-05-22 17:48:20 -060042 if (IS_ERR(cfg))
43 return cfg;
David Daney4e64dbe2016-03-11 15:35:55 -060044
Fuqian Huangbefa45fb2019-07-08 20:33:54 +080045 err = devm_add_action_or_reset(dev, gen_pci_unmap_cfg, cfg);
Rob Herringe63434f2020-05-22 17:48:20 -060046 if (err)
47 return ERR_PTR(err);
Jayachandran C1958e712016-05-11 17:34:46 -050048
Rob Herringe63434f2020-05-22 17:48:20 -060049 return cfg;
David Daney4e64dbe2016-03-11 15:35:55 -060050}
51
Rob Herringb2f75a42020-04-09 17:49:23 -060052int pci_host_common_probe(struct platform_device *pdev)
David Daney4e64dbe2016-03-11 15:35:55 -060053{
David Daney4e64dbe2016-03-11 15:35:55 -060054 struct device *dev = &pdev->dev;
Lorenzo Pieralisi4246a862017-06-28 15:14:00 -050055 struct pci_host_bridge *bridge;
Jayachandran C1958e712016-05-11 17:34:46 -050056 struct pci_config_window *cfg;
Rob Herringb2f75a42020-04-09 17:49:23 -060057 const struct pci_ecam_ops *ops;
Lorenzo Pieralisi4246a862017-06-28 15:14:00 -050058
Rob Herringb2f75a42020-04-09 17:49:23 -060059 ops = of_device_get_match_data(&pdev->dev);
60 if (!ops)
61 return -ENODEV;
62
Lorenzo Pieralisi4246a862017-06-28 15:14:00 -050063 bridge = devm_pci_alloc_host_bridge(dev, 0);
64 if (!bridge)
65 return -ENOMEM;
David Daney4e64dbe2016-03-11 15:35:55 -060066
Daire McNamara791c9f12021-01-25 16:29:31 +000067 platform_set_drvdata(pdev, bridge);
68
David Daney4e64dbe2016-03-11 15:35:55 -060069 of_pci_check_probe_only();
70
David Daney4e64dbe2016-03-11 15:35:55 -060071 /* Parse and map our Configuration Space windows */
Rob Herringe63434f2020-05-22 17:48:20 -060072 cfg = gen_pci_init(dev, bridge, ops);
Jayachandran C1958e712016-05-11 17:34:46 -050073 if (IS_ERR(cfg))
74 return PTR_ERR(cfg);
David Daney4e64dbe2016-03-11 15:35:55 -060075
76 /* Do not reassign resources if probe only */
77 if (!pci_has_flag(PCI_PROBE_ONLY))
Bjorn Helgaas71538842017-11-30 11:21:57 -060078 pci_add_flags(PCI_REASSIGN_ALL_BUS);
David Daney4e64dbe2016-03-11 15:35:55 -060079
Lorenzo Pieralisi4246a862017-06-28 15:14:00 -050080 bridge->sysdata = cfg;
Rob Herring0b104772020-04-09 17:49:21 -060081 bridge->ops = (struct pci_ops *)&ops->pci_ops;
Marc Zyngier9ec37ef2021-03-30 16:11:42 +010082 bridge->msi_domain = true;
Lorenzo Pieralisi4246a862017-06-28 15:14:00 -050083
Rob Herringe63434f2020-05-22 17:48:20 -060084 return pci_host_probe(bridge);
Jan Kiszka01fcb7f2018-05-15 11:07:06 +020085}
Rob Herring0c59c062020-04-09 17:49:22 -060086EXPORT_SYMBOL_GPL(pci_host_common_probe);
Jan Kiszka01fcb7f2018-05-15 11:07:06 +020087
88int pci_host_common_remove(struct platform_device *pdev)
89{
Rob Herringe63434f2020-05-22 17:48:20 -060090 struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
Jan Kiszka01fcb7f2018-05-15 11:07:06 +020091
92 pci_lock_rescan_remove();
Rob Herringe63434f2020-05-22 17:48:20 -060093 pci_stop_root_bus(bridge->bus);
94 pci_remove_root_bus(bridge->bus);
Jan Kiszka01fcb7f2018-05-15 11:07:06 +020095 pci_unlock_rescan_remove();
96
David Daney4e64dbe2016-03-11 15:35:55 -060097 return 0;
98}
Rob Herring0c59c062020-04-09 17:49:22 -060099EXPORT_SYMBOL_GPL(pci_host_common_remove);
100
101MODULE_LICENSE("GPL v2");