1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * A hwmon driver for the Intel 5000 series chipset FB-DIMM AMB 4 * temperature sensors 5 * Copyright (C) 2007 IBM 6 * 7 * Author: Darrick J. Wong <darrick.wong@oracle.com> 8 */ 9 10 #include <linux/module.h> 11 #include <linux/hwmon.h> 12 #include <linux/hwmon-sysfs.h> 13 #include <linux/err.h> 14 #include <linux/mutex.h> 15 #include <linux/log2.h> 16 #include <linux/pci.h> 17 #include <linux/platform_device.h> 18 #include <linux/slab.h> 19 20 #define DRVNAME "i5k_amb" 21 22 #define I5K_REG_AMB_BASE_ADDR 0x48 23 #define I5K_REG_AMB_LEN_ADDR 0x50 24 #define I5K_REG_CHAN0_PRESENCE_ADDR 0x64 25 #define I5K_REG_CHAN1_PRESENCE_ADDR 0x66 26 27 #define AMB_REG_TEMP_MIN_ADDR 0x80 28 #define AMB_REG_TEMP_MID_ADDR 0x81 29 #define AMB_REG_TEMP_MAX_ADDR 0x82 30 #define AMB_REG_TEMP_STATUS_ADDR 0x84 31 #define AMB_REG_TEMP_ADDR 0x85 32 33 #define AMB_CONFIG_SIZE 2048 34 #define AMB_FUNC_3_OFFSET 768 35 36 static unsigned long amb_reg_temp_status(unsigned int amb) 37 { 38 return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_STATUS_ADDR + 39 AMB_CONFIG_SIZE * amb; 40 } 41 42 static unsigned long amb_reg_temp_min(unsigned int amb) 43 { 44 return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MIN_ADDR + 45 AMB_CONFIG_SIZE * amb; 46 } 47 48 static unsigned long amb_reg_temp_mid(unsigned int amb) 49 { 50 return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MID_ADDR + 51 AMB_CONFIG_SIZE * amb; 52 } 53 54 static unsigned long amb_reg_temp_max(unsigned int amb) 55 { 56 return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MAX_ADDR + 57 AMB_CONFIG_SIZE * amb; 58 } 59 60 static unsigned long amb_reg_temp(unsigned int amb) 61 { 62 return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_ADDR + 63 AMB_CONFIG_SIZE * amb; 64 } 65 66 #define MAX_MEM_CHANNELS 4 67 #define MAX_AMBS_PER_CHANNEL 16 68 #define MAX_AMBS (MAX_MEM_CHANNELS * \ 69 MAX_AMBS_PER_CHANNEL) 70 #define CHANNEL_SHIFT 4 71 #define DIMM_MASK 0xF 72 /* 73 * Ugly hack: For some reason the highest bit is set if there 74 * are _any_ DIMMs in the channel. Attempting to read from 75 * this "high-order" AMB results in a memory bus error, so 76 * for now we'll just ignore that top bit, even though that 77 * might prevent us from seeing the 16th DIMM in the channel. 78 */ 79 #define REAL_MAX_AMBS_PER_CHANNEL 15 80 #define KNOBS_PER_AMB 6 81 82 static unsigned long amb_num_from_reg(unsigned int byte_num, unsigned int bit) 83 { 84 return byte_num * MAX_AMBS_PER_CHANNEL + bit; 85 } 86 87 #define AMB_SYSFS_NAME_LEN 16 88 struct i5k_device_attribute { 89 struct sensor_device_attribute s_attr; 90 char name[AMB_SYSFS_NAME_LEN]; 91 }; 92 93 struct i5k_amb_data { 94 struct device *hwmon_dev; 95 96 unsigned long amb_base; 97 unsigned long amb_len; 98 u16 amb_present[MAX_MEM_CHANNELS]; 99 void __iomem *amb_mmio; 100 struct i5k_device_attribute *attrs; 101 unsigned int num_attrs; 102 }; 103 104 static DEVICE_STRING_ATTR_RO(name, 0444, DRVNAME); 105 106 static struct platform_device *amb_pdev; 107 108 static u8 amb_read_byte(struct i5k_amb_data *data, unsigned long offset) 109 { 110 return ioread8(data->amb_mmio + offset); 111 } 112 113 static void amb_write_byte(struct i5k_amb_data *data, unsigned long offset, 114 u8 val) 115 { 116 iowrite8(val, data->amb_mmio + offset); 117 } 118 119 static ssize_t show_amb_alarm(struct device *dev, 120 struct device_attribute *devattr, 121 char *buf) 122 { 123 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 124 struct i5k_amb_data *data = dev_get_drvdata(dev); 125 126 if (!(amb_read_byte(data, amb_reg_temp_status(attr->index)) & 0x20) && 127 (amb_read_byte(data, amb_reg_temp_status(attr->index)) & 0x8)) 128 return sprintf(buf, "1\n"); 129 else 130 return sprintf(buf, "0\n"); 131 } 132 133 static ssize_t store_amb_min(struct device *dev, 134 struct device_attribute *devattr, 135 const char *buf, 136 size_t count) 137 { 138 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 139 struct i5k_amb_data *data = dev_get_drvdata(dev); 140 unsigned long temp; 141 int ret = kstrtoul(buf, 10, &temp); 142 if (ret < 0) 143 return ret; 144 145 temp = temp / 500; 146 if (temp > 255) 147 temp = 255; 148 149 amb_write_byte(data, amb_reg_temp_min(attr->index), temp); 150 return count; 151 } 152 153 static ssize_t store_amb_mid(struct device *dev, 154 struct device_attribute *devattr, 155 const char *buf, 156 size_t count) 157 { 158 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 159 struct i5k_amb_data *data = dev_get_drvdata(dev); 160 unsigned long temp; 161 int ret = kstrtoul(buf, 10, &temp); 162 if (ret < 0) 163 return ret; 164 165 temp = temp / 500; 166 if (temp > 255) 167 temp = 255; 168 169 amb_write_byte(data, amb_reg_temp_mid(attr->index), temp); 170 return count; 171 } 172 173 static ssize_t store_amb_max(struct device *dev, 174 struct device_attribute *devattr, 175 const char *buf, 176 size_t count) 177 { 178 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 179 struct i5k_amb_data *data = dev_get_drvdata(dev); 180 unsigned long temp; 181 int ret = kstrtoul(buf, 10, &temp); 182 if (ret < 0) 183 return ret; 184 185 temp = temp / 500; 186 if (temp > 255) 187 temp = 255; 188 189 amb_write_byte(data, amb_reg_temp_max(attr->index), temp); 190 return count; 191 } 192 193 static ssize_t show_amb_min(struct device *dev, 194 struct device_attribute *devattr, 195 char *buf) 196 { 197 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 198 struct i5k_amb_data *data = dev_get_drvdata(dev); 199 return sprintf(buf, "%d\n", 200 500 * amb_read_byte(data, amb_reg_temp_min(attr->index))); 201 } 202 203 static ssize_t show_amb_mid(struct device *dev, 204 struct device_attribute *devattr, 205 char *buf) 206 { 207 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 208 struct i5k_amb_data *data = dev_get_drvdata(dev); 209 return sprintf(buf, "%d\n", 210 500 * amb_read_byte(data, amb_reg_temp_mid(attr->index))); 211 } 212 213 static ssize_t show_amb_max(struct device *dev, 214 struct device_attribute *devattr, 215 char *buf) 216 { 217 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 218 struct i5k_amb_data *data = dev_get_drvdata(dev); 219 return sprintf(buf, "%d\n", 220 500 * amb_read_byte(data, amb_reg_temp_max(attr->index))); 221 } 222 223 static ssize_t show_amb_temp(struct device *dev, 224 struct device_attribute *devattr, 225 char *buf) 226 { 227 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 228 struct i5k_amb_data *data = dev_get_drvdata(dev); 229 return sprintf(buf, "%d\n", 230 500 * amb_read_byte(data, amb_reg_temp(attr->index))); 231 } 232 233 static ssize_t show_label(struct device *dev, 234 struct device_attribute *devattr, 235 char *buf) 236 { 237 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 238 239 return sprintf(buf, "Ch. %d DIMM %d\n", attr->index >> CHANNEL_SHIFT, 240 attr->index & DIMM_MASK); 241 } 242 243 static int i5k_amb_hwmon_init(struct platform_device *pdev) 244 { 245 int i, j, k, d = 0; 246 u16 c; 247 int res = 0; 248 int num_ambs = 0; 249 struct i5k_amb_data *data = platform_get_drvdata(pdev); 250 251 /* Count the number of AMBs found */ 252 /* ignore the high-order bit, see "Ugly hack" comment above */ 253 for (i = 0; i < MAX_MEM_CHANNELS; i++) 254 num_ambs += hweight16(data->amb_present[i] & 0x7fff); 255 256 /* Set up sysfs stuff */ 257 data->attrs = kzalloc(array3_size(num_ambs, KNOBS_PER_AMB, 258 sizeof(*data->attrs)), 259 GFP_KERNEL); 260 if (!data->attrs) 261 return -ENOMEM; 262 data->num_attrs = 0; 263 264 for (i = 0; i < MAX_MEM_CHANNELS; i++) { 265 c = data->amb_present[i]; 266 for (j = 0; j < REAL_MAX_AMBS_PER_CHANNEL; j++, c >>= 1) { 267 struct i5k_device_attribute *iattr; 268 269 k = amb_num_from_reg(i, j); 270 if (!(c & 0x1)) 271 continue; 272 d++; 273 274 /* sysfs label */ 275 iattr = data->attrs + data->num_attrs; 276 snprintf(iattr->name, AMB_SYSFS_NAME_LEN, 277 "temp%d_label", d); 278 iattr->s_attr.dev_attr.attr.name = iattr->name; 279 iattr->s_attr.dev_attr.attr.mode = 0444; 280 iattr->s_attr.dev_attr.show = show_label; 281 iattr->s_attr.index = k; 282 sysfs_attr_init(&iattr->s_attr.dev_attr.attr); 283 res = device_create_file(&pdev->dev, 284 &iattr->s_attr.dev_attr); 285 if (res) 286 goto exit_remove; 287 data->num_attrs++; 288 289 /* Temperature sysfs knob */ 290 iattr = data->attrs + data->num_attrs; 291 snprintf(iattr->name, AMB_SYSFS_NAME_LEN, 292 "temp%d_input", d); 293 iattr->s_attr.dev_attr.attr.name = iattr->name; 294 iattr->s_attr.dev_attr.attr.mode = 0444; 295 iattr->s_attr.dev_attr.show = show_amb_temp; 296 iattr->s_attr.index = k; 297 sysfs_attr_init(&iattr->s_attr.dev_attr.attr); 298 res = device_create_file(&pdev->dev, 299 &iattr->s_attr.dev_attr); 300 if (res) 301 goto exit_remove; 302 data->num_attrs++; 303 304 /* Temperature min sysfs knob */ 305 iattr = data->attrs + data->num_attrs; 306 snprintf(iattr->name, AMB_SYSFS_NAME_LEN, 307 "temp%d_min", d); 308 iattr->s_attr.dev_attr.attr.name = iattr->name; 309 iattr->s_attr.dev_attr.attr.mode = 0644; 310 iattr->s_attr.dev_attr.show = show_amb_min; 311 iattr->s_attr.dev_attr.store = store_amb_min; 312 iattr->s_attr.index = k; 313 sysfs_attr_init(&iattr->s_attr.dev_attr.attr); 314 res = device_create_file(&pdev->dev, 315 &iattr->s_attr.dev_attr); 316 if (res) 317 goto exit_remove; 318 data->num_attrs++; 319 320 /* Temperature mid sysfs knob */ 321 iattr = data->attrs + data->num_attrs; 322 snprintf(iattr->name, AMB_SYSFS_NAME_LEN, 323 "temp%d_mid", d); 324 iattr->s_attr.dev_attr.attr.name = iattr->name; 325 iattr->s_attr.dev_attr.attr.mode = 0644; 326 iattr->s_attr.dev_attr.show = show_amb_mid; 327 iattr->s_attr.dev_attr.store = store_amb_mid; 328 iattr->s_attr.index = k; 329 sysfs_attr_init(&iattr->s_attr.dev_attr.attr); 330 res = device_create_file(&pdev->dev, 331 &iattr->s_attr.dev_attr); 332 if (res) 333 goto exit_remove; 334 data->num_attrs++; 335 336 /* Temperature max sysfs knob */ 337 iattr = data->attrs + data->num_attrs; 338 snprintf(iattr->name, AMB_SYSFS_NAME_LEN, 339 "temp%d_max", d); 340 iattr->s_attr.dev_attr.attr.name = iattr->name; 341 iattr->s_attr.dev_attr.attr.mode = 0644; 342 iattr->s_attr.dev_attr.show = show_amb_max; 343 iattr->s_attr.dev_attr.store = store_amb_max; 344 iattr->s_attr.index = k; 345 sysfs_attr_init(&iattr->s_attr.dev_attr.attr); 346 res = device_create_file(&pdev->dev, 347 &iattr->s_attr.dev_attr); 348 if (res) 349 goto exit_remove; 350 data->num_attrs++; 351 352 /* Temperature alarm sysfs knob */ 353 iattr = data->attrs + data->num_attrs; 354 snprintf(iattr->name, AMB_SYSFS_NAME_LEN, 355 "temp%d_alarm", d); 356 iattr->s_attr.dev_attr.attr.name = iattr->name; 357 iattr->s_attr.dev_attr.attr.mode = 0444; 358 iattr->s_attr.dev_attr.show = show_amb_alarm; 359 iattr->s_attr.index = k; 360 sysfs_attr_init(&iattr->s_attr.dev_attr.attr); 361 res = device_create_file(&pdev->dev, 362 &iattr->s_attr.dev_attr); 363 if (res) 364 goto exit_remove; 365 data->num_attrs++; 366 } 367 } 368 369 res = device_create_file(&pdev->dev, &dev_attr_name.attr); 370 if (res) 371 goto exit_remove; 372 373 data->hwmon_dev = hwmon_device_register(&pdev->dev); 374 if (IS_ERR(data->hwmon_dev)) { 375 res = PTR_ERR(data->hwmon_dev); 376 goto exit_remove; 377 } 378 379 return res; 380 381 exit_remove: 382 device_remove_file(&pdev->dev, &dev_attr_name.attr); 383 for (i = 0; i < data->num_attrs; i++) 384 device_remove_file(&pdev->dev, &data->attrs[i].s_attr.dev_attr); 385 kfree(data->attrs); 386 387 return res; 388 } 389 390 static int i5k_amb_add(void) 391 { 392 int res; 393 394 /* only ever going to be one of these */ 395 amb_pdev = platform_device_alloc(DRVNAME, 0); 396 if (!amb_pdev) 397 return -ENOMEM; 398 399 res = platform_device_add(amb_pdev); 400 if (res) 401 goto err; 402 return 0; 403 404 err: 405 platform_device_put(amb_pdev); 406 return res; 407 } 408 409 static int i5k_find_amb_registers(struct i5k_amb_data *data, 410 unsigned long devid) 411 { 412 struct pci_dev *pcidev; 413 u32 val32; 414 int res = -ENODEV; 415 416 /* Find AMB register memory space */ 417 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, 418 devid, 419 NULL); 420 if (!pcidev) 421 return -ENODEV; 422 423 pci_read_config_dword(pcidev, I5K_REG_AMB_BASE_ADDR, &val32); 424 if (val32 == (u32)~0) 425 goto out; 426 data->amb_base = val32; 427 428 pci_read_config_dword(pcidev, I5K_REG_AMB_LEN_ADDR, &val32); 429 if (val32 == (u32)~0) 430 goto out; 431 data->amb_len = val32; 432 433 /* Is it big enough? */ 434 if (data->amb_len < AMB_CONFIG_SIZE * MAX_AMBS) { 435 dev_err(&pcidev->dev, "AMB region too small!\n"); 436 goto out; 437 } 438 439 res = 0; 440 out: 441 pci_dev_put(pcidev); 442 return res; 443 } 444 445 static int i5k_channel_probe(u16 *amb_present, unsigned long dev_id) 446 { 447 struct pci_dev *pcidev; 448 u16 val16; 449 int res = -ENODEV; 450 451 /* Copy the DIMM presence map for these two channels */ 452 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL); 453 if (!pcidev) 454 return -ENODEV; 455 456 pci_read_config_word(pcidev, I5K_REG_CHAN0_PRESENCE_ADDR, &val16); 457 if (val16 == (u16)~0) 458 goto out; 459 amb_present[0] = val16; 460 461 pci_read_config_word(pcidev, I5K_REG_CHAN1_PRESENCE_ADDR, &val16); 462 if (val16 == (u16)~0) 463 goto out; 464 amb_present[1] = val16; 465 466 res = 0; 467 468 out: 469 pci_dev_put(pcidev); 470 return res; 471 } 472 473 static struct { 474 unsigned long err; 475 unsigned long fbd0; 476 } chipset_ids[] = { 477 { PCI_DEVICE_ID_INTEL_5000_ERR, PCI_DEVICE_ID_INTEL_5000_FBD0 }, 478 { PCI_DEVICE_ID_INTEL_5400_ERR, PCI_DEVICE_ID_INTEL_5400_FBD0 }, 479 { 0, 0 } 480 }; 481 482 #ifdef MODULE 483 static const struct pci_device_id i5k_amb_ids[] = { 484 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) }, 485 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) }, 486 { 0, } 487 }; 488 MODULE_DEVICE_TABLE(pci, i5k_amb_ids); 489 #endif 490 491 static int i5k_amb_probe(struct platform_device *pdev) 492 { 493 struct i5k_amb_data *data; 494 struct resource *reso; 495 int i, res; 496 497 data = kzalloc(sizeof(*data), GFP_KERNEL); 498 if (!data) 499 return -ENOMEM; 500 501 /* Figure out where the AMB registers live */ 502 i = 0; 503 do { 504 res = i5k_find_amb_registers(data, chipset_ids[i].err); 505 if (res == 0) 506 break; 507 i++; 508 } while (chipset_ids[i].err); 509 510 if (res) 511 goto err; 512 513 /* Copy the DIMM presence map for the first two channels */ 514 res = i5k_channel_probe(&data->amb_present[0], chipset_ids[i].fbd0); 515 if (res) 516 goto err; 517 518 /* Copy the DIMM presence map for the optional second two channels */ 519 i5k_channel_probe(&data->amb_present[2], chipset_ids[i].fbd0 + 1); 520 521 /* Set up resource regions */ 522 reso = request_mem_region(data->amb_base, data->amb_len, DRVNAME); 523 if (!reso) { 524 res = -EBUSY; 525 goto err; 526 } 527 528 data->amb_mmio = ioremap(data->amb_base, data->amb_len); 529 if (!data->amb_mmio) { 530 res = -EBUSY; 531 goto err_map_failed; 532 } 533 534 platform_set_drvdata(pdev, data); 535 536 res = i5k_amb_hwmon_init(pdev); 537 if (res) 538 goto err_init_failed; 539 540 return res; 541 542 err_init_failed: 543 iounmap(data->amb_mmio); 544 err_map_failed: 545 release_mem_region(data->amb_base, data->amb_len); 546 err: 547 kfree(data); 548 return res; 549 } 550 551 static void i5k_amb_remove(struct platform_device *pdev) 552 { 553 int i; 554 struct i5k_amb_data *data = platform_get_drvdata(pdev); 555 556 hwmon_device_unregister(data->hwmon_dev); 557 device_remove_file(&pdev->dev, &dev_attr_name.attr); 558 for (i = 0; i < data->num_attrs; i++) 559 device_remove_file(&pdev->dev, &data->attrs[i].s_attr.dev_attr); 560 kfree(data->attrs); 561 iounmap(data->amb_mmio); 562 release_mem_region(data->amb_base, data->amb_len); 563 kfree(data); 564 } 565 566 static struct platform_driver i5k_amb_driver = { 567 .driver = { 568 .name = DRVNAME, 569 }, 570 .probe = i5k_amb_probe, 571 .remove = i5k_amb_remove, 572 }; 573 574 static int __init i5k_amb_init(void) 575 { 576 int res; 577 578 res = platform_driver_register(&i5k_amb_driver); 579 if (res) 580 return res; 581 582 res = i5k_amb_add(); 583 if (res) 584 platform_driver_unregister(&i5k_amb_driver); 585 586 return res; 587 } 588 589 static void __exit i5k_amb_exit(void) 590 { 591 platform_device_unregister(amb_pdev); 592 platform_driver_unregister(&i5k_amb_driver); 593 } 594 595 MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>"); 596 MODULE_DESCRIPTION("Intel 5000 chipset FB-DIMM AMB temperature sensor"); 597 MODULE_LICENSE("GPL"); 598 599 module_init(i5k_amb_init); 600 module_exit(i5k_amb_exit); 601