|
Lines 51-66
Link Here
|
| 51 |
#include "imcsmb_reg.h" |
51 |
#include "imcsmb_reg.h" |
| 52 |
#include "imcsmb_var.h" |
52 |
#include "imcsmb_var.h" |
| 53 |
|
53 |
|
| 54 |
/* (Sandy,Ivy)bridge-Xeon and (Has,Broad)well-Xeon CPUs contain one or two |
54 |
/* (Sandy,Ivy)bridge-Xeon, (Has,Broad)well-Xeon, and Skylake-Xeon CPUs contain |
| 55 |
* "Integrated Memory Controllers" (iMCs), and each iMC contains two separate |
55 |
* one or two "Integrated Memory Controllers" (iMCs), and each iMC contains |
| 56 |
* SMBus controllers. These are used for reading SPD data from the DIMMs, and |
56 |
* two separate SMBus controllers. These are used for reading SPD data from the |
| 57 |
* for reading the "Thermal Sensor on DIMM" (TSODs). The iMC SMBus controllers |
57 |
* DIMMs, and for reading the "Thermal Sensor on DIMM" (TSODs). The iMC SMBus |
| 58 |
* are very simple devices, and have limited functionality compared to |
58 |
* controllers are very simple devices, and have limited functionality compared |
| 59 |
* full-fledged SMBus controllers, like the one in Intel ICHs and PCHs. |
59 |
* to full-fledged SMBus controllers, like the one in Intel ICHs and PCHs. |
| 60 |
* |
60 |
* |
| 61 |
* The publicly available documentation for the iMC SMBus controllers can be |
61 |
* The publicly available documentation for the iMC SMBus controllers can be |
| 62 |
* found in the CPU datasheets for (Sandy,Ivy)bridge-Xeon and |
62 |
* found in the CPU datasheets for (Sandy,Ivy)bridge-Xeon, (Has,Broad)well-Xeon, |
| 63 |
* (Has,broad)well-Xeon, respectively: |
63 |
* and Skylake-Xeon, respectively: |
| 64 |
* |
64 |
* |
| 65 |
* https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/ |
65 |
* https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/ |
| 66 |
* Sandybridge xeon-e5-1600-2600-vol-2-datasheet.pdf |
66 |
* Sandybridge xeon-e5-1600-2600-vol-2-datasheet.pdf |
|
Lines 67-72
Link Here
|
| 67 |
* Ivybridge xeon-e5-v2-datasheet-vol-2.pdf |
67 |
* Ivybridge xeon-e5-v2-datasheet-vol-2.pdf |
| 68 |
* Haswell xeon-e5-v3-datasheet-vol-2.pdf |
68 |
* Haswell xeon-e5-v3-datasheet-vol-2.pdf |
| 69 |
* Broadwell xeon-e5-v4-datasheet-vol-2.pdf |
69 |
* Broadwell xeon-e5-v4-datasheet-vol-2.pdf |
|
|
70 |
* Skylake xeon-scalable-datasheet-vol-2.pdf |
| 70 |
* |
71 |
* |
| 71 |
* Another useful resource is the Linux driver. It is not in the main tree. |
72 |
* Another useful resource is the Linux driver. It is not in the main tree. |
| 72 |
* |
73 |
* |
|
Lines 101-149
Link Here
|
| 101 |
* driver such as this one. |
102 |
* driver such as this one. |
| 102 |
*/ |
103 |
*/ |
| 103 |
|
104 |
|
| 104 |
/* PCIe device IDs for (Sandy,Ivy)bridge)-Xeon and (Has,Broad)well-Xeon */ |
105 |
/* PCIe device IDs for (Sandy,Ivy)bridge)-Xeon, (Has,Broad)well-Xeon, and |
|
|
106 |
* Skylake-Xeon |
| 107 |
*/ |
| 105 |
#define PCI_VENDOR_INTEL 0x8086 |
108 |
#define PCI_VENDOR_INTEL 0x8086 |
| 106 |
#define IMCSMB_PCI_DEV_ID_IMC0_SBX 0x3ca8 |
109 |
#define IMCSMB_PCI_DEV_ID_IMC0_SBX 0x3ca8 |
| 107 |
#define IMCSMB_PCI_DEV_ID_IMC0_IBX 0x0ea8 |
110 |
#define IMCSMB_PCI_DEV_ID_IMC0_IBX 0x0ea8 |
| 108 |
#define IMCSMB_PCI_DEV_ID_IMC0_HSX 0x2fa8 |
111 |
#define IMCSMB_PCI_DEV_ID_IMC0_HSX 0x2fa8 |
| 109 |
#define IMCSMB_PCI_DEV_ID_IMC0_BDX 0x6fa8 |
112 |
#define IMCSMB_PCI_DEV_ID_IMC0_BDX 0x6fa8 |
| 110 |
/* (Sandy,Ivy)bridge-Xeon only have a single memory controller per socket */ |
113 |
#define IMCSMB_PCI_DEV_ID_IMC0_SLX 0x2085 |
|
|
114 |
/* Sandybridge-Xeon only has a single memory controller per socket */ |
| 115 |
#define IMCSMB_PCI_DEV_ID_IMC1_IBX 0x0e68 |
| 111 |
#define IMCSMB_PCI_DEV_ID_IMC1_HSX 0x2f68 |
116 |
#define IMCSMB_PCI_DEV_ID_IMC1_HSX 0x2f68 |
| 112 |
#define IMCSMB_PCI_DEV_ID_IMC1_BDX 0x6f68 |
117 |
#define IMCSMB_PCI_DEV_ID_IMC1_BDX 0x6f68 |
|
|
118 |
#define IMCSMB_PCI_DEV_ID_IMC1_SLX 0x2086 |
| 113 |
|
119 |
|
| 114 |
/* There are two SMBus controllers in each device. These define the registers |
120 |
/* There are two SMBus controllers in each device. These define the registers |
| 115 |
* for each of these devices. |
121 |
* for each of these devices. |
| 116 |
*/ |
122 |
*/ |
| 117 |
static struct imcsmb_reg_set imcsmb_regs[] = { |
123 |
static struct imcsmb_reg_set imcsmb_regs[2]; |
| 118 |
{ |
|
|
| 119 |
.smb_stat = IMCSMB_REG_STATUS0, |
| 120 |
.smb_cmd = IMCSMB_REG_COMMAND0, |
| 121 |
.smb_cntl = IMCSMB_REG_CONTROL0 |
| 122 |
}, |
| 123 |
{ |
| 124 |
.smb_stat = IMCSMB_REG_STATUS1, |
| 125 |
.smb_cmd = IMCSMB_REG_COMMAND1, |
| 126 |
.smb_cntl = IMCSMB_REG_CONTROL1 |
| 127 |
}, |
| 128 |
}; |
| 129 |
|
124 |
|
| 130 |
static struct imcsmb_pci_device { |
125 |
static struct imcsmb_pci_device { |
| 131 |
uint16_t id; |
126 |
uint16_t id; |
| 132 |
char *name; |
127 |
char *name; |
|
|
128 |
uint16_t base; |
| 133 |
} imcsmb_pci_devices[] = { |
129 |
} imcsmb_pci_devices[] = { |
| 134 |
{IMCSMB_PCI_DEV_ID_IMC0_SBX, |
130 |
{IMCSMB_PCI_DEV_ID_IMC0_SBX, |
| 135 |
"Intel Sandybridge Xeon iMC 0 SMBus controllers" }, |
131 |
"Intel Sandybridge Xeon iMC 0 SMBus controllers", |
|
|
132 |
IMCSMB_REG_BASE_SBX}, |
| 136 |
{IMCSMB_PCI_DEV_ID_IMC0_IBX, |
133 |
{IMCSMB_PCI_DEV_ID_IMC0_IBX, |
| 137 |
"Intel Ivybridge Xeon iMC 0 SMBus controllers" }, |
134 |
"Intel Ivybridge Xeon iMC 0 SMBus controllers", |
|
|
135 |
IMCSMB_REG_BASE_IBX}, |
| 136 |
{IMCSMB_PCI_DEV_ID_IMC1_IBX, |
| 137 |
"Intel Ivybridge Xeon iMC 1 SMBus controllers", |
| 138 |
IMCSMB_REG_BASE_IBX}, |
| 138 |
{IMCSMB_PCI_DEV_ID_IMC0_HSX, |
139 |
{IMCSMB_PCI_DEV_ID_IMC0_HSX, |
| 139 |
"Intel Haswell Xeon iMC 0 SMBus controllers" }, |
140 |
"Intel Haswell Xeon iMC 0 SMBus controllers", |
|
|
141 |
IMCSMB_REG_BASE_HSX}, |
| 140 |
{IMCSMB_PCI_DEV_ID_IMC1_HSX, |
142 |
{IMCSMB_PCI_DEV_ID_IMC1_HSX, |
| 141 |
"Intel Haswell Xeon iMC 1 SMBus controllers" }, |
143 |
"Intel Haswell Xeon iMC 1 SMBus controllers", |
|
|
144 |
IMCSMB_REG_BASE_HSX}, |
| 142 |
{IMCSMB_PCI_DEV_ID_IMC0_BDX, |
145 |
{IMCSMB_PCI_DEV_ID_IMC0_BDX, |
| 143 |
"Intel Broadwell Xeon iMC 0 SMBus controllers" }, |
146 |
"Intel Broadwell Xeon iMC 0 SMBus controllers", |
|
|
147 |
IMCSMB_REG_BASE_BDX}, |
| 144 |
{IMCSMB_PCI_DEV_ID_IMC1_BDX, |
148 |
{IMCSMB_PCI_DEV_ID_IMC1_BDX, |
| 145 |
"Intel Broadwell Xeon iMC 1 SMBus controllers" }, |
149 |
"Intel Broadwell Xeon iMC 1 SMBus controllers", |
| 146 |
{0, NULL}, |
150 |
IMCSMB_REG_BASE_BDX}, |
|
|
151 |
{IMCSMB_PCI_DEV_ID_IMC0_SLX, |
| 152 |
"Intel Skylake Xeon iMC 0 SMBus controllers", |
| 153 |
IMCSMB_REG_BASE_SLX}, |
| 154 |
{IMCSMB_PCI_DEV_ID_IMC1_SLX, |
| 155 |
"Intel Skylake Xeon iMC 1 SMBus controllers", |
| 156 |
IMCSMB_REG_BASE_SLX}, |
| 157 |
{0, NULL, 0}, |
| 147 |
}; |
158 |
}; |
| 148 |
|
159 |
|
| 149 |
/* Device methods. */ |
160 |
/* Device methods. */ |
|
Lines 165-170
Link Here
|
| 165 |
imcsmb_pci_attach(device_t dev) |
176 |
imcsmb_pci_attach(device_t dev) |
| 166 |
{ |
177 |
{ |
| 167 |
struct imcsmb_pci_softc *sc; |
178 |
struct imcsmb_pci_softc *sc; |
|
|
179 |
struct imcsmb_pci_device *pci_device; |
| 180 |
uint16_t pci_dev_id; |
| 181 |
uint16_t base; |
| 168 |
device_t child; |
182 |
device_t child; |
| 169 |
int rc; |
183 |
int rc; |
| 170 |
int unit; |
184 |
int unit; |
|
Lines 174-179
Link Here
|
| 174 |
sc->dev = dev; |
188 |
sc->dev = dev; |
| 175 |
sc->semaphore = 0; |
189 |
sc->semaphore = 0; |
| 176 |
|
190 |
|
|
|
191 |
/* Walk the list of supported devices again to find the base address; |
| 192 |
* we only get here if imcsmb_pci_probe() found a match, so it |
| 193 |
* shouldn't be possible to end up with 'base' of 0; handle it anyway. |
| 194 |
*/ |
| 195 |
base = 0; |
| 196 |
pci_dev_id = pci_get_device(dev); |
| 197 |
for (pci_device = imcsmb_pci_devices; |
| 198 |
pci_device->base != 0; |
| 199 |
pci_device++) { |
| 200 |
if (pci_dev_id == pci_device->id) { |
| 201 |
base = pci_device->base; |
| 202 |
break; |
| 203 |
} |
| 204 |
} |
| 205 |
if (base == 0) { |
| 206 |
device_printf(dev, "Could not find register base address\n"); |
| 207 |
rc = ENXIO; |
| 208 |
goto out; |
| 209 |
} |
| 210 |
|
| 177 |
/* Create the imcsmbX children */ |
211 |
/* Create the imcsmbX children */ |
| 178 |
for (unit = 0; unit < 2; unit++) { |
212 |
for (unit = 0; unit < 2; unit++) { |
| 179 |
child = device_add_child(dev, "imcsmb", -1); |
213 |
child = device_add_child(dev, "imcsmb", -1); |
|
Lines 183-188
Link Here
|
| 183 |
rc = ENXIO; |
217 |
rc = ENXIO; |
| 184 |
goto out; |
218 |
goto out; |
| 185 |
} |
219 |
} |
|
|
220 |
/* Initialize the register array for the base address and |
| 221 |
* unit. |
| 222 |
*/ |
| 223 |
imcsmb_regs[unit].smb_stat = IMCSMB_REG_STATUS(base, unit); |
| 224 |
imcsmb_regs[unit].smb_cmd = IMCSMB_REG_COMMAND(base, unit); |
| 225 |
imcsmb_regs[unit].smb_cntl = IMCSMB_REG_CONTROL(base, unit); |
| 186 |
/* Set the child's ivars to point to the appropriate set of |
226 |
/* Set the child's ivars to point to the appropriate set of |
| 187 |
* the PCI device's registers. |
227 |
* the PCI device's registers. |
| 188 |
*/ |
228 |
*/ |