mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-11 18:26:02 +00:00
Revert "powerpc/pci: unmap legacy INTx interrupts when a PHB is removed"
This reverts commit 3a3181e16f
which
causes memory corruptions on POWER9 powernv. eg:
pci_bus 0035:08: busn_res: [bus 08-0c] is released
=============================================================================
BUG kmalloc-16 (Tainted: G W O ): Object already free
-----------------------------------------------------------------------------
Disabling lock debugging due to kernel taint
INFO: Allocated in pcibios_scan_phb+0x104/0x3e0 age=1960714 cpu=4 pid=1
__slab_alloc+0xa4/0xf0
__kmalloc+0x294/0x330
pcibios_scan_phb+0x104/0x3e0
pcibios_init+0x84/0x124
do_one_initcall+0xac/0x528
kernel_init_freeable+0x35c/0x3fc
kernel_init+0x24/0x148
ret_from_kernel_thread+0x5c/0x80
INFO: Freed in pcibios_remove_bus+0x70/0x90 age=0 cpu=16 pid=1717146
kfree+0x49c/0x510
pcibios_remove_bus+0x70/0x90
pci_remove_bus+0xe4/0x110
pci_remove_bus_device+0x74/0x170
pci_remove_bus_device+0x4c/0x170
pci_stop_and_remove_bus_device_locked+0x34/0x50
remove_store+0xc0/0xe0
dev_attr_store+0x30/0x50
sysfs_kf_write+0x68/0xb0
kernfs_fop_write+0x114/0x260
vfs_write+0xe4/0x260
ksys_write+0x74/0x130
system_call_exception+0xf8/0x1d0
system_call_common+0xe8/0x218
INFO: Slab 0x0000000099caaf22 objects=178 used=174 fp=0x00000000006a64b0 flags=0x7fff8000000201
INFO: Object 0x00000000f360132d @offset=30192 fp=0x0000000000000000
Signed-off-by: Qian Cai <cai@lca.pw>
Acked-by: Oliver O'Halloran <oohall@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20201014182811.12027-1-cai@lca.pw
This commit is contained in:
parent
996f9e0f93
commit
ffd0b25ca0
@ -48,9 +48,6 @@ struct pci_controller_ops {
|
||||
|
||||
/*
|
||||
* Structure of a PCI controller (host bridge)
|
||||
*
|
||||
* @irq_count: number of interrupt mappings
|
||||
* @irq_map: interrupt mappings
|
||||
*/
|
||||
struct pci_controller {
|
||||
struct pci_bus *bus;
|
||||
@ -130,9 +127,6 @@ struct pci_controller {
|
||||
|
||||
void *private_data;
|
||||
struct npu *npu;
|
||||
|
||||
unsigned int irq_count;
|
||||
unsigned int *irq_map;
|
||||
};
|
||||
|
||||
/* These are used for config access before all the PCI probing
|
||||
|
@ -353,115 +353,6 @@ struct pci_controller *pci_find_controller_for_domain(int domain_nr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assumption is made on the interrupt parent. All interrupt-map
|
||||
* entries are considered to have the same parent.
|
||||
*/
|
||||
static int pcibios_irq_map_count(struct pci_controller *phb)
|
||||
{
|
||||
const __be32 *imap;
|
||||
int imaplen;
|
||||
struct device_node *parent;
|
||||
u32 intsize, addrsize, parintsize, paraddrsize;
|
||||
|
||||
if (of_property_read_u32(phb->dn, "#interrupt-cells", &intsize))
|
||||
return 0;
|
||||
if (of_property_read_u32(phb->dn, "#address-cells", &addrsize))
|
||||
return 0;
|
||||
|
||||
imap = of_get_property(phb->dn, "interrupt-map", &imaplen);
|
||||
if (!imap) {
|
||||
pr_debug("%pOF : no interrupt-map\n", phb->dn);
|
||||
return 0;
|
||||
}
|
||||
imaplen /= sizeof(u32);
|
||||
pr_debug("%pOF : imaplen=%d\n", phb->dn, imaplen);
|
||||
|
||||
if (imaplen < (addrsize + intsize + 1))
|
||||
return 0;
|
||||
|
||||
imap += intsize + addrsize;
|
||||
parent = of_find_node_by_phandle(be32_to_cpup(imap));
|
||||
if (!parent) {
|
||||
pr_debug("%pOF : no imap parent found !\n", phb->dn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(parent, "#interrupt-cells", &parintsize)) {
|
||||
pr_debug("%pOF : parent lacks #interrupt-cells!\n", phb->dn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(parent, "#address-cells", ¶ddrsize))
|
||||
paraddrsize = 0;
|
||||
|
||||
return imaplen / (addrsize + intsize + 1 + paraddrsize + parintsize);
|
||||
}
|
||||
|
||||
static void pcibios_irq_map_init(struct pci_controller *phb)
|
||||
{
|
||||
phb->irq_count = pcibios_irq_map_count(phb);
|
||||
if (phb->irq_count < PCI_NUM_INTX)
|
||||
phb->irq_count = PCI_NUM_INTX;
|
||||
|
||||
pr_debug("%pOF : interrupt map #%d\n", phb->dn, phb->irq_count);
|
||||
|
||||
phb->irq_map = kcalloc(phb->irq_count, sizeof(unsigned int),
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void pci_irq_map_register(struct pci_dev *pdev, unsigned int virq)
|
||||
{
|
||||
struct pci_controller *phb = pci_bus_to_host(pdev->bus);
|
||||
int i;
|
||||
|
||||
if (!phb->irq_map)
|
||||
return;
|
||||
|
||||
for (i = 0; i < phb->irq_count; i++) {
|
||||
/*
|
||||
* Look for an empty or an equivalent slot, as INTx
|
||||
* interrupts can be shared between adapters.
|
||||
*/
|
||||
if (phb->irq_map[i] == virq || !phb->irq_map[i]) {
|
||||
phb->irq_map[i] = virq;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == phb->irq_count)
|
||||
pr_err("PCI:%s all platform interrupts mapped\n",
|
||||
pci_name(pdev));
|
||||
}
|
||||
|
||||
/*
|
||||
* Clearing the mapped interrupts will also clear the underlying
|
||||
* mappings of the ESB pages of the interrupts when under XIVE. It is
|
||||
* a requirement of PowerVM to clear all memory mappings before
|
||||
* removing a PHB.
|
||||
*/
|
||||
static void pci_irq_map_dispose(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_controller *phb = pci_bus_to_host(bus);
|
||||
int i;
|
||||
|
||||
if (!phb->irq_map)
|
||||
return;
|
||||
|
||||
pr_debug("PCI: Clearing interrupt mappings for PHB %04x:%02x...\n",
|
||||
pci_domain_nr(bus), bus->number);
|
||||
for (i = 0; i < phb->irq_count; i++)
|
||||
irq_dispose_mapping(phb->irq_map[i]);
|
||||
|
||||
kfree(phb->irq_map);
|
||||
}
|
||||
|
||||
void pcibios_remove_bus(struct pci_bus *bus)
|
||||
{
|
||||
pci_irq_map_dispose(bus);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pcibios_remove_bus);
|
||||
|
||||
/*
|
||||
* Reads the interrupt pin to determine if interrupt is use by card.
|
||||
* If the interrupt is used, then gets the interrupt line from the
|
||||
@ -510,8 +401,6 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
|
||||
|
||||
pci_dev->irq = virq;
|
||||
|
||||
/* Record all interrut mappings for later removal of a PHB */
|
||||
pci_irq_map_register(pci_dev, virq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1665,9 +1554,6 @@ void pcibios_scan_phb(struct pci_controller *hose)
|
||||
|
||||
pr_debug("PCI: Scanning PHB %pOF\n", node);
|
||||
|
||||
/* Allocate interrupt mappings array */
|
||||
pcibios_irq_map_init(hose);
|
||||
|
||||
/* Get some IO space for the new PHB */
|
||||
pcibios_setup_phb_io_space(hose);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user