Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2c0bffe authored by Daniel J Blueman's avatar Daniel J Blueman Committed by Borislav Petkov
Browse files

amd64_edac: Fix PCI function lookup



Fix locating sibling memory controller PCI functions by using the
correct PCI domain and use a northbridge descriptor only if found. We
need to at least warn if it wasn't found so that it gets fixed and we
don't go off with wrong results.

Signed-off-by: default avatarDaniel J Blueman <daniel@numascale-asia.com>
Link: http://lkml.kernel.org/r/1354265060-22956-1-git-send-email-daniel@numascale-asia.com


[Boris: remove wrong comment, sanitize code and warn if NB desc lookup fails]
Signed-off-by: default avatarBorislav Petkov <bp@alien8.de>
parent 8b84c8df
Loading
Loading
Loading
Loading
+38 −34
Original line number Diff line number Diff line
@@ -980,10 +980,29 @@ static u64 get_error_address(struct mce *m)
	return addr;
}

static struct pci_dev *pci_get_related_function(unsigned int vendor,
						unsigned int device,
						struct pci_dev *related)
{
	struct pci_dev *dev = NULL;

	while ((dev = pci_get_device(vendor, device, dev))) {
		if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
		    (dev->bus->number == related->bus->number) &&
		    (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
			break;
	}

	return dev;
}

static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
{
	struct amd_northbridge *nb;
	struct pci_dev *misc, *f1 = NULL;
	struct cpuinfo_x86 *c = &boot_cpu_data;
	int off = range << 3;
	u32 llim;

	amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off,  &pvt->ranges[range].base.lo);
	amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
@@ -997,13 +1016,16 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
	amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off,  &pvt->ranges[range].base.hi);
	amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);

	/* Factor in CC6 save area by reading dst node's limit reg */
	if (c->x86 == 0x15) {
		struct pci_dev *f1 = NULL;
		u8 nid = dram_dst_node(pvt, range);
		u32 llim;
	/* F15h: factor in CC6 save area by reading dst node's limit reg */
	if (c->x86 != 0x15)
		return;

		f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1));
	nb = node_to_amd_nb(dram_dst_node(pvt, range));
	if (WARN_ON(!nb))
		return;

	misc = nb->misc;
	f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc);
	if (WARN_ON(!f1))
		return;

@@ -1021,7 +1043,6 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)

	pci_dev_put(f1);
}
}

static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
				    struct err_info *err)
@@ -1673,23 +1694,6 @@ static struct amd64_family_type amd64_family_types[] = {
	},
};

static struct pci_dev *pci_get_related_function(unsigned int vendor,
						unsigned int device,
						struct pci_dev *related)
{
	struct pci_dev *dev = NULL;

	dev = pci_get_device(vendor, device, dev);
	while (dev) {
		if ((dev->bus->number == related->bus->number) &&
		    (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
			break;
		dev = pci_get_device(vendor, device, dev);
	}

	return dev;
}

/*
 * These are tables of eigenvectors (one per line) which can be used for the
 * construction of the syndrome tables. The modified syndrome search algorithm