LCOV - code coverage report
Current view: top level - arch/x86/kernel - mmconf-fam10h_64.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 106 0.0 %
Date: 2022-03-28 15:32:58 Functions: 0 5 0.0 %
Branches: 0 54 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * AMD Family 10h mmconfig enablement
       4                 :            :  */
       5                 :            : 
       6                 :            : #include <linux/types.h>
       7                 :            : #include <linux/mm.h>
       8                 :            : #include <linux/string.h>
       9                 :            : #include <linux/pci.h>
      10                 :            : #include <linux/dmi.h>
      11                 :            : #include <linux/range.h>
      12                 :            : 
      13                 :            : #include <asm/pci-direct.h>
      14                 :            : #include <linux/sort.h>
      15                 :            : #include <asm/io.h>
      16                 :            : #include <asm/msr.h>
      17                 :            : #include <asm/acpi.h>
      18                 :            : #include <asm/mmconfig.h>
      19                 :            : #include <asm/pci_x86.h>
      20                 :            : 
      21                 :            : struct pci_hostbridge_probe {
      22                 :            :         u32 bus;
      23                 :            :         u32 slot;
      24                 :            :         u32 vendor;
      25                 :            :         u32 device;
      26                 :            : };
      27                 :            : 
      28                 :            : static u64 fam10h_pci_mmconf_base;
      29                 :            : 
      30                 :            : static struct pci_hostbridge_probe pci_probes[] = {
      31                 :            :         { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
      32                 :            :         { 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 },
      33                 :            : };
      34                 :            : 
      35                 :          0 : static int cmp_range(const void *x1, const void *x2)
      36                 :            : {
      37                 :          0 :         const struct range *r1 = x1;
      38                 :          0 :         const struct range *r2 = x2;
      39                 :          0 :         int start1, start2;
      40                 :            : 
      41                 :          0 :         start1 = r1->start >> 32;
      42                 :          0 :         start2 = r2->start >> 32;
      43                 :            : 
      44                 :          0 :         return start1 - start2;
      45                 :            : }
      46                 :            : 
      47                 :            : #define MMCONF_UNIT (1ULL << FAM10H_MMIO_CONF_BASE_SHIFT)
      48                 :            : #define MMCONF_MASK (~(MMCONF_UNIT - 1))
      49                 :            : #define MMCONF_SIZE (MMCONF_UNIT << 8)
      50                 :            : /* need to avoid (0xfd<<32), (0xfe<<32), and (0xff<<32), ht used space */
      51                 :            : #define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
      52                 :            : #define BASE_VALID(b) ((b) + MMCONF_SIZE <= (0xfdULL<<32) || (b) >= (1ULL<<40))
      53                 :          0 : static void get_fam10h_pci_mmconf_base(void)
      54                 :            : {
      55                 :          0 :         int i;
      56                 :          0 :         unsigned bus;
      57                 :          0 :         unsigned slot;
      58                 :          0 :         int found;
      59                 :            : 
      60                 :          0 :         u64 val;
      61                 :          0 :         u32 address;
      62                 :          0 :         u64 tom2;
      63                 :          0 :         u64 base = FAM10H_PCI_MMCONF_BASE;
      64                 :            : 
      65                 :          0 :         int hi_mmio_num;
      66                 :          0 :         struct range range[8];
      67                 :            : 
      68                 :            :         /* only try to get setting from BSP */
      69         [ #  # ]:          0 :         if (fam10h_pci_mmconf_base)
      70                 :          0 :                 return;
      71                 :            : 
      72         [ #  # ]:          0 :         if (!early_pci_allowed())
      73                 :            :                 return;
      74                 :            : 
      75                 :            :         found = 0;
      76         [ #  # ]:          0 :         for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
      77                 :          0 :                 u32 id;
      78                 :          0 :                 u16 device;
      79                 :          0 :                 u16 vendor;
      80                 :            : 
      81                 :          0 :                 bus = pci_probes[i].bus;
      82                 :          0 :                 slot = pci_probes[i].slot;
      83                 :          0 :                 id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
      84                 :            : 
      85                 :          0 :                 vendor = id & 0xffff;
      86                 :          0 :                 device = (id>>16) & 0xffff;
      87         [ #  # ]:          0 :                 if (pci_probes[i].vendor == vendor &&
      88         [ #  # ]:          0 :                     pci_probes[i].device == device) {
      89                 :            :                         found = 1;
      90                 :            :                         break;
      91                 :            :                 }
      92                 :            :         }
      93                 :            : 
      94         [ #  # ]:          0 :         if (!found)
      95                 :            :                 return;
      96                 :            : 
      97                 :            :         /* SYS_CFG */
      98                 :          0 :         address = MSR_K8_SYSCFG;
      99                 :          0 :         rdmsrl(address, val);
     100                 :            : 
     101                 :            :         /* TOP_MEM2 is not enabled? */
     102         [ #  # ]:          0 :         if (!(val & (1<<21))) {
     103                 :            :                 tom2 = 1ULL << 32;
     104                 :            :         } else {
     105                 :            :                 /* TOP_MEM2 */
     106                 :          0 :                 address = MSR_K8_TOP_MEM2;
     107                 :          0 :                 rdmsrl(address, val);
     108                 :          0 :                 tom2 = max(val & 0xffffff800000ULL, 1ULL << 32);
     109                 :            :         }
     110                 :            : 
     111         [ #  # ]:          0 :         if (base <= tom2)
     112                 :          0 :                 base = (tom2 + 2 * MMCONF_UNIT - 1) & MMCONF_MASK;
     113                 :            : 
     114                 :            :         /*
     115                 :            :          * need to check if the range is in the high mmio range that is
     116                 :            :          * above 4G
     117                 :            :          */
     118                 :          0 :         hi_mmio_num = 0;
     119         [ #  # ]:          0 :         for (i = 0; i < 8; i++) {
     120                 :          0 :                 u32 reg;
     121                 :          0 :                 u64 start;
     122                 :          0 :                 u64 end;
     123                 :          0 :                 reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
     124         [ #  # ]:          0 :                 if (!(reg & 3))
     125                 :          0 :                         continue;
     126                 :            : 
     127                 :          0 :                 start = (u64)(reg & 0xffffff00) << 8; /* 39:16 on 31:8*/
     128                 :          0 :                 reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
     129                 :          0 :                 end = ((u64)(reg & 0xffffff00) << 8) | 0xffff; /* 39:16 on 31:8*/
     130                 :            : 
     131         [ #  # ]:          0 :                 if (end < tom2)
     132                 :          0 :                         continue;
     133                 :            : 
     134                 :          0 :                 range[hi_mmio_num].start = start;
     135                 :          0 :                 range[hi_mmio_num].end = end;
     136                 :          0 :                 hi_mmio_num++;
     137                 :            :         }
     138                 :            : 
     139         [ #  # ]:          0 :         if (!hi_mmio_num)
     140                 :          0 :                 goto out;
     141                 :            : 
     142                 :            :         /* sort the range */
     143                 :          0 :         sort(range, hi_mmio_num, sizeof(struct range), cmp_range, NULL);
     144                 :            : 
     145         [ #  # ]:          0 :         if (range[hi_mmio_num - 1].end < base)
     146                 :          0 :                 goto out;
     147         [ #  # ]:          0 :         if (range[0].start > base + MMCONF_SIZE)
     148                 :          0 :                 goto out;
     149                 :            : 
     150                 :            :         /* need to find one window */
     151                 :          0 :         base = (range[0].start & MMCONF_MASK) - MMCONF_UNIT;
     152   [ #  #  #  # ]:          0 :         if ((base > tom2) && BASE_VALID(base))
     153                 :          0 :                 goto out;
     154                 :          0 :         base = (range[hi_mmio_num - 1].end + MMCONF_UNIT) & MMCONF_MASK;
     155         [ #  # ]:          0 :         if (BASE_VALID(base))
     156                 :          0 :                 goto out;
     157                 :            :         /* need to find window between ranges */
     158         [ #  # ]:          0 :         for (i = 1; i < hi_mmio_num; i++) {
     159                 :          0 :                 base = (range[i - 1].end + MMCONF_UNIT) & MMCONF_MASK;
     160                 :          0 :                 val = range[i].start & MMCONF_MASK;
     161   [ #  #  #  # ]:          0 :                 if (val >= base + MMCONF_SIZE && BASE_VALID(base))
     162                 :          0 :                         goto out;
     163                 :            :         }
     164                 :            :         return;
     165                 :            : 
     166                 :          0 : out:
     167                 :          0 :         fam10h_pci_mmconf_base = base;
     168                 :            : }
     169                 :            : 
     170                 :          0 : void fam10h_check_enable_mmcfg(void)
     171                 :            : {
     172                 :          0 :         u64 val;
     173                 :          0 :         u32 address;
     174                 :            : 
     175         [ #  # ]:          0 :         if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
     176                 :            :                 return;
     177                 :            : 
     178                 :          0 :         address = MSR_FAM10H_MMIO_CONF_BASE;
     179                 :          0 :         rdmsrl(address, val);
     180                 :            : 
     181                 :            :         /* try to make sure that AP's setting is identical to BSP setting */
     182         [ #  # ]:          0 :         if (val & FAM10H_MMIO_CONF_ENABLE) {
     183                 :          0 :                 unsigned busnbits;
     184                 :          0 :                 busnbits = (val >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
     185                 :            :                         FAM10H_MMIO_CONF_BUSRANGE_MASK;
     186                 :            : 
     187                 :            :                 /* only trust the one handle 256 buses, if acpi=off */
     188   [ #  #  #  # ]:          0 :                 if (!acpi_pci_disabled || busnbits >= 8) {
     189                 :          0 :                         u64 base = val & MMCONF_MASK;
     190                 :            : 
     191         [ #  # ]:          0 :                         if (!fam10h_pci_mmconf_base) {
     192                 :          0 :                                 fam10h_pci_mmconf_base = base;
     193                 :          0 :                                 return;
     194         [ #  # ]:          0 :                         } else if (fam10h_pci_mmconf_base ==  base)
     195                 :            :                                 return;
     196                 :            :                 }
     197                 :            :         }
     198                 :            : 
     199                 :            :         /*
     200                 :            :          * if it is not enabled, try to enable it and assume only one segment
     201                 :            :          * with 256 buses
     202                 :            :          */
     203                 :          0 :         get_fam10h_pci_mmconf_base();
     204         [ #  # ]:          0 :         if (!fam10h_pci_mmconf_base) {
     205                 :          0 :                 pci_probe &= ~PCI_CHECK_ENABLE_AMD_MMCONF;
     206                 :          0 :                 return;
     207                 :            :         }
     208                 :            : 
     209                 :          0 :         printk(KERN_INFO "Enable MMCONFIG on AMD Family 10h\n");
     210                 :          0 :         val &= ~((FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT) |
     211                 :            :              (FAM10H_MMIO_CONF_BUSRANGE_MASK<<FAM10H_MMIO_CONF_BUSRANGE_SHIFT));
     212                 :          0 :         val |= fam10h_pci_mmconf_base | (8 << FAM10H_MMIO_CONF_BUSRANGE_SHIFT) |
     213                 :            :                FAM10H_MMIO_CONF_ENABLE;
     214                 :          0 :         wrmsrl(address, val);
     215                 :            : }
     216                 :            : 
     217                 :          0 : static int __init set_check_enable_amd_mmconf(const struct dmi_system_id *d)
     218                 :            : {
     219                 :          0 :         pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;
     220                 :          0 :         return 0;
     221                 :            : }
     222                 :            : 
     223                 :            : static const struct dmi_system_id __initconst mmconf_dmi_table[] = {
     224                 :            :         {
     225                 :            :                 .callback = set_check_enable_amd_mmconf,
     226                 :            :                 .ident = "Sun Microsystems Machine",
     227                 :            :                 .matches = {
     228                 :            :                         DMI_MATCH(DMI_SYS_VENDOR, "Sun Microsystems"),
     229                 :            :                 },
     230                 :            :         },
     231                 :            :         {}
     232                 :            : };
     233                 :            : 
     234                 :            : /* Called from a non __init function, but only on the BSP. */
     235                 :          0 : void __ref check_enable_amd_mmconf_dmi(void)
     236                 :            : {
     237                 :          0 :         dmi_check_system(mmconf_dmi_table);
     238                 :          0 : }

Generated by: LCOV version 1.14