diff options
Diffstat (limited to 'arch/arm64/kernel/pci.c')
-rw-r--r-- | arch/arm64/kernel/pci.c | 67 |
1 files changed, 43 insertions, 24 deletions
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index acf38722457b..4f0e3ebfea4b 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c | |||
@@ -114,6 +114,19 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) | |||
114 | return 0; | 114 | return 0; |
115 | } | 115 | } |
116 | 116 | ||
117 | static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) | ||
118 | { | ||
119 | struct resource_entry *entry, *tmp; | ||
120 | int status; | ||
121 | |||
122 | status = acpi_pci_probe_root_resources(ci); | ||
123 | resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { | ||
124 | if (!(entry->res->flags & IORESOURCE_WINDOW)) | ||
125 | resource_list_destroy_entry(entry); | ||
126 | } | ||
127 | return status; | ||
128 | } | ||
129 | |||
117 | /* | 130 | /* |
118 | * Lookup the bus range for the domain in MCFG, and set up config space | 131 | * Lookup the bus range for the domain in MCFG, and set up config space |
119 | * mapping. | 132 | * mapping. |
@@ -121,31 +134,33 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) | |||
121 | static struct pci_config_window * | 134 | static struct pci_config_window * |
122 | pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) | 135 | pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) |
123 | { | 136 | { |
137 | struct device *dev = &root->device->dev; | ||
124 | struct resource *bus_res = &root->secondary; | 138 | struct resource *bus_res = &root->secondary; |
125 | u16 seg = root->segment; | 139 | u16 seg = root->segment; |
126 | struct pci_config_window *cfg; | 140 | struct pci_ecam_ops *ecam_ops; |
127 | struct resource cfgres; | 141 | struct resource cfgres; |
128 | unsigned int bsz; | 142 | struct acpi_device *adev; |
129 | 143 | struct pci_config_window *cfg; | |
130 | /* Use address from _CBA if present, otherwise lookup MCFG */ | 144 | int ret; |
131 | if (!root->mcfg_addr) | ||
132 | root->mcfg_addr = pci_mcfg_lookup(seg, bus_res); | ||
133 | 145 | ||
134 | if (!root->mcfg_addr) { | 146 | ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops); |
135 | dev_err(&root->device->dev, "%04x:%pR ECAM region not found\n", | 147 | if (ret) { |
136 | seg, bus_res); | 148 | dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res); |
137 | return NULL; | 149 | return NULL; |
138 | } | 150 | } |
139 | 151 | ||
140 | bsz = 1 << pci_generic_ecam_ops.bus_shift; | 152 | adev = acpi_resource_consumer(&cfgres); |
141 | cfgres.start = root->mcfg_addr + bus_res->start * bsz; | 153 | if (adev) |
142 | cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1; | 154 | dev_info(dev, "ECAM area %pR reserved by %s\n", &cfgres, |
143 | cfgres.flags = IORESOURCE_MEM; | 155 | dev_name(&adev->dev)); |
144 | cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res, | 156 | else |
145 | &pci_generic_ecam_ops); | 157 | dev_warn(dev, FW_BUG "ECAM area %pR not reserved in ACPI namespace\n", |
158 | &cfgres); | ||
159 | |||
160 | cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops); | ||
146 | if (IS_ERR(cfg)) { | 161 | if (IS_ERR(cfg)) { |
147 | dev_err(&root->device->dev, "%04x:%pR error %ld mapping ECAM\n", | 162 | dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res, |
148 | seg, bus_res, PTR_ERR(cfg)); | 163 | PTR_ERR(cfg)); |
149 | return NULL; | 164 | return NULL; |
150 | } | 165 | } |
151 | 166 | ||
@@ -159,33 +174,37 @@ static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci) | |||
159 | 174 | ||
160 | ri = container_of(ci, struct acpi_pci_generic_root_info, common); | 175 | ri = container_of(ci, struct acpi_pci_generic_root_info, common); |
161 | pci_ecam_free(ri->cfg); | 176 | pci_ecam_free(ri->cfg); |
177 | kfree(ci->ops); | ||
162 | kfree(ri); | 178 | kfree(ri); |
163 | } | 179 | } |
164 | 180 | ||
165 | static struct acpi_pci_root_ops acpi_pci_root_ops = { | ||
166 | .release_info = pci_acpi_generic_release_info, | ||
167 | }; | ||
168 | |||
169 | /* Interface called from ACPI code to setup PCI host controller */ | 181 | /* Interface called from ACPI code to setup PCI host controller */ |
170 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | 182 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) |
171 | { | 183 | { |
172 | int node = acpi_get_node(root->device->handle); | 184 | int node = acpi_get_node(root->device->handle); |
173 | struct acpi_pci_generic_root_info *ri; | 185 | struct acpi_pci_generic_root_info *ri; |
174 | struct pci_bus *bus, *child; | 186 | struct pci_bus *bus, *child; |
187 | struct acpi_pci_root_ops *root_ops; | ||
175 | 188 | ||
176 | ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node); | 189 | ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node); |
177 | if (!ri) | 190 | if (!ri) |
178 | return NULL; | 191 | return NULL; |
179 | 192 | ||
193 | root_ops = kzalloc_node(sizeof(*root_ops), GFP_KERNEL, node); | ||
194 | if (!root_ops) | ||
195 | return NULL; | ||
196 | |||
180 | ri->cfg = pci_acpi_setup_ecam_mapping(root); | 197 | ri->cfg = pci_acpi_setup_ecam_mapping(root); |
181 | if (!ri->cfg) { | 198 | if (!ri->cfg) { |
182 | kfree(ri); | 199 | kfree(ri); |
200 | kfree(root_ops); | ||
183 | return NULL; | 201 | return NULL; |
184 | } | 202 | } |
185 | 203 | ||
186 | acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops; | 204 | root_ops->release_info = pci_acpi_generic_release_info; |
187 | bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common, | 205 | root_ops->prepare_resources = pci_acpi_root_prepare_resources; |
188 | ri->cfg); | 206 | root_ops->pci_ops = &ri->cfg->ops->pci_ops; |
207 | bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg); | ||
189 | if (!bus) | 208 | if (!bus) |
190 | return NULL; | 209 | return NULL; |
191 | 210 | ||