Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/x86_64/mmconf-fam10h.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * AMD Family 10h mmconfig enablement (taken from Linux 2.6.36)
3
 */
4
5
#include <xen/lib.h>
6
#include <xen/acpi.h>
7
#include <xen/pci.h>
8
#include <xen/pci_regs.h>
9
#include <xen/pci_ids.h>
10
#include <xen/init.h>
11
#include <xen/dmi.h>
12
#include <asm/amd.h>
13
#include <asm/e820.h>
14
#include <asm/msr.h>
15
#include <asm/processor.h>
16
17
#include "mmconfig.h"
18
19
struct pci_hostbridge_probe {
20
  u32 bus;
21
  u32 slot;
22
  u32 vendor;
23
  u32 device;
24
};
25
26
static u64 fam10h_pci_mmconf_base;
27
28
static struct pci_hostbridge_probe pci_probes[] = {
29
  { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
30
  { 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 },
31
};
32
33
0
#define UNIT (1ULL << FAM10H_MMIO_CONF_BASE_SHIFT)
34
0
#define MASK (~(UNIT - 1))
35
0
#define SIZE (UNIT << 8)
36
/* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */
37
0
#define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
38
0
#define BASE_VALID(b) ((b) + SIZE <= (0xfdULL<<32) || (b) >= (1ULL<<40))
39
static void __init get_fam10h_pci_mmconf_base(void)
40
0
{
41
0
  unsigned int i, j, bus, slot, hi_mmio_num;
42
0
  u32 address;
43
0
  u64 val, tom2, start, end;
44
0
  struct range {
45
0
    u64 start, end;
46
0
  } range[8];
47
0
48
0
  for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
49
0
    u32 id;
50
0
    u16 device;
51
0
    u16 vendor;
52
0
53
0
    bus = pci_probes[i].bus;
54
0
    slot = pci_probes[i].slot;
55
0
    id = pci_conf_read32(0, bus, slot, 0, PCI_VENDOR_ID);
56
0
57
0
    vendor = id & 0xffff;
58
0
    device = (id>>16) & 0xffff;
59
0
    if (pci_probes[i].vendor == vendor &&
60
0
        pci_probes[i].device == device)
61
0
      break;
62
0
  }
63
0
64
0
  if (i >= ARRAY_SIZE(pci_probes))
65
0
    return;
66
0
67
0
  /* SYS_CFG */
68
0
  address = MSR_K8_SYSCFG;
69
0
  rdmsrl(address, val);
70
0
71
0
  /* TOP_MEM2 is not enabled? */
72
0
  if (!(val & (1<<21))) {
73
0
    tom2 = 1ULL << 32;
74
0
  } else {
75
0
    /* TOP_MEM2 */
76
0
    address = MSR_K8_TOP_MEM2;
77
0
    rdmsrl(address, val);
78
0
    tom2 = max(val & 0xffffff800000ULL, 1ULL << 32);
79
0
  }
80
0
81
0
  /*
82
0
   * need to check if the range is in the high mmio range that is
83
0
   * above 4G
84
0
   */
85
0
  for (hi_mmio_num = i = 0; i < 8; i++) {
86
0
    val = pci_conf_read32(0, bus, slot, 1, 0x80 + (i << 3));
87
0
    if (!(val & 3))
88
0
      continue;
89
0
90
0
    start = (val & 0xffffff00) << 8; /* 39:16 on 31:8*/
91
0
    val = pci_conf_read32(0, bus, slot, 1, 0x84 + (i << 3));
92
0
    end = ((val & 0xffffff00) << 8) | 0xffff; /* 39:16 on 31:8*/
93
0
94
0
    if (end < tom2)
95
0
      continue;
96
0
97
0
    for (j = hi_mmio_num; j; --j) {
98
0
      if (range[j - 1].start < start)
99
0
        break;
100
0
      range[j] = range[j - 1];
101
0
    }
102
0
    range[j].start = start;
103
0
    range[j].end = end;
104
0
    hi_mmio_num++;
105
0
  }
106
0
107
0
  start = FAM10H_PCI_MMCONF_BASE;
108
0
  if (start <= tom2)
109
0
    start = (tom2 + 2 * UNIT - 1) & MASK;
110
0
111
0
  if (!hi_mmio_num)
112
0
    goto out;
113
0
114
0
  if (range[hi_mmio_num - 1].end < start)
115
0
    goto out;
116
0
  if (range[0].start > start + SIZE)
117
0
    goto out;
118
0
119
0
  /* need to find one window */
120
0
  start = (range[0].start & MASK) - UNIT;
121
0
  if (start > tom2 && BASE_VALID(start))
122
0
    goto out;
123
0
  start = (range[hi_mmio_num - 1].end + UNIT) & MASK;
124
0
  if (BASE_VALID(start))
125
0
    goto out;
126
0
  /* need to find window between ranges */
127
0
  for (i = 1; i < hi_mmio_num; i++) {
128
0
    start = (range[i - 1].end + UNIT) & MASK;
129
0
    end = range[i].start & MASK;
130
0
    if (end >= start + SIZE && BASE_VALID(start))
131
0
      goto out;
132
0
  }
133
0
  return;
134
0
135
0
out:
136
0
  if (e820_add_range(&e820, start, start + SIZE, E820_RESERVED))
137
0
    fam10h_pci_mmconf_base = start;
138
0
}
139
140
void fam10h_check_enable_mmcfg(void)
141
0
{
142
0
  u64 val;
143
0
  bool_t print = opt_cpu_info;
144
0
145
0
  if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
146
0
    return;
147
0
148
0
  rdmsrl(MSR_FAM10H_MMIO_CONF_BASE, val);
149
0
150
0
  /* try to make sure that AP's setting is identical to BSP setting */
151
0
  if (val & FAM10H_MMIO_CONF_ENABLE) {
152
0
    u64 base = val & MASK;
153
0
154
0
    if (!fam10h_pci_mmconf_base) {
155
0
      fam10h_pci_mmconf_base = base;
156
0
      return;
157
0
    }
158
0
    if (fam10h_pci_mmconf_base == base)
159
0
      return;
160
0
  }
161
0
162
0
  /*
163
0
   * if it is not enabled, try to enable it and assume only one segment
164
0
   * with 256 buses
165
0
   */
166
0
  /* only try to get setting from BSP */
167
0
  if (!fam10h_pci_mmconf_base) {
168
0
    get_fam10h_pci_mmconf_base();
169
0
    print = 1;
170
0
  }
171
0
  if (!fam10h_pci_mmconf_base) {
172
0
    pci_probe &= ~PCI_CHECK_ENABLE_AMD_MMCONF;
173
0
    return;
174
0
  }
175
0
176
0
  if (print)
177
0
    printk(KERN_INFO "Enable MMCONFIG on AMD Fam10h at %"PRIx64"\n",
178
0
           fam10h_pci_mmconf_base);
179
0
  val &= ~((FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT) |
180
0
       (FAM10H_MMIO_CONF_BUSRANGE_MASK<<FAM10H_MMIO_CONF_BUSRANGE_SHIFT));
181
0
  val |= fam10h_pci_mmconf_base | (8 << FAM10H_MMIO_CONF_BUSRANGE_SHIFT) |
182
0
         FAM10H_MMIO_CONF_ENABLE;
183
0
  wrmsrl(MSR_FAM10H_MMIO_CONF_BASE, val);
184
0
}
185
186
static int __init set_check_enable_amd_mmconf(struct dmi_system_id *d)
187
0
{
188
0
        pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;
189
0
        return 0;
190
0
}
191
192
static struct dmi_system_id __initdata mmconf_dmi_table[] = {
193
  {
194
    .callback = set_check_enable_amd_mmconf,
195
    .ident = "Sun Microsystems Machine",
196
    .matches = {
197
      DMI_MATCH(DMI_SYS_VENDOR, "Sun Microsystems"),
198
    },
199
  },
200
  {}
201
};
202
203
void __init check_enable_amd_mmconf_dmi(void)
204
0
{
205
0
  dmi_check_system(mmconf_dmi_table);
206
0
}