at v4.9-rc8 650 lines 16 kB view raw
1/* 2 * dcdbas.c: Dell Systems Management Base Driver 3 * 4 * The Dell Systems Management Base Driver provides a sysfs interface for 5 * systems management software to perform System Management Interrupts (SMIs) 6 * and Host Control Actions (power cycle or power off after OS shutdown) on 7 * Dell systems. 8 * 9 * See Documentation/dcdbas.txt for more information. 10 * 11 * Copyright (C) 1995-2006 Dell Inc. 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License v2.0 as published by 15 * the Free Software Foundation. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 */ 22 23#include <linux/platform_device.h> 24#include <linux/dma-mapping.h> 25#include <linux/errno.h> 26#include <linux/cpu.h> 27#include <linux/gfp.h> 28#include <linux/init.h> 29#include <linux/kernel.h> 30#include <linux/mc146818rtc.h> 31#include <linux/module.h> 32#include <linux/reboot.h> 33#include <linux/sched.h> 34#include <linux/smp.h> 35#include <linux/spinlock.h> 36#include <linux/string.h> 37#include <linux/types.h> 38#include <linux/mutex.h> 39#include <asm/io.h> 40 41#include "dcdbas.h" 42 43#define DRIVER_NAME "dcdbas" 44#define DRIVER_VERSION "5.6.0-3.2" 45#define DRIVER_DESCRIPTION "Dell Systems Management Base Driver" 46 47static struct platform_device *dcdbas_pdev; 48 49static u8 *smi_data_buf; 50static dma_addr_t smi_data_buf_handle; 51static unsigned long smi_data_buf_size; 52static u32 smi_data_buf_phys_addr; 53static DEFINE_MUTEX(smi_data_lock); 54 55static unsigned int host_control_action; 56static unsigned int host_control_smi_type; 57static unsigned int host_control_on_shutdown; 58 59/** 60 * smi_data_buf_free: free SMI data buffer 61 */ 62static void smi_data_buf_free(void) 63{ 64 if (!smi_data_buf) 65 return; 66 67 dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", 68 __func__, smi_data_buf_phys_addr, smi_data_buf_size); 69 70 dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf, 71 smi_data_buf_handle); 72 smi_data_buf = NULL; 73 smi_data_buf_handle = 0; 74 smi_data_buf_phys_addr = 0; 75 smi_data_buf_size = 0; 76} 77 78/** 79 * smi_data_buf_realloc: grow SMI data buffer if needed 80 */ 81static int smi_data_buf_realloc(unsigned long size) 82{ 83 void *buf; 84 dma_addr_t handle; 85 86 if (smi_data_buf_size >= size) 87 return 0; 88 89 if (size > MAX_SMI_DATA_BUF_SIZE) 90 return -EINVAL; 91 92 /* new buffer is needed */ 93 buf = dma_alloc_coherent(&dcdbas_pdev->dev, size, &handle, GFP_KERNEL); 94 if (!buf) { 95 dev_dbg(&dcdbas_pdev->dev, 96 "%s: failed to allocate memory size %lu\n", 97 __func__, size); 98 return -ENOMEM; 99 } 100 /* memory zeroed by dma_alloc_coherent */ 101 102 if (smi_data_buf) 103 memcpy(buf, smi_data_buf, smi_data_buf_size); 104 105 /* free any existing buffer */ 106 smi_data_buf_free(); 107 108 /* set up new buffer for use */ 109 smi_data_buf = buf; 110 smi_data_buf_handle = handle; 111 smi_data_buf_phys_addr = (u32) virt_to_phys(buf); 112 smi_data_buf_size = size; 113 114 dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", 115 __func__, smi_data_buf_phys_addr, smi_data_buf_size); 116 117 return 0; 118} 119 120static ssize_t smi_data_buf_phys_addr_show(struct device *dev, 121 struct device_attribute *attr, 122 char *buf) 123{ 124 return sprintf(buf, "%x\n", smi_data_buf_phys_addr); 125} 126 127static ssize_t smi_data_buf_size_show(struct device *dev, 128 struct device_attribute *attr, 129 char *buf) 130{ 131 return sprintf(buf, "%lu\n", smi_data_buf_size); 132} 133 134static ssize_t smi_data_buf_size_store(struct device *dev, 135 struct device_attribute *attr, 136 const char *buf, size_t count) 137{ 138 unsigned long buf_size; 139 ssize_t ret; 140 141 buf_size = simple_strtoul(buf, NULL, 10); 142 143 /* make sure SMI data buffer is at least buf_size */ 144 mutex_lock(&smi_data_lock); 145 ret = smi_data_buf_realloc(buf_size); 146 mutex_unlock(&smi_data_lock); 147 if (ret) 148 return ret; 149 150 return count; 151} 152 153static ssize_t smi_data_read(struct file *filp, struct kobject *kobj, 154 struct bin_attribute *bin_attr, 155 char *buf, loff_t pos, size_t count) 156{ 157 ssize_t ret; 158 159 mutex_lock(&smi_data_lock); 160 ret = memory_read_from_buffer(buf, count, &pos, smi_data_buf, 161 smi_data_buf_size); 162 mutex_unlock(&smi_data_lock); 163 return ret; 164} 165 166static ssize_t smi_data_write(struct file *filp, struct kobject *kobj, 167 struct bin_attribute *bin_attr, 168 char *buf, loff_t pos, size_t count) 169{ 170 ssize_t ret; 171 172 if ((pos + count) > MAX_SMI_DATA_BUF_SIZE) 173 return -EINVAL; 174 175 mutex_lock(&smi_data_lock); 176 177 ret = smi_data_buf_realloc(pos + count); 178 if (ret) 179 goto out; 180 181 memcpy(smi_data_buf + pos, buf, count); 182 ret = count; 183out: 184 mutex_unlock(&smi_data_lock); 185 return ret; 186} 187 188static ssize_t host_control_action_show(struct device *dev, 189 struct device_attribute *attr, 190 char *buf) 191{ 192 return sprintf(buf, "%u\n", host_control_action); 193} 194 195static ssize_t host_control_action_store(struct device *dev, 196 struct device_attribute *attr, 197 const char *buf, size_t count) 198{ 199 ssize_t ret; 200 201 /* make sure buffer is available for host control command */ 202 mutex_lock(&smi_data_lock); 203 ret = smi_data_buf_realloc(sizeof(struct apm_cmd)); 204 mutex_unlock(&smi_data_lock); 205 if (ret) 206 return ret; 207 208 host_control_action = simple_strtoul(buf, NULL, 10); 209 return count; 210} 211 212static ssize_t host_control_smi_type_show(struct device *dev, 213 struct device_attribute *attr, 214 char *buf) 215{ 216 return sprintf(buf, "%u\n", host_control_smi_type); 217} 218 219static ssize_t host_control_smi_type_store(struct device *dev, 220 struct device_attribute *attr, 221 const char *buf, size_t count) 222{ 223 host_control_smi_type = simple_strtoul(buf, NULL, 10); 224 return count; 225} 226 227static ssize_t host_control_on_shutdown_show(struct device *dev, 228 struct device_attribute *attr, 229 char *buf) 230{ 231 return sprintf(buf, "%u\n", host_control_on_shutdown); 232} 233 234static ssize_t host_control_on_shutdown_store(struct device *dev, 235 struct device_attribute *attr, 236 const char *buf, size_t count) 237{ 238 host_control_on_shutdown = simple_strtoul(buf, NULL, 10); 239 return count; 240} 241 242static int raise_smi(void *par) 243{ 244 struct smi_cmd *smi_cmd = par; 245 246 if (smp_processor_id() != 0) { 247 dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n", 248 __func__); 249 return -EBUSY; 250 } 251 252 /* generate SMI */ 253 /* inb to force posted write through and make SMI happen now */ 254 asm volatile ( 255 "outb %b0,%w1\n" 256 "inb %w1" 257 : /* no output args */ 258 : "a" (smi_cmd->command_code), 259 "d" (smi_cmd->command_address), 260 "b" (smi_cmd->ebx), 261 "c" (smi_cmd->ecx) 262 : "memory" 263 ); 264 265 return 0; 266} 267/** 268 * dcdbas_smi_request: generate SMI request 269 * 270 * Called with smi_data_lock. 271 */ 272int dcdbas_smi_request(struct smi_cmd *smi_cmd) 273{ 274 int ret; 275 276 if (smi_cmd->magic != SMI_CMD_MAGIC) { 277 dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n", 278 __func__); 279 return -EBADR; 280 } 281 282 /* SMI requires CPU 0 */ 283 get_online_cpus(); 284 ret = smp_call_on_cpu(0, raise_smi, smi_cmd, true); 285 put_online_cpus(); 286 287 return ret; 288} 289 290/** 291 * smi_request_store: 292 * 293 * The valid values are: 294 * 0: zero SMI data buffer 295 * 1: generate calling interface SMI 296 * 2: generate raw SMI 297 * 298 * User application writes smi_cmd to smi_data before telling driver 299 * to generate SMI. 300 */ 301static ssize_t smi_request_store(struct device *dev, 302 struct device_attribute *attr, 303 const char *buf, size_t count) 304{ 305 struct smi_cmd *smi_cmd; 306 unsigned long val = simple_strtoul(buf, NULL, 10); 307 ssize_t ret; 308 309 mutex_lock(&smi_data_lock); 310 311 if (smi_data_buf_size < sizeof(struct smi_cmd)) { 312 ret = -ENODEV; 313 goto out; 314 } 315 smi_cmd = (struct smi_cmd *)smi_data_buf; 316 317 switch (val) { 318 case 2: 319 /* Raw SMI */ 320 ret = dcdbas_smi_request(smi_cmd); 321 if (!ret) 322 ret = count; 323 break; 324 case 1: 325 /* Calling Interface SMI */ 326 smi_cmd->ebx = (u32) virt_to_phys(smi_cmd->command_buffer); 327 ret = dcdbas_smi_request(smi_cmd); 328 if (!ret) 329 ret = count; 330 break; 331 case 0: 332 memset(smi_data_buf, 0, smi_data_buf_size); 333 ret = count; 334 break; 335 default: 336 ret = -EINVAL; 337 break; 338 } 339 340out: 341 mutex_unlock(&smi_data_lock); 342 return ret; 343} 344EXPORT_SYMBOL(dcdbas_smi_request); 345 346/** 347 * host_control_smi: generate host control SMI 348 * 349 * Caller must set up the host control command in smi_data_buf. 350 */ 351static int host_control_smi(void) 352{ 353 struct apm_cmd *apm_cmd; 354 u8 *data; 355 unsigned long flags; 356 u32 num_ticks; 357 s8 cmd_status; 358 u8 index; 359 360 apm_cmd = (struct apm_cmd *)smi_data_buf; 361 apm_cmd->status = ESM_STATUS_CMD_UNSUCCESSFUL; 362 363 switch (host_control_smi_type) { 364 case HC_SMITYPE_TYPE1: 365 spin_lock_irqsave(&rtc_lock, flags); 366 /* write SMI data buffer physical address */ 367 data = (u8 *)&smi_data_buf_phys_addr; 368 for (index = PE1300_CMOS_CMD_STRUCT_PTR; 369 index < (PE1300_CMOS_CMD_STRUCT_PTR + 4); 370 index++, data++) { 371 outb(index, 372 (CMOS_BASE_PORT + CMOS_PAGE2_INDEX_PORT_PIIX4)); 373 outb(*data, 374 (CMOS_BASE_PORT + CMOS_PAGE2_DATA_PORT_PIIX4)); 375 } 376 377 /* first set status to -1 as called by spec */ 378 cmd_status = ESM_STATUS_CMD_UNSUCCESSFUL; 379 outb((u8) cmd_status, PCAT_APM_STATUS_PORT); 380 381 /* generate SMM call */ 382 outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT); 383 spin_unlock_irqrestore(&rtc_lock, flags); 384 385 /* wait a few to see if it executed */ 386 num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING; 387 while ((cmd_status = inb(PCAT_APM_STATUS_PORT)) 388 == ESM_STATUS_CMD_UNSUCCESSFUL) { 389 num_ticks--; 390 if (num_ticks == EXPIRED_TIMER) 391 return -ETIME; 392 } 393 break; 394 395 case HC_SMITYPE_TYPE2: 396 case HC_SMITYPE_TYPE3: 397 spin_lock_irqsave(&rtc_lock, flags); 398 /* write SMI data buffer physical address */ 399 data = (u8 *)&smi_data_buf_phys_addr; 400 for (index = PE1400_CMOS_CMD_STRUCT_PTR; 401 index < (PE1400_CMOS_CMD_STRUCT_PTR + 4); 402 index++, data++) { 403 outb(index, (CMOS_BASE_PORT + CMOS_PAGE1_INDEX_PORT)); 404 outb(*data, (CMOS_BASE_PORT + CMOS_PAGE1_DATA_PORT)); 405 } 406 407 /* generate SMM call */ 408 if (host_control_smi_type == HC_SMITYPE_TYPE3) 409 outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT); 410 else 411 outb(ESM_APM_CMD, PE1400_APM_CONTROL_PORT); 412 413 /* restore RTC index pointer since it was written to above */ 414 CMOS_READ(RTC_REG_C); 415 spin_unlock_irqrestore(&rtc_lock, flags); 416 417 /* read control port back to serialize write */ 418 cmd_status = inb(PE1400_APM_CONTROL_PORT); 419 420 /* wait a few to see if it executed */ 421 num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING; 422 while (apm_cmd->status == ESM_STATUS_CMD_UNSUCCESSFUL) { 423 num_ticks--; 424 if (num_ticks == EXPIRED_TIMER) 425 return -ETIME; 426 } 427 break; 428 429 default: 430 dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n", 431 __func__, host_control_smi_type); 432 return -ENOSYS; 433 } 434 435 return 0; 436} 437 438/** 439 * dcdbas_host_control: initiate host control 440 * 441 * This function is called by the driver after the system has 442 * finished shutting down if the user application specified a 443 * host control action to perform on shutdown. It is safe to 444 * use smi_data_buf at this point because the system has finished 445 * shutting down and no userspace apps are running. 446 */ 447static void dcdbas_host_control(void) 448{ 449 struct apm_cmd *apm_cmd; 450 u8 action; 451 452 if (host_control_action == HC_ACTION_NONE) 453 return; 454 455 action = host_control_action; 456 host_control_action = HC_ACTION_NONE; 457 458 if (!smi_data_buf) { 459 dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __func__); 460 return; 461 } 462 463 if (smi_data_buf_size < sizeof(struct apm_cmd)) { 464 dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n", 465 __func__); 466 return; 467 } 468 469 apm_cmd = (struct apm_cmd *)smi_data_buf; 470 471 /* power off takes precedence */ 472 if (action & HC_ACTION_HOST_CONTROL_POWEROFF) { 473 apm_cmd->command = ESM_APM_POWER_CYCLE; 474 apm_cmd->reserved = 0; 475 *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 0; 476 host_control_smi(); 477 } else if (action & HC_ACTION_HOST_CONTROL_POWERCYCLE) { 478 apm_cmd->command = ESM_APM_POWER_CYCLE; 479 apm_cmd->reserved = 0; 480 *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 20; 481 host_control_smi(); 482 } 483} 484 485/** 486 * dcdbas_reboot_notify: handle reboot notification for host control 487 */ 488static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code, 489 void *unused) 490{ 491 switch (code) { 492 case SYS_DOWN: 493 case SYS_HALT: 494 case SYS_POWER_OFF: 495 if (host_control_on_shutdown) { 496 /* firmware is going to perform host control action */ 497 printk(KERN_WARNING "Please wait for shutdown " 498 "action to complete...\n"); 499 dcdbas_host_control(); 500 } 501 break; 502 } 503 504 return NOTIFY_DONE; 505} 506 507static struct notifier_block dcdbas_reboot_nb = { 508 .notifier_call = dcdbas_reboot_notify, 509 .next = NULL, 510 .priority = INT_MIN 511}; 512 513static DCDBAS_BIN_ATTR_RW(smi_data); 514 515static struct bin_attribute *dcdbas_bin_attrs[] = { 516 &bin_attr_smi_data, 517 NULL 518}; 519 520static DCDBAS_DEV_ATTR_RW(smi_data_buf_size); 521static DCDBAS_DEV_ATTR_RO(smi_data_buf_phys_addr); 522static DCDBAS_DEV_ATTR_WO(smi_request); 523static DCDBAS_DEV_ATTR_RW(host_control_action); 524static DCDBAS_DEV_ATTR_RW(host_control_smi_type); 525static DCDBAS_DEV_ATTR_RW(host_control_on_shutdown); 526 527static struct attribute *dcdbas_dev_attrs[] = { 528 &dev_attr_smi_data_buf_size.attr, 529 &dev_attr_smi_data_buf_phys_addr.attr, 530 &dev_attr_smi_request.attr, 531 &dev_attr_host_control_action.attr, 532 &dev_attr_host_control_smi_type.attr, 533 &dev_attr_host_control_on_shutdown.attr, 534 NULL 535}; 536 537static struct attribute_group dcdbas_attr_group = { 538 .attrs = dcdbas_dev_attrs, 539 .bin_attrs = dcdbas_bin_attrs, 540}; 541 542static int dcdbas_probe(struct platform_device *dev) 543{ 544 int error; 545 546 host_control_action = HC_ACTION_NONE; 547 host_control_smi_type = HC_SMITYPE_NONE; 548 549 dcdbas_pdev = dev; 550 551 /* 552 * BIOS SMI calls require buffer addresses be in 32-bit address space. 553 * This is done by setting the DMA mask below. 554 */ 555 error = dma_set_coherent_mask(&dcdbas_pdev->dev, DMA_BIT_MASK(32)); 556 if (error) 557 return error; 558 559 error = sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group); 560 if (error) 561 return error; 562 563 register_reboot_notifier(&dcdbas_reboot_nb); 564 565 dev_info(&dev->dev, "%s (version %s)\n", 566 DRIVER_DESCRIPTION, DRIVER_VERSION); 567 568 return 0; 569} 570 571static int dcdbas_remove(struct platform_device *dev) 572{ 573 unregister_reboot_notifier(&dcdbas_reboot_nb); 574 sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group); 575 576 return 0; 577} 578 579static struct platform_driver dcdbas_driver = { 580 .driver = { 581 .name = DRIVER_NAME, 582 }, 583 .probe = dcdbas_probe, 584 .remove = dcdbas_remove, 585}; 586 587static const struct platform_device_info dcdbas_dev_info __initconst = { 588 .name = DRIVER_NAME, 589 .id = -1, 590 .dma_mask = DMA_BIT_MASK(32), 591}; 592 593static struct platform_device *dcdbas_pdev_reg; 594 595/** 596 * dcdbas_init: initialize driver 597 */ 598static int __init dcdbas_init(void) 599{ 600 int error; 601 602 error = platform_driver_register(&dcdbas_driver); 603 if (error) 604 return error; 605 606 dcdbas_pdev_reg = platform_device_register_full(&dcdbas_dev_info); 607 if (IS_ERR(dcdbas_pdev_reg)) { 608 error = PTR_ERR(dcdbas_pdev_reg); 609 goto err_unregister_driver; 610 } 611 612 return 0; 613 614 err_unregister_driver: 615 platform_driver_unregister(&dcdbas_driver); 616 return error; 617} 618 619/** 620 * dcdbas_exit: perform driver cleanup 621 */ 622static void __exit dcdbas_exit(void) 623{ 624 /* 625 * make sure functions that use dcdbas_pdev are called 626 * before platform_device_unregister 627 */ 628 unregister_reboot_notifier(&dcdbas_reboot_nb); 629 630 /* 631 * We have to free the buffer here instead of dcdbas_remove 632 * because only in module exit function we can be sure that 633 * all sysfs attributes belonging to this module have been 634 * released. 635 */ 636 if (dcdbas_pdev) 637 smi_data_buf_free(); 638 platform_device_unregister(dcdbas_pdev_reg); 639 platform_driver_unregister(&dcdbas_driver); 640} 641 642module_init(dcdbas_init); 643module_exit(dcdbas_exit); 644 645MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")"); 646MODULE_VERSION(DRIVER_VERSION); 647MODULE_AUTHOR("Dell Inc."); 648MODULE_LICENSE("GPL"); 649/* Any System or BIOS claiming to be by Dell */ 650MODULE_ALIAS("dmi:*:[bs]vnD[Ee][Ll][Ll]*:*");