Skip to content

Commit aa2ddd2

Browse files
spandruvadajwrdegoede
authored andcommitted
platform/x86: ISST: Use numa node id for cpu pci dev mapping
There is a problem in mapping CPU to a PCI device instance when the bus numbers are reused in different packages. This was observed on some Sapphire Rapids systems. The current implementation reads bus number assigned to a CPU package via MSR 0x128. This allows to establish relationship between a CPU and a PCI device. This allows to update power related parameters to a MMIO offset in a PCI device space which is unique to a CPU. But if two packages uses same bus number then this mapping will not be unique. When bus number is reused, PCI device will use different domain number or segment number. So we need to be aware of this domain information while matching CPU to PCI bus number. This domain information is not available via any MSR. So need to use ACPI numa node information. There is an interface already available in the Linux to read numa node for a CPU and a PCI device. This change uses this interface to check the numa node of a match PCI device with bus number. If the bus number and numa node matches with the CPU's assigned bus number and numa node, the matched PCI device instance will be returned to the caller. It is possible that before Sapphire Rapids, the numa node is not defined for the Speed Select PCI device in some OEM systems. In this case to restore old behavior, return the last matched PCI device for domain 0 unlsess there are more than one matches. Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Link: https://lore.kernel.org/r/20210616221329.1909276-2-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
1 parent 1e42de8 commit aa2ddd2

1 file changed

Lines changed: 46 additions & 2 deletions

File tree

drivers/platform/x86/intel_speed_select_if/isst_if_common.c

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,13 +283,18 @@ struct isst_if_cpu_info {
283283
int bus_info[2];
284284
struct pci_dev *pci_dev[2];
285285
int punit_cpu_id;
286+
int numa_node;
286287
};
287288

288289
static struct isst_if_cpu_info *isst_cpu_info;
290+
#define ISST_MAX_PCI_DOMAINS 8
289291

290292
static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn)
291293
{
292-
int bus_number;
294+
struct pci_dev *matched_pci_dev = NULL;
295+
struct pci_dev *pci_dev = NULL;
296+
int no_matches = 0;
297+
int i, bus_number;
293298

294299
if (bus_no < 0 || bus_no > 1 || cpu < 0 || cpu >= nr_cpu_ids ||
295300
cpu >= num_possible_cpus())
@@ -299,7 +304,45 @@ static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn
299304
if (bus_number < 0)
300305
return NULL;
301306

302-
return pci_get_domain_bus_and_slot(0, bus_number, PCI_DEVFN(dev, fn));
307+
for (i = 0; i < ISST_MAX_PCI_DOMAINS; ++i) {
308+
struct pci_dev *_pci_dev;
309+
int node;
310+
311+
_pci_dev = pci_get_domain_bus_and_slot(i, bus_number, PCI_DEVFN(dev, fn));
312+
if (!_pci_dev)
313+
continue;
314+
315+
++no_matches;
316+
if (!matched_pci_dev)
317+
matched_pci_dev = _pci_dev;
318+
319+
node = dev_to_node(&_pci_dev->dev);
320+
if (node == NUMA_NO_NODE) {
321+
pr_info("Fail to get numa node for CPU:%d bus:%d dev:%d fn:%d\n",
322+
cpu, bus_no, dev, fn);
323+
continue;
324+
}
325+
326+
if (node == isst_cpu_info[cpu].numa_node) {
327+
pci_dev = _pci_dev;
328+
break;
329+
}
330+
}
331+
332+
/*
333+
* If there is no numa matched pci_dev, then there can be following cases:
334+
* 1. CONFIG_NUMA is not defined: In this case if there is only single device
335+
* match, then we don't need numa information. Simply return last match.
336+
* Othewise return NULL.
337+
* 2. NUMA information is not exposed via _SEG method. In this case it is similar
338+
* to case 1.
339+
* 3. Numa information doesn't match with CPU numa node and more than one match
340+
* return NULL.
341+
*/
342+
if (!pci_dev && no_matches == 1)
343+
pci_dev = matched_pci_dev;
344+
345+
return pci_dev;
303346
}
304347

305348
/**
@@ -354,6 +397,7 @@ static int isst_if_cpu_online(unsigned int cpu)
354397
return ret;
355398
}
356399
isst_cpu_info[cpu].punit_cpu_id = data;
400+
isst_cpu_info[cpu].numa_node = cpu_to_node(cpu);
357401

358402
isst_restore_msr_local(cpu);
359403

0 commit comments

Comments
 (0)