Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: PCI: Manage controller-specific data on per-controller basis

Currently we use one shared global acpi_pci_root_ops structure to keep
controller-specific ops. We pass its pointer to acpi_pci_root_create() and
associate it with a host bridge instance for good. Such a design implies
serious drawback. Any potential manipulation on the single system-wide
acpi_pci_root_ops leads to kernel crash. The structure content is not
really changing even across multiple host bridges creation; thus it was not
an issue so far.

In preparation for adding ECAM quirks mechanism (where controller-specific
PCI ops may be different for each host bridge) allocate new
acpi_pci_root_ops and fill in with data for each bridge. Now it is safe to
have different controller-specific info. As a consequence free
acpi_pci_root_ops when host bridge is released.

No functional changes in this patch.

Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

authored by

Tomasz Nowicki and committed by
Bjorn Helgaas
093d24a2 08b1c196

+10 -7
+10 -7
arch/arm64/kernel/pci.c
··· 168 168 169 169 ri = container_of(ci, struct acpi_pci_generic_root_info, common); 170 170 pci_ecam_free(ri->cfg); 171 + kfree(ci->ops); 171 172 kfree(ri); 172 173 } 173 - 174 - static struct acpi_pci_root_ops acpi_pci_root_ops = { 175 - .release_info = pci_acpi_generic_release_info, 176 - }; 177 174 178 175 /* Interface called from ACPI code to setup PCI host controller */ 179 176 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) ··· 178 181 int node = acpi_get_node(root->device->handle); 179 182 struct acpi_pci_generic_root_info *ri; 180 183 struct pci_bus *bus, *child; 184 + struct acpi_pci_root_ops *root_ops; 181 185 182 186 ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node); 183 187 if (!ri) 184 188 return NULL; 185 189 190 + root_ops = kzalloc_node(sizeof(*root_ops), GFP_KERNEL, node); 191 + if (!root_ops) 192 + return NULL; 193 + 186 194 ri->cfg = pci_acpi_setup_ecam_mapping(root); 187 195 if (!ri->cfg) { 188 196 kfree(ri); 197 + kfree(root_ops); 189 198 return NULL; 190 199 } 191 200 192 - acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops; 193 - bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common, 194 - ri->cfg); 201 + root_ops->release_info = pci_acpi_generic_release_info; 202 + root_ops->pci_ops = &ri->cfg->ops->pci_ops; 203 + bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg); 195 204 if (!bus) 196 205 return NULL; 197 206