LCOV - code coverage report
Current view: top level - arch/x86/mm - amdtopology.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 19 84 22.6 %
Date: 2022-03-28 16:04:14 Functions: 2 2 100.0 %
Branches: 6 48 12.5 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * AMD NUMA support.
       4                 :            :  * Discover the memory map and associated nodes.
       5                 :            :  *
       6                 :            :  * This version reads it directly from the AMD northbridge.
       7                 :            :  *
       8                 :            :  * Copyright 2002,2003 Andi Kleen, SuSE Labs.
       9                 :            :  */
      10                 :            : #include <linux/kernel.h>
      11                 :            : #include <linux/init.h>
      12                 :            : #include <linux/string.h>
      13                 :            : #include <linux/nodemask.h>
      14                 :            : #include <linux/memblock.h>
      15                 :            : 
      16                 :            : #include <asm/io.h>
      17                 :            : #include <linux/pci_ids.h>
      18                 :            : #include <linux/acpi.h>
      19                 :            : #include <asm/types.h>
      20                 :            : #include <asm/mmzone.h>
      21                 :            : #include <asm/proto.h>
      22                 :            : #include <asm/e820/api.h>
      23                 :            : #include <asm/pci-direct.h>
      24                 :            : #include <asm/numa.h>
      25                 :            : #include <asm/mpspec.h>
      26                 :            : #include <asm/apic.h>
      27                 :            : #include <asm/amd_nb.h>
      28                 :            : 
      29                 :            : static unsigned char __initdata nodeids[8];
      30                 :            : 
      31                 :         13 : static __init int find_northbridge(void)
      32                 :            : {
      33                 :         13 :         int num;
      34                 :            : 
      35         [ +  + ]:        429 :         for (num = 0; num < 32; num++) {
      36                 :        416 :                 u32 header;
      37                 :            : 
      38                 :        416 :                 header = read_pci_config(0, num, 0, 0x00);
      39                 :        416 :                 if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16)) &&
      40   [ +  -  +  - ]:        416 :                         header != (PCI_VENDOR_ID_AMD | (0x1200<<16)) &&
      41                 :            :                         header != (PCI_VENDOR_ID_AMD | (0x1300<<16)))
      42                 :        416 :                         continue;
      43                 :            : 
      44                 :          0 :                 header = read_pci_config(0, num, 1, 0x00);
      45                 :          0 :                 if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16)) &&
      46   [ #  #  #  # ]:          0 :                         header != (PCI_VENDOR_ID_AMD | (0x1201<<16)) &&
      47                 :            :                         header != (PCI_VENDOR_ID_AMD | (0x1301<<16)))
      48                 :          0 :                         continue;
      49                 :            :                 return num;
      50                 :            :         }
      51                 :            : 
      52                 :            :         return -ENOENT;
      53                 :            : }
      54                 :            : 
      55                 :         13 : int __init amd_numa_init(void)
      56                 :            : {
      57                 :         13 :         u64 start = PFN_PHYS(0);
      58                 :         13 :         u64 end = PFN_PHYS(max_pfn);
      59                 :         13 :         unsigned numnodes;
      60                 :         13 :         u64 prevbase;
      61                 :         13 :         int i, j, nb;
      62                 :         13 :         u32 nodeid, reg;
      63                 :         13 :         unsigned int bits, cores, apicid_base;
      64                 :            : 
      65         [ +  - ]:         13 :         if (!early_pci_allowed())
      66                 :            :                 return -EINVAL;
      67                 :            : 
      68                 :         13 :         nb = find_northbridge();
      69         [ -  + ]:         13 :         if (nb < 0)
      70                 :            :                 return nb;
      71                 :            : 
      72                 :          0 :         pr_info("Scanning NUMA topology in Northbridge %d\n", nb);
      73                 :            : 
      74                 :          0 :         reg = read_pci_config(0, nb, 0, 0x60);
      75                 :          0 :         numnodes = ((reg >> 4) & 0xF) + 1;
      76         [ #  # ]:          0 :         if (numnodes <= 1)
      77                 :            :                 return -ENOENT;
      78                 :            : 
      79                 :          0 :         pr_info("Number of physical nodes %d\n", numnodes);
      80                 :            : 
      81                 :          0 :         prevbase = 0;
      82         [ #  # ]:          0 :         for (i = 0; i < 8; i++) {
      83                 :          0 :                 u64 base, limit;
      84                 :            : 
      85                 :          0 :                 base = read_pci_config(0, nb, 1, 0x40 + i*8);
      86                 :          0 :                 limit = read_pci_config(0, nb, 1, 0x44 + i*8);
      87                 :            : 
      88                 :          0 :                 nodeids[i] = nodeid = limit & 7;
      89         [ #  # ]:          0 :                 if ((base & 3) == 0) {
      90         [ #  # ]:          0 :                         if (i < numnodes)
      91                 :          0 :                                 pr_info("Skipping disabled node %d\n", i);
      92                 :          0 :                         continue;
      93                 :            :                 }
      94         [ #  # ]:          0 :                 if (nodeid >= numnodes) {
      95                 :          0 :                         pr_info("Ignoring excess node %d (%Lx:%Lx)\n", nodeid,
      96                 :            :                                 base, limit);
      97                 :          0 :                         continue;
      98                 :            :                 }
      99                 :            : 
     100         [ #  # ]:          0 :                 if (!limit) {
     101                 :          0 :                         pr_info("Skipping node entry %d (base %Lx)\n",
     102                 :            :                                 i, base);
     103                 :          0 :                         continue;
     104                 :            :                 }
     105   [ #  #  #  # ]:          0 :                 if ((base >> 8) & 3 || (limit >> 8) & 3) {
     106                 :          0 :                         pr_err("Node %d using interleaving mode %Lx/%Lx\n",
     107                 :            :                                nodeid, (base >> 8) & 3, (limit >> 8) & 3);
     108                 :          0 :                         return -EINVAL;
     109                 :            :                 }
     110         [ #  # ]:          0 :                 if (node_isset(nodeid, numa_nodes_parsed)) {
     111                 :          0 :                         pr_info("Node %d already present, skipping\n",
     112                 :            :                                 nodeid);
     113                 :          0 :                         continue;
     114                 :            :                 }
     115                 :            : 
     116                 :          0 :                 limit >>= 16;
     117                 :          0 :                 limit++;
     118                 :          0 :                 limit <<= 24;
     119                 :            : 
     120                 :          0 :                 if (limit > end)
     121                 :            :                         limit = end;
     122         [ #  # ]:          0 :                 if (limit <= base)
     123                 :          0 :                         continue;
     124                 :            : 
     125                 :          0 :                 base >>= 16;
     126                 :          0 :                 base <<= 24;
     127                 :            : 
     128                 :          0 :                 if (base < start)
     129                 :            :                         base = start;
     130                 :          0 :                 if (limit > end)
     131                 :            :                         limit = end;
     132         [ #  # ]:          0 :                 if (limit == base) {
     133                 :          0 :                         pr_err("Empty node %d\n", nodeid);
     134                 :          0 :                         continue;
     135                 :            :                 }
     136         [ #  # ]:          0 :                 if (limit < base) {
     137                 :          0 :                         pr_err("Node %d bogus settings %Lx-%Lx.\n",
     138                 :            :                                nodeid, base, limit);
     139                 :          0 :                         continue;
     140                 :            :                 }
     141                 :            : 
     142                 :            :                 /* Could sort here, but pun for now. Should not happen anyroads. */
     143         [ #  # ]:          0 :                 if (prevbase > base) {
     144                 :          0 :                         pr_err("Node map not sorted %Lx,%Lx\n",
     145                 :            :                                prevbase, base);
     146                 :          0 :                         return -EINVAL;
     147                 :            :                 }
     148                 :            : 
     149                 :          0 :                 pr_info("Node %d MemBase %016Lx Limit %016Lx\n",
     150                 :            :                         nodeid, base, limit);
     151                 :            : 
     152                 :          0 :                 prevbase = base;
     153                 :          0 :                 numa_add_memblk(nodeid, base, limit);
     154                 :          0 :                 node_set(nodeid, numa_nodes_parsed);
     155                 :            :         }
     156                 :            : 
     157         [ #  # ]:          0 :         if (!nodes_weight(numa_nodes_parsed))
     158                 :            :                 return -ENOENT;
     159                 :            : 
     160                 :            :         /*
     161                 :            :          * We seem to have valid NUMA configuration.  Map apicids to nodes
     162                 :            :          * using the coreid bits from early_identify_cpu.
     163                 :            :          */
     164                 :          0 :         bits = boot_cpu_data.x86_coreid_bits;
     165                 :          0 :         cores = 1 << bits;
     166                 :          0 :         apicid_base = 0;
     167                 :            : 
     168                 :            :         /*
     169                 :            :          * get boot-time SMP configuration:
     170                 :            :          */
     171                 :          0 :         early_get_smp_config();
     172                 :            : 
     173         [ #  # ]:          0 :         if (boot_cpu_physical_apicid > 0) {
     174                 :          0 :                 pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid);
     175                 :          0 :                 apicid_base = boot_cpu_physical_apicid;
     176                 :            :         }
     177                 :            : 
     178         [ #  # ]:          0 :         for_each_node_mask(i, numa_nodes_parsed)
     179         [ #  # ]:          0 :                 for (j = apicid_base; j < cores + apicid_base; j++)
     180                 :          0 :                         set_apicid_to_node((i << bits) + j, i);
     181                 :            : 
     182                 :            :         return 0;
     183                 :            : }

Generated by: LCOV version 1.14