Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'platform-drivers-x86-v4.2-2' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86

Pull late x86 platform driver updates from Darren Hart:
"The following came in a bit later and I wanted them to bake in next a
few more days before submitting, thus the second pull.

A new intel_pmc_ipc driver, a symmetrical allocation and free fix in
dell-laptop, a couple minor fixes, and some updated documentation in
the dell-laptop comments.

intel_pmc_ipc:
- Add Intel Apollo Lake PMC IPC driver

tc1100-wmi:
- Delete an unnecessary check before the function call "kfree"

dell-laptop:
- Fix allocating & freeing SMI buffer page
- Show info about WiGig and UWB in debugfs
- Update information about wireless control"

* tag 'platform-drivers-x86-v4.2-2' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86:
intel_pmc_ipc: Add Intel Apollo Lake PMC IPC driver
tc1100-wmi: Delete an unnecessary check before the function call "kfree"
dell-laptop: Fix allocating & freeing SMI buffer page
dell-laptop: Show info about WiGig and UWB in debugfs
dell-laptop: Update information about wireless control

+1004 -45
+7
MAINTAINERS
··· 5470 5470 F: drivers/misc/mei/* 5471 5471 F: Documentation/misc-devices/mei/* 5472 5472 5473 + INTEL PMC IPC DRIVER 5474 + M: Zha Qipeng<qipeng.zha@intel.com> 5475 + L: platform-driver-x86@vger.kernel.org 5476 + S: Maintained 5477 + F: drivers/platform/x86/intel_pmc_ipc.c 5478 + F: arch/x86/include/asm/intel_pmc_ipc.h 5479 + 5473 5480 IOC3 ETHERNET DRIVER 5474 5481 M: Ralf Baechle <ralf@linux-mips.org> 5475 5482 L: linux-mips@linux-mips.org
+82
arch/x86/include/asm/intel_pmc_ipc.h
··· 1 + #ifndef _ASM_X86_INTEL_PMC_IPC_H_ 2 + #define _ASM_X86_INTEL_PMC_IPC_H_ 3 + 4 + /* Commands */ 5 + #define PMC_IPC_PMIC_ACCESS 0xFF 6 + #define PMC_IPC_PMIC_ACCESS_READ 0x0 7 + #define PMC_IPC_PMIC_ACCESS_WRITE 0x1 8 + #define PMC_IPC_USB_PWR_CTRL 0xF0 9 + #define PMC_IPC_PMIC_BLACKLIST_SEL 0xEF 10 + #define PMC_IPC_PHY_CONFIG 0xEE 11 + #define PMC_IPC_NORTHPEAK_CTRL 0xED 12 + #define PMC_IPC_PM_DEBUG 0xEC 13 + #define PMC_IPC_PMC_TELEMTRY 0xEB 14 + #define PMC_IPC_PMC_FW_MSG_CTRL 0xEA 15 + 16 + /* IPC return code */ 17 + #define IPC_ERR_NONE 0 18 + #define IPC_ERR_CMD_NOT_SUPPORTED 1 19 + #define IPC_ERR_CMD_NOT_SERVICED 2 20 + #define IPC_ERR_UNABLE_TO_SERVICE 3 21 + #define IPC_ERR_CMD_INVALID 4 22 + #define IPC_ERR_CMD_FAILED 5 23 + #define IPC_ERR_EMSECURITY 6 24 + #define IPC_ERR_UNSIGNEDKERNEL 7 25 + 26 + #if IS_ENABLED(CONFIG_INTEL_PMC_IPC) 27 + 28 + /* 29 + * intel_pmc_ipc_simple_command 30 + * @cmd: command 31 + * @sub: sub type 32 + */ 33 + int intel_pmc_ipc_simple_command(int cmd, int sub); 34 + 35 + /* 36 + * intel_pmc_ipc_raw_cmd 37 + * @cmd: command 38 + * @sub: sub type 39 + * @in: input data 40 + * @inlen: input length in bytes 41 + * @out: output data 42 + * @outlen: output length in dwords 43 + * @sptr: data writing to SPTR register 44 + * @dptr: data writing to DPTR register 45 + */ 46 + int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, 47 + u32 *out, u32 outlen, u32 dptr, u32 sptr); 48 + 49 + /* 50 + * intel_pmc_ipc_command 51 + * @cmd: command 52 + * @sub: sub type 53 + * @in: input data 54 + * @inlen: input length in bytes 55 + * @out: output data 56 + * @outlen: output length in dwords 57 + */ 58 + int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, 59 + u32 *out, u32 outlen); 60 + 61 + #else 62 + 63 + static inline int intel_pmc_ipc_simple_command(int cmd, int sub) 64 + { 65 + return -EINVAL; 66 + } 67 + 68 + static inline int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, 69 + u32 *out, u32 outlen, u32 dptr, u32 sptr) 70 + { 71 + return -EINVAL; 72 + } 73 + 74 + static inline int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, 75 + u32 *out, u32 outlen) 76 + { 77 + return -EINVAL; 78 + } 79 + 80 + #endif /*CONFIG_INTEL_PMC_IPC*/ 81 + 82 + #endif
+7
drivers/platform/x86/Kconfig
··· 912 912 a paravirtualized device provided by QEMU; it lets a virtual machine 913 913 (guest) communicate panic events to the host. 914 914 915 + config INTEL_PMC_IPC 916 + tristate "Intel PMC IPC Driver" 917 + ---help--- 918 + This driver provides support for PMC control on some Intel platforms. 919 + The PMC is an ARC processor which defines IPC commands for communication 920 + with other entities in the CPU. 921 + 915 922 endif # X86_PLATFORM_DEVICES
+1
drivers/platform/x86/Makefile
··· 59 59 60 60 obj-$(CONFIG_PVPANIC) += pvpanic.o 61 61 obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o 62 + obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
+139 -44
drivers/platform/x86/dell-laptop.c
··· 307 307 }; 308 308 309 309 static struct calling_interface_buffer *buffer; 310 - static struct page *bufferpage; 311 310 static DEFINE_MUTEX(buffer_mutex); 312 311 313 312 static int hwswitch_state; ··· 423 424 } 424 425 } 425 426 426 - /* Derived from information in DellWirelessCtl.cpp: 427 - Class 17, select 11 is radio control. It returns an array of 32-bit values. 428 - 429 - Input byte 0 = 0: Wireless information 430 - 431 - result[0]: return code 432 - result[1]: 433 - Bit 0: Hardware switch supported 434 - Bit 1: Wifi locator supported 435 - Bit 2: Wifi is supported 436 - Bit 3: Bluetooth is supported 437 - Bit 4: WWAN is supported 438 - Bit 5: Wireless keyboard supported 439 - Bits 6-7: Reserved 440 - Bit 8: Wifi is installed 441 - Bit 9: Bluetooth is installed 442 - Bit 10: WWAN is installed 443 - Bits 11-15: Reserved 444 - Bit 16: Hardware switch is on 445 - Bit 17: Wifi is blocked 446 - Bit 18: Bluetooth is blocked 447 - Bit 19: WWAN is blocked 448 - Bits 20-31: Reserved 449 - result[2]: NVRAM size in bytes 450 - result[3]: NVRAM format version number 451 - 452 - Input byte 0 = 2: Wireless switch configuration 453 - result[0]: return code 454 - result[1]: 455 - Bit 0: Wifi controlled by switch 456 - Bit 1: Bluetooth controlled by switch 457 - Bit 2: WWAN controlled by switch 458 - Bits 3-6: Reserved 459 - Bit 7: Wireless switch config locked 460 - Bit 8: Wifi locator enabled 461 - Bits 9-14: Reserved 462 - Bit 15: Wifi locator setting locked 463 - Bits 16-31: Reserved 464 - */ 427 + /* 428 + * Derived from information in smbios-wireless-ctl: 429 + * 430 + * cbSelect 17, Value 11 431 + * 432 + * Return Wireless Info 433 + * cbArg1, byte0 = 0x00 434 + * 435 + * cbRes1 Standard return codes (0, -1, -2) 436 + * cbRes2 Info bit flags: 437 + * 438 + * 0 Hardware switch supported (1) 439 + * 1 WiFi locator supported (1) 440 + * 2 WLAN supported (1) 441 + * 3 Bluetooth (BT) supported (1) 442 + * 4 WWAN supported (1) 443 + * 5 Wireless KBD supported (1) 444 + * 6 Uw b supported (1) 445 + * 7 WiGig supported (1) 446 + * 8 WLAN installed (1) 447 + * 9 BT installed (1) 448 + * 10 WWAN installed (1) 449 + * 11 Uw b installed (1) 450 + * 12 WiGig installed (1) 451 + * 13-15 Reserved (0) 452 + * 16 Hardware (HW) switch is On (1) 453 + * 17 WLAN disabled (1) 454 + * 18 BT disabled (1) 455 + * 19 WWAN disabled (1) 456 + * 20 Uw b disabled (1) 457 + * 21 WiGig disabled (1) 458 + * 20-31 Reserved (0) 459 + * 460 + * cbRes3 NVRAM size in bytes 461 + * cbRes4, byte 0 NVRAM format version number 462 + * 463 + * 464 + * Set QuickSet Radio Disable Flag 465 + * cbArg1, byte0 = 0x01 466 + * cbArg1, byte1 467 + * Radio ID value: 468 + * 0 Radio Status 469 + * 1 WLAN ID 470 + * 2 BT ID 471 + * 3 WWAN ID 472 + * 4 UWB ID 473 + * 5 WIGIG ID 474 + * cbArg1, byte2 Flag bits: 475 + * 0 QuickSet disables radio (1) 476 + * 1-7 Reserved (0) 477 + * 478 + * cbRes1 Standard return codes (0, -1, -2) 479 + * cbRes2 QuickSet (QS) radio disable bit map: 480 + * 0 QS disables WLAN 481 + * 1 QS disables BT 482 + * 2 QS disables WWAN 483 + * 3 QS disables UWB 484 + * 4 QS disables WIGIG 485 + * 5-31 Reserved (0) 486 + * 487 + * Wireless Switch Configuration 488 + * cbArg1, byte0 = 0x02 489 + * 490 + * cbArg1, byte1 491 + * Subcommand: 492 + * 0 Get config 493 + * 1 Set config 494 + * 2 Set WiFi locator enable/disable 495 + * cbArg1,byte2 496 + * Switch settings (if byte 1==1): 497 + * 0 WLAN sw itch control (1) 498 + * 1 BT sw itch control (1) 499 + * 2 WWAN sw itch control (1) 500 + * 3 UWB sw itch control (1) 501 + * 4 WiGig sw itch control (1) 502 + * 5-7 Reserved (0) 503 + * cbArg1, byte2 Enable bits (if byte 1==2): 504 + * 0 Enable WiFi locator (1) 505 + * 506 + * cbRes1 Standard return codes (0, -1, -2) 507 + * cbRes2 QuickSet radio disable bit map: 508 + * 0 WLAN controlled by sw itch (1) 509 + * 1 BT controlled by sw itch (1) 510 + * 2 WWAN controlled by sw itch (1) 511 + * 3 UWB controlled by sw itch (1) 512 + * 4 WiGig controlled by sw itch (1) 513 + * 5-6 Reserved (0) 514 + * 7 Wireless sw itch config locked (1) 515 + * 8 WiFi locator enabled (1) 516 + * 9-14 Reserved (0) 517 + * 15 WiFi locator setting locked (1) 518 + * 16-31 Reserved (0) 519 + * 520 + * Read Local Config Data (LCD) 521 + * cbArg1, byte0 = 0x10 522 + * cbArg1, byte1 NVRAM index low byte 523 + * cbArg1, byte2 NVRAM index high byte 524 + * cbRes1 Standard return codes (0, -1, -2) 525 + * cbRes2 4 bytes read from LCD[index] 526 + * cbRes3 4 bytes read from LCD[index+4] 527 + * cbRes4 4 bytes read from LCD[index+8] 528 + * 529 + * Write Local Config Data (LCD) 530 + * cbArg1, byte0 = 0x11 531 + * cbArg1, byte1 NVRAM index low byte 532 + * cbArg1, byte2 NVRAM index high byte 533 + * cbArg2 4 bytes to w rite at LCD[index] 534 + * cbArg3 4 bytes to w rite at LCD[index+4] 535 + * cbArg4 4 bytes to w rite at LCD[index+8] 536 + * cbRes1 Standard return codes (0, -1, -2) 537 + * 538 + * Populate Local Config Data from NVRAM 539 + * cbArg1, byte0 = 0x12 540 + * cbRes1 Standard return codes (0, -1, -2) 541 + * 542 + * Commit Local Config Data to NVRAM 543 + * cbArg1, byte0 = 0x13 544 + * cbRes1 Standard return codes (0, -1, -2) 545 + */ 465 546 466 547 static int dell_rfkill_set(void *data, bool blocked) 467 548 { ··· 629 550 (status & BIT(4)) >> 4); 630 551 seq_printf(s, "Bit 5 : Wireless keyboard supported: %lu\n", 631 552 (status & BIT(5)) >> 5); 553 + seq_printf(s, "Bit 6 : UWB supported: %lu\n", 554 + (status & BIT(6)) >> 6); 555 + seq_printf(s, "Bit 7 : WiGig supported: %lu\n", 556 + (status & BIT(7)) >> 7); 632 557 seq_printf(s, "Bit 8 : Wifi is installed: %lu\n", 633 558 (status & BIT(8)) >> 8); 634 559 seq_printf(s, "Bit 9 : Bluetooth is installed: %lu\n", 635 560 (status & BIT(9)) >> 9); 636 561 seq_printf(s, "Bit 10: WWAN is installed: %lu\n", 637 562 (status & BIT(10)) >> 10); 563 + seq_printf(s, "Bit 11: UWB installed: %lu\n", 564 + (status & BIT(11)) >> 11); 565 + seq_printf(s, "Bit 12: WiGig installed: %lu\n", 566 + (status & BIT(12)) >> 12); 567 + 638 568 seq_printf(s, "Bit 16: Hardware switch is on: %lu\n", 639 569 (status & BIT(16)) >> 16); 640 570 seq_printf(s, "Bit 17: Wifi is blocked: %lu\n", ··· 652 564 (status & BIT(18)) >> 18); 653 565 seq_printf(s, "Bit 19: WWAN is blocked: %lu\n", 654 566 (status & BIT(19)) >> 19); 567 + seq_printf(s, "Bit 20: UWB is blocked: %lu\n", 568 + (status & BIT(20)) >> 20); 569 + seq_printf(s, "Bit 21: WiGig is blocked: %lu\n", 570 + (status & BIT(21)) >> 21); 655 571 656 572 seq_printf(s, "\nhwswitch_state:\t0x%X\n", hwswitch_state); 657 573 seq_printf(s, "Bit 0 : Wifi controlled by switch: %lu\n", ··· 664 572 (hwswitch_state & BIT(1)) >> 1); 665 573 seq_printf(s, "Bit 2 : WWAN controlled by switch: %lu\n", 666 574 (hwswitch_state & BIT(2)) >> 2); 575 + seq_printf(s, "Bit 3 : UWB controlled by switch: %lu\n", 576 + (hwswitch_state & BIT(3)) >> 3); 577 + seq_printf(s, "Bit 4 : WiGig controlled by switch: %lu\n", 578 + (hwswitch_state & BIT(4)) >> 4); 667 579 seq_printf(s, "Bit 7 : Wireless switch config locked: %lu\n", 668 580 (hwswitch_state & BIT(7)) >> 7); 669 581 seq_printf(s, "Bit 8 : Wifi locator enabled: %lu\n", ··· 2068 1972 * Allocate buffer below 4GB for SMI data--only 32-bit physical addr 2069 1973 * is passed to SMI handler. 2070 1974 */ 2071 - bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32); 2072 - if (!bufferpage) { 1975 + buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32); 1976 + if (!buffer) { 2073 1977 ret = -ENOMEM; 2074 1978 goto fail_buffer; 2075 1979 } 2076 - buffer = page_address(bufferpage); 2077 1980 2078 1981 ret = dell_setup_rfkill(); 2079 1982 ··· 2129 2034 fail_backlight: 2130 2035 dell_cleanup_rfkill(); 2131 2036 fail_rfkill: 2132 - free_page((unsigned long)bufferpage); 2037 + free_page((unsigned long)buffer); 2133 2038 fail_buffer: 2134 2039 platform_device_del(platform_device); 2135 2040 fail_platform_device2:
+767
drivers/platform/x86/intel_pmc_ipc.c
··· 1 + /* 2 + * intel_pmc_ipc.c: Driver for the Intel PMC IPC mechanism 3 + * 4 + * (C) Copyright 2014-2015 Intel Corporation 5 + * 6 + * This driver is based on Intel SCU IPC driver(intel_scu_opc.c) by 7 + * Sreedhara DS <sreedhara.ds@intel.com> 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License 11 + * as published by the Free Software Foundation; version 2 12 + * of the License. 13 + * 14 + * PMC running in ARC processor communicates with other entity running in IA 15 + * core through IPC mechanism which in turn messaging between IA core ad PMC. 16 + */ 17 + 18 + #include <linux/module.h> 19 + #include <linux/delay.h> 20 + #include <linux/errno.h> 21 + #include <linux/init.h> 22 + #include <linux/device.h> 23 + #include <linux/pm.h> 24 + #include <linux/pci.h> 25 + #include <linux/platform_device.h> 26 + #include <linux/interrupt.h> 27 + #include <linux/pm_qos.h> 28 + #include <linux/kernel.h> 29 + #include <linux/bitops.h> 30 + #include <linux/sched.h> 31 + #include <linux/atomic.h> 32 + #include <linux/notifier.h> 33 + #include <linux/suspend.h> 34 + #include <linux/acpi.h> 35 + #include <asm/intel_pmc_ipc.h> 36 + #include <linux/mfd/lpc_ich.h> 37 + 38 + /* 39 + * IPC registers 40 + * The IA write to IPC_CMD command register triggers an interrupt to the ARC, 41 + * The ARC handles the interrupt and services it, writing optional data to 42 + * the IPC1 registers, updates the IPC_STS response register with the status. 43 + */ 44 + #define IPC_CMD 0x0 45 + #define IPC_CMD_MSI 0x100 46 + #define IPC_CMD_SIZE 16 47 + #define IPC_CMD_SUBCMD 12 48 + #define IPC_STATUS 0x04 49 + #define IPC_STATUS_IRQ 0x4 50 + #define IPC_STATUS_ERR 0x2 51 + #define IPC_STATUS_BUSY 0x1 52 + #define IPC_SPTR 0x08 53 + #define IPC_DPTR 0x0C 54 + #define IPC_WRITE_BUFFER 0x80 55 + #define IPC_READ_BUFFER 0x90 56 + 57 + /* 58 + * 16-byte buffer for sending data associated with IPC command. 59 + */ 60 + #define IPC_DATA_BUFFER_SIZE 16 61 + 62 + #define IPC_LOOP_CNT 3000000 63 + #define IPC_MAX_SEC 3 64 + 65 + #define IPC_TRIGGER_MODE_IRQ true 66 + 67 + /* exported resources from IFWI */ 68 + #define PLAT_RESOURCE_IPC_INDEX 0 69 + #define PLAT_RESOURCE_IPC_SIZE 0x1000 70 + #define PLAT_RESOURCE_GCR_SIZE 0x1000 71 + #define PLAT_RESOURCE_PUNIT_DATA_INDEX 1 72 + #define PLAT_RESOURCE_PUNIT_INTER_INDEX 2 73 + #define PLAT_RESOURCE_ACPI_IO_INDEX 0 74 + 75 + /* 76 + * BIOS does not create an ACPI device for each PMC function, 77 + * but exports multiple resources from one ACPI device(IPC) for 78 + * multiple functions. This driver is responsible to create a 79 + * platform device and to export resources for those functions. 80 + */ 81 + #define TCO_DEVICE_NAME "iTCO_wdt" 82 + #define SMI_EN_OFFSET 0x30 83 + #define SMI_EN_SIZE 4 84 + #define TCO_BASE_OFFSET 0x60 85 + #define TCO_REGS_SIZE 16 86 + #define PUNIT_DEVICE_NAME "intel_punit_ipc" 87 + 88 + static const int iTCO_version = 3; 89 + 90 + static struct intel_pmc_ipc_dev { 91 + struct device *dev; 92 + void __iomem *ipc_base; 93 + bool irq_mode; 94 + int irq; 95 + int cmd; 96 + struct completion cmd_complete; 97 + 98 + /* The following PMC BARs share the same ACPI device with the IPC */ 99 + void *acpi_io_base; 100 + int acpi_io_size; 101 + struct platform_device *tco_dev; 102 + 103 + /* gcr */ 104 + void *gcr_base; 105 + int gcr_size; 106 + 107 + /* punit */ 108 + void *punit_base; 109 + int punit_size; 110 + void *punit_base2; 111 + int punit_size2; 112 + struct platform_device *punit_dev; 113 + } ipcdev; 114 + 115 + static char *ipc_err_sources[] = { 116 + [IPC_ERR_NONE] = 117 + "no error", 118 + [IPC_ERR_CMD_NOT_SUPPORTED] = 119 + "command not supported", 120 + [IPC_ERR_CMD_NOT_SERVICED] = 121 + "command not serviced", 122 + [IPC_ERR_UNABLE_TO_SERVICE] = 123 + "unable to service", 124 + [IPC_ERR_CMD_INVALID] = 125 + "command invalid", 126 + [IPC_ERR_CMD_FAILED] = 127 + "command failed", 128 + [IPC_ERR_EMSECURITY] = 129 + "Invalid Battery", 130 + [IPC_ERR_UNSIGNEDKERNEL] = 131 + "Unsigned kernel", 132 + }; 133 + 134 + /* Prevent concurrent calls to the PMC */ 135 + static DEFINE_MUTEX(ipclock); 136 + 137 + static inline void ipc_send_command(u32 cmd) 138 + { 139 + ipcdev.cmd = cmd; 140 + if (ipcdev.irq_mode) { 141 + reinit_completion(&ipcdev.cmd_complete); 142 + cmd |= IPC_CMD_MSI; 143 + } 144 + writel(cmd, ipcdev.ipc_base + IPC_CMD); 145 + } 146 + 147 + static inline u32 ipc_read_status(void) 148 + { 149 + return readl(ipcdev.ipc_base + IPC_STATUS); 150 + } 151 + 152 + static inline void ipc_data_writel(u32 data, u32 offset) 153 + { 154 + writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset); 155 + } 156 + 157 + static inline u8 ipc_data_readb(u32 offset) 158 + { 159 + return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 160 + } 161 + 162 + static inline u32 ipc_data_readl(u32 offset) 163 + { 164 + return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 165 + } 166 + 167 + static int intel_pmc_ipc_check_status(void) 168 + { 169 + int status; 170 + int ret = 0; 171 + 172 + if (ipcdev.irq_mode) { 173 + if (0 == wait_for_completion_timeout( 174 + &ipcdev.cmd_complete, IPC_MAX_SEC * HZ)) 175 + ret = -ETIMEDOUT; 176 + } else { 177 + int loop_count = IPC_LOOP_CNT; 178 + 179 + while ((ipc_read_status() & IPC_STATUS_BUSY) && --loop_count) 180 + udelay(1); 181 + if (loop_count == 0) 182 + ret = -ETIMEDOUT; 183 + } 184 + 185 + status = ipc_read_status(); 186 + if (ret == -ETIMEDOUT) { 187 + dev_err(ipcdev.dev, 188 + "IPC timed out, TS=0x%x, CMD=0x%x\n", 189 + status, ipcdev.cmd); 190 + return ret; 191 + } 192 + 193 + if (status & IPC_STATUS_ERR) { 194 + int i; 195 + 196 + ret = -EIO; 197 + i = (status >> IPC_CMD_SIZE) & 0xFF; 198 + if (i < ARRAY_SIZE(ipc_err_sources)) 199 + dev_err(ipcdev.dev, 200 + "IPC failed: %s, STS=0x%x, CMD=0x%x\n", 201 + ipc_err_sources[i], status, ipcdev.cmd); 202 + else 203 + dev_err(ipcdev.dev, 204 + "IPC failed: unknown, STS=0x%x, CMD=0x%x\n", 205 + status, ipcdev.cmd); 206 + if ((i == IPC_ERR_UNSIGNEDKERNEL) || (i == IPC_ERR_EMSECURITY)) 207 + ret = -EACCES; 208 + } 209 + 210 + return ret; 211 + } 212 + 213 + /* 214 + * intel_pmc_ipc_simple_command 215 + * @cmd: command 216 + * @sub: sub type 217 + */ 218 + int intel_pmc_ipc_simple_command(int cmd, int sub) 219 + { 220 + int ret; 221 + 222 + mutex_lock(&ipclock); 223 + if (ipcdev.dev == NULL) { 224 + mutex_unlock(&ipclock); 225 + return -ENODEV; 226 + } 227 + ipc_send_command(sub << IPC_CMD_SUBCMD | cmd); 228 + ret = intel_pmc_ipc_check_status(); 229 + mutex_unlock(&ipclock); 230 + 231 + return ret; 232 + } 233 + EXPORT_SYMBOL_GPL(intel_pmc_ipc_simple_command); 234 + 235 + /* 236 + * intel_pmc_ipc_raw_cmd 237 + * @cmd: command 238 + * @sub: sub type 239 + * @in: input data 240 + * @inlen: input length in bytes 241 + * @out: output data 242 + * @outlen: output length in dwords 243 + * @sptr: data writing to SPTR register 244 + * @dptr: data writing to DPTR register 245 + */ 246 + int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out, 247 + u32 outlen, u32 dptr, u32 sptr) 248 + { 249 + u32 wbuf[4] = { 0 }; 250 + int ret; 251 + int i; 252 + 253 + if (inlen > IPC_DATA_BUFFER_SIZE || outlen > IPC_DATA_BUFFER_SIZE / 4) 254 + return -EINVAL; 255 + 256 + mutex_lock(&ipclock); 257 + if (ipcdev.dev == NULL) { 258 + mutex_unlock(&ipclock); 259 + return -ENODEV; 260 + } 261 + memcpy(wbuf, in, inlen); 262 + writel(dptr, ipcdev.ipc_base + IPC_DPTR); 263 + writel(sptr, ipcdev.ipc_base + IPC_SPTR); 264 + /* The input data register is 32bit register and inlen is in Byte */ 265 + for (i = 0; i < ((inlen + 3) / 4); i++) 266 + ipc_data_writel(wbuf[i], 4 * i); 267 + ipc_send_command((inlen << IPC_CMD_SIZE) | 268 + (sub << IPC_CMD_SUBCMD) | cmd); 269 + ret = intel_pmc_ipc_check_status(); 270 + if (!ret) { 271 + /* out is read from 32bit register and outlen is in 32bit */ 272 + for (i = 0; i < outlen; i++) 273 + *out++ = ipc_data_readl(4 * i); 274 + } 275 + mutex_unlock(&ipclock); 276 + 277 + return ret; 278 + } 279 + EXPORT_SYMBOL_GPL(intel_pmc_ipc_raw_cmd); 280 + 281 + /* 282 + * intel_pmc_ipc_command 283 + * @cmd: command 284 + * @sub: sub type 285 + * @in: input data 286 + * @inlen: input length in bytes 287 + * @out: output data 288 + * @outlen: output length in dwords 289 + */ 290 + int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, 291 + u32 *out, u32 outlen) 292 + { 293 + return intel_pmc_ipc_raw_cmd(cmd, sub, in, inlen, out, outlen, 0, 0); 294 + } 295 + EXPORT_SYMBOL_GPL(intel_pmc_ipc_command); 296 + 297 + static irqreturn_t ioc(int irq, void *dev_id) 298 + { 299 + int status; 300 + 301 + if (ipcdev.irq_mode) { 302 + status = ipc_read_status(); 303 + writel(status | IPC_STATUS_IRQ, ipcdev.ipc_base + IPC_STATUS); 304 + } 305 + complete(&ipcdev.cmd_complete); 306 + 307 + return IRQ_HANDLED; 308 + } 309 + 310 + static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 311 + { 312 + resource_size_t pci_resource; 313 + int ret; 314 + int len; 315 + 316 + ipcdev.dev = &pci_dev_get(pdev)->dev; 317 + ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ; 318 + 319 + ret = pci_enable_device(pdev); 320 + if (ret) 321 + return ret; 322 + 323 + ret = pci_request_regions(pdev, "intel_pmc_ipc"); 324 + if (ret) 325 + return ret; 326 + 327 + pci_resource = pci_resource_start(pdev, 0); 328 + len = pci_resource_len(pdev, 0); 329 + if (!pci_resource || !len) { 330 + dev_err(&pdev->dev, "Failed to get resource\n"); 331 + return -ENOMEM; 332 + } 333 + 334 + init_completion(&ipcdev.cmd_complete); 335 + 336 + if (request_irq(pdev->irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) { 337 + dev_err(&pdev->dev, "Failed to request irq\n"); 338 + return -EBUSY; 339 + } 340 + 341 + ipcdev.ipc_base = ioremap_nocache(pci_resource, len); 342 + if (!ipcdev.ipc_base) { 343 + dev_err(&pdev->dev, "Failed to ioremap ipc base\n"); 344 + free_irq(pdev->irq, &ipcdev); 345 + ret = -ENOMEM; 346 + } 347 + 348 + return ret; 349 + } 350 + 351 + static void ipc_pci_remove(struct pci_dev *pdev) 352 + { 353 + free_irq(pdev->irq, &ipcdev); 354 + pci_release_regions(pdev); 355 + pci_dev_put(pdev); 356 + iounmap(ipcdev.ipc_base); 357 + ipcdev.dev = NULL; 358 + } 359 + 360 + static const struct pci_device_id ipc_pci_ids[] = { 361 + {PCI_VDEVICE(INTEL, 0x0a94), 0}, 362 + {PCI_VDEVICE(INTEL, 0x1a94), 0}, 363 + { 0,} 364 + }; 365 + MODULE_DEVICE_TABLE(pci, ipc_pci_ids); 366 + 367 + static struct pci_driver ipc_pci_driver = { 368 + .name = "intel_pmc_ipc", 369 + .id_table = ipc_pci_ids, 370 + .probe = ipc_pci_probe, 371 + .remove = ipc_pci_remove, 372 + }; 373 + 374 + static ssize_t intel_pmc_ipc_simple_cmd_store(struct device *dev, 375 + struct device_attribute *attr, 376 + const char *buf, size_t count) 377 + { 378 + int subcmd; 379 + int cmd; 380 + int ret; 381 + 382 + ret = sscanf(buf, "%d %d", &cmd, &subcmd); 383 + if (ret != 2) { 384 + dev_err(dev, "Error args\n"); 385 + return -EINVAL; 386 + } 387 + 388 + ret = intel_pmc_ipc_simple_command(cmd, subcmd); 389 + if (ret) { 390 + dev_err(dev, "command %d error with %d\n", cmd, ret); 391 + return ret; 392 + } 393 + return (ssize_t)count; 394 + } 395 + 396 + static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev, 397 + struct device_attribute *attr, 398 + const char *buf, size_t count) 399 + { 400 + unsigned long val; 401 + int subcmd; 402 + int ret; 403 + 404 + if (kstrtoul(buf, 0, &val)) 405 + return -EINVAL; 406 + 407 + if (val) 408 + subcmd = 1; 409 + else 410 + subcmd = 0; 411 + ret = intel_pmc_ipc_simple_command(PMC_IPC_NORTHPEAK_CTRL, subcmd); 412 + if (ret) { 413 + dev_err(dev, "command north %d error with %d\n", subcmd, ret); 414 + return ret; 415 + } 416 + return (ssize_t)count; 417 + } 418 + 419 + static DEVICE_ATTR(simplecmd, S_IWUSR, 420 + NULL, intel_pmc_ipc_simple_cmd_store); 421 + static DEVICE_ATTR(northpeak, S_IWUSR, 422 + NULL, intel_pmc_ipc_northpeak_store); 423 + 424 + static struct attribute *intel_ipc_attrs[] = { 425 + &dev_attr_northpeak.attr, 426 + &dev_attr_simplecmd.attr, 427 + NULL 428 + }; 429 + 430 + static const struct attribute_group intel_ipc_group = { 431 + .attrs = intel_ipc_attrs, 432 + }; 433 + 434 + #define PUNIT_RESOURCE_INTER 1 435 + static struct resource punit_res[] = { 436 + /* Punit */ 437 + { 438 + .flags = IORESOURCE_MEM, 439 + }, 440 + { 441 + .flags = IORESOURCE_MEM, 442 + }, 443 + }; 444 + 445 + #define TCO_RESOURCE_ACPI_IO 0 446 + #define TCO_RESOURCE_SMI_EN_IO 1 447 + #define TCO_RESOURCE_GCR_MEM 2 448 + static struct resource tco_res[] = { 449 + /* ACPI - TCO */ 450 + { 451 + .flags = IORESOURCE_IO, 452 + }, 453 + /* ACPI - SMI */ 454 + { 455 + .flags = IORESOURCE_IO, 456 + }, 457 + /* GCS */ 458 + { 459 + .flags = IORESOURCE_MEM, 460 + }, 461 + }; 462 + 463 + static struct lpc_ich_info tco_info = { 464 + .name = "Apollo Lake SoC", 465 + .iTCO_version = 3, 466 + }; 467 + 468 + static int ipc_create_punit_device(void) 469 + { 470 + struct platform_device *pdev; 471 + struct resource *res; 472 + int ret; 473 + 474 + pdev = platform_device_alloc(PUNIT_DEVICE_NAME, -1); 475 + if (!pdev) { 476 + dev_err(ipcdev.dev, "Failed to alloc punit platform device\n"); 477 + return -ENOMEM; 478 + } 479 + 480 + pdev->dev.parent = ipcdev.dev; 481 + 482 + res = punit_res; 483 + res->start = (resource_size_t)ipcdev.punit_base; 484 + res->end = res->start + ipcdev.punit_size - 1; 485 + 486 + res = punit_res + PUNIT_RESOURCE_INTER; 487 + res->start = (resource_size_t)ipcdev.punit_base2; 488 + res->end = res->start + ipcdev.punit_size2 - 1; 489 + 490 + ret = platform_device_add_resources(pdev, punit_res, 491 + ARRAY_SIZE(punit_res)); 492 + if (ret) { 493 + dev_err(ipcdev.dev, "Failed to add platform punit resources\n"); 494 + goto err; 495 + } 496 + 497 + ret = platform_device_add(pdev); 498 + if (ret) { 499 + dev_err(ipcdev.dev, "Failed to add punit platform device\n"); 500 + goto err; 501 + } 502 + ipcdev.punit_dev = pdev; 503 + 504 + return 0; 505 + err: 506 + platform_device_put(pdev); 507 + return ret; 508 + } 509 + 510 + static int ipc_create_tco_device(void) 511 + { 512 + struct platform_device *pdev; 513 + struct resource *res; 514 + int ret; 515 + 516 + pdev = platform_device_alloc(TCO_DEVICE_NAME, -1); 517 + if (!pdev) { 518 + dev_err(ipcdev.dev, "Failed to alloc tco platform device\n"); 519 + return -ENOMEM; 520 + } 521 + 522 + pdev->dev.parent = ipcdev.dev; 523 + 524 + res = tco_res + TCO_RESOURCE_ACPI_IO; 525 + res->start = (resource_size_t)ipcdev.acpi_io_base + TCO_BASE_OFFSET; 526 + res->end = res->start + TCO_REGS_SIZE - 1; 527 + 528 + res = tco_res + TCO_RESOURCE_SMI_EN_IO; 529 + res->start = (resource_size_t)ipcdev.acpi_io_base + SMI_EN_OFFSET; 530 + res->end = res->start + SMI_EN_SIZE - 1; 531 + 532 + res = tco_res + TCO_RESOURCE_GCR_MEM; 533 + res->start = (resource_size_t)ipcdev.gcr_base; 534 + res->end = res->start + ipcdev.gcr_size - 1; 535 + 536 + ret = platform_device_add_resources(pdev, tco_res, ARRAY_SIZE(tco_res)); 537 + if (ret) { 538 + dev_err(ipcdev.dev, "Failed to add tco platform resources\n"); 539 + goto err; 540 + } 541 + 542 + ret = platform_device_add_data(pdev, &tco_info, 543 + sizeof(struct lpc_ich_info)); 544 + if (ret) { 545 + dev_err(ipcdev.dev, "Failed to add tco platform data\n"); 546 + goto err; 547 + } 548 + 549 + ret = platform_device_add(pdev); 550 + if (ret) { 551 + dev_err(ipcdev.dev, "Failed to add tco platform device\n"); 552 + goto err; 553 + } 554 + ipcdev.tco_dev = pdev; 555 + 556 + return 0; 557 + err: 558 + platform_device_put(pdev); 559 + return ret; 560 + } 561 + 562 + static int ipc_create_pmc_devices(void) 563 + { 564 + int ret; 565 + 566 + ret = ipc_create_tco_device(); 567 + if (ret) { 568 + dev_err(ipcdev.dev, "Failed to add tco platform device\n"); 569 + return ret; 570 + } 571 + ret = ipc_create_punit_device(); 572 + if (ret) { 573 + dev_err(ipcdev.dev, "Failed to add punit platform device\n"); 574 + platform_device_unregister(ipcdev.tco_dev); 575 + } 576 + return ret; 577 + } 578 + 579 + static int ipc_plat_get_res(struct platform_device *pdev) 580 + { 581 + struct resource *res; 582 + void __iomem *addr; 583 + int size; 584 + 585 + res = platform_get_resource(pdev, IORESOURCE_IO, 586 + PLAT_RESOURCE_ACPI_IO_INDEX); 587 + if (!res) { 588 + dev_err(&pdev->dev, "Failed to get io resource\n"); 589 + return -ENXIO; 590 + } 591 + size = resource_size(res); 592 + ipcdev.acpi_io_base = (void *)res->start; 593 + ipcdev.acpi_io_size = size; 594 + dev_info(&pdev->dev, "io res: %llx %x\n", 595 + (long long)res->start, (int)resource_size(res)); 596 + 597 + res = platform_get_resource(pdev, IORESOURCE_MEM, 598 + PLAT_RESOURCE_PUNIT_DATA_INDEX); 599 + if (!res) { 600 + dev_err(&pdev->dev, "Failed to get punit resource\n"); 601 + return -ENXIO; 602 + } 603 + size = resource_size(res); 604 + ipcdev.punit_base = (void *)res->start; 605 + ipcdev.punit_size = size; 606 + dev_info(&pdev->dev, "punit data res: %llx %x\n", 607 + (long long)res->start, (int)resource_size(res)); 608 + 609 + res = platform_get_resource(pdev, IORESOURCE_MEM, 610 + PLAT_RESOURCE_PUNIT_INTER_INDEX); 611 + if (!res) { 612 + dev_err(&pdev->dev, "Failed to get punit inter resource\n"); 613 + return -ENXIO; 614 + } 615 + size = resource_size(res); 616 + ipcdev.punit_base2 = (void *)res->start; 617 + ipcdev.punit_size2 = size; 618 + dev_info(&pdev->dev, "punit interface res: %llx %x\n", 619 + (long long)res->start, (int)resource_size(res)); 620 + 621 + res = platform_get_resource(pdev, IORESOURCE_MEM, 622 + PLAT_RESOURCE_IPC_INDEX); 623 + if (!res) { 624 + dev_err(&pdev->dev, "Failed to get ipc resource\n"); 625 + return -ENXIO; 626 + } 627 + size = PLAT_RESOURCE_IPC_SIZE; 628 + if (!request_mem_region(res->start, size, pdev->name)) { 629 + dev_err(&pdev->dev, "Failed to request ipc resource\n"); 630 + return -EBUSY; 631 + } 632 + addr = ioremap_nocache(res->start, size); 633 + if (!addr) { 634 + dev_err(&pdev->dev, "I/O memory remapping failed\n"); 635 + release_mem_region(res->start, size); 636 + return -ENOMEM; 637 + } 638 + ipcdev.ipc_base = addr; 639 + 640 + ipcdev.gcr_base = (void *)(res->start + size); 641 + ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; 642 + dev_info(&pdev->dev, "ipc res: %llx %x\n", 643 + (long long)res->start, (int)resource_size(res)); 644 + 645 + return 0; 646 + } 647 + 648 + #ifdef CONFIG_ACPI 649 + static const struct acpi_device_id ipc_acpi_ids[] = { 650 + { "INT34D2", 0}, 651 + { } 652 + }; 653 + MODULE_DEVICE_TABLE(acpi, ipc_acpi_ids); 654 + #endif 655 + 656 + static int ipc_plat_probe(struct platform_device *pdev) 657 + { 658 + struct resource *res; 659 + int ret; 660 + 661 + ipcdev.dev = &pdev->dev; 662 + ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ; 663 + init_completion(&ipcdev.cmd_complete); 664 + 665 + ipcdev.irq = platform_get_irq(pdev, 0); 666 + if (ipcdev.irq < 0) { 667 + dev_err(&pdev->dev, "Failed to get irq\n"); 668 + return -EINVAL; 669 + } 670 + 671 + ret = ipc_plat_get_res(pdev); 672 + if (ret) { 673 + dev_err(&pdev->dev, "Failed to request resource\n"); 674 + return ret; 675 + } 676 + 677 + ret = ipc_create_pmc_devices(); 678 + if (ret) { 679 + dev_err(&pdev->dev, "Failed to create pmc devices\n"); 680 + goto err_device; 681 + } 682 + 683 + if (request_irq(ipcdev.irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) { 684 + dev_err(&pdev->dev, "Failed to request irq\n"); 685 + ret = -EBUSY; 686 + goto err_irq; 687 + } 688 + 689 + ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group); 690 + if (ret) { 691 + dev_err(&pdev->dev, "Failed to create sysfs group %d\n", 692 + ret); 693 + goto err_sys; 694 + } 695 + 696 + return 0; 697 + err_sys: 698 + free_irq(ipcdev.irq, &ipcdev); 699 + err_irq: 700 + platform_device_unregister(ipcdev.tco_dev); 701 + platform_device_unregister(ipcdev.punit_dev); 702 + err_device: 703 + iounmap(ipcdev.ipc_base); 704 + res = platform_get_resource(pdev, IORESOURCE_MEM, 705 + PLAT_RESOURCE_IPC_INDEX); 706 + if (res) 707 + release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE); 708 + return ret; 709 + } 710 + 711 + static int ipc_plat_remove(struct platform_device *pdev) 712 + { 713 + struct resource *res; 714 + 715 + sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group); 716 + free_irq(ipcdev.irq, &ipcdev); 717 + platform_device_unregister(ipcdev.tco_dev); 718 + platform_device_unregister(ipcdev.punit_dev); 719 + iounmap(ipcdev.ipc_base); 720 + res = platform_get_resource(pdev, IORESOURCE_MEM, 721 + PLAT_RESOURCE_IPC_INDEX); 722 + if (res) 723 + release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE); 724 + ipcdev.dev = NULL; 725 + return 0; 726 + } 727 + 728 + static struct platform_driver ipc_plat_driver = { 729 + .remove = ipc_plat_remove, 730 + .probe = ipc_plat_probe, 731 + .driver = { 732 + .name = "pmc-ipc-plat", 733 + .acpi_match_table = ACPI_PTR(ipc_acpi_ids), 734 + }, 735 + }; 736 + 737 + static int __init intel_pmc_ipc_init(void) 738 + { 739 + int ret; 740 + 741 + ret = platform_driver_register(&ipc_plat_driver); 742 + if (ret) { 743 + pr_err("Failed to register PMC ipc platform driver\n"); 744 + return ret; 745 + } 746 + ret = pci_register_driver(&ipc_pci_driver); 747 + if (ret) { 748 + pr_err("Failed to register PMC ipc pci driver\n"); 749 + platform_driver_unregister(&ipc_plat_driver); 750 + return ret; 751 + } 752 + return ret; 753 + } 754 + 755 + static void __exit intel_pmc_ipc_exit(void) 756 + { 757 + pci_unregister_driver(&ipc_pci_driver); 758 + platform_driver_unregister(&ipc_plat_driver); 759 + } 760 + 761 + MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>"); 762 + MODULE_DESCRIPTION("Intel PMC IPC driver"); 763 + MODULE_LICENSE("GPL"); 764 + 765 + /* Some modules are dependent on this, so init earlier */ 766 + fs_initcall(intel_pmc_ipc_init); 767 + module_exit(intel_pmc_ipc_exit);
+1 -1
drivers/platform/x86/tc1100-wmi.c
··· 82 82 tmp = 0; 83 83 } 84 84 85 - if (result.length > 0 && result.pointer) 85 + if (result.length > 0) 86 86 kfree(result.pointer); 87 87 88 88 switch (instance) {