diff options
143 files changed, 3613 insertions, 911 deletions
diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.txt b/Documentation/devicetree/bindings/thermal/imx-thermal.txt index 1f0f67234a91..3c67bd50aa10 100644 --- a/Documentation/devicetree/bindings/thermal/imx-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/imx-thermal.txt | |||
| @@ -1,7 +1,10 @@ | |||
| 1 | * Temperature Monitor (TEMPMON) on Freescale i.MX SoCs | 1 | * Temperature Monitor (TEMPMON) on Freescale i.MX SoCs |
| 2 | 2 | ||
| 3 | Required properties: | 3 | Required properties: |
| 4 | - compatible : "fsl,imx6q-thermal" | 4 | - compatible : "fsl,imx6q-tempmon" for i.MX6Q, "fsl,imx6sx-tempmon" for i.MX6SX. |
| 5 | i.MX6SX has two more IRQs than i.MX6Q, one is IRQ_LOW and the other is IRQ_PANIC, | ||
| 6 | when temperature is below than low threshold, IRQ_LOW will be triggered, when temperature | ||
| 7 | is higher than panic threshold, system will auto reboot by SRC module. | ||
| 5 | - fsl,tempmon : phandle pointer to system controller that contains TEMPMON | 8 | - fsl,tempmon : phandle pointer to system controller that contains TEMPMON |
| 6 | control registers, e.g. ANATOP on imx6q. | 9 | control registers, e.g. ANATOP on imx6q. |
| 7 | - fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON | 10 | - fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON |
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 988160a4ad31..74339c57b914 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -1015,10 +1015,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 1015 | Format: {"off" | "on" | "skip[mbr]"} | 1015 | Format: {"off" | "on" | "skip[mbr]"} |
| 1016 | 1016 | ||
| 1017 | efi= [EFI] | 1017 | efi= [EFI] |
| 1018 | Format: { "old_map" } | 1018 | Format: { "old_map", "nochunk", "noruntime" } |
| 1019 | old_map [X86-64]: switch to the old ioremap-based EFI | 1019 | old_map [X86-64]: switch to the old ioremap-based EFI |
| 1020 | runtime services mapping. 32-bit still uses this one by | 1020 | runtime services mapping. 32-bit still uses this one by |
| 1021 | default. | 1021 | default. |
| 1022 | nochunk: disable reading files in "chunks" in the EFI | ||
| 1023 | boot stub, as chunking can cause problems with some | ||
| 1024 | firmware implementations. | ||
| 1025 | noruntime : disable EFI runtime services support | ||
| 1022 | 1026 | ||
| 1023 | efi_no_storage_paranoia [EFI; X86] | 1027 | efi_no_storage_paranoia [EFI; X86] |
| 1024 | Using this parameter you can use more than 50% of | 1028 | Using this parameter you can use more than 50% of |
| @@ -2232,7 +2236,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 2232 | 2236 | ||
| 2233 | nodsp [SH] Disable hardware DSP at boot time. | 2237 | nodsp [SH] Disable hardware DSP at boot time. |
| 2234 | 2238 | ||
| 2235 | noefi [X86] Disable EFI runtime services support. | 2239 | noefi Disable EFI runtime services support. |
| 2236 | 2240 | ||
| 2237 | noexec [IA-64] | 2241 | noexec [IA-64] |
| 2238 | 2242 | ||
diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt index a5da5c7e7128..129f7c0e1483 100644 --- a/Documentation/power/pm_qos_interface.txt +++ b/Documentation/power/pm_qos_interface.txt | |||
| @@ -5,7 +5,8 @@ performance expectations by drivers, subsystems and user space applications on | |||
| 5 | one of the parameters. | 5 | one of the parameters. |
| 6 | 6 | ||
| 7 | Two different PM QoS frameworks are available: | 7 | Two different PM QoS frameworks are available: |
| 8 | 1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput. | 8 | 1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput, |
| 9 | memory_bandwidth. | ||
| 9 | 2. the per-device PM QoS framework provides the API to manage the per-device latency | 10 | 2. the per-device PM QoS framework provides the API to manage the per-device latency |
| 10 | constraints and PM QoS flags. | 11 | constraints and PM QoS flags. |
| 11 | 12 | ||
| @@ -13,6 +14,7 @@ Each parameters have defined units: | |||
| 13 | * latency: usec | 14 | * latency: usec |
| 14 | * timeout: usec | 15 | * timeout: usec |
| 15 | * throughput: kbs (kilo bit / sec) | 16 | * throughput: kbs (kilo bit / sec) |
| 17 | * memory bandwidth: mbs (mega bit / sec) | ||
| 16 | 18 | ||
| 17 | 19 | ||
| 18 | 1. PM QoS framework | 20 | 1. PM QoS framework |
diff --git a/arch/arc/kernel/kgdb.c b/arch/arc/kernel/kgdb.c index a2ff5c5d1450..ecf6a7869375 100644 --- a/arch/arc/kernel/kgdb.c +++ b/arch/arc/kernel/kgdb.c | |||
| @@ -158,11 +158,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
| 158 | return -1; | 158 | return -1; |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs) | ||
| 162 | { | ||
| 163 | return instruction_pointer(regs); | ||
| 164 | } | ||
| 165 | |||
| 166 | int kgdb_arch_init(void) | 161 | int kgdb_arch_init(void) |
| 167 | { | 162 | { |
| 168 | single_step_data.armed = 0; | 163 | single_step_data.armed = 0; |
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 03aaa99e1ea0..95c49ebc660d 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c | |||
| @@ -89,7 +89,8 @@ static int __init uefi_init(void) | |||
| 89 | */ | 89 | */ |
| 90 | if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { | 90 | if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { |
| 91 | pr_err("System table signature incorrect\n"); | 91 | pr_err("System table signature incorrect\n"); |
| 92 | return -EINVAL; | 92 | retval = -EINVAL; |
| 93 | goto out; | ||
| 93 | } | 94 | } |
| 94 | if ((efi.systab->hdr.revision >> 16) < 2) | 95 | if ((efi.systab->hdr.revision >> 16) < 2) |
| 95 | pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n", | 96 | pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n", |
| @@ -103,6 +104,7 @@ static int __init uefi_init(void) | |||
| 103 | for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) | 104 | for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) |
| 104 | vendor[i] = c16[i]; | 105 | vendor[i] = c16[i]; |
| 105 | vendor[i] = '\0'; | 106 | vendor[i] = '\0'; |
| 107 | early_memunmap(c16, sizeof(vendor)); | ||
| 106 | } | 108 | } |
| 107 | 109 | ||
| 108 | pr_info("EFI v%u.%.02u by %s\n", | 110 | pr_info("EFI v%u.%.02u by %s\n", |
| @@ -113,29 +115,11 @@ static int __init uefi_init(void) | |||
| 113 | if (retval == 0) | 115 | if (retval == 0) |
| 114 | set_bit(EFI_CONFIG_TABLES, &efi.flags); | 116 | set_bit(EFI_CONFIG_TABLES, &efi.flags); |
| 115 | 117 | ||
| 116 | early_memunmap(c16, sizeof(vendor)); | 118 | out: |
| 117 | early_memunmap(efi.systab, sizeof(efi_system_table_t)); | 119 | early_memunmap(efi.systab, sizeof(efi_system_table_t)); |
| 118 | |||
| 119 | return retval; | 120 | return retval; |
| 120 | } | 121 | } |
| 121 | 122 | ||
| 122 | static __initdata char memory_type_name[][32] = { | ||
| 123 | {"Reserved"}, | ||
| 124 | {"Loader Code"}, | ||
| 125 | {"Loader Data"}, | ||
| 126 | {"Boot Code"}, | ||
| 127 | {"Boot Data"}, | ||
| 128 | {"Runtime Code"}, | ||
| 129 | {"Runtime Data"}, | ||
| 130 | {"Conventional Memory"}, | ||
| 131 | {"Unusable Memory"}, | ||
| 132 | {"ACPI Reclaim Memory"}, | ||
| 133 | {"ACPI Memory NVS"}, | ||
| 134 | {"Memory Mapped I/O"}, | ||
| 135 | {"MMIO Port Space"}, | ||
| 136 | {"PAL Code"}, | ||
| 137 | }; | ||
| 138 | |||
| 139 | /* | 123 | /* |
| 140 | * Return true for RAM regions we want to permanently reserve. | 124 | * Return true for RAM regions we want to permanently reserve. |
| 141 | */ | 125 | */ |
| @@ -166,10 +150,13 @@ static __init void reserve_regions(void) | |||
| 166 | paddr = md->phys_addr; | 150 | paddr = md->phys_addr; |
| 167 | npages = md->num_pages; | 151 | npages = md->num_pages; |
| 168 | 152 | ||
| 169 | if (uefi_debug) | 153 | if (uefi_debug) { |
| 170 | pr_info(" 0x%012llx-0x%012llx [%s]", | 154 | char buf[64]; |
| 155 | |||
| 156 | pr_info(" 0x%012llx-0x%012llx %s", | ||
| 171 | paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1, | 157 | paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1, |
| 172 | memory_type_name[md->type]); | 158 | efi_md_typeattr_format(buf, sizeof(buf), md)); |
| 159 | } | ||
| 173 | 160 | ||
| 174 | memrange_efi_to_native(&paddr, &npages); | 161 | memrange_efi_to_native(&paddr, &npages); |
| 175 | size = npages << PAGE_SHIFT; | 162 | size = npages << PAGE_SHIFT; |
| @@ -393,11 +380,16 @@ static int __init arm64_enter_virtual_mode(void) | |||
| 393 | return -1; | 380 | return -1; |
| 394 | } | 381 | } |
| 395 | 382 | ||
| 396 | pr_info("Remapping and enabling EFI services.\n"); | ||
| 397 | |||
| 398 | /* replace early memmap mapping with permanent mapping */ | ||
| 399 | mapsize = memmap.map_end - memmap.map; | 383 | mapsize = memmap.map_end - memmap.map; |
| 400 | early_memunmap(memmap.map, mapsize); | 384 | early_memunmap(memmap.map, mapsize); |
| 385 | |||
| 386 | if (efi_runtime_disabled()) { | ||
| 387 | pr_info("EFI runtime services will be disabled.\n"); | ||
| 388 | return -1; | ||
| 389 | } | ||
| 390 | |||
| 391 | pr_info("Remapping and enabling EFI services.\n"); | ||
| 392 | /* replace early memmap mapping with permanent mapping */ | ||
| 401 | memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map, | 393 | memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map, |
| 402 | mapsize); | 394 | mapsize); |
| 403 | memmap.map_end = memmap.map + mapsize; | 395 | memmap.map_end = memmap.map + mapsize; |
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 741b99c1a0b1..c52d7540dc05 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c | |||
| @@ -568,6 +568,7 @@ efi_init (void) | |||
| 568 | { | 568 | { |
| 569 | const char *unit; | 569 | const char *unit; |
| 570 | unsigned long size; | 570 | unsigned long size; |
| 571 | char buf[64]; | ||
| 571 | 572 | ||
| 572 | md = p; | 573 | md = p; |
| 573 | size = md->num_pages << EFI_PAGE_SHIFT; | 574 | size = md->num_pages << EFI_PAGE_SHIFT; |
| @@ -586,9 +587,10 @@ efi_init (void) | |||
| 586 | unit = "KB"; | 587 | unit = "KB"; |
| 587 | } | 588 | } |
| 588 | 589 | ||
| 589 | printk("mem%02d: type=%2u, attr=0x%016lx, " | 590 | printk("mem%02d: %s " |
| 590 | "range=[0x%016lx-0x%016lx) (%4lu%s)\n", | 591 | "range=[0x%016lx-0x%016lx) (%4lu%s)\n", |
| 591 | i, md->type, md->attribute, md->phys_addr, | 592 | i, efi_md_typeattr_format(buf, sizeof(buf), md), |
| 593 | md->phys_addr, | ||
| 592 | md->phys_addr + efi_md_size(md), size, unit); | 594 | md->phys_addr + efi_md_size(md), size, unit); |
| 593 | } | 595 | } |
| 594 | } | 596 | } |
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index de8eebd6f67c..1acf605a646d 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c | |||
| @@ -330,8 +330,10 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) | |||
| 330 | size = pci->romsize + sizeof(*rom); | 330 | size = pci->romsize + sizeof(*rom); |
| 331 | 331 | ||
| 332 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); | 332 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); |
| 333 | if (status != EFI_SUCCESS) | 333 | if (status != EFI_SUCCESS) { |
| 334 | efi_printk(sys_table, "Failed to alloc mem for rom\n"); | ||
| 334 | return status; | 335 | return status; |
| 336 | } | ||
| 335 | 337 | ||
| 336 | memset(rom, 0, sizeof(*rom)); | 338 | memset(rom, 0, sizeof(*rom)); |
| 337 | 339 | ||
| @@ -344,14 +346,18 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) | |||
| 344 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, | 346 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, |
| 345 | PCI_VENDOR_ID, 1, &(rom->vendor)); | 347 | PCI_VENDOR_ID, 1, &(rom->vendor)); |
| 346 | 348 | ||
| 347 | if (status != EFI_SUCCESS) | 349 | if (status != EFI_SUCCESS) { |
| 350 | efi_printk(sys_table, "Failed to read rom->vendor\n"); | ||
| 348 | goto free_struct; | 351 | goto free_struct; |
| 352 | } | ||
| 349 | 353 | ||
| 350 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, | 354 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, |
| 351 | PCI_DEVICE_ID, 1, &(rom->devid)); | 355 | PCI_DEVICE_ID, 1, &(rom->devid)); |
| 352 | 356 | ||
| 353 | if (status != EFI_SUCCESS) | 357 | if (status != EFI_SUCCESS) { |
| 358 | efi_printk(sys_table, "Failed to read rom->devid\n"); | ||
| 354 | goto free_struct; | 359 | goto free_struct; |
| 360 | } | ||
| 355 | 361 | ||
| 356 | status = efi_early->call(pci->get_location, pci, &(rom->segment), | 362 | status = efi_early->call(pci->get_location, pci, &(rom->segment), |
| 357 | &(rom->bus), &(rom->device), &(rom->function)); | 363 | &(rom->bus), &(rom->device), &(rom->function)); |
| @@ -432,8 +438,10 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) | |||
| 432 | size = pci->romsize + sizeof(*rom); | 438 | size = pci->romsize + sizeof(*rom); |
| 433 | 439 | ||
| 434 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); | 440 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); |
| 435 | if (status != EFI_SUCCESS) | 441 | if (status != EFI_SUCCESS) { |
| 442 | efi_printk(sys_table, "Failed to alloc mem for rom\n"); | ||
| 436 | return status; | 443 | return status; |
| 444 | } | ||
| 437 | 445 | ||
| 438 | rom->data.type = SETUP_PCI; | 446 | rom->data.type = SETUP_PCI; |
| 439 | rom->data.len = size - sizeof(struct setup_data); | 447 | rom->data.len = size - sizeof(struct setup_data); |
| @@ -444,14 +452,18 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) | |||
| 444 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, | 452 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, |
| 445 | PCI_VENDOR_ID, 1, &(rom->vendor)); | 453 | PCI_VENDOR_ID, 1, &(rom->vendor)); |
| 446 | 454 | ||
| 447 | if (status != EFI_SUCCESS) | 455 | if (status != EFI_SUCCESS) { |
| 456 | efi_printk(sys_table, "Failed to read rom->vendor\n"); | ||
| 448 | goto free_struct; | 457 | goto free_struct; |
| 458 | } | ||
| 449 | 459 | ||
| 450 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, | 460 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, |
| 451 | PCI_DEVICE_ID, 1, &(rom->devid)); | 461 | PCI_DEVICE_ID, 1, &(rom->devid)); |
| 452 | 462 | ||
| 453 | if (status != EFI_SUCCESS) | 463 | if (status != EFI_SUCCESS) { |
| 464 | efi_printk(sys_table, "Failed to read rom->devid\n"); | ||
| 454 | goto free_struct; | 465 | goto free_struct; |
| 466 | } | ||
| 455 | 467 | ||
| 456 | status = efi_early->call(pci->get_location, pci, &(rom->segment), | 468 | status = efi_early->call(pci->get_location, pci, &(rom->segment), |
| 457 | &(rom->bus), &(rom->device), &(rom->function)); | 469 | &(rom->bus), &(rom->device), &(rom->function)); |
| @@ -538,8 +550,10 @@ static void setup_efi_pci(struct boot_params *params) | |||
| 538 | EFI_LOADER_DATA, | 550 | EFI_LOADER_DATA, |
| 539 | size, (void **)&pci_handle); | 551 | size, (void **)&pci_handle); |
| 540 | 552 | ||
| 541 | if (status != EFI_SUCCESS) | 553 | if (status != EFI_SUCCESS) { |
| 554 | efi_printk(sys_table, "Failed to alloc mem for pci_handle\n"); | ||
| 542 | return; | 555 | return; |
| 556 | } | ||
| 543 | 557 | ||
| 544 | status = efi_call_early(locate_handle, | 558 | status = efi_call_early(locate_handle, |
| 545 | EFI_LOCATE_BY_PROTOCOL, &pci_proto, | 559 | EFI_LOCATE_BY_PROTOCOL, &pci_proto, |
| @@ -1105,6 +1119,10 @@ struct boot_params *make_boot_params(struct efi_config *c) | |||
| 1105 | 1119 | ||
| 1106 | memset(sdt, 0, sizeof(*sdt)); | 1120 | memset(sdt, 0, sizeof(*sdt)); |
| 1107 | 1121 | ||
| 1122 | status = efi_parse_options(cmdline_ptr); | ||
| 1123 | if (status != EFI_SUCCESS) | ||
| 1124 | goto fail2; | ||
| 1125 | |||
| 1108 | status = handle_cmdline_files(sys_table, image, | 1126 | status = handle_cmdline_files(sys_table, image, |
| 1109 | (char *)(unsigned long)hdr->cmd_line_ptr, | 1127 | (char *)(unsigned long)hdr->cmd_line_ptr, |
| 1110 | "initrd=", hdr->initrd_addr_max, | 1128 | "initrd=", hdr->initrd_addr_max, |
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 0ec241ede5a2..9b11757975d0 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h | |||
| @@ -81,24 +81,23 @@ extern u64 asmlinkage efi_call(void *fp, ...); | |||
| 81 | */ | 81 | */ |
| 82 | #define __efi_call_virt(f, args...) efi_call_virt(f, args) | 82 | #define __efi_call_virt(f, args...) efi_call_virt(f, args) |
| 83 | 83 | ||
| 84 | extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, | 84 | extern void __iomem *__init efi_ioremap(unsigned long addr, unsigned long size, |
| 85 | u32 type, u64 attribute); | 85 | u32 type, u64 attribute); |
| 86 | 86 | ||
| 87 | #endif /* CONFIG_X86_32 */ | 87 | #endif /* CONFIG_X86_32 */ |
| 88 | 88 | ||
| 89 | extern int add_efi_memmap; | ||
| 90 | extern struct efi_scratch efi_scratch; | 89 | extern struct efi_scratch efi_scratch; |
| 91 | extern void efi_set_executable(efi_memory_desc_t *md, bool executable); | 90 | extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable); |
| 92 | extern int efi_memblock_x86_reserve_range(void); | 91 | extern int __init efi_memblock_x86_reserve_range(void); |
| 93 | extern void efi_call_phys_prelog(void); | 92 | extern void __init efi_call_phys_prolog(void); |
| 94 | extern void efi_call_phys_epilog(void); | 93 | extern void __init efi_call_phys_epilog(void); |
| 95 | extern void efi_unmap_memmap(void); | 94 | extern void __init efi_unmap_memmap(void); |
| 96 | extern void efi_memory_uc(u64 addr, unsigned long size); | 95 | extern void __init efi_memory_uc(u64 addr, unsigned long size); |
| 97 | extern void __init efi_map_region(efi_memory_desc_t *md); | 96 | extern void __init efi_map_region(efi_memory_desc_t *md); |
| 98 | extern void __init efi_map_region_fixed(efi_memory_desc_t *md); | 97 | extern void __init efi_map_region_fixed(efi_memory_desc_t *md); |
| 99 | extern void efi_sync_low_kernel_mappings(void); | 98 | extern void efi_sync_low_kernel_mappings(void); |
| 100 | extern int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages); | 99 | extern int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages); |
| 101 | extern void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages); | 100 | extern void __init efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages); |
| 102 | extern void __init old_map_region(efi_memory_desc_t *md); | 101 | extern void __init old_map_region(efi_memory_desc_t *md); |
| 103 | extern void __init runtime_code_page_mkexec(void); | 102 | extern void __init runtime_code_page_mkexec(void); |
| 104 | extern void __init efi_runtime_mkexec(void); | 103 | extern void __init efi_runtime_mkexec(void); |
| @@ -162,16 +161,6 @@ static inline efi_status_t efi_thunk_set_virtual_address_map( | |||
| 162 | extern bool efi_reboot_required(void); | 161 | extern bool efi_reboot_required(void); |
| 163 | 162 | ||
| 164 | #else | 163 | #else |
| 165 | /* | ||
| 166 | * IF EFI is not configured, have the EFI calls return -ENOSYS. | ||
| 167 | */ | ||
| 168 | #define efi_call0(_f) (-ENOSYS) | ||
| 169 | #define efi_call1(_f, _a1) (-ENOSYS) | ||
| 170 | #define efi_call2(_f, _a1, _a2) (-ENOSYS) | ||
| 171 | #define efi_call3(_f, _a1, _a2, _a3) (-ENOSYS) | ||
| 172 | #define efi_call4(_f, _a1, _a2, _a3, _a4) (-ENOSYS) | ||
| 173 | #define efi_call5(_f, _a1, _a2, _a3, _a4, _a5) (-ENOSYS) | ||
| 174 | #define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6) (-ENOSYS) | ||
| 175 | static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} | 164 | static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} |
| 176 | static inline bool efi_reboot_required(void) | 165 | static inline bool efi_reboot_required(void) |
| 177 | { | 166 | { |
diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c index f15103dff4b4..d143d216d52b 100644 --- a/arch/x86/platform/efi/efi-bgrt.c +++ b/arch/x86/platform/efi/efi-bgrt.c | |||
| @@ -40,20 +40,40 @@ void __init efi_bgrt_init(void) | |||
| 40 | if (ACPI_FAILURE(status)) | 40 | if (ACPI_FAILURE(status)) |
| 41 | return; | 41 | return; |
| 42 | 42 | ||
| 43 | if (bgrt_tab->header.length < sizeof(*bgrt_tab)) | 43 | if (bgrt_tab->header.length < sizeof(*bgrt_tab)) { |
| 44 | pr_err("Ignoring BGRT: invalid length %u (expected %zu)\n", | ||
| 45 | bgrt_tab->header.length, sizeof(*bgrt_tab)); | ||
| 44 | return; | 46 | return; |
| 45 | if (bgrt_tab->version != 1 || bgrt_tab->status != 1) | 47 | } |
| 48 | if (bgrt_tab->version != 1) { | ||
| 49 | pr_err("Ignoring BGRT: invalid version %u (expected 1)\n", | ||
| 50 | bgrt_tab->version); | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | if (bgrt_tab->status != 1) { | ||
| 54 | pr_err("Ignoring BGRT: invalid status %u (expected 1)\n", | ||
| 55 | bgrt_tab->status); | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | if (bgrt_tab->image_type != 0) { | ||
| 59 | pr_err("Ignoring BGRT: invalid image type %u (expected 0)\n", | ||
| 60 | bgrt_tab->image_type); | ||
| 46 | return; | 61 | return; |
| 47 | if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address) | 62 | } |
| 63 | if (!bgrt_tab->image_address) { | ||
| 64 | pr_err("Ignoring BGRT: null image address\n"); | ||
| 48 | return; | 65 | return; |
| 66 | } | ||
| 49 | 67 | ||
| 50 | image = efi_lookup_mapped_addr(bgrt_tab->image_address); | 68 | image = efi_lookup_mapped_addr(bgrt_tab->image_address); |
| 51 | if (!image) { | 69 | if (!image) { |
| 52 | image = early_memremap(bgrt_tab->image_address, | 70 | image = early_memremap(bgrt_tab->image_address, |
| 53 | sizeof(bmp_header)); | 71 | sizeof(bmp_header)); |
| 54 | ioremapped = true; | 72 | ioremapped = true; |
| 55 | if (!image) | 73 | if (!image) { |
| 74 | pr_err("Ignoring BGRT: failed to map image header memory\n"); | ||
| 56 | return; | 75 | return; |
| 76 | } | ||
| 57 | } | 77 | } |
| 58 | 78 | ||
| 59 | memcpy_fromio(&bmp_header, image, sizeof(bmp_header)); | 79 | memcpy_fromio(&bmp_header, image, sizeof(bmp_header)); |
| @@ -61,14 +81,18 @@ void __init efi_bgrt_init(void) | |||
| 61 | early_iounmap(image, sizeof(bmp_header)); | 81 | early_iounmap(image, sizeof(bmp_header)); |
| 62 | bgrt_image_size = bmp_header.size; | 82 | bgrt_image_size = bmp_header.size; |
| 63 | 83 | ||
| 64 | bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL); | 84 | bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL | __GFP_NOWARN); |
| 65 | if (!bgrt_image) | 85 | if (!bgrt_image) { |
| 86 | pr_err("Ignoring BGRT: failed to allocate memory for image (wanted %zu bytes)\n", | ||
| 87 | bgrt_image_size); | ||
| 66 | return; | 88 | return; |
| 89 | } | ||
| 67 | 90 | ||
| 68 | if (ioremapped) { | 91 | if (ioremapped) { |
| 69 | image = early_memremap(bgrt_tab->image_address, | 92 | image = early_memremap(bgrt_tab->image_address, |
| 70 | bmp_header.size); | 93 | bmp_header.size); |
| 71 | if (!image) { | 94 | if (!image) { |
| 95 | pr_err("Ignoring BGRT: failed to map image memory\n"); | ||
| 72 | kfree(bgrt_image); | 96 | kfree(bgrt_image); |
| 73 | bgrt_image = NULL; | 97 | bgrt_image = NULL; |
| 74 | return; | 98 | return; |
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 850da94fef30..dbc8627a5cdf 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
| @@ -70,17 +70,7 @@ static efi_config_table_type_t arch_tables[] __initdata = { | |||
| 70 | 70 | ||
| 71 | u64 efi_setup; /* efi setup_data physical address */ | 71 | u64 efi_setup; /* efi setup_data physical address */ |
| 72 | 72 | ||
| 73 | static bool disable_runtime __initdata = false; | 73 | static int add_efi_memmap __initdata; |
| 74 | static int __init setup_noefi(char *arg) | ||
| 75 | { | ||
| 76 | disable_runtime = true; | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | early_param("noefi", setup_noefi); | ||
| 80 | |||
| 81 | int add_efi_memmap; | ||
| 82 | EXPORT_SYMBOL(add_efi_memmap); | ||
| 83 | |||
| 84 | static int __init setup_add_efi_memmap(char *arg) | 74 | static int __init setup_add_efi_memmap(char *arg) |
| 85 | { | 75 | { |
| 86 | add_efi_memmap = 1; | 76 | add_efi_memmap = 1; |
| @@ -96,7 +86,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map( | |||
| 96 | { | 86 | { |
| 97 | efi_status_t status; | 87 | efi_status_t status; |
| 98 | 88 | ||
| 99 | efi_call_phys_prelog(); | 89 | efi_call_phys_prolog(); |
| 100 | status = efi_call_phys(efi_phys.set_virtual_address_map, | 90 | status = efi_call_phys(efi_phys.set_virtual_address_map, |
| 101 | memory_map_size, descriptor_size, | 91 | memory_map_size, descriptor_size, |
| 102 | descriptor_version, virtual_map); | 92 | descriptor_version, virtual_map); |
| @@ -210,9 +200,12 @@ static void __init print_efi_memmap(void) | |||
| 210 | for (p = memmap.map, i = 0; | 200 | for (p = memmap.map, i = 0; |
| 211 | p < memmap.map_end; | 201 | p < memmap.map_end; |
| 212 | p += memmap.desc_size, i++) { | 202 | p += memmap.desc_size, i++) { |
| 203 | char buf[64]; | ||
| 204 | |||
| 213 | md = p; | 205 | md = p; |
| 214 | pr_info("mem%02u: type=%u, attr=0x%llx, range=[0x%016llx-0x%016llx) (%lluMB)\n", | 206 | pr_info("mem%02u: %s range=[0x%016llx-0x%016llx) (%lluMB)\n", |
| 215 | i, md->type, md->attribute, md->phys_addr, | 207 | i, efi_md_typeattr_format(buf, sizeof(buf), md), |
| 208 | md->phys_addr, | ||
| 216 | md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), | 209 | md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), |
| 217 | (md->num_pages >> (20 - EFI_PAGE_SHIFT))); | 210 | (md->num_pages >> (20 - EFI_PAGE_SHIFT))); |
| 218 | } | 211 | } |
| @@ -344,9 +337,9 @@ static int __init efi_runtime_init32(void) | |||
| 344 | } | 337 | } |
| 345 | 338 | ||
| 346 | /* | 339 | /* |
| 347 | * We will only need *early* access to the following two | 340 | * We will only need *early* access to the SetVirtualAddressMap |
| 348 | * EFI runtime services before set_virtual_address_map | 341 | * EFI runtime service. All other runtime services will be called |
| 349 | * is invoked. | 342 | * via the virtual mapping. |
| 350 | */ | 343 | */ |
| 351 | efi_phys.set_virtual_address_map = | 344 | efi_phys.set_virtual_address_map = |
| 352 | (efi_set_virtual_address_map_t *) | 345 | (efi_set_virtual_address_map_t *) |
| @@ -368,9 +361,9 @@ static int __init efi_runtime_init64(void) | |||
| 368 | } | 361 | } |
| 369 | 362 | ||
| 370 | /* | 363 | /* |
| 371 | * We will only need *early* access to the following two | 364 | * We will only need *early* access to the SetVirtualAddressMap |
| 372 | * EFI runtime services before set_virtual_address_map | 365 | * EFI runtime service. All other runtime services will be called |
| 373 | * is invoked. | 366 | * via the virtual mapping. |
| 374 | */ | 367 | */ |
| 375 | efi_phys.set_virtual_address_map = | 368 | efi_phys.set_virtual_address_map = |
| 376 | (efi_set_virtual_address_map_t *) | 369 | (efi_set_virtual_address_map_t *) |
| @@ -492,7 +485,7 @@ void __init efi_init(void) | |||
| 492 | if (!efi_runtime_supported()) | 485 | if (!efi_runtime_supported()) |
| 493 | pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); | 486 | pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); |
| 494 | else { | 487 | else { |
| 495 | if (disable_runtime || efi_runtime_init()) | 488 | if (efi_runtime_disabled() || efi_runtime_init()) |
| 496 | return; | 489 | return; |
| 497 | } | 490 | } |
| 498 | if (efi_memmap_init()) | 491 | if (efi_memmap_init()) |
| @@ -537,7 +530,7 @@ void __init runtime_code_page_mkexec(void) | |||
| 537 | } | 530 | } |
| 538 | } | 531 | } |
| 539 | 532 | ||
| 540 | void efi_memory_uc(u64 addr, unsigned long size) | 533 | void __init efi_memory_uc(u64 addr, unsigned long size) |
| 541 | { | 534 | { |
| 542 | unsigned long page_shift = 1UL << EFI_PAGE_SHIFT; | 535 | unsigned long page_shift = 1UL << EFI_PAGE_SHIFT; |
| 543 | u64 npages; | 536 | u64 npages; |
| @@ -732,6 +725,7 @@ static void __init kexec_enter_virtual_mode(void) | |||
| 732 | */ | 725 | */ |
| 733 | if (!efi_is_native()) { | 726 | if (!efi_is_native()) { |
| 734 | efi_unmap_memmap(); | 727 | efi_unmap_memmap(); |
| 728 | clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); | ||
| 735 | return; | 729 | return; |
| 736 | } | 730 | } |
| 737 | 731 | ||
| @@ -805,6 +799,7 @@ static void __init __efi_enter_virtual_mode(void) | |||
| 805 | new_memmap = efi_map_regions(&count, &pg_shift); | 799 | new_memmap = efi_map_regions(&count, &pg_shift); |
| 806 | if (!new_memmap) { | 800 | if (!new_memmap) { |
| 807 | pr_err("Error reallocating memory, EFI runtime non-functional!\n"); | 801 | pr_err("Error reallocating memory, EFI runtime non-functional!\n"); |
| 802 | clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); | ||
| 808 | return; | 803 | return; |
| 809 | } | 804 | } |
| 810 | 805 | ||
| @@ -812,8 +807,10 @@ static void __init __efi_enter_virtual_mode(void) | |||
| 812 | 807 | ||
| 813 | BUG_ON(!efi.systab); | 808 | BUG_ON(!efi.systab); |
| 814 | 809 | ||
| 815 | if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift)) | 810 | if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift)) { |
| 811 | clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); | ||
| 816 | return; | 812 | return; |
| 813 | } | ||
| 817 | 814 | ||
| 818 | efi_sync_low_kernel_mappings(); | 815 | efi_sync_low_kernel_mappings(); |
| 819 | efi_dump_pagetable(); | 816 | efi_dump_pagetable(); |
| @@ -938,14 +935,11 @@ u64 efi_mem_attributes(unsigned long phys_addr) | |||
| 938 | return 0; | 935 | return 0; |
| 939 | } | 936 | } |
| 940 | 937 | ||
| 941 | static int __init parse_efi_cmdline(char *str) | 938 | static int __init arch_parse_efi_cmdline(char *str) |
| 942 | { | 939 | { |
| 943 | if (*str == '=') | 940 | if (parse_option_str(str, "old_map")) |
| 944 | str++; | ||
| 945 | |||
| 946 | if (!strncmp(str, "old_map", 7)) | ||
| 947 | set_bit(EFI_OLD_MEMMAP, &efi.flags); | 941 | set_bit(EFI_OLD_MEMMAP, &efi.flags); |
| 948 | 942 | ||
| 949 | return 0; | 943 | return 0; |
| 950 | } | 944 | } |
| 951 | early_param("efi", parse_efi_cmdline); | 945 | early_param("efi", arch_parse_efi_cmdline); |
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c index 9ee3491e31fb..40e7cda52936 100644 --- a/arch/x86/platform/efi/efi_32.c +++ b/arch/x86/platform/efi/efi_32.c | |||
| @@ -33,7 +33,7 @@ | |||
| 33 | 33 | ||
| 34 | /* | 34 | /* |
| 35 | * To make EFI call EFI runtime service in physical addressing mode we need | 35 | * To make EFI call EFI runtime service in physical addressing mode we need |
| 36 | * prelog/epilog before/after the invocation to disable interrupt, to | 36 | * prolog/epilog before/after the invocation to disable interrupt, to |
| 37 | * claim EFI runtime service handler exclusively and to duplicate a memory in | 37 | * claim EFI runtime service handler exclusively and to duplicate a memory in |
| 38 | * low memory space say 0 - 3G. | 38 | * low memory space say 0 - 3G. |
| 39 | */ | 39 | */ |
| @@ -41,11 +41,13 @@ static unsigned long efi_rt_eflags; | |||
| 41 | 41 | ||
| 42 | void efi_sync_low_kernel_mappings(void) {} | 42 | void efi_sync_low_kernel_mappings(void) {} |
| 43 | void __init efi_dump_pagetable(void) {} | 43 | void __init efi_dump_pagetable(void) {} |
| 44 | int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) | 44 | int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) |
| 45 | { | 45 | { |
| 46 | return 0; | 46 | return 0; |
| 47 | } | 47 | } |
| 48 | void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) {} | 48 | void __init efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) |
| 49 | { | ||
| 50 | } | ||
| 49 | 51 | ||
| 50 | void __init efi_map_region(efi_memory_desc_t *md) | 52 | void __init efi_map_region(efi_memory_desc_t *md) |
| 51 | { | 53 | { |
| @@ -55,7 +57,7 @@ void __init efi_map_region(efi_memory_desc_t *md) | |||
| 55 | void __init efi_map_region_fixed(efi_memory_desc_t *md) {} | 57 | void __init efi_map_region_fixed(efi_memory_desc_t *md) {} |
| 56 | void __init parse_efi_setup(u64 phys_addr, u32 data_len) {} | 58 | void __init parse_efi_setup(u64 phys_addr, u32 data_len) {} |
| 57 | 59 | ||
| 58 | void efi_call_phys_prelog(void) | 60 | void __init efi_call_phys_prolog(void) |
| 59 | { | 61 | { |
| 60 | struct desc_ptr gdt_descr; | 62 | struct desc_ptr gdt_descr; |
| 61 | 63 | ||
| @@ -69,7 +71,7 @@ void efi_call_phys_prelog(void) | |||
| 69 | load_gdt(&gdt_descr); | 71 | load_gdt(&gdt_descr); |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 72 | void efi_call_phys_epilog(void) | 74 | void __init efi_call_phys_epilog(void) |
| 73 | { | 75 | { |
| 74 | struct desc_ptr gdt_descr; | 76 | struct desc_ptr gdt_descr; |
| 75 | 77 | ||
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 290d397e1dd9..35aecb6042fb 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c | |||
| @@ -79,7 +79,7 @@ static void __init early_code_mapping_set_exec(int executable) | |||
| 79 | } | 79 | } |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | void __init efi_call_phys_prelog(void) | 82 | void __init efi_call_phys_prolog(void) |
| 83 | { | 83 | { |
| 84 | unsigned long vaddress; | 84 | unsigned long vaddress; |
| 85 | int pgd; | 85 | int pgd; |
| @@ -139,7 +139,7 @@ void efi_sync_low_kernel_mappings(void) | |||
| 139 | sizeof(pgd_t) * num_pgds); | 139 | sizeof(pgd_t) * num_pgds); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) | 142 | int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) |
| 143 | { | 143 | { |
| 144 | unsigned long text; | 144 | unsigned long text; |
| 145 | struct page *page; | 145 | struct page *page; |
| @@ -192,7 +192,7 @@ int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) | |||
| 192 | return 0; | 192 | return 0; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) | 195 | void __init efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) |
| 196 | { | 196 | { |
| 197 | pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd); | 197 | pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd); |
| 198 | 198 | ||
diff --git a/arch/x86/platform/efi/efi_stub_32.S b/arch/x86/platform/efi/efi_stub_32.S index fbe66e626c09..040192b50d02 100644 --- a/arch/x86/platform/efi/efi_stub_32.S +++ b/arch/x86/platform/efi/efi_stub_32.S | |||
| @@ -27,13 +27,13 @@ ENTRY(efi_call_phys) | |||
| 27 | * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found | 27 | * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found |
| 28 | * the values of these registers are the same. And, the corresponding | 28 | * the values of these registers are the same. And, the corresponding |
| 29 | * GDT entries are identical. So I will do nothing about segment reg | 29 | * GDT entries are identical. So I will do nothing about segment reg |
| 30 | * and GDT, but change GDT base register in prelog and epilog. | 30 | * and GDT, but change GDT base register in prolog and epilog. |
| 31 | */ | 31 | */ |
| 32 | 32 | ||
| 33 | /* | 33 | /* |
| 34 | * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET. | 34 | * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET. |
| 35 | * But to make it smoothly switch from virtual mode to flat mode. | 35 | * But to make it smoothly switch from virtual mode to flat mode. |
| 36 | * The mapping of lower virtual memory has been created in prelog and | 36 | * The mapping of lower virtual memory has been created in prolog and |
| 37 | * epilog. | 37 | * epilog. |
| 38 | */ | 38 | */ |
| 39 | movl $1f, %edx | 39 | movl $1f, %edx |
diff --git a/arch/x86/platform/intel-mid/intel_mid_weak_decls.h b/arch/x86/platform/intel-mid/intel_mid_weak_decls.h index 46aa25c8ce06..3c1c3866d82b 100644 --- a/arch/x86/platform/intel-mid/intel_mid_weak_decls.h +++ b/arch/x86/platform/intel-mid/intel_mid_weak_decls.h | |||
| @@ -10,10 +10,9 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | /* __attribute__((weak)) makes these declarations overridable */ | ||
| 14 | /* For every CPU addition a new get_<cpuname>_ops interface needs | 13 | /* For every CPU addition a new get_<cpuname>_ops interface needs |
| 15 | * to be added. | 14 | * to be added. |
| 16 | */ | 15 | */ |
| 17 | extern void *get_penwell_ops(void) __attribute__((weak)); | 16 | extern void *get_penwell_ops(void); |
| 18 | extern void *get_cloverview_ops(void) __attribute__((weak)); | 17 | extern void *get_cloverview_ops(void); |
| 19 | extern void *get_tangier_ops(void) __attribute__((weak)); | 18 | extern void *get_tangier_ops(void); |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 1a3f0445432a..fac5e4f9607c 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
| @@ -1636,9 +1636,6 @@ asmlinkage __visible void __init xen_start_kernel(void) | |||
| 1636 | xen_raw_console_write("mapping kernel into physical memory\n"); | 1636 | xen_raw_console_write("mapping kernel into physical memory\n"); |
| 1637 | xen_setup_kernel_pagetable((pgd_t *)xen_start_info->pt_base, xen_start_info->nr_pages); | 1637 | xen_setup_kernel_pagetable((pgd_t *)xen_start_info->pt_base, xen_start_info->nr_pages); |
| 1638 | 1638 | ||
| 1639 | /* Allocate and initialize top and mid mfn levels for p2m structure */ | ||
| 1640 | xen_build_mfn_list_list(); | ||
| 1641 | |||
| 1642 | /* keep using Xen gdt for now; no urgent need to change it */ | 1639 | /* keep using Xen gdt for now; no urgent need to change it */ |
| 1643 | 1640 | ||
| 1644 | #ifdef CONFIG_X86_32 | 1641 | #ifdef CONFIG_X86_32 |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index f62af7647ec9..a8a1a3d08d4d 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
| @@ -1217,10 +1217,13 @@ static void __init xen_pagetable_p2m_copy(void) | |||
| 1217 | static void __init xen_pagetable_init(void) | 1217 | static void __init xen_pagetable_init(void) |
| 1218 | { | 1218 | { |
| 1219 | paging_init(); | 1219 | paging_init(); |
| 1220 | xen_setup_shared_info(); | ||
| 1221 | #ifdef CONFIG_X86_64 | 1220 | #ifdef CONFIG_X86_64 |
| 1222 | xen_pagetable_p2m_copy(); | 1221 | xen_pagetable_p2m_copy(); |
| 1223 | #endif | 1222 | #endif |
| 1223 | /* Allocate and initialize top and mid mfn levels for p2m structure */ | ||
| 1224 | xen_build_mfn_list_list(); | ||
| 1225 | |||
| 1226 | xen_setup_shared_info(); | ||
| 1224 | xen_post_allocator_init(); | 1227 | xen_post_allocator_init(); |
| 1225 | } | 1228 | } |
| 1226 | static void xen_write_cr2(unsigned long cr2) | 1229 | static void xen_write_cr2(unsigned long cr2) |
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 9f5983b01ed9..b456b048eca9 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c | |||
| @@ -163,6 +163,7 @@ | |||
| 163 | #include <linux/hash.h> | 163 | #include <linux/hash.h> |
| 164 | #include <linux/sched.h> | 164 | #include <linux/sched.h> |
| 165 | #include <linux/seq_file.h> | 165 | #include <linux/seq_file.h> |
| 166 | #include <linux/bootmem.h> | ||
| 166 | 167 | ||
| 167 | #include <asm/cache.h> | 168 | #include <asm/cache.h> |
| 168 | #include <asm/setup.h> | 169 | #include <asm/setup.h> |
| @@ -181,21 +182,20 @@ static void __init m2p_override_init(void); | |||
| 181 | 182 | ||
| 182 | unsigned long xen_max_p2m_pfn __read_mostly; | 183 | unsigned long xen_max_p2m_pfn __read_mostly; |
| 183 | 184 | ||
| 185 | static unsigned long *p2m_mid_missing_mfn; | ||
| 186 | static unsigned long *p2m_top_mfn; | ||
| 187 | static unsigned long **p2m_top_mfn_p; | ||
| 188 | |||
| 184 | /* Placeholders for holes in the address space */ | 189 | /* Placeholders for holes in the address space */ |
| 185 | static RESERVE_BRK_ARRAY(unsigned long, p2m_missing, P2M_PER_PAGE); | 190 | static RESERVE_BRK_ARRAY(unsigned long, p2m_missing, P2M_PER_PAGE); |
| 186 | static RESERVE_BRK_ARRAY(unsigned long *, p2m_mid_missing, P2M_MID_PER_PAGE); | 191 | static RESERVE_BRK_ARRAY(unsigned long *, p2m_mid_missing, P2M_MID_PER_PAGE); |
| 187 | static RESERVE_BRK_ARRAY(unsigned long, p2m_mid_missing_mfn, P2M_MID_PER_PAGE); | ||
| 188 | 192 | ||
| 189 | static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE); | 193 | static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE); |
| 190 | static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE); | ||
| 191 | static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE); | ||
| 192 | 194 | ||
| 193 | static RESERVE_BRK_ARRAY(unsigned long, p2m_identity, P2M_PER_PAGE); | 195 | static RESERVE_BRK_ARRAY(unsigned long, p2m_identity, P2M_PER_PAGE); |
| 194 | static RESERVE_BRK_ARRAY(unsigned long *, p2m_mid_identity, P2M_MID_PER_PAGE); | 196 | static RESERVE_BRK_ARRAY(unsigned long *, p2m_mid_identity, P2M_MID_PER_PAGE); |
| 195 | static RESERVE_BRK_ARRAY(unsigned long, p2m_mid_identity_mfn, P2M_MID_PER_PAGE); | ||
| 196 | 197 | ||
| 197 | RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE))); | 198 | RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE))); |
| 198 | RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE))); | ||
| 199 | 199 | ||
| 200 | /* For each I/O range remapped we may lose up to two leaf pages for the boundary | 200 | /* For each I/O range remapped we may lose up to two leaf pages for the boundary |
| 201 | * violations and three mid pages to cover up to 3GB. With | 201 | * violations and three mid pages to cover up to 3GB. With |
| @@ -272,11 +272,11 @@ static void p2m_init(unsigned long *p2m) | |||
| 272 | * Build the parallel p2m_top_mfn and p2m_mid_mfn structures | 272 | * Build the parallel p2m_top_mfn and p2m_mid_mfn structures |
| 273 | * | 273 | * |
| 274 | * This is called both at boot time, and after resuming from suspend: | 274 | * This is called both at boot time, and after resuming from suspend: |
| 275 | * - At boot time we're called very early, and must use extend_brk() | 275 | * - At boot time we're called rather early, and must use alloc_bootmem*() |
| 276 | * to allocate memory. | 276 | * to allocate memory. |
| 277 | * | 277 | * |
| 278 | * - After resume we're called from within stop_machine, but the mfn | 278 | * - After resume we're called from within stop_machine, but the mfn |
| 279 | * tree should alreay be completely allocated. | 279 | * tree should already be completely allocated. |
| 280 | */ | 280 | */ |
| 281 | void __ref xen_build_mfn_list_list(void) | 281 | void __ref xen_build_mfn_list_list(void) |
| 282 | { | 282 | { |
| @@ -287,20 +287,17 @@ void __ref xen_build_mfn_list_list(void) | |||
| 287 | 287 | ||
| 288 | /* Pre-initialize p2m_top_mfn to be completely missing */ | 288 | /* Pre-initialize p2m_top_mfn to be completely missing */ |
| 289 | if (p2m_top_mfn == NULL) { | 289 | if (p2m_top_mfn == NULL) { |
| 290 | p2m_mid_missing_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE); | 290 | p2m_mid_missing_mfn = alloc_bootmem_align(PAGE_SIZE, PAGE_SIZE); |
| 291 | p2m_mid_mfn_init(p2m_mid_missing_mfn, p2m_missing); | 291 | p2m_mid_mfn_init(p2m_mid_missing_mfn, p2m_missing); |
| 292 | p2m_mid_identity_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE); | ||
| 293 | p2m_mid_mfn_init(p2m_mid_identity_mfn, p2m_identity); | ||
| 294 | 292 | ||
| 295 | p2m_top_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE); | 293 | p2m_top_mfn_p = alloc_bootmem_align(PAGE_SIZE, PAGE_SIZE); |
| 296 | p2m_top_mfn_p_init(p2m_top_mfn_p); | 294 | p2m_top_mfn_p_init(p2m_top_mfn_p); |
| 297 | 295 | ||
| 298 | p2m_top_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE); | 296 | p2m_top_mfn = alloc_bootmem_align(PAGE_SIZE, PAGE_SIZE); |
| 299 | p2m_top_mfn_init(p2m_top_mfn); | 297 | p2m_top_mfn_init(p2m_top_mfn); |
| 300 | } else { | 298 | } else { |
| 301 | /* Reinitialise, mfn's all change after migration */ | 299 | /* Reinitialise, mfn's all change after migration */ |
| 302 | p2m_mid_mfn_init(p2m_mid_missing_mfn, p2m_missing); | 300 | p2m_mid_mfn_init(p2m_mid_missing_mfn, p2m_missing); |
| 303 | p2m_mid_mfn_init(p2m_mid_identity_mfn, p2m_identity); | ||
| 304 | } | 301 | } |
| 305 | 302 | ||
| 306 | for (pfn = 0; pfn < xen_max_p2m_pfn; pfn += P2M_PER_PAGE) { | 303 | for (pfn = 0; pfn < xen_max_p2m_pfn; pfn += P2M_PER_PAGE) { |
| @@ -328,10 +325,9 @@ void __ref xen_build_mfn_list_list(void) | |||
| 328 | /* | 325 | /* |
| 329 | * XXX boot-time only! We should never find | 326 | * XXX boot-time only! We should never find |
| 330 | * missing parts of the mfn tree after | 327 | * missing parts of the mfn tree after |
| 331 | * runtime. extend_brk() will BUG if we call | 328 | * runtime. |
| 332 | * it too late. | ||
| 333 | */ | 329 | */ |
| 334 | mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE); | 330 | mid_mfn_p = alloc_bootmem_align(PAGE_SIZE, PAGE_SIZE); |
| 335 | p2m_mid_mfn_init(mid_mfn_p, p2m_missing); | 331 | p2m_mid_mfn_init(mid_mfn_p, p2m_missing); |
| 336 | 332 | ||
| 337 | p2m_top_mfn_p[topidx] = mid_mfn_p; | 333 | p2m_top_mfn_p[topidx] = mid_mfn_p; |
| @@ -415,7 +411,6 @@ void __init xen_build_dynamic_phys_to_machine(void) | |||
| 415 | m2p_override_init(); | 411 | m2p_override_init(); |
| 416 | } | 412 | } |
| 417 | #ifdef CONFIG_X86_64 | 413 | #ifdef CONFIG_X86_64 |
| 418 | #include <linux/bootmem.h> | ||
| 419 | unsigned long __init xen_revector_p2m_tree(void) | 414 | unsigned long __init xen_revector_p2m_tree(void) |
| 420 | { | 415 | { |
| 421 | unsigned long va_start; | 416 | unsigned long va_start; |
| @@ -477,7 +472,6 @@ unsigned long __init xen_revector_p2m_tree(void) | |||
| 477 | 472 | ||
| 478 | copy_page(new, mid_p); | 473 | copy_page(new, mid_p); |
| 479 | p2m_top[topidx][mididx] = &mfn_list[pfn_free]; | 474 | p2m_top[topidx][mididx] = &mfn_list[pfn_free]; |
| 480 | p2m_top_mfn_p[topidx][mididx] = virt_to_mfn(&mfn_list[pfn_free]); | ||
| 481 | 475 | ||
| 482 | pfn_free += P2M_PER_PAGE; | 476 | pfn_free += P2M_PER_PAGE; |
| 483 | 477 | ||
| @@ -538,12 +532,13 @@ static bool alloc_p2m(unsigned long pfn) | |||
| 538 | unsigned topidx, mididx; | 532 | unsigned topidx, mididx; |
| 539 | unsigned long ***top_p, **mid; | 533 | unsigned long ***top_p, **mid; |
| 540 | unsigned long *top_mfn_p, *mid_mfn; | 534 | unsigned long *top_mfn_p, *mid_mfn; |
| 535 | unsigned long *p2m_orig; | ||
| 541 | 536 | ||
| 542 | topidx = p2m_top_index(pfn); | 537 | topidx = p2m_top_index(pfn); |
| 543 | mididx = p2m_mid_index(pfn); | 538 | mididx = p2m_mid_index(pfn); |
| 544 | 539 | ||
| 545 | top_p = &p2m_top[topidx]; | 540 | top_p = &p2m_top[topidx]; |
| 546 | mid = *top_p; | 541 | mid = ACCESS_ONCE(*top_p); |
| 547 | 542 | ||
| 548 | if (mid == p2m_mid_missing) { | 543 | if (mid == p2m_mid_missing) { |
| 549 | /* Mid level is missing, allocate a new one */ | 544 | /* Mid level is missing, allocate a new one */ |
| @@ -558,7 +553,7 @@ static bool alloc_p2m(unsigned long pfn) | |||
| 558 | } | 553 | } |
| 559 | 554 | ||
| 560 | top_mfn_p = &p2m_top_mfn[topidx]; | 555 | top_mfn_p = &p2m_top_mfn[topidx]; |
| 561 | mid_mfn = p2m_top_mfn_p[topidx]; | 556 | mid_mfn = ACCESS_ONCE(p2m_top_mfn_p[topidx]); |
| 562 | 557 | ||
| 563 | BUG_ON(virt_to_mfn(mid_mfn) != *top_mfn_p); | 558 | BUG_ON(virt_to_mfn(mid_mfn) != *top_mfn_p); |
| 564 | 559 | ||
| @@ -566,6 +561,7 @@ static bool alloc_p2m(unsigned long pfn) | |||
| 566 | /* Separately check the mid mfn level */ | 561 | /* Separately check the mid mfn level */ |
| 567 | unsigned long missing_mfn; | 562 | unsigned long missing_mfn; |
| 568 | unsigned long mid_mfn_mfn; | 563 | unsigned long mid_mfn_mfn; |
| 564 | unsigned long old_mfn; | ||
| 569 | 565 | ||
| 570 | mid_mfn = alloc_p2m_page(); | 566 | mid_mfn = alloc_p2m_page(); |
| 571 | if (!mid_mfn) | 567 | if (!mid_mfn) |
| @@ -575,17 +571,19 @@ static bool alloc_p2m(unsigned long pfn) | |||
| 575 | 571 | ||
| 576 | missing_mfn = virt_to_mfn(p2m_mid_missing_mfn); | 572 | missing_mfn = virt_to_mfn(p2m_mid_missing_mfn); |
| 577 | mid_mfn_mfn = virt_to_mfn(mid_mfn); | 573 | mid_mfn_mfn = virt_to_mfn(mid_mfn); |
| 578 | if (cmpxchg(top_mfn_p, missing_mfn, mid_mfn_mfn) != missing_mfn) | 574 | old_mfn = cmpxchg(top_mfn_p, missing_mfn, mid_mfn_mfn); |
| 575 | if (old_mfn != missing_mfn) { | ||
| 579 | free_p2m_page(mid_mfn); | 576 | free_p2m_page(mid_mfn); |
| 580 | else | 577 | mid_mfn = mfn_to_virt(old_mfn); |
| 578 | } else { | ||
| 581 | p2m_top_mfn_p[topidx] = mid_mfn; | 579 | p2m_top_mfn_p[topidx] = mid_mfn; |
| 580 | } | ||
| 582 | } | 581 | } |
| 583 | 582 | ||
| 584 | if (p2m_top[topidx][mididx] == p2m_identity || | 583 | p2m_orig = ACCESS_ONCE(p2m_top[topidx][mididx]); |
| 585 | p2m_top[topidx][mididx] == p2m_missing) { | 584 | if (p2m_orig == p2m_identity || p2m_orig == p2m_missing) { |
| 586 | /* p2m leaf page is missing */ | 585 | /* p2m leaf page is missing */ |
| 587 | unsigned long *p2m; | 586 | unsigned long *p2m; |
| 588 | unsigned long *p2m_orig = p2m_top[topidx][mididx]; | ||
| 589 | 587 | ||
| 590 | p2m = alloc_p2m_page(); | 588 | p2m = alloc_p2m_page(); |
| 591 | if (!p2m) | 589 | if (!p2m) |
| @@ -606,7 +604,6 @@ static bool __init early_alloc_p2m(unsigned long pfn, bool check_boundary) | |||
| 606 | { | 604 | { |
| 607 | unsigned topidx, mididx, idx; | 605 | unsigned topidx, mididx, idx; |
| 608 | unsigned long *p2m; | 606 | unsigned long *p2m; |
| 609 | unsigned long *mid_mfn_p; | ||
| 610 | 607 | ||
| 611 | topidx = p2m_top_index(pfn); | 608 | topidx = p2m_top_index(pfn); |
| 612 | mididx = p2m_mid_index(pfn); | 609 | mididx = p2m_mid_index(pfn); |
| @@ -633,43 +630,21 @@ static bool __init early_alloc_p2m(unsigned long pfn, bool check_boundary) | |||
| 633 | 630 | ||
| 634 | p2m_top[topidx][mididx] = p2m; | 631 | p2m_top[topidx][mididx] = p2m; |
| 635 | 632 | ||
| 636 | /* For save/restore we need to MFN of the P2M saved */ | ||
| 637 | |||
| 638 | mid_mfn_p = p2m_top_mfn_p[topidx]; | ||
| 639 | WARN(mid_mfn_p[mididx] != virt_to_mfn(p2m_missing), | ||
| 640 | "P2M_TOP_P[%d][%d] != MFN of p2m_missing!\n", | ||
| 641 | topidx, mididx); | ||
| 642 | mid_mfn_p[mididx] = virt_to_mfn(p2m); | ||
| 643 | |||
| 644 | return true; | 633 | return true; |
| 645 | } | 634 | } |
| 646 | 635 | ||
| 647 | static bool __init early_alloc_p2m_middle(unsigned long pfn) | 636 | static bool __init early_alloc_p2m_middle(unsigned long pfn) |
| 648 | { | 637 | { |
| 649 | unsigned topidx = p2m_top_index(pfn); | 638 | unsigned topidx = p2m_top_index(pfn); |
| 650 | unsigned long *mid_mfn_p; | ||
| 651 | unsigned long **mid; | 639 | unsigned long **mid; |
| 652 | 640 | ||
| 653 | mid = p2m_top[topidx]; | 641 | mid = p2m_top[topidx]; |
| 654 | mid_mfn_p = p2m_top_mfn_p[topidx]; | ||
| 655 | if (mid == p2m_mid_missing) { | 642 | if (mid == p2m_mid_missing) { |
| 656 | mid = extend_brk(PAGE_SIZE, PAGE_SIZE); | 643 | mid = extend_brk(PAGE_SIZE, PAGE_SIZE); |
| 657 | 644 | ||
| 658 | p2m_mid_init(mid, p2m_missing); | 645 | p2m_mid_init(mid, p2m_missing); |
| 659 | 646 | ||
| 660 | p2m_top[topidx] = mid; | 647 | p2m_top[topidx] = mid; |
| 661 | |||
| 662 | BUG_ON(mid_mfn_p != p2m_mid_missing_mfn); | ||
| 663 | } | ||
| 664 | /* And the save/restore P2M tables.. */ | ||
| 665 | if (mid_mfn_p == p2m_mid_missing_mfn) { | ||
| 666 | mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE); | ||
| 667 | p2m_mid_mfn_init(mid_mfn_p, p2m_missing); | ||
| 668 | |||
| 669 | p2m_top_mfn_p[topidx] = mid_mfn_p; | ||
| 670 | p2m_top_mfn[topidx] = virt_to_mfn(mid_mfn_p); | ||
| 671 | /* Note: we don't set mid_mfn_p[midix] here, | ||
| 672 | * look in early_alloc_p2m() */ | ||
| 673 | } | 648 | } |
| 674 | return true; | 649 | return true; |
| 675 | } | 650 | } |
| @@ -680,14 +655,13 @@ static bool __init early_alloc_p2m_middle(unsigned long pfn) | |||
| 680 | * replace the P2M leaf with a p2m_missing or p2m_identity. | 655 | * replace the P2M leaf with a p2m_missing or p2m_identity. |
| 681 | * Stick the old page in the new P2M tree location. | 656 | * Stick the old page in the new P2M tree location. |
| 682 | */ | 657 | */ |
| 683 | bool __init early_can_reuse_p2m_middle(unsigned long set_pfn, unsigned long set_mfn) | 658 | static bool __init early_can_reuse_p2m_middle(unsigned long set_pfn) |
| 684 | { | 659 | { |
| 685 | unsigned topidx; | 660 | unsigned topidx; |
| 686 | unsigned mididx; | 661 | unsigned mididx; |
| 687 | unsigned ident_pfns; | 662 | unsigned ident_pfns; |
| 688 | unsigned inv_pfns; | 663 | unsigned inv_pfns; |
| 689 | unsigned long *p2m; | 664 | unsigned long *p2m; |
| 690 | unsigned long *mid_mfn_p; | ||
| 691 | unsigned idx; | 665 | unsigned idx; |
| 692 | unsigned long pfn; | 666 | unsigned long pfn; |
| 693 | 667 | ||
| @@ -733,11 +707,6 @@ bool __init early_can_reuse_p2m_middle(unsigned long set_pfn, unsigned long set_ | |||
| 733 | found: | 707 | found: |
| 734 | /* Found one, replace old with p2m_identity or p2m_missing */ | 708 | /* Found one, replace old with p2m_identity or p2m_missing */ |
| 735 | p2m_top[topidx][mididx] = (ident_pfns ? p2m_identity : p2m_missing); | 709 | p2m_top[topidx][mididx] = (ident_pfns ? p2m_identity : p2m_missing); |
| 736 | /* And the other for save/restore.. */ | ||
| 737 | mid_mfn_p = p2m_top_mfn_p[topidx]; | ||
| 738 | /* NOTE: Even if it is a p2m_identity it should still be point to | ||
| 739 | * a page filled with INVALID_P2M_ENTRY entries. */ | ||
| 740 | mid_mfn_p[mididx] = virt_to_mfn(p2m_missing); | ||
| 741 | 710 | ||
| 742 | /* Reset where we want to stick the old page in. */ | 711 | /* Reset where we want to stick the old page in. */ |
| 743 | topidx = p2m_top_index(set_pfn); | 712 | topidx = p2m_top_index(set_pfn); |
| @@ -752,8 +721,6 @@ found: | |||
| 752 | 721 | ||
| 753 | p2m_init(p2m); | 722 | p2m_init(p2m); |
| 754 | p2m_top[topidx][mididx] = p2m; | 723 | p2m_top[topidx][mididx] = p2m; |
| 755 | mid_mfn_p = p2m_top_mfn_p[topidx]; | ||
| 756 | mid_mfn_p[mididx] = virt_to_mfn(p2m); | ||
| 757 | 724 | ||
| 758 | return true; | 725 | return true; |
| 759 | } | 726 | } |
| @@ -763,7 +730,7 @@ bool __init early_set_phys_to_machine(unsigned long pfn, unsigned long mfn) | |||
| 763 | if (!early_alloc_p2m_middle(pfn)) | 730 | if (!early_alloc_p2m_middle(pfn)) |
| 764 | return false; | 731 | return false; |
| 765 | 732 | ||
| 766 | if (early_can_reuse_p2m_middle(pfn, mfn)) | 733 | if (early_can_reuse_p2m_middle(pfn)) |
| 767 | return __set_phys_to_machine(pfn, mfn); | 734 | return __set_phys_to_machine(pfn, mfn); |
| 768 | 735 | ||
| 769 | if (!early_alloc_p2m(pfn, false /* boundary crossover OK!*/)) | 736 | if (!early_alloc_p2m(pfn, false /* boundary crossover OK!*/)) |
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index af7216128d93..29834b3fd87f 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c | |||
| @@ -595,6 +595,7 @@ char * __init xen_memory_setup(void) | |||
| 595 | rc = 0; | 595 | rc = 0; |
| 596 | } | 596 | } |
| 597 | BUG_ON(rc); | 597 | BUG_ON(rc); |
| 598 | BUG_ON(memmap.nr_entries == 0); | ||
| 598 | 599 | ||
| 599 | /* | 600 | /* |
| 600 | * Xen won't allow a 1:1 mapping to be created to UNUSABLE | 601 | * Xen won't allow a 1:1 mapping to be created to UNUSABLE |
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index a1d430b112b3..f473d268d387 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c | |||
| @@ -158,7 +158,7 @@ cycle_t xen_clocksource_read(void) | |||
| 158 | cycle_t ret; | 158 | cycle_t ret; |
| 159 | 159 | ||
| 160 | preempt_disable_notrace(); | 160 | preempt_disable_notrace(); |
| 161 | src = this_cpu_ptr(&xen_vcpu->time); | 161 | src = &__this_cpu_read(xen_vcpu)->time; |
| 162 | ret = pvclock_clocksource_read(src); | 162 | ret = pvclock_clocksource_read(src); |
| 163 | preempt_enable_notrace(); | 163 | preempt_enable_notrace(); |
| 164 | return ret; | 164 | return ret; |
diff --git a/crypto/cts.c b/crypto/cts.c index 042223f8e733..133f0874c95e 100644 --- a/crypto/cts.c +++ b/crypto/cts.c | |||
| @@ -202,7 +202,8 @@ static int cts_cbc_decrypt(struct crypto_cts_ctx *ctx, | |||
| 202 | /* 5. Append the tail (BB - Ln) bytes of Xn (tmp) to Cn to create En */ | 202 | /* 5. Append the tail (BB - Ln) bytes of Xn (tmp) to Cn to create En */ |
| 203 | memcpy(s + bsize + lastn, tmp + lastn, bsize - lastn); | 203 | memcpy(s + bsize + lastn, tmp + lastn, bsize - lastn); |
| 204 | /* 6. Decrypt En to create Pn-1 */ | 204 | /* 6. Decrypt En to create Pn-1 */ |
| 205 | memset(iv, 0, sizeof(iv)); | 205 | memzero_explicit(iv, sizeof(iv)); |
| 206 | |||
| 206 | sg_set_buf(&sgsrc[0], s + bsize, bsize); | 207 | sg_set_buf(&sgsrc[0], s + bsize, bsize); |
| 207 | sg_set_buf(&sgdst[0], d, bsize); | 208 | sg_set_buf(&sgdst[0], d, bsize); |
| 208 | err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize); | 209 | err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize); |
diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c index 42794803c480..7bb047432782 100644 --- a/crypto/sha1_generic.c +++ b/crypto/sha1_generic.c | |||
| @@ -64,7 +64,7 @@ int crypto_sha1_update(struct shash_desc *desc, const u8 *data, | |||
| 64 | src = data + done; | 64 | src = data + done; |
| 65 | } while (done + SHA1_BLOCK_SIZE <= len); | 65 | } while (done + SHA1_BLOCK_SIZE <= len); |
| 66 | 66 | ||
| 67 | memset(temp, 0, sizeof(temp)); | 67 | memzero_explicit(temp, sizeof(temp)); |
| 68 | partial = 0; | 68 | partial = 0; |
| 69 | } | 69 | } |
| 70 | memcpy(sctx->buffer + partial, src, len - done); | 70 | memcpy(sctx->buffer + partial, src, len - done); |
diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index 0bb558344699..65e7b76b057f 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c | |||
| @@ -211,10 +211,9 @@ static void sha256_transform(u32 *state, const u8 *input) | |||
| 211 | 211 | ||
| 212 | /* clear any sensitive info... */ | 212 | /* clear any sensitive info... */ |
| 213 | a = b = c = d = e = f = g = h = t1 = t2 = 0; | 213 | a = b = c = d = e = f = g = h = t1 = t2 = 0; |
| 214 | memset(W, 0, 64 * sizeof(u32)); | 214 | memzero_explicit(W, 64 * sizeof(u32)); |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | |||
| 218 | static int sha224_init(struct shash_desc *desc) | 217 | static int sha224_init(struct shash_desc *desc) |
| 219 | { | 218 | { |
| 220 | struct sha256_state *sctx = shash_desc_ctx(desc); | 219 | struct sha256_state *sctx = shash_desc_ctx(desc); |
| @@ -317,7 +316,7 @@ static int sha224_final(struct shash_desc *desc, u8 *hash) | |||
| 317 | sha256_final(desc, D); | 316 | sha256_final(desc, D); |
| 318 | 317 | ||
| 319 | memcpy(hash, D, SHA224_DIGEST_SIZE); | 318 | memcpy(hash, D, SHA224_DIGEST_SIZE); |
| 320 | memset(D, 0, SHA256_DIGEST_SIZE); | 319 | memzero_explicit(D, SHA256_DIGEST_SIZE); |
| 321 | 320 | ||
| 322 | return 0; | 321 | return 0; |
| 323 | } | 322 | } |
diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index 6dde57dc511b..95db67197cd9 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c | |||
| @@ -239,7 +239,7 @@ static int sha384_final(struct shash_desc *desc, u8 *hash) | |||
| 239 | sha512_final(desc, D); | 239 | sha512_final(desc, D); |
| 240 | 240 | ||
| 241 | memcpy(hash, D, 48); | 241 | memcpy(hash, D, 48); |
| 242 | memset(D, 0, 64); | 242 | memzero_explicit(D, 64); |
| 243 | 243 | ||
| 244 | return 0; | 244 | return 0; |
| 245 | } | 245 | } |
diff --git a/crypto/tgr192.c b/crypto/tgr192.c index 87403556fd0b..3c7af0d1ff7a 100644 --- a/crypto/tgr192.c +++ b/crypto/tgr192.c | |||
| @@ -612,7 +612,7 @@ static int tgr160_final(struct shash_desc *desc, u8 * out) | |||
| 612 | 612 | ||
| 613 | tgr192_final(desc, D); | 613 | tgr192_final(desc, D); |
| 614 | memcpy(out, D, TGR160_DIGEST_SIZE); | 614 | memcpy(out, D, TGR160_DIGEST_SIZE); |
| 615 | memset(D, 0, TGR192_DIGEST_SIZE); | 615 | memzero_explicit(D, TGR192_DIGEST_SIZE); |
| 616 | 616 | ||
| 617 | return 0; | 617 | return 0; |
| 618 | } | 618 | } |
| @@ -623,7 +623,7 @@ static int tgr128_final(struct shash_desc *desc, u8 * out) | |||
| 623 | 623 | ||
| 624 | tgr192_final(desc, D); | 624 | tgr192_final(desc, D); |
| 625 | memcpy(out, D, TGR128_DIGEST_SIZE); | 625 | memcpy(out, D, TGR128_DIGEST_SIZE); |
| 626 | memset(D, 0, TGR192_DIGEST_SIZE); | 626 | memzero_explicit(D, TGR192_DIGEST_SIZE); |
| 627 | 627 | ||
| 628 | return 0; | 628 | return 0; |
| 629 | } | 629 | } |
diff --git a/crypto/vmac.c b/crypto/vmac.c index 2eb11a30c29c..d84c24bd7ff7 100644 --- a/crypto/vmac.c +++ b/crypto/vmac.c | |||
| @@ -613,7 +613,7 @@ static int vmac_final(struct shash_desc *pdesc, u8 *out) | |||
| 613 | } | 613 | } |
| 614 | mac = vmac(ctx->partial, ctx->partial_size, nonce, NULL, ctx); | 614 | mac = vmac(ctx->partial, ctx->partial_size, nonce, NULL, ctx); |
| 615 | memcpy(out, &mac, sizeof(vmac_t)); | 615 | memcpy(out, &mac, sizeof(vmac_t)); |
| 616 | memset(&mac, 0, sizeof(vmac_t)); | 616 | memzero_explicit(&mac, sizeof(vmac_t)); |
| 617 | memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx)); | 617 | memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx)); |
| 618 | ctx->partial_size = 0; | 618 | ctx->partial_size = 0; |
| 619 | return 0; | 619 | return 0; |
diff --git a/crypto/wp512.c b/crypto/wp512.c index 180f1d6e03f4..ec64e7762fbb 100644 --- a/crypto/wp512.c +++ b/crypto/wp512.c | |||
| @@ -1102,8 +1102,8 @@ static int wp384_final(struct shash_desc *desc, u8 *out) | |||
| 1102 | u8 D[64]; | 1102 | u8 D[64]; |
| 1103 | 1103 | ||
| 1104 | wp512_final(desc, D); | 1104 | wp512_final(desc, D); |
| 1105 | memcpy (out, D, WP384_DIGEST_SIZE); | 1105 | memcpy(out, D, WP384_DIGEST_SIZE); |
| 1106 | memset (D, 0, WP512_DIGEST_SIZE); | 1106 | memzero_explicit(D, WP512_DIGEST_SIZE); |
| 1107 | 1107 | ||
| 1108 | return 0; | 1108 | return 0; |
| 1109 | } | 1109 | } |
| @@ -1113,8 +1113,8 @@ static int wp256_final(struct shash_desc *desc, u8 *out) | |||
| 1113 | u8 D[64]; | 1113 | u8 D[64]; |
| 1114 | 1114 | ||
| 1115 | wp512_final(desc, D); | 1115 | wp512_final(desc, D); |
| 1116 | memcpy (out, D, WP256_DIGEST_SIZE); | 1116 | memcpy(out, D, WP256_DIGEST_SIZE); |
| 1117 | memset (D, 0, WP512_DIGEST_SIZE); | 1117 | memzero_explicit(D, WP512_DIGEST_SIZE); |
| 1118 | 1118 | ||
| 1119 | return 0; | 1119 | return 0; |
| 1120 | } | 1120 | } |
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index d0f3265fb85d..b23fe37f67c0 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
| @@ -144,7 +144,7 @@ config ACPI_VIDEO | |||
| 144 | 144 | ||
| 145 | config ACPI_FAN | 145 | config ACPI_FAN |
| 146 | tristate "Fan" | 146 | tristate "Fan" |
| 147 | select THERMAL | 147 | depends on THERMAL |
| 148 | default y | 148 | default y |
| 149 | help | 149 | help |
| 150 | This driver supports ACPI fan devices, allowing user-mode | 150 | This driver supports ACPI fan devices, allowing user-mode |
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 505d4d79fe3e..c3b2fcb729f3 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
| @@ -43,6 +43,7 @@ acpi-y += pci_root.o pci_link.o pci_irq.o | |||
| 43 | acpi-y += acpi_lpss.o | 43 | acpi-y += acpi_lpss.o |
| 44 | acpi-y += acpi_platform.o | 44 | acpi-y += acpi_platform.o |
| 45 | acpi-y += acpi_pnp.o | 45 | acpi-y += acpi_pnp.o |
| 46 | acpi-y += int340x_thermal.o | ||
| 46 | acpi-y += power.o | 47 | acpi-y += power.o |
| 47 | acpi-y += event.o | 48 | acpi-y += event.o |
| 48 | acpi-y += sysfs.o | 49 | acpi-y += sysfs.o |
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 2bf9082f7523..6ba8beb6b9d2 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/dma-mapping.h> | ||
| 19 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| 20 | 21 | ||
| 21 | #include "internal.h" | 22 | #include "internal.h" |
| @@ -102,6 +103,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) | |||
| 102 | pdevinfo.res = resources; | 103 | pdevinfo.res = resources; |
| 103 | pdevinfo.num_res = count; | 104 | pdevinfo.num_res = count; |
| 104 | pdevinfo.acpi_node.companion = adev; | 105 | pdevinfo.acpi_node.companion = adev; |
| 106 | pdevinfo.dma_mask = DMA_BIT_MASK(32); | ||
| 105 | pdev = platform_device_register_full(&pdevinfo); | 107 | pdev = platform_device_register_full(&pdevinfo); |
| 106 | if (IS_ERR(pdev)) | 108 | if (IS_ERR(pdev)) |
| 107 | dev_err(&adev->dev, "platform device creation failed: %ld\n", | 109 | dev_err(&adev->dev, "platform device creation failed: %ld\n", |
| @@ -113,3 +115,4 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) | |||
| 113 | kfree(resources); | 115 | kfree(resources); |
| 114 | return pdev; | 116 | return pdev; |
| 115 | } | 117 | } |
| 118 | EXPORT_SYMBOL_GPL(acpi_create_platform_device); | ||
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 2ad2351a9833..c318d3e27893 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h | |||
| @@ -127,7 +127,7 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, | |||
| 127 | 127 | ||
| 128 | acpi_status | 128 | acpi_status |
| 129 | acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info, | 129 | acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info, |
| 130 | acpi_event_status * event_status); | 130 | acpi_event_status *event_status); |
| 131 | 131 | ||
| 132 | acpi_status acpi_hw_disable_all_gpes(void); | 132 | acpi_status acpi_hw_disable_all_gpes(void); |
| 133 | 133 | ||
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 2747279fbe3c..c00e7e41ad75 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h | |||
| @@ -413,8 +413,8 @@ struct acpi_gpe_handler_info { | |||
| 413 | acpi_gpe_handler address; /* Address of handler, if any */ | 413 | acpi_gpe_handler address; /* Address of handler, if any */ |
| 414 | void *context; /* Context to be passed to handler */ | 414 | void *context; /* Context to be passed to handler */ |
| 415 | struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ | 415 | struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ |
| 416 | u8 original_flags; /* Original (pre-handler) GPE info */ | 416 | u8 original_flags; /* Original (pre-handler) GPE info */ |
| 417 | u8 originally_enabled; /* True if GPE was originally enabled */ | 417 | u8 originally_enabled; /* True if GPE was originally enabled */ |
| 418 | }; | 418 | }; |
| 419 | 419 | ||
| 420 | /* Notify info for implicit notify, multiple device objects */ | 420 | /* Notify info for implicit notify, multiple device objects */ |
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index f14882788eee..1afe46e44dac 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h | |||
| @@ -49,6 +49,8 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count); | |||
| 49 | /* | 49 | /* |
| 50 | * tbxfroot - Root pointer utilities | 50 | * tbxfroot - Root pointer utilities |
| 51 | */ | 51 | */ |
| 52 | u32 acpi_tb_get_rsdp_length(struct acpi_table_rsdp *rsdp); | ||
| 53 | |||
| 52 | acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); | 54 | acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); |
| 53 | 55 | ||
| 54 | u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length); | 56 | u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length); |
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index f3f834408441..3a0beeb86ba5 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h | |||
| @@ -117,6 +117,12 @@ struct asl_resource_node { | |||
| 117 | struct asl_resource_node *next; | 117 | struct asl_resource_node *next; |
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | struct asl_resource_info { | ||
| 121 | union acpi_parse_object *descriptor_type_op; /* Resource descriptor parse node */ | ||
| 122 | union acpi_parse_object *mapping_op; /* Used for mapfile support */ | ||
| 123 | u32 current_byte_offset; /* Offset in resource template */ | ||
| 124 | }; | ||
| 125 | |||
| 120 | /* Macros used to generate AML resource length fields */ | 126 | /* Macros used to generate AML resource length fields */ |
| 121 | 127 | ||
| 122 | #define ACPI_AML_SIZE_LARGE(r) (sizeof (r) - sizeof (struct aml_resource_large_header)) | 128 | #define ACPI_AML_SIZE_LARGE(r) (sizeof (r) - sizeof (struct aml_resource_large_header)) |
| @@ -449,4 +455,32 @@ union aml_resource { | |||
| 449 | u8 byte_item; | 455 | u8 byte_item; |
| 450 | }; | 456 | }; |
| 451 | 457 | ||
| 458 | /* Interfaces used by both the disassembler and compiler */ | ||
| 459 | |||
| 460 | void | ||
| 461 | mp_save_gpio_info(union acpi_parse_object *op, | ||
| 462 | union aml_resource *resource, | ||
| 463 | u32 pin_count, u16 *pin_list, char *device_name); | ||
| 464 | |||
| 465 | void | ||
| 466 | mp_save_serial_info(union acpi_parse_object *op, | ||
| 467 | union aml_resource *resource, char *device_name); | ||
| 468 | |||
| 469 | char *mp_get_hid_from_parse_tree(struct acpi_namespace_node *hid_node); | ||
| 470 | |||
| 471 | char *mp_get_hid_via_namestring(char *device_name); | ||
| 472 | |||
| 473 | char *mp_get_connection_info(union acpi_parse_object *op, | ||
| 474 | u32 pin_index, | ||
| 475 | struct acpi_namespace_node **target_node, | ||
| 476 | char **target_name); | ||
| 477 | |||
| 478 | char *mp_get_parent_device_hid(union acpi_parse_object *op, | ||
| 479 | struct acpi_namespace_node **target_node, | ||
| 480 | char **parent_device_name); | ||
| 481 | |||
| 482 | char *mp_get_ddn_value(char *device_name); | ||
| 483 | |||
| 484 | char *mp_get_hid_value(struct acpi_namespace_node *device_node); | ||
| 485 | |||
| 452 | #endif | 486 | #endif |
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index e4ba4dec86af..2095dfb72bcb 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c | |||
| @@ -100,13 +100,14 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info) | |||
| 100 | * | 100 | * |
| 101 | * FUNCTION: acpi_ev_enable_gpe | 101 | * FUNCTION: acpi_ev_enable_gpe |
| 102 | * | 102 | * |
| 103 | * PARAMETERS: gpe_event_info - GPE to enable | 103 | * PARAMETERS: gpe_event_info - GPE to enable |
| 104 | * | 104 | * |
| 105 | * RETURN: Status | 105 | * RETURN: Status |
| 106 | * | 106 | * |
| 107 | * DESCRIPTION: Clear a GPE of stale events and enable it. | 107 | * DESCRIPTION: Clear a GPE of stale events and enable it. |
| 108 | * | 108 | * |
| 109 | ******************************************************************************/ | 109 | ******************************************************************************/ |
| 110 | |||
| 110 | acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) | 111 | acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) |
| 111 | { | 112 | { |
| 112 | acpi_status status; | 113 | acpi_status status; |
| @@ -125,6 +126,7 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) | |||
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | /* Clear the GPE (of stale events) */ | 128 | /* Clear the GPE (of stale events) */ |
| 129 | |||
| 128 | status = acpi_hw_clear_gpe(gpe_event_info); | 130 | status = acpi_hw_clear_gpe(gpe_event_info); |
| 129 | if (ACPI_FAILURE(status)) { | 131 | if (ACPI_FAILURE(status)) { |
| 130 | return_ACPI_STATUS(status); | 132 | return_ACPI_STATUS(status); |
| @@ -136,7 +138,6 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) | |||
| 136 | return_ACPI_STATUS(status); | 138 | return_ACPI_STATUS(status); |
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | |||
| 140 | /******************************************************************************* | 141 | /******************************************************************************* |
| 141 | * | 142 | * |
| 142 | * FUNCTION: acpi_ev_add_gpe_reference | 143 | * FUNCTION: acpi_ev_add_gpe_reference |
| @@ -212,7 +213,7 @@ acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) | |||
| 212 | if (ACPI_SUCCESS(status)) { | 213 | if (ACPI_SUCCESS(status)) { |
| 213 | status = | 214 | status = |
| 214 | acpi_hw_low_set_gpe(gpe_event_info, | 215 | acpi_hw_low_set_gpe(gpe_event_info, |
| 215 | ACPI_GPE_DISABLE); | 216 | ACPI_GPE_DISABLE); |
| 216 | } | 217 | } |
| 217 | 218 | ||
| 218 | if (ACPI_FAILURE(status)) { | 219 | if (ACPI_FAILURE(status)) { |
| @@ -334,7 +335,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, | |||
| 334 | * | 335 | * |
| 335 | ******************************************************************************/ | 336 | ******************************************************************************/ |
| 336 | 337 | ||
| 337 | u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) | 338 | u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) |
| 338 | { | 339 | { |
| 339 | acpi_status status; | 340 | acpi_status status; |
| 340 | struct acpi_gpe_block_info *gpe_block; | 341 | struct acpi_gpe_block_info *gpe_block; |
| @@ -427,7 +428,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) | |||
| 427 | 428 | ||
| 428 | /* Check if there is anything active at all in this register */ | 429 | /* Check if there is anything active at all in this register */ |
| 429 | 430 | ||
| 430 | enabled_status_byte = (u8) (status_reg & enable_reg); | 431 | enabled_status_byte = (u8)(status_reg & enable_reg); |
| 431 | if (!enabled_status_byte) { | 432 | if (!enabled_status_byte) { |
| 432 | 433 | ||
| 433 | /* No active GPEs in this register, move on */ | 434 | /* No active GPEs in this register, move on */ |
| @@ -450,7 +451,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) | |||
| 450 | acpi_ev_gpe_dispatch(gpe_block-> | 451 | acpi_ev_gpe_dispatch(gpe_block-> |
| 451 | node, | 452 | node, |
| 452 | &gpe_block-> | 453 | &gpe_block-> |
| 453 | event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number); | 454 | event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number); |
| 454 | } | 455 | } |
| 455 | } | 456 | } |
| 456 | } | 457 | } |
| @@ -636,7 +637,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context) | |||
| 636 | * | 637 | * |
| 637 | ******************************************************************************/ | 638 | ******************************************************************************/ |
| 638 | 639 | ||
| 639 | acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info) | 640 | acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info) |
| 640 | { | 641 | { |
| 641 | acpi_status status; | 642 | acpi_status status; |
| 642 | 643 | ||
| @@ -666,9 +667,9 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info) | |||
| 666 | * | 667 | * |
| 667 | * FUNCTION: acpi_ev_gpe_dispatch | 668 | * FUNCTION: acpi_ev_gpe_dispatch |
| 668 | * | 669 | * |
| 669 | * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 | 670 | * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 |
| 670 | * gpe_event_info - Info for this GPE | 671 | * gpe_event_info - Info for this GPE |
| 671 | * gpe_number - Number relative to the parent GPE block | 672 | * gpe_number - Number relative to the parent GPE block |
| 672 | * | 673 | * |
| 673 | * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED | 674 | * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED |
| 674 | * | 675 | * |
| @@ -681,7 +682,7 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info) | |||
| 681 | 682 | ||
| 682 | u32 | 683 | u32 |
| 683 | acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, | 684 | acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, |
| 684 | struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) | 685 | struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) |
| 685 | { | 686 | { |
| 686 | acpi_status status; | 687 | acpi_status status; |
| 687 | u32 return_value; | 688 | u32 return_value; |
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 49fc7effd961..7be928379879 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c | |||
| @@ -424,6 +424,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, | |||
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | /* Disable the GPE in case it's been enabled already. */ | 426 | /* Disable the GPE in case it's been enabled already. */ |
| 427 | |||
| 427 | (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); | 428 | (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); |
| 428 | 429 | ||
| 429 | /* | 430 | /* |
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 11e5803b8b41..55a58f3ec8df 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c | |||
| @@ -786,18 +786,26 @@ acpi_install_gpe_handler(acpi_handle gpe_device, | |||
| 786 | handler->method_node = gpe_event_info->dispatch.method_node; | 786 | handler->method_node = gpe_event_info->dispatch.method_node; |
| 787 | handler->original_flags = (u8)(gpe_event_info->flags & | 787 | handler->original_flags = (u8)(gpe_event_info->flags & |
| 788 | (ACPI_GPE_XRUPT_TYPE_MASK | | 788 | (ACPI_GPE_XRUPT_TYPE_MASK | |
| 789 | ACPI_GPE_DISPATCH_MASK)); | 789 | ACPI_GPE_DISPATCH_MASK)); |
| 790 | 790 | ||
| 791 | /* | 791 | /* |
| 792 | * If the GPE is associated with a method, it may have been enabled | 792 | * If the GPE is associated with a method, it may have been enabled |
| 793 | * automatically during initialization, in which case it has to be | 793 | * automatically during initialization, in which case it has to be |
| 794 | * disabled now to avoid spurious execution of the handler. | 794 | * disabled now to avoid spurious execution of the handler. |
| 795 | */ | 795 | */ |
| 796 | 796 | if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) || | |
| 797 | if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) | 797 | (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) && |
| 798 | && gpe_event_info->runtime_count) { | 798 | gpe_event_info->runtime_count) { |
| 799 | handler->originally_enabled = 1; | 799 | handler->originally_enabled = TRUE; |
| 800 | (void)acpi_ev_remove_gpe_reference(gpe_event_info); | 800 | (void)acpi_ev_remove_gpe_reference(gpe_event_info); |
| 801 | |||
| 802 | /* Sanity check of original type against new type */ | ||
| 803 | |||
| 804 | if (type != | ||
| 805 | (u32)(gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) { | ||
| 806 | ACPI_WARNING((AE_INFO, | ||
| 807 | "GPE type mismatch (level/edge)")); | ||
| 808 | } | ||
| 801 | } | 809 | } |
| 802 | 810 | ||
| 803 | /* Install the handler */ | 811 | /* Install the handler */ |
| @@ -808,7 +816,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, | |||
| 808 | 816 | ||
| 809 | gpe_event_info->flags &= | 817 | gpe_event_info->flags &= |
| 810 | ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); | 818 | ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); |
| 811 | gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER); | 819 | gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_HANDLER); |
| 812 | 820 | ||
| 813 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 821 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
| 814 | 822 | ||
| @@ -893,7 +901,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, | |||
| 893 | 901 | ||
| 894 | gpe_event_info->dispatch.method_node = handler->method_node; | 902 | gpe_event_info->dispatch.method_node = handler->method_node; |
| 895 | gpe_event_info->flags &= | 903 | gpe_event_info->flags &= |
| 896 | ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); | 904 | ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); |
| 897 | gpe_event_info->flags |= handler->original_flags; | 905 | gpe_event_info->flags |= handler->original_flags; |
| 898 | 906 | ||
| 899 | /* | 907 | /* |
| @@ -901,7 +909,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, | |||
| 901 | * enabled, it should be enabled at this point to restore the | 909 | * enabled, it should be enabled at this point to restore the |
| 902 | * post-initialization configuration. | 910 | * post-initialization configuration. |
| 903 | */ | 911 | */ |
| 904 | if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) && | 912 | if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) || |
| 913 | (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) && | ||
| 905 | handler->originally_enabled) { | 914 | handler->originally_enabled) { |
| 906 | (void)acpi_ev_add_gpe_reference(gpe_event_info); | 915 | (void)acpi_ev_add_gpe_reference(gpe_event_info); |
| 907 | } | 916 | } |
| @@ -946,7 +955,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler) | |||
| 946 | * handle is returned. | 955 | * handle is returned. |
| 947 | * | 956 | * |
| 948 | ******************************************************************************/ | 957 | ******************************************************************************/ |
| 949 | acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle) | 958 | acpi_status acpi_acquire_global_lock(u16 timeout, u32 *handle) |
| 950 | { | 959 | { |
| 951 | acpi_status status; | 960 | acpi_status status; |
| 952 | 961 | ||
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index e286640ad4ff..bb8cbf5961bf 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c | |||
| @@ -324,8 +324,9 @@ ACPI_EXPORT_SYMBOL(acpi_clear_event) | |||
| 324 | ******************************************************************************/ | 324 | ******************************************************************************/ |
| 325 | acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) | 325 | acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) |
| 326 | { | 326 | { |
| 327 | acpi_status status = AE_OK; | 327 | acpi_status status; |
| 328 | u32 value; | 328 | acpi_event_status local_event_status = 0; |
| 329 | u32 in_byte; | ||
| 329 | 330 | ||
| 330 | ACPI_FUNCTION_TRACE(acpi_get_event_status); | 331 | ACPI_FUNCTION_TRACE(acpi_get_event_status); |
| 331 | 332 | ||
| @@ -339,29 +340,40 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) | |||
| 339 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 340 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
| 340 | } | 341 | } |
| 341 | 342 | ||
| 342 | /* Get the status of the requested fixed event */ | 343 | /* Fixed event currently can be dispatched? */ |
| 344 | |||
| 345 | if (acpi_gbl_fixed_event_handlers[event].handler) { | ||
| 346 | local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER; | ||
| 347 | } | ||
| 348 | |||
| 349 | /* Fixed event currently enabled? */ | ||
| 343 | 350 | ||
| 344 | status = | 351 | status = |
| 345 | acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. | 352 | acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. |
| 346 | enable_register_id, &value); | 353 | enable_register_id, &in_byte); |
| 347 | if (ACPI_FAILURE(status)) | 354 | if (ACPI_FAILURE(status)) { |
| 348 | return_ACPI_STATUS(status); | 355 | return_ACPI_STATUS(status); |
| 356 | } | ||
| 349 | 357 | ||
| 350 | *event_status = value; | 358 | if (in_byte) { |
| 359 | local_event_status |= ACPI_EVENT_FLAG_ENABLED; | ||
| 360 | } | ||
| 361 | |||
| 362 | /* Fixed event currently active? */ | ||
| 351 | 363 | ||
| 352 | status = | 364 | status = |
| 353 | acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. | 365 | acpi_read_bit_register(acpi_gbl_fixed_event_info[event]. |
| 354 | status_register_id, &value); | 366 | status_register_id, &in_byte); |
| 355 | if (ACPI_FAILURE(status)) | 367 | if (ACPI_FAILURE(status)) { |
| 356 | return_ACPI_STATUS(status); | 368 | return_ACPI_STATUS(status); |
| 369 | } | ||
| 357 | 370 | ||
| 358 | if (value) | 371 | if (in_byte) { |
| 359 | *event_status |= ACPI_EVENT_FLAG_SET; | 372 | local_event_status |= ACPI_EVENT_FLAG_SET; |
| 360 | 373 | } | |
| 361 | if (acpi_gbl_fixed_event_handlers[event].handler) | ||
| 362 | *event_status |= ACPI_EVENT_FLAG_HANDLE; | ||
| 363 | 374 | ||
| 364 | return_ACPI_STATUS(status); | 375 | (*event_status) = local_event_status; |
| 376 | return_ACPI_STATUS(AE_OK); | ||
| 365 | } | 377 | } |
| 366 | 378 | ||
| 367 | ACPI_EXPORT_SYMBOL(acpi_get_event_status) | 379 | ACPI_EXPORT_SYMBOL(acpi_get_event_status) |
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 56710a03c9b0..e889a5304abd 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c | |||
| @@ -106,8 +106,8 @@ ACPI_EXPORT_SYMBOL(acpi_update_all_gpes) | |||
| 106 | * | 106 | * |
| 107 | * FUNCTION: acpi_enable_gpe | 107 | * FUNCTION: acpi_enable_gpe |
| 108 | * | 108 | * |
| 109 | * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 | 109 | * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
| 110 | * gpe_number - GPE level within the GPE block | 110 | * gpe_number - GPE level within the GPE block |
| 111 | * | 111 | * |
| 112 | * RETURN: Status | 112 | * RETURN: Status |
| 113 | * | 113 | * |
| @@ -115,7 +115,6 @@ ACPI_EXPORT_SYMBOL(acpi_update_all_gpes) | |||
| 115 | * hardware-enabled. | 115 | * hardware-enabled. |
| 116 | * | 116 | * |
| 117 | ******************************************************************************/ | 117 | ******************************************************************************/ |
| 118 | |||
| 119 | acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) | 118 | acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) |
| 120 | { | 119 | { |
| 121 | acpi_status status = AE_BAD_PARAMETER; | 120 | acpi_status status = AE_BAD_PARAMETER; |
| @@ -490,8 +489,8 @@ ACPI_EXPORT_SYMBOL(acpi_clear_gpe) | |||
| 490 | * | 489 | * |
| 491 | * FUNCTION: acpi_get_gpe_status | 490 | * FUNCTION: acpi_get_gpe_status |
| 492 | * | 491 | * |
| 493 | * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 | 492 | * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 |
| 494 | * gpe_number - GPE level within the GPE block | 493 | * gpe_number - GPE level within the GPE block |
| 495 | * event_status - Where the current status of the event | 494 | * event_status - Where the current status of the event |
| 496 | * will be returned | 495 | * will be returned |
| 497 | * | 496 | * |
| @@ -524,9 +523,6 @@ acpi_get_gpe_status(acpi_handle gpe_device, | |||
| 524 | 523 | ||
| 525 | status = acpi_hw_get_gpe_status(gpe_event_info, event_status); | 524 | status = acpi_hw_get_gpe_status(gpe_event_info, event_status); |
| 526 | 525 | ||
| 527 | if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) | ||
| 528 | *event_status |= ACPI_EVENT_FLAG_HANDLE; | ||
| 529 | |||
| 530 | unlock_and_exit: | 526 | unlock_and_exit: |
| 531 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 527 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
| 532 | return_ACPI_STATUS(status); | 528 | return_ACPI_STATUS(status); |
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index ea62d40fd161..48ac7b7b59cd 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c | |||
| @@ -202,7 +202,7 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) | |||
| 202 | 202 | ||
| 203 | acpi_status | 203 | acpi_status |
| 204 | acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, | 204 | acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, |
| 205 | acpi_event_status * event_status) | 205 | acpi_event_status *event_status) |
| 206 | { | 206 | { |
| 207 | u32 in_byte; | 207 | u32 in_byte; |
| 208 | u32 register_bit; | 208 | u32 register_bit; |
| @@ -216,6 +216,13 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, | |||
| 216 | return (AE_BAD_PARAMETER); | 216 | return (AE_BAD_PARAMETER); |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | /* GPE currently handled? */ | ||
| 220 | |||
| 221 | if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != | ||
| 222 | ACPI_GPE_DISPATCH_NONE) { | ||
| 223 | local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER; | ||
| 224 | } | ||
| 225 | |||
| 219 | /* Get the info block for the entire GPE register */ | 226 | /* Get the info block for the entire GPE register */ |
| 220 | 227 | ||
| 221 | gpe_register_info = gpe_event_info->register_info; | 228 | gpe_register_info = gpe_event_info->register_info; |
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 65ab8fed3d5e..43a54af2b548 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c | |||
| @@ -50,6 +50,36 @@ ACPI_MODULE_NAME("tbxfroot") | |||
| 50 | 50 | ||
| 51 | /******************************************************************************* | 51 | /******************************************************************************* |
| 52 | * | 52 | * |
| 53 | * FUNCTION: acpi_tb_get_rsdp_length | ||
| 54 | * | ||
| 55 | * PARAMETERS: rsdp - Pointer to RSDP | ||
| 56 | * | ||
| 57 | * RETURN: Table length | ||
| 58 | * | ||
| 59 | * DESCRIPTION: Get the length of the RSDP | ||
| 60 | * | ||
| 61 | ******************************************************************************/ | ||
| 62 | u32 acpi_tb_get_rsdp_length(struct acpi_table_rsdp *rsdp) | ||
| 63 | { | ||
| 64 | |||
| 65 | if (!ACPI_VALIDATE_RSDP_SIG(rsdp->signature)) { | ||
| 66 | |||
| 67 | /* BAD Signature */ | ||
| 68 | |||
| 69 | return (0); | ||
| 70 | } | ||
| 71 | |||
| 72 | /* "Length" field is available if table version >= 2 */ | ||
| 73 | |||
| 74 | if (rsdp->revision >= 2) { | ||
| 75 | return (rsdp->length); | ||
| 76 | } else { | ||
| 77 | return (ACPI_RSDP_CHECKSUM_LENGTH); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | /******************************************************************************* | ||
| 82 | * | ||
| 53 | * FUNCTION: acpi_tb_validate_rsdp | 83 | * FUNCTION: acpi_tb_validate_rsdp |
| 54 | * | 84 | * |
| 55 | * PARAMETERS: rsdp - Pointer to unvalidated RSDP | 85 | * PARAMETERS: rsdp - Pointer to unvalidated RSDP |
| @@ -59,7 +89,8 @@ ACPI_MODULE_NAME("tbxfroot") | |||
| 59 | * DESCRIPTION: Validate the RSDP (ptr) | 89 | * DESCRIPTION: Validate the RSDP (ptr) |
| 60 | * | 90 | * |
| 61 | ******************************************************************************/ | 91 | ******************************************************************************/ |
| 62 | acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) | 92 | |
| 93 | acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp * rsdp) | ||
| 63 | { | 94 | { |
| 64 | 95 | ||
| 65 | /* | 96 | /* |
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index bea6896be122..143ec6ea1468 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c | |||
| @@ -343,6 +343,7 @@ int acpi_device_update_power(struct acpi_device *device, int *state_p) | |||
| 343 | 343 | ||
| 344 | return 0; | 344 | return 0; |
| 345 | } | 345 | } |
| 346 | EXPORT_SYMBOL_GPL(acpi_device_update_power); | ||
| 346 | 347 | ||
| 347 | int acpi_bus_update_power(acpi_handle handle, int *state_p) | 348 | int acpi_bus_update_power(acpi_handle handle, int *state_p) |
| 348 | { | 349 | { |
| @@ -710,7 +711,7 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) | |||
| 710 | return -ENODEV; | 711 | return -ENODEV; |
| 711 | } | 712 | } |
| 712 | 713 | ||
| 713 | return acpi_device_wakeup(adev, enable, ACPI_STATE_S0); | 714 | return acpi_device_wakeup(adev, ACPI_STATE_S0, enable); |
| 714 | } | 715 | } |
| 715 | EXPORT_SYMBOL(acpi_pm_device_run_wake); | 716 | EXPORT_SYMBOL(acpi_pm_device_run_wake); |
| 716 | #endif /* CONFIG_PM_RUNTIME */ | 717 | #endif /* CONFIG_PM_RUNTIME */ |
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index cb6066c809ea..3d304ff7f095 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
| @@ -128,12 +128,13 @@ static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */ | |||
| 128 | static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ | 128 | static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ |
| 129 | 129 | ||
| 130 | /* -------------------------------------------------------------------------- | 130 | /* -------------------------------------------------------------------------- |
| 131 | Transaction Management | 131 | * Transaction Management |
| 132 | -------------------------------------------------------------------------- */ | 132 | * -------------------------------------------------------------------------- */ |
| 133 | 133 | ||
| 134 | static inline u8 acpi_ec_read_status(struct acpi_ec *ec) | 134 | static inline u8 acpi_ec_read_status(struct acpi_ec *ec) |
| 135 | { | 135 | { |
| 136 | u8 x = inb(ec->command_addr); | 136 | u8 x = inb(ec->command_addr); |
| 137 | |||
| 137 | pr_debug("EC_SC(R) = 0x%2.2x " | 138 | pr_debug("EC_SC(R) = 0x%2.2x " |
| 138 | "SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d\n", | 139 | "SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d\n", |
| 139 | x, | 140 | x, |
| @@ -148,6 +149,7 @@ static inline u8 acpi_ec_read_status(struct acpi_ec *ec) | |||
| 148 | static inline u8 acpi_ec_read_data(struct acpi_ec *ec) | 149 | static inline u8 acpi_ec_read_data(struct acpi_ec *ec) |
| 149 | { | 150 | { |
| 150 | u8 x = inb(ec->data_addr); | 151 | u8 x = inb(ec->data_addr); |
| 152 | |||
| 151 | pr_debug("EC_DATA(R) = 0x%2.2x\n", x); | 153 | pr_debug("EC_DATA(R) = 0x%2.2x\n", x); |
| 152 | return x; | 154 | return x; |
| 153 | } | 155 | } |
| @@ -164,10 +166,32 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) | |||
| 164 | outb(data, ec->data_addr); | 166 | outb(data, ec->data_addr); |
| 165 | } | 167 | } |
| 166 | 168 | ||
| 169 | #ifdef DEBUG | ||
| 170 | static const char *acpi_ec_cmd_string(u8 cmd) | ||
| 171 | { | ||
| 172 | switch (cmd) { | ||
| 173 | case 0x80: | ||
| 174 | return "RD_EC"; | ||
| 175 | case 0x81: | ||
| 176 | return "WR_EC"; | ||
| 177 | case 0x82: | ||
| 178 | return "BE_EC"; | ||
| 179 | case 0x83: | ||
| 180 | return "BD_EC"; | ||
| 181 | case 0x84: | ||
| 182 | return "QR_EC"; | ||
| 183 | } | ||
| 184 | return "UNKNOWN"; | ||
| 185 | } | ||
| 186 | #else | ||
| 187 | #define acpi_ec_cmd_string(cmd) "UNDEF" | ||
| 188 | #endif | ||
| 189 | |||
| 167 | static int ec_transaction_completed(struct acpi_ec *ec) | 190 | static int ec_transaction_completed(struct acpi_ec *ec) |
| 168 | { | 191 | { |
| 169 | unsigned long flags; | 192 | unsigned long flags; |
| 170 | int ret = 0; | 193 | int ret = 0; |
| 194 | |||
| 171 | spin_lock_irqsave(&ec->lock, flags); | 195 | spin_lock_irqsave(&ec->lock, flags); |
| 172 | if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE)) | 196 | if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE)) |
| 173 | ret = 1; | 197 | ret = 1; |
| @@ -181,7 +205,8 @@ static bool advance_transaction(struct acpi_ec *ec) | |||
| 181 | u8 status; | 205 | u8 status; |
| 182 | bool wakeup = false; | 206 | bool wakeup = false; |
| 183 | 207 | ||
| 184 | pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK"); | 208 | pr_debug("===== %s (%d) =====\n", |
| 209 | in_interrupt() ? "IRQ" : "TASK", smp_processor_id()); | ||
| 185 | status = acpi_ec_read_status(ec); | 210 | status = acpi_ec_read_status(ec); |
| 186 | t = ec->curr; | 211 | t = ec->curr; |
| 187 | if (!t) | 212 | if (!t) |
| @@ -198,7 +223,8 @@ static bool advance_transaction(struct acpi_ec *ec) | |||
| 198 | if (t->rlen == t->ri) { | 223 | if (t->rlen == t->ri) { |
| 199 | t->flags |= ACPI_EC_COMMAND_COMPLETE; | 224 | t->flags |= ACPI_EC_COMMAND_COMPLETE; |
| 200 | if (t->command == ACPI_EC_COMMAND_QUERY) | 225 | if (t->command == ACPI_EC_COMMAND_QUERY) |
| 201 | pr_debug("hardware QR_EC completion\n"); | 226 | pr_debug("***** Command(%s) hardware completion *****\n", |
| 227 | acpi_ec_cmd_string(t->command)); | ||
| 202 | wakeup = true; | 228 | wakeup = true; |
| 203 | } | 229 | } |
| 204 | } else | 230 | } else |
| @@ -221,7 +247,8 @@ static bool advance_transaction(struct acpi_ec *ec) | |||
| 221 | t->flags |= ACPI_EC_COMMAND_POLL; | 247 | t->flags |= ACPI_EC_COMMAND_POLL; |
| 222 | t->rdata[t->ri++] = 0x00; | 248 | t->rdata[t->ri++] = 0x00; |
| 223 | t->flags |= ACPI_EC_COMMAND_COMPLETE; | 249 | t->flags |= ACPI_EC_COMMAND_COMPLETE; |
| 224 | pr_debug("software QR_EC completion\n"); | 250 | pr_debug("***** Command(%s) software completion *****\n", |
| 251 | acpi_ec_cmd_string(t->command)); | ||
| 225 | wakeup = true; | 252 | wakeup = true; |
| 226 | } else if ((status & ACPI_EC_FLAG_IBF) == 0) { | 253 | } else if ((status & ACPI_EC_FLAG_IBF) == 0) { |
| 227 | acpi_ec_write_cmd(ec, t->command); | 254 | acpi_ec_write_cmd(ec, t->command); |
| @@ -264,6 +291,7 @@ static int ec_poll(struct acpi_ec *ec) | |||
| 264 | { | 291 | { |
| 265 | unsigned long flags; | 292 | unsigned long flags; |
| 266 | int repeat = 5; /* number of command restarts */ | 293 | int repeat = 5; /* number of command restarts */ |
| 294 | |||
| 267 | while (repeat--) { | 295 | while (repeat--) { |
| 268 | unsigned long delay = jiffies + | 296 | unsigned long delay = jiffies + |
| 269 | msecs_to_jiffies(ec_delay); | 297 | msecs_to_jiffies(ec_delay); |
| @@ -296,18 +324,25 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, | |||
| 296 | { | 324 | { |
| 297 | unsigned long tmp; | 325 | unsigned long tmp; |
| 298 | int ret = 0; | 326 | int ret = 0; |
| 327 | |||
| 299 | if (EC_FLAGS_MSI) | 328 | if (EC_FLAGS_MSI) |
| 300 | udelay(ACPI_EC_MSI_UDELAY); | 329 | udelay(ACPI_EC_MSI_UDELAY); |
| 301 | /* start transaction */ | 330 | /* start transaction */ |
| 302 | spin_lock_irqsave(&ec->lock, tmp); | 331 | spin_lock_irqsave(&ec->lock, tmp); |
| 303 | /* following two actions should be kept atomic */ | 332 | /* following two actions should be kept atomic */ |
| 304 | ec->curr = t; | 333 | ec->curr = t; |
| 334 | pr_debug("***** Command(%s) started *****\n", | ||
| 335 | acpi_ec_cmd_string(t->command)); | ||
| 305 | start_transaction(ec); | 336 | start_transaction(ec); |
| 306 | spin_unlock_irqrestore(&ec->lock, tmp); | 337 | spin_unlock_irqrestore(&ec->lock, tmp); |
| 307 | ret = ec_poll(ec); | 338 | ret = ec_poll(ec); |
| 308 | spin_lock_irqsave(&ec->lock, tmp); | 339 | spin_lock_irqsave(&ec->lock, tmp); |
| 309 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) | 340 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { |
| 310 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 341 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
| 342 | pr_debug("***** Event stopped *****\n"); | ||
| 343 | } | ||
| 344 | pr_debug("***** Command(%s) stopped *****\n", | ||
| 345 | acpi_ec_cmd_string(t->command)); | ||
| 311 | ec->curr = NULL; | 346 | ec->curr = NULL; |
| 312 | spin_unlock_irqrestore(&ec->lock, tmp); | 347 | spin_unlock_irqrestore(&ec->lock, tmp); |
| 313 | return ret; | 348 | return ret; |
| @@ -317,6 +352,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
| 317 | { | 352 | { |
| 318 | int status; | 353 | int status; |
| 319 | u32 glk; | 354 | u32 glk; |
| 355 | |||
| 320 | if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) | 356 | if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) |
| 321 | return -EINVAL; | 357 | return -EINVAL; |
| 322 | if (t->rdata) | 358 | if (t->rdata) |
| @@ -333,8 +369,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
| 333 | goto unlock; | 369 | goto unlock; |
| 334 | } | 370 | } |
| 335 | } | 371 | } |
| 336 | pr_debug("transaction start (cmd=0x%02x, addr=0x%02x)\n", | ||
| 337 | t->command, t->wdata ? t->wdata[0] : 0); | ||
| 338 | /* disable GPE during transaction if storm is detected */ | 372 | /* disable GPE during transaction if storm is detected */ |
| 339 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { | 373 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { |
| 340 | /* It has to be disabled, so that it doesn't trigger. */ | 374 | /* It has to be disabled, so that it doesn't trigger. */ |
| @@ -355,7 +389,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
| 355 | t->irq_count); | 389 | t->irq_count); |
| 356 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); | 390 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); |
| 357 | } | 391 | } |
| 358 | pr_debug("transaction end\n"); | ||
| 359 | if (ec->global_lock) | 392 | if (ec->global_lock) |
| 360 | acpi_release_global_lock(glk); | 393 | acpi_release_global_lock(glk); |
| 361 | unlock: | 394 | unlock: |
| @@ -383,7 +416,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec) | |||
| 383 | acpi_ec_transaction(ec, &t) : 0; | 416 | acpi_ec_transaction(ec, &t) : 0; |
| 384 | } | 417 | } |
| 385 | 418 | ||
| 386 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) | 419 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) |
| 387 | { | 420 | { |
| 388 | int result; | 421 | int result; |
| 389 | u8 d; | 422 | u8 d; |
| @@ -419,10 +452,9 @@ int ec_read(u8 addr, u8 *val) | |||
| 419 | if (!err) { | 452 | if (!err) { |
| 420 | *val = temp_data; | 453 | *val = temp_data; |
| 421 | return 0; | 454 | return 0; |
| 422 | } else | 455 | } |
| 423 | return err; | 456 | return err; |
| 424 | } | 457 | } |
| 425 | |||
| 426 | EXPORT_SYMBOL(ec_read); | 458 | EXPORT_SYMBOL(ec_read); |
| 427 | 459 | ||
| 428 | int ec_write(u8 addr, u8 val) | 460 | int ec_write(u8 addr, u8 val) |
| @@ -436,22 +468,21 @@ int ec_write(u8 addr, u8 val) | |||
| 436 | 468 | ||
| 437 | return err; | 469 | return err; |
| 438 | } | 470 | } |
| 439 | |||
| 440 | EXPORT_SYMBOL(ec_write); | 471 | EXPORT_SYMBOL(ec_write); |
| 441 | 472 | ||
| 442 | int ec_transaction(u8 command, | 473 | int ec_transaction(u8 command, |
| 443 | const u8 * wdata, unsigned wdata_len, | 474 | const u8 *wdata, unsigned wdata_len, |
| 444 | u8 * rdata, unsigned rdata_len) | 475 | u8 *rdata, unsigned rdata_len) |
| 445 | { | 476 | { |
| 446 | struct transaction t = {.command = command, | 477 | struct transaction t = {.command = command, |
| 447 | .wdata = wdata, .rdata = rdata, | 478 | .wdata = wdata, .rdata = rdata, |
| 448 | .wlen = wdata_len, .rlen = rdata_len}; | 479 | .wlen = wdata_len, .rlen = rdata_len}; |
| 480 | |||
| 449 | if (!first_ec) | 481 | if (!first_ec) |
| 450 | return -ENODEV; | 482 | return -ENODEV; |
| 451 | 483 | ||
| 452 | return acpi_ec_transaction(first_ec, &t); | 484 | return acpi_ec_transaction(first_ec, &t); |
| 453 | } | 485 | } |
| 454 | |||
| 455 | EXPORT_SYMBOL(ec_transaction); | 486 | EXPORT_SYMBOL(ec_transaction); |
| 456 | 487 | ||
| 457 | /* Get the handle to the EC device */ | 488 | /* Get the handle to the EC device */ |
| @@ -461,7 +492,6 @@ acpi_handle ec_get_handle(void) | |||
| 461 | return NULL; | 492 | return NULL; |
| 462 | return first_ec->handle; | 493 | return first_ec->handle; |
| 463 | } | 494 | } |
| 464 | |||
| 465 | EXPORT_SYMBOL(ec_get_handle); | 495 | EXPORT_SYMBOL(ec_get_handle); |
| 466 | 496 | ||
| 467 | /* | 497 | /* |
| @@ -525,13 +555,14 @@ void acpi_ec_unblock_transactions_early(void) | |||
| 525 | clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); | 555 | clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); |
| 526 | } | 556 | } |
| 527 | 557 | ||
| 528 | static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) | 558 | static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data) |
| 529 | { | 559 | { |
| 530 | int result; | 560 | int result; |
| 531 | u8 d; | 561 | u8 d; |
| 532 | struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, | 562 | struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, |
| 533 | .wdata = NULL, .rdata = &d, | 563 | .wdata = NULL, .rdata = &d, |
| 534 | .wlen = 0, .rlen = 1}; | 564 | .wlen = 0, .rlen = 1}; |
| 565 | |||
| 535 | if (!ec || !data) | 566 | if (!ec || !data) |
| 536 | return -EINVAL; | 567 | return -EINVAL; |
| 537 | /* | 568 | /* |
| @@ -557,6 +588,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | |||
| 557 | { | 588 | { |
| 558 | struct acpi_ec_query_handler *handler = | 589 | struct acpi_ec_query_handler *handler = |
| 559 | kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL); | 590 | kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL); |
| 591 | |||
| 560 | if (!handler) | 592 | if (!handler) |
| 561 | return -ENOMEM; | 593 | return -ENOMEM; |
| 562 | 594 | ||
| @@ -569,12 +601,12 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | |||
| 569 | mutex_unlock(&ec->mutex); | 601 | mutex_unlock(&ec->mutex); |
| 570 | return 0; | 602 | return 0; |
| 571 | } | 603 | } |
| 572 | |||
| 573 | EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); | 604 | EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); |
| 574 | 605 | ||
| 575 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) | 606 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) |
| 576 | { | 607 | { |
| 577 | struct acpi_ec_query_handler *handler, *tmp; | 608 | struct acpi_ec_query_handler *handler, *tmp; |
| 609 | |||
| 578 | mutex_lock(&ec->mutex); | 610 | mutex_lock(&ec->mutex); |
| 579 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { | 611 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { |
| 580 | if (query_bit == handler->query_bit) { | 612 | if (query_bit == handler->query_bit) { |
| @@ -584,20 +616,20 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) | |||
| 584 | } | 616 | } |
| 585 | mutex_unlock(&ec->mutex); | 617 | mutex_unlock(&ec->mutex); |
| 586 | } | 618 | } |
| 587 | |||
| 588 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); | 619 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); |
| 589 | 620 | ||
| 590 | static void acpi_ec_run(void *cxt) | 621 | static void acpi_ec_run(void *cxt) |
| 591 | { | 622 | { |
| 592 | struct acpi_ec_query_handler *handler = cxt; | 623 | struct acpi_ec_query_handler *handler = cxt; |
| 624 | |||
| 593 | if (!handler) | 625 | if (!handler) |
| 594 | return; | 626 | return; |
| 595 | pr_debug("start query execution\n"); | 627 | pr_debug("##### Query(0x%02x) started #####\n", handler->query_bit); |
| 596 | if (handler->func) | 628 | if (handler->func) |
| 597 | handler->func(handler->data); | 629 | handler->func(handler->data); |
| 598 | else if (handler->handle) | 630 | else if (handler->handle) |
| 599 | acpi_evaluate_object(handler->handle, NULL, NULL, NULL); | 631 | acpi_evaluate_object(handler->handle, NULL, NULL, NULL); |
| 600 | pr_debug("stop query execution\n"); | 632 | pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit); |
| 601 | kfree(handler); | 633 | kfree(handler); |
| 602 | } | 634 | } |
| 603 | 635 | ||
| @@ -620,8 +652,8 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) | |||
| 620 | if (!copy) | 652 | if (!copy) |
| 621 | return -ENOMEM; | 653 | return -ENOMEM; |
| 622 | memcpy(copy, handler, sizeof(*copy)); | 654 | memcpy(copy, handler, sizeof(*copy)); |
| 623 | pr_debug("push query execution (0x%2x) on queue\n", | 655 | pr_debug("##### Query(0x%02x) scheduled #####\n", |
| 624 | value); | 656 | handler->query_bit); |
| 625 | return acpi_os_execute((copy->func) ? | 657 | return acpi_os_execute((copy->func) ? |
| 626 | OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, | 658 | OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, |
| 627 | acpi_ec_run, copy); | 659 | acpi_ec_run, copy); |
| @@ -633,6 +665,7 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) | |||
| 633 | static void acpi_ec_gpe_query(void *ec_cxt) | 665 | static void acpi_ec_gpe_query(void *ec_cxt) |
| 634 | { | 666 | { |
| 635 | struct acpi_ec *ec = ec_cxt; | 667 | struct acpi_ec *ec = ec_cxt; |
| 668 | |||
| 636 | if (!ec) | 669 | if (!ec) |
| 637 | return; | 670 | return; |
| 638 | mutex_lock(&ec->mutex); | 671 | mutex_lock(&ec->mutex); |
| @@ -644,7 +677,7 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state) | |||
| 644 | { | 677 | { |
| 645 | if (state & ACPI_EC_FLAG_SCI) { | 678 | if (state & ACPI_EC_FLAG_SCI) { |
| 646 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { | 679 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { |
| 647 | pr_debug("push gpe query to the queue\n"); | 680 | pr_debug("***** Event started *****\n"); |
| 648 | return acpi_os_execute(OSL_NOTIFY_HANDLER, | 681 | return acpi_os_execute(OSL_NOTIFY_HANDLER, |
| 649 | acpi_ec_gpe_query, ec); | 682 | acpi_ec_gpe_query, ec); |
| 650 | } | 683 | } |
| @@ -667,8 +700,8 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, | |||
| 667 | } | 700 | } |
| 668 | 701 | ||
| 669 | /* -------------------------------------------------------------------------- | 702 | /* -------------------------------------------------------------------------- |
| 670 | Address Space Management | 703 | * Address Space Management |
| 671 | -------------------------------------------------------------------------- */ | 704 | * -------------------------------------------------------------------------- */ |
| 672 | 705 | ||
| 673 | static acpi_status | 706 | static acpi_status |
| 674 | acpi_ec_space_handler(u32 function, acpi_physical_address address, | 707 | acpi_ec_space_handler(u32 function, acpi_physical_address address, |
| @@ -699,27 +732,26 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, | |||
| 699 | switch (result) { | 732 | switch (result) { |
| 700 | case -EINVAL: | 733 | case -EINVAL: |
| 701 | return AE_BAD_PARAMETER; | 734 | return AE_BAD_PARAMETER; |
| 702 | break; | ||
| 703 | case -ENODEV: | 735 | case -ENODEV: |
| 704 | return AE_NOT_FOUND; | 736 | return AE_NOT_FOUND; |
| 705 | break; | ||
| 706 | case -ETIME: | 737 | case -ETIME: |
| 707 | return AE_TIME; | 738 | return AE_TIME; |
| 708 | break; | ||
| 709 | default: | 739 | default: |
| 710 | return AE_OK; | 740 | return AE_OK; |
| 711 | } | 741 | } |
| 712 | } | 742 | } |
| 713 | 743 | ||
| 714 | /* -------------------------------------------------------------------------- | 744 | /* -------------------------------------------------------------------------- |
| 715 | Driver Interface | 745 | * Driver Interface |
| 716 | -------------------------------------------------------------------------- */ | 746 | * -------------------------------------------------------------------------- */ |
| 747 | |||
| 717 | static acpi_status | 748 | static acpi_status |
| 718 | ec_parse_io_ports(struct acpi_resource *resource, void *context); | 749 | ec_parse_io_ports(struct acpi_resource *resource, void *context); |
| 719 | 750 | ||
| 720 | static struct acpi_ec *make_acpi_ec(void) | 751 | static struct acpi_ec *make_acpi_ec(void) |
| 721 | { | 752 | { |
| 722 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); | 753 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); |
| 754 | |||
| 723 | if (!ec) | 755 | if (!ec) |
| 724 | return NULL; | 756 | return NULL; |
| 725 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; | 757 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; |
| @@ -742,9 +774,8 @@ acpi_ec_register_query_methods(acpi_handle handle, u32 level, | |||
| 742 | 774 | ||
| 743 | status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); | 775 | status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); |
| 744 | 776 | ||
| 745 | if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1) { | 777 | if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1) |
| 746 | acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); | 778 | acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); |
| 747 | } | ||
| 748 | return AE_OK; | 779 | return AE_OK; |
| 749 | } | 780 | } |
| 750 | 781 | ||
| @@ -753,7 +784,6 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | |||
| 753 | { | 784 | { |
| 754 | acpi_status status; | 785 | acpi_status status; |
| 755 | unsigned long long tmp = 0; | 786 | unsigned long long tmp = 0; |
| 756 | |||
| 757 | struct acpi_ec *ec = context; | 787 | struct acpi_ec *ec = context; |
| 758 | 788 | ||
| 759 | /* clear addr values, ec_parse_io_ports depend on it */ | 789 | /* clear addr values, ec_parse_io_ports depend on it */ |
| @@ -781,6 +811,7 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | |||
| 781 | static int ec_install_handlers(struct acpi_ec *ec) | 811 | static int ec_install_handlers(struct acpi_ec *ec) |
| 782 | { | 812 | { |
| 783 | acpi_status status; | 813 | acpi_status status; |
| 814 | |||
| 784 | if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) | 815 | if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) |
| 785 | return 0; | 816 | return 0; |
| 786 | status = acpi_install_gpe_handler(NULL, ec->gpe, | 817 | status = acpi_install_gpe_handler(NULL, ec->gpe, |
| @@ -1078,7 +1109,8 @@ int __init acpi_ec_ecdt_probe(void) | |||
| 1078 | boot_ec->data_addr = ecdt_ptr->data.address; | 1109 | boot_ec->data_addr = ecdt_ptr->data.address; |
| 1079 | boot_ec->gpe = ecdt_ptr->gpe; | 1110 | boot_ec->gpe = ecdt_ptr->gpe; |
| 1080 | boot_ec->handle = ACPI_ROOT_OBJECT; | 1111 | boot_ec->handle = ACPI_ROOT_OBJECT; |
| 1081 | acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); | 1112 | acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, |
| 1113 | &boot_ec->handle); | ||
| 1082 | /* Don't trust ECDT, which comes from ASUSTek */ | 1114 | /* Don't trust ECDT, which comes from ASUSTek */ |
| 1083 | if (!EC_FLAGS_VALIDATE_ECDT) | 1115 | if (!EC_FLAGS_VALIDATE_ECDT) |
| 1084 | goto install; | 1116 | goto install; |
| @@ -1162,6 +1194,5 @@ static void __exit acpi_ec_exit(void) | |||
| 1162 | { | 1194 | { |
| 1163 | 1195 | ||
| 1164 | acpi_bus_unregister_driver(&acpi_ec_driver); | 1196 | acpi_bus_unregister_driver(&acpi_ec_driver); |
| 1165 | return; | ||
| 1166 | } | 1197 | } |
| 1167 | #endif /* 0 */ | 1198 | #endif /* 0 */ |
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 5328b1090e08..caf9b76b7ef8 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c | |||
| @@ -30,22 +30,19 @@ | |||
| 30 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
| 31 | #include <linux/thermal.h> | 31 | #include <linux/thermal.h> |
| 32 | #include <linux/acpi.h> | 32 | #include <linux/acpi.h> |
| 33 | 33 | #include <linux/platform_device.h> | |
| 34 | #define ACPI_FAN_CLASS "fan" | 34 | #include <linux/sort.h> |
| 35 | #define ACPI_FAN_FILE_STATE "state" | ||
| 36 | |||
| 37 | #define _COMPONENT ACPI_FAN_COMPONENT | ||
| 38 | ACPI_MODULE_NAME("fan"); | ||
| 39 | 35 | ||
| 40 | MODULE_AUTHOR("Paul Diefenbaugh"); | 36 | MODULE_AUTHOR("Paul Diefenbaugh"); |
| 41 | MODULE_DESCRIPTION("ACPI Fan Driver"); | 37 | MODULE_DESCRIPTION("ACPI Fan Driver"); |
| 42 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
| 43 | 39 | ||
| 44 | static int acpi_fan_add(struct acpi_device *device); | 40 | static int acpi_fan_probe(struct platform_device *pdev); |
| 45 | static int acpi_fan_remove(struct acpi_device *device); | 41 | static int acpi_fan_remove(struct platform_device *pdev); |
| 46 | 42 | ||
| 47 | static const struct acpi_device_id fan_device_ids[] = { | 43 | static const struct acpi_device_id fan_device_ids[] = { |
| 48 | {"PNP0C0B", 0}, | 44 | {"PNP0C0B", 0}, |
| 45 | {"INT3404", 0}, | ||
| 49 | {"", 0}, | 46 | {"", 0}, |
| 50 | }; | 47 | }; |
| 51 | MODULE_DEVICE_TABLE(acpi, fan_device_ids); | 48 | MODULE_DEVICE_TABLE(acpi, fan_device_ids); |
| @@ -64,37 +61,100 @@ static struct dev_pm_ops acpi_fan_pm = { | |||
| 64 | #define FAN_PM_OPS_PTR NULL | 61 | #define FAN_PM_OPS_PTR NULL |
| 65 | #endif | 62 | #endif |
| 66 | 63 | ||
| 67 | static struct acpi_driver acpi_fan_driver = { | 64 | struct acpi_fan_fps { |
| 68 | .name = "fan", | 65 | u64 control; |
| 69 | .class = ACPI_FAN_CLASS, | 66 | u64 trip_point; |
| 70 | .ids = fan_device_ids, | 67 | u64 speed; |
| 71 | .ops = { | 68 | u64 noise_level; |
| 72 | .add = acpi_fan_add, | 69 | u64 power; |
| 73 | .remove = acpi_fan_remove, | 70 | }; |
| 74 | }, | 71 | |
| 75 | .drv.pm = FAN_PM_OPS_PTR, | 72 | struct acpi_fan_fif { |
| 73 | u64 revision; | ||
| 74 | u64 fine_grain_ctrl; | ||
| 75 | u64 step_size; | ||
| 76 | u64 low_speed_notification; | ||
| 77 | }; | ||
| 78 | |||
| 79 | struct acpi_fan { | ||
| 80 | bool acpi4; | ||
| 81 | struct acpi_fan_fif fif; | ||
| 82 | struct acpi_fan_fps *fps; | ||
| 83 | int fps_count; | ||
| 84 | struct thermal_cooling_device *cdev; | ||
| 85 | }; | ||
| 86 | |||
| 87 | static struct platform_driver acpi_fan_driver = { | ||
| 88 | .probe = acpi_fan_probe, | ||
| 89 | .remove = acpi_fan_remove, | ||
| 90 | .driver = { | ||
| 91 | .name = "acpi-fan", | ||
| 92 | .acpi_match_table = fan_device_ids, | ||
| 93 | .pm = FAN_PM_OPS_PTR, | ||
| 94 | }, | ||
| 76 | }; | 95 | }; |
| 77 | 96 | ||
| 78 | /* thermal cooling device callbacks */ | 97 | /* thermal cooling device callbacks */ |
| 79 | static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long | 98 | static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long |
| 80 | *state) | 99 | *state) |
| 81 | { | 100 | { |
| 82 | /* ACPI fan device only support two states: ON/OFF */ | 101 | struct acpi_device *device = cdev->devdata; |
| 83 | *state = 1; | 102 | struct acpi_fan *fan = acpi_driver_data(device); |
| 103 | |||
| 104 | if (fan->acpi4) | ||
| 105 | *state = fan->fps_count - 1; | ||
| 106 | else | ||
| 107 | *state = 1; | ||
| 84 | return 0; | 108 | return 0; |
| 85 | } | 109 | } |
| 86 | 110 | ||
| 87 | static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long | 111 | static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state) |
| 88 | *state) | 112 | { |
| 113 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 114 | struct acpi_fan *fan = acpi_driver_data(device); | ||
| 115 | union acpi_object *obj; | ||
| 116 | acpi_status status; | ||
| 117 | int control, i; | ||
| 118 | |||
| 119 | status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer); | ||
| 120 | if (ACPI_FAILURE(status)) { | ||
| 121 | dev_err(&device->dev, "Get fan state failed\n"); | ||
| 122 | return status; | ||
| 123 | } | ||
| 124 | |||
| 125 | obj = buffer.pointer; | ||
| 126 | if (!obj || obj->type != ACPI_TYPE_PACKAGE || | ||
| 127 | obj->package.count != 3 || | ||
| 128 | obj->package.elements[1].type != ACPI_TYPE_INTEGER) { | ||
| 129 | dev_err(&device->dev, "Invalid _FST data\n"); | ||
| 130 | status = -EINVAL; | ||
| 131 | goto err; | ||
| 132 | } | ||
| 133 | |||
| 134 | control = obj->package.elements[1].integer.value; | ||
| 135 | for (i = 0; i < fan->fps_count; i++) { | ||
| 136 | if (control == fan->fps[i].control) | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | if (i == fan->fps_count) { | ||
| 140 | dev_dbg(&device->dev, "Invalid control value returned\n"); | ||
| 141 | status = -EINVAL; | ||
| 142 | goto err; | ||
| 143 | } | ||
| 144 | |||
| 145 | *state = i; | ||
| 146 | |||
| 147 | err: | ||
| 148 | kfree(obj); | ||
| 149 | return status; | ||
| 150 | } | ||
| 151 | |||
| 152 | static int fan_get_state(struct acpi_device *device, unsigned long *state) | ||
| 89 | { | 153 | { |
| 90 | struct acpi_device *device = cdev->devdata; | ||
| 91 | int result; | 154 | int result; |
| 92 | int acpi_state = ACPI_STATE_D0; | 155 | int acpi_state = ACPI_STATE_D0; |
| 93 | 156 | ||
| 94 | if (!device) | 157 | result = acpi_device_update_power(device, &acpi_state); |
| 95 | return -EINVAL; | ||
| 96 | |||
| 97 | result = acpi_bus_update_power(device->handle, &acpi_state); | ||
| 98 | if (result) | 158 | if (result) |
| 99 | return result; | 159 | return result; |
| 100 | 160 | ||
| @@ -103,21 +163,57 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long | |||
| 103 | return 0; | 163 | return 0; |
| 104 | } | 164 | } |
| 105 | 165 | ||
| 106 | static int | 166 | static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long |
| 107 | fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) | 167 | *state) |
| 108 | { | 168 | { |
| 109 | struct acpi_device *device = cdev->devdata; | 169 | struct acpi_device *device = cdev->devdata; |
| 110 | int result; | 170 | struct acpi_fan *fan = acpi_driver_data(device); |
| 111 | 171 | ||
| 112 | if (!device || (state != 0 && state != 1)) | 172 | if (fan->acpi4) |
| 173 | return fan_get_state_acpi4(device, state); | ||
| 174 | else | ||
| 175 | return fan_get_state(device, state); | ||
| 176 | } | ||
| 177 | |||
| 178 | static int fan_set_state(struct acpi_device *device, unsigned long state) | ||
| 179 | { | ||
| 180 | if (state != 0 && state != 1) | ||
| 113 | return -EINVAL; | 181 | return -EINVAL; |
| 114 | 182 | ||
| 115 | result = acpi_bus_set_power(device->handle, | 183 | return acpi_device_set_power(device, |
| 116 | state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD); | 184 | state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD); |
| 185 | } | ||
| 117 | 186 | ||
| 118 | return result; | 187 | static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state) |
| 188 | { | ||
| 189 | struct acpi_fan *fan = acpi_driver_data(device); | ||
| 190 | acpi_status status; | ||
| 191 | |||
| 192 | if (state >= fan->fps_count) | ||
| 193 | return -EINVAL; | ||
| 194 | |||
| 195 | status = acpi_execute_simple_method(device->handle, "_FSL", | ||
| 196 | fan->fps[state].control); | ||
| 197 | if (ACPI_FAILURE(status)) { | ||
| 198 | dev_dbg(&device->dev, "Failed to set state by _FSL\n"); | ||
| 199 | return status; | ||
| 200 | } | ||
| 201 | |||
| 202 | return 0; | ||
| 119 | } | 203 | } |
| 120 | 204 | ||
| 205 | static int | ||
| 206 | fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) | ||
| 207 | { | ||
| 208 | struct acpi_device *device = cdev->devdata; | ||
| 209 | struct acpi_fan *fan = acpi_driver_data(device); | ||
| 210 | |||
| 211 | if (fan->acpi4) | ||
| 212 | return fan_set_state_acpi4(device, state); | ||
| 213 | else | ||
| 214 | return fan_set_state(device, state); | ||
| 215 | } | ||
| 216 | |||
| 121 | static const struct thermal_cooling_device_ops fan_cooling_ops = { | 217 | static const struct thermal_cooling_device_ops fan_cooling_ops = { |
| 122 | .get_max_state = fan_get_max_state, | 218 | .get_max_state = fan_get_max_state, |
| 123 | .get_cur_state = fan_get_cur_state, | 219 | .get_cur_state = fan_get_cur_state, |
| @@ -129,21 +225,125 @@ static const struct thermal_cooling_device_ops fan_cooling_ops = { | |||
| 129 | * -------------------------------------------------------------------------- | 225 | * -------------------------------------------------------------------------- |
| 130 | */ | 226 | */ |
| 131 | 227 | ||
| 132 | static int acpi_fan_add(struct acpi_device *device) | 228 | static bool acpi_fan_is_acpi4(struct acpi_device *device) |
| 133 | { | 229 | { |
| 134 | int result = 0; | 230 | return acpi_has_method(device->handle, "_FIF") && |
| 135 | struct thermal_cooling_device *cdev; | 231 | acpi_has_method(device->handle, "_FPS") && |
| 232 | acpi_has_method(device->handle, "_FSL") && | ||
| 233 | acpi_has_method(device->handle, "_FST"); | ||
| 234 | } | ||
| 136 | 235 | ||
| 137 | if (!device) | 236 | static int acpi_fan_get_fif(struct acpi_device *device) |
| 138 | return -EINVAL; | 237 | { |
| 238 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 239 | struct acpi_fan *fan = acpi_driver_data(device); | ||
| 240 | struct acpi_buffer format = { sizeof("NNNN"), "NNNN" }; | ||
| 241 | struct acpi_buffer fif = { sizeof(fan->fif), &fan->fif }; | ||
| 242 | union acpi_object *obj; | ||
| 243 | acpi_status status; | ||
| 244 | |||
| 245 | status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer); | ||
| 246 | if (ACPI_FAILURE(status)) | ||
| 247 | return status; | ||
| 248 | |||
| 249 | obj = buffer.pointer; | ||
| 250 | if (!obj || obj->type != ACPI_TYPE_PACKAGE) { | ||
| 251 | dev_err(&device->dev, "Invalid _FIF data\n"); | ||
| 252 | status = -EINVAL; | ||
| 253 | goto err; | ||
| 254 | } | ||
| 139 | 255 | ||
| 140 | strcpy(acpi_device_name(device), "Fan"); | 256 | status = acpi_extract_package(obj, &format, &fif); |
| 141 | strcpy(acpi_device_class(device), ACPI_FAN_CLASS); | 257 | if (ACPI_FAILURE(status)) { |
| 258 | dev_err(&device->dev, "Invalid _FIF element\n"); | ||
| 259 | status = -EINVAL; | ||
| 260 | } | ||
| 142 | 261 | ||
| 143 | result = acpi_bus_update_power(device->handle, NULL); | 262 | err: |
| 144 | if (result) { | 263 | kfree(obj); |
| 145 | dev_err(&device->dev, "Setting initial power state\n"); | 264 | return status; |
| 146 | goto end; | 265 | } |
| 266 | |||
| 267 | static int acpi_fan_speed_cmp(const void *a, const void *b) | ||
| 268 | { | ||
| 269 | const struct acpi_fan_fps *fps1 = a; | ||
| 270 | const struct acpi_fan_fps *fps2 = b; | ||
| 271 | return fps1->speed - fps2->speed; | ||
| 272 | } | ||
| 273 | |||
| 274 | static int acpi_fan_get_fps(struct acpi_device *device) | ||
| 275 | { | ||
| 276 | struct acpi_fan *fan = acpi_driver_data(device); | ||
| 277 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 278 | union acpi_object *obj; | ||
| 279 | acpi_status status; | ||
| 280 | int i; | ||
| 281 | |||
| 282 | status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer); | ||
| 283 | if (ACPI_FAILURE(status)) | ||
| 284 | return status; | ||
| 285 | |||
| 286 | obj = buffer.pointer; | ||
| 287 | if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) { | ||
| 288 | dev_err(&device->dev, "Invalid _FPS data\n"); | ||
| 289 | status = -EINVAL; | ||
| 290 | goto err; | ||
| 291 | } | ||
| 292 | |||
| 293 | fan->fps_count = obj->package.count - 1; /* minus revision field */ | ||
| 294 | fan->fps = devm_kzalloc(&device->dev, | ||
| 295 | fan->fps_count * sizeof(struct acpi_fan_fps), | ||
| 296 | GFP_KERNEL); | ||
| 297 | if (!fan->fps) { | ||
| 298 | dev_err(&device->dev, "Not enough memory\n"); | ||
| 299 | status = -ENOMEM; | ||
| 300 | goto err; | ||
| 301 | } | ||
| 302 | for (i = 0; i < fan->fps_count; i++) { | ||
| 303 | struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" }; | ||
| 304 | struct acpi_buffer fps = { sizeof(fan->fps[i]), &fan->fps[i] }; | ||
| 305 | status = acpi_extract_package(&obj->package.elements[i + 1], | ||
| 306 | &format, &fps); | ||
| 307 | if (ACPI_FAILURE(status)) { | ||
| 308 | dev_err(&device->dev, "Invalid _FPS element\n"); | ||
| 309 | break; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | /* sort the state array according to fan speed in increase order */ | ||
| 314 | sort(fan->fps, fan->fps_count, sizeof(*fan->fps), | ||
| 315 | acpi_fan_speed_cmp, NULL); | ||
| 316 | |||
| 317 | err: | ||
| 318 | kfree(obj); | ||
| 319 | return status; | ||
| 320 | } | ||
| 321 | |||
| 322 | static int acpi_fan_probe(struct platform_device *pdev) | ||
| 323 | { | ||
| 324 | int result = 0; | ||
| 325 | struct thermal_cooling_device *cdev; | ||
| 326 | struct acpi_fan *fan; | ||
| 327 | struct acpi_device *device = ACPI_COMPANION(&pdev->dev); | ||
| 328 | |||
| 329 | fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); | ||
| 330 | if (!fan) { | ||
| 331 | dev_err(&device->dev, "No memory for fan\n"); | ||
| 332 | return -ENOMEM; | ||
| 333 | } | ||
| 334 | device->driver_data = fan; | ||
| 335 | platform_set_drvdata(pdev, fan); | ||
| 336 | |||
| 337 | if (acpi_fan_is_acpi4(device)) { | ||
| 338 | if (acpi_fan_get_fif(device) || acpi_fan_get_fps(device)) | ||
| 339 | goto end; | ||
| 340 | fan->acpi4 = true; | ||
| 341 | } else { | ||
| 342 | result = acpi_device_update_power(device, NULL); | ||
| 343 | if (result) { | ||
| 344 | dev_err(&device->dev, "Setting initial power state\n"); | ||
| 345 | goto end; | ||
| 346 | } | ||
| 147 | } | 347 | } |
| 148 | 348 | ||
| 149 | cdev = thermal_cooling_device_register("Fan", device, | 349 | cdev = thermal_cooling_device_register("Fan", device, |
| @@ -153,44 +353,32 @@ static int acpi_fan_add(struct acpi_device *device) | |||
| 153 | goto end; | 353 | goto end; |
| 154 | } | 354 | } |
| 155 | 355 | ||
| 156 | dev_dbg(&device->dev, "registered as cooling_device%d\n", cdev->id); | 356 | dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id); |
| 157 | 357 | ||
| 158 | device->driver_data = cdev; | 358 | fan->cdev = cdev; |
| 159 | result = sysfs_create_link(&device->dev.kobj, | 359 | result = sysfs_create_link(&pdev->dev.kobj, |
| 160 | &cdev->device.kobj, | 360 | &cdev->device.kobj, |
| 161 | "thermal_cooling"); | 361 | "thermal_cooling"); |
| 162 | if (result) | 362 | if (result) |
| 163 | dev_err(&device->dev, "Failed to create sysfs link " | 363 | dev_err(&pdev->dev, "Failed to create sysfs link 'thermal_cooling'\n"); |
| 164 | "'thermal_cooling'\n"); | ||
| 165 | 364 | ||
| 166 | result = sysfs_create_link(&cdev->device.kobj, | 365 | result = sysfs_create_link(&cdev->device.kobj, |
| 167 | &device->dev.kobj, | 366 | &pdev->dev.kobj, |
| 168 | "device"); | 367 | "device"); |
| 169 | if (result) | 368 | if (result) |
| 170 | dev_err(&device->dev, "Failed to create sysfs link 'device'\n"); | 369 | dev_err(&pdev->dev, "Failed to create sysfs link 'device'\n"); |
| 171 | |||
| 172 | dev_info(&device->dev, "ACPI: %s [%s] (%s)\n", | ||
| 173 | acpi_device_name(device), acpi_device_bid(device), | ||
| 174 | !device->power.state ? "on" : "off"); | ||
| 175 | 370 | ||
| 176 | end: | 371 | end: |
| 177 | return result; | 372 | return result; |
| 178 | } | 373 | } |
| 179 | 374 | ||
| 180 | static int acpi_fan_remove(struct acpi_device *device) | 375 | static int acpi_fan_remove(struct platform_device *pdev) |
| 181 | { | 376 | { |
| 182 | struct thermal_cooling_device *cdev; | 377 | struct acpi_fan *fan = platform_get_drvdata(pdev); |
| 183 | |||
| 184 | if (!device) | ||
| 185 | return -EINVAL; | ||
| 186 | |||
| 187 | cdev = acpi_driver_data(device); | ||
| 188 | if (!cdev) | ||
| 189 | return -EINVAL; | ||
| 190 | 378 | ||
| 191 | sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); | 379 | sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling"); |
| 192 | sysfs_remove_link(&cdev->device.kobj, "device"); | 380 | sysfs_remove_link(&fan->cdev->device.kobj, "device"); |
| 193 | thermal_cooling_device_unregister(cdev); | 381 | thermal_cooling_device_unregister(fan->cdev); |
| 194 | 382 | ||
| 195 | return 0; | 383 | return 0; |
| 196 | } | 384 | } |
| @@ -198,10 +386,11 @@ static int acpi_fan_remove(struct acpi_device *device) | |||
| 198 | #ifdef CONFIG_PM_SLEEP | 386 | #ifdef CONFIG_PM_SLEEP |
| 199 | static int acpi_fan_suspend(struct device *dev) | 387 | static int acpi_fan_suspend(struct device *dev) |
| 200 | { | 388 | { |
| 201 | if (!dev) | 389 | struct acpi_fan *fan = dev_get_drvdata(dev); |
| 202 | return -EINVAL; | 390 | if (fan->acpi4) |
| 391 | return 0; | ||
| 203 | 392 | ||
| 204 | acpi_bus_set_power(to_acpi_device(dev)->handle, ACPI_STATE_D0); | 393 | acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D0); |
| 205 | 394 | ||
| 206 | return AE_OK; | 395 | return AE_OK; |
| 207 | } | 396 | } |
| @@ -209,11 +398,12 @@ static int acpi_fan_suspend(struct device *dev) | |||
| 209 | static int acpi_fan_resume(struct device *dev) | 398 | static int acpi_fan_resume(struct device *dev) |
| 210 | { | 399 | { |
| 211 | int result; | 400 | int result; |
| 401 | struct acpi_fan *fan = dev_get_drvdata(dev); | ||
| 212 | 402 | ||
| 213 | if (!dev) | 403 | if (fan->acpi4) |
| 214 | return -EINVAL; | 404 | return 0; |
| 215 | 405 | ||
| 216 | result = acpi_bus_update_power(to_acpi_device(dev)->handle, NULL); | 406 | result = acpi_device_update_power(ACPI_COMPANION(dev), NULL); |
| 217 | if (result) | 407 | if (result) |
| 218 | dev_err(dev, "Error updating fan power state\n"); | 408 | dev_err(dev, "Error updating fan power state\n"); |
| 219 | 409 | ||
| @@ -221,4 +411,4 @@ static int acpi_fan_resume(struct device *dev) | |||
| 221 | } | 411 | } |
| 222 | #endif | 412 | #endif |
| 223 | 413 | ||
| 224 | module_acpi_driver(acpi_fan_driver); | 414 | module_platform_driver(acpi_fan_driver); |
diff --git a/drivers/acpi/int340x_thermal.c b/drivers/acpi/int340x_thermal.c new file mode 100644 index 000000000000..a27d31d1ba24 --- /dev/null +++ b/drivers/acpi/int340x_thermal.c | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | /* | ||
| 2 | * ACPI support for int340x thermal drivers | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014, Intel Corporation | ||
| 5 | * Authors: Zhang Rui <rui.zhang@intel.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/acpi.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | |||
| 15 | #include "internal.h" | ||
| 16 | |||
| 17 | #define DO_ENUMERATION 0x01 | ||
| 18 | static const struct acpi_device_id int340x_thermal_device_ids[] = { | ||
| 19 | {"INT3400", DO_ENUMERATION }, | ||
| 20 | {"INT3401"}, | ||
| 21 | {"INT3402"}, | ||
| 22 | {"INT3403"}, | ||
| 23 | {"INT3404"}, | ||
| 24 | {"INT3406"}, | ||
| 25 | {"INT3407"}, | ||
| 26 | {"INT3408"}, | ||
| 27 | {"INT3409"}, | ||
| 28 | {"INT340A"}, | ||
| 29 | {"INT340B"}, | ||
| 30 | {""}, | ||
| 31 | }; | ||
| 32 | |||
| 33 | static int int340x_thermal_handler_attach(struct acpi_device *adev, | ||
| 34 | const struct acpi_device_id *id) | ||
| 35 | { | ||
| 36 | #if defined(CONFIG_INT340X_THERMAL) || defined(CONFIG_INT340X_THERMAL_MODULE) | ||
| 37 | if (id->driver_data == DO_ENUMERATION) | ||
| 38 | acpi_create_platform_device(adev); | ||
| 39 | #endif | ||
| 40 | return 1; | ||
| 41 | } | ||
| 42 | |||
| 43 | static struct acpi_scan_handler int340x_thermal_handler = { | ||
| 44 | .ids = int340x_thermal_device_ids, | ||
| 45 | .attach = int340x_thermal_handler_attach, | ||
| 46 | }; | ||
| 47 | |||
| 48 | void __init acpi_int340x_thermal_init(void) | ||
| 49 | { | ||
| 50 | acpi_scan_add_handler(&int340x_thermal_handler); | ||
| 51 | } | ||
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4c5cf77e7576..447f6d679b29 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
| @@ -31,6 +31,7 @@ void acpi_pci_link_init(void); | |||
| 31 | void acpi_processor_init(void); | 31 | void acpi_processor_init(void); |
| 32 | void acpi_platform_init(void); | 32 | void acpi_platform_init(void); |
| 33 | void acpi_pnp_init(void); | 33 | void acpi_pnp_init(void); |
| 34 | void acpi_int340x_thermal_init(void); | ||
| 34 | int acpi_sysfs_init(void); | 35 | int acpi_sysfs_init(void); |
| 35 | void acpi_container_init(void); | 36 | void acpi_container_init(void); |
| 36 | void acpi_memory_hotplug_init(void); | 37 | void acpi_memory_hotplug_init(void); |
| @@ -103,8 +104,6 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state); | |||
| 103 | int acpi_power_on_resources(struct acpi_device *device, int state); | 104 | int acpi_power_on_resources(struct acpi_device *device, int state); |
| 104 | int acpi_power_transition(struct acpi_device *device, int state); | 105 | int acpi_power_transition(struct acpi_device *device, int state); |
| 105 | 106 | ||
| 106 | int acpi_device_update_power(struct acpi_device *device, int *state_p); | ||
| 107 | |||
| 108 | int acpi_wakeup_device_init(void); | 107 | int acpi_wakeup_device_init(void); |
| 109 | 108 | ||
| 110 | #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC | 109 | #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC |
| @@ -168,13 +167,6 @@ static inline void suspend_nvs_restore(void) {} | |||
| 168 | #endif | 167 | #endif |
| 169 | 168 | ||
| 170 | /*-------------------------------------------------------------------------- | 169 | /*-------------------------------------------------------------------------- |
| 171 | Platform bus support | ||
| 172 | -------------------------------------------------------------------------- */ | ||
| 173 | struct platform_device; | ||
| 174 | |||
| 175 | struct platform_device *acpi_create_platform_device(struct acpi_device *adev); | ||
| 176 | |||
| 177 | /*-------------------------------------------------------------------------- | ||
| 178 | Video | 170 | Video |
| 179 | -------------------------------------------------------------------------- */ | 171 | -------------------------------------------------------------------------- */ |
| 180 | #if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) | 172 | #if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ae44d8654c82..d670158a26c5 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
| @@ -1470,7 +1470,7 @@ static void acpi_wakeup_gpe_init(struct acpi_device *device) | |||
| 1470 | if (ACPI_FAILURE(status)) | 1470 | if (ACPI_FAILURE(status)) |
| 1471 | return; | 1471 | return; |
| 1472 | 1472 | ||
| 1473 | wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HANDLE); | 1473 | wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HAS_HANDLER); |
| 1474 | } | 1474 | } |
| 1475 | 1475 | ||
| 1476 | static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | 1476 | static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) |
| @@ -2315,6 +2315,7 @@ int __init acpi_scan_init(void) | |||
| 2315 | acpi_container_init(); | 2315 | acpi_container_init(); |
| 2316 | acpi_memory_hotplug_init(); | 2316 | acpi_memory_hotplug_init(); |
| 2317 | acpi_pnp_init(); | 2317 | acpi_pnp_init(); |
| 2318 | acpi_int340x_thermal_init(); | ||
| 2318 | 2319 | ||
| 2319 | mutex_lock(&acpi_scan_lock); | 2320 | mutex_lock(&acpi_scan_lock); |
| 2320 | /* | 2321 | /* |
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 38cb9782d4b8..13e577c80201 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c | |||
| @@ -537,7 +537,7 @@ static ssize_t counter_show(struct kobject *kobj, | |||
| 537 | if (result) | 537 | if (result) |
| 538 | goto end; | 538 | goto end; |
| 539 | 539 | ||
| 540 | if (!(status & ACPI_EVENT_FLAG_HANDLE)) | 540 | if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) |
| 541 | size += sprintf(buf + size, " invalid"); | 541 | size += sprintf(buf + size, " invalid"); |
| 542 | else if (status & ACPI_EVENT_FLAG_ENABLED) | 542 | else if (status & ACPI_EVENT_FLAG_ENABLED) |
| 543 | size += sprintf(buf + size, " enabled"); | 543 | size += sprintf(buf + size, " enabled"); |
| @@ -581,7 +581,7 @@ static ssize_t counter_set(struct kobject *kobj, | |||
| 581 | if (result) | 581 | if (result) |
| 582 | goto end; | 582 | goto end; |
| 583 | 583 | ||
| 584 | if (!(status & ACPI_EVENT_FLAG_HANDLE)) { | 584 | if (!(status & ACPI_EVENT_FLAG_HAS_HANDLER)) { |
| 585 | printk(KERN_WARNING PREFIX | 585 | printk(KERN_WARNING PREFIX |
| 586 | "Can not change Invalid GPE/Fixed Event status\n"); | 586 | "Can not change Invalid GPE/Fixed Event status\n"); |
| 587 | return -EINVAL; | 587 | return -EINVAL; |
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 112817e963e0..d24fa1964eb8 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c | |||
| @@ -528,7 +528,6 @@ static void acpi_thermal_check(void *data) | |||
| 528 | } | 528 | } |
| 529 | 529 | ||
| 530 | /* sys I/F for generic thermal sysfs support */ | 530 | /* sys I/F for generic thermal sysfs support */ |
| 531 | #define KELVIN_TO_MILLICELSIUS(t, off) (((t) - (off)) * 100) | ||
| 532 | 531 | ||
| 533 | static int thermal_get_temp(struct thermal_zone_device *thermal, | 532 | static int thermal_get_temp(struct thermal_zone_device *thermal, |
| 534 | unsigned long *temp) | 533 | unsigned long *temp) |
| @@ -543,7 +542,8 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, | |||
| 543 | if (result) | 542 | if (result) |
| 544 | return result; | 543 | return result; |
| 545 | 544 | ||
| 546 | *temp = KELVIN_TO_MILLICELSIUS(tz->temperature, tz->kelvin_offset); | 545 | *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(tz->temperature, |
| 546 | tz->kelvin_offset); | ||
| 547 | return 0; | 547 | return 0; |
| 548 | } | 548 | } |
| 549 | 549 | ||
| @@ -647,7 +647,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, | |||
| 647 | 647 | ||
| 648 | if (tz->trips.critical.flags.valid) { | 648 | if (tz->trips.critical.flags.valid) { |
| 649 | if (!trip) { | 649 | if (!trip) { |
| 650 | *temp = KELVIN_TO_MILLICELSIUS( | 650 | *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET( |
| 651 | tz->trips.critical.temperature, | 651 | tz->trips.critical.temperature, |
| 652 | tz->kelvin_offset); | 652 | tz->kelvin_offset); |
| 653 | return 0; | 653 | return 0; |
| @@ -657,7 +657,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, | |||
| 657 | 657 | ||
| 658 | if (tz->trips.hot.flags.valid) { | 658 | if (tz->trips.hot.flags.valid) { |
| 659 | if (!trip) { | 659 | if (!trip) { |
| 660 | *temp = KELVIN_TO_MILLICELSIUS( | 660 | *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET( |
| 661 | tz->trips.hot.temperature, | 661 | tz->trips.hot.temperature, |
| 662 | tz->kelvin_offset); | 662 | tz->kelvin_offset); |
| 663 | return 0; | 663 | return 0; |
| @@ -667,7 +667,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, | |||
| 667 | 667 | ||
| 668 | if (tz->trips.passive.flags.valid) { | 668 | if (tz->trips.passive.flags.valid) { |
| 669 | if (!trip) { | 669 | if (!trip) { |
| 670 | *temp = KELVIN_TO_MILLICELSIUS( | 670 | *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET( |
| 671 | tz->trips.passive.temperature, | 671 | tz->trips.passive.temperature, |
| 672 | tz->kelvin_offset); | 672 | tz->kelvin_offset); |
| 673 | return 0; | 673 | return 0; |
| @@ -678,7 +678,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, | |||
| 678 | for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && | 678 | for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && |
| 679 | tz->trips.active[i].flags.valid; i++) { | 679 | tz->trips.active[i].flags.valid; i++) { |
| 680 | if (!trip) { | 680 | if (!trip) { |
| 681 | *temp = KELVIN_TO_MILLICELSIUS( | 681 | *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET( |
| 682 | tz->trips.active[i].temperature, | 682 | tz->trips.active[i].temperature, |
| 683 | tz->kelvin_offset); | 683 | tz->kelvin_offset); |
| 684 | return 0; | 684 | return 0; |
| @@ -694,7 +694,7 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal, | |||
| 694 | struct acpi_thermal *tz = thermal->devdata; | 694 | struct acpi_thermal *tz = thermal->devdata; |
| 695 | 695 | ||
| 696 | if (tz->trips.critical.flags.valid) { | 696 | if (tz->trips.critical.flags.valid) { |
| 697 | *temperature = KELVIN_TO_MILLICELSIUS( | 697 | *temperature = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET( |
| 698 | tz->trips.critical.temperature, | 698 | tz->trips.critical.temperature, |
| 699 | tz->kelvin_offset); | 699 | tz->kelvin_offset); |
| 700 | return 0; | 700 | return 0; |
| @@ -714,8 +714,8 @@ static int thermal_get_trend(struct thermal_zone_device *thermal, | |||
| 714 | 714 | ||
| 715 | if (type == THERMAL_TRIP_ACTIVE) { | 715 | if (type == THERMAL_TRIP_ACTIVE) { |
| 716 | unsigned long trip_temp; | 716 | unsigned long trip_temp; |
| 717 | unsigned long temp = KELVIN_TO_MILLICELSIUS(tz->temperature, | 717 | unsigned long temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET( |
| 718 | tz->kelvin_offset); | 718 | tz->temperature, tz->kelvin_offset); |
| 719 | if (thermal_get_trip_temp(thermal, trip, &trip_temp)) | 719 | if (thermal_get_trip_temp(thermal, trip, &trip_temp)) |
| 720 | return -EINVAL; | 720 | return -EINVAL; |
| 721 | 721 | ||
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 834f35c4bf8d..371ac12d25b1 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c | |||
| @@ -149,6 +149,21 @@ acpi_extract_package(union acpi_object *package, | |||
| 149 | break; | 149 | break; |
| 150 | } | 150 | } |
| 151 | break; | 151 | break; |
| 152 | case ACPI_TYPE_LOCAL_REFERENCE: | ||
| 153 | switch (format_string[i]) { | ||
| 154 | case 'R': | ||
| 155 | size_required += sizeof(void *); | ||
| 156 | tail_offset += sizeof(void *); | ||
| 157 | break; | ||
| 158 | default: | ||
| 159 | printk(KERN_WARNING PREFIX "Invalid package element" | ||
| 160 | " [%d] got reference," | ||
| 161 | " expecting [%c]\n", | ||
| 162 | i, format_string[i]); | ||
| 163 | return AE_BAD_DATA; | ||
| 164 | break; | ||
| 165 | } | ||
| 166 | break; | ||
| 152 | 167 | ||
| 153 | case ACPI_TYPE_PACKAGE: | 168 | case ACPI_TYPE_PACKAGE: |
| 154 | default: | 169 | default: |
| @@ -247,7 +262,18 @@ acpi_extract_package(union acpi_object *package, | |||
| 247 | break; | 262 | break; |
| 248 | } | 263 | } |
| 249 | break; | 264 | break; |
| 250 | 265 | case ACPI_TYPE_LOCAL_REFERENCE: | |
| 266 | switch (format_string[i]) { | ||
| 267 | case 'R': | ||
| 268 | *(void **)head = | ||
| 269 | (void *)element->reference.handle; | ||
| 270 | head += sizeof(void *); | ||
| 271 | break; | ||
| 272 | default: | ||
| 273 | /* Should never get here */ | ||
| 274 | break; | ||
| 275 | } | ||
| 276 | break; | ||
| 251 | case ACPI_TYPE_PACKAGE: | 277 | case ACPI_TYPE_PACKAGE: |
| 252 | /* TBD: handle nested packages... */ | 278 | /* TBD: handle nested packages... */ |
| 253 | default: | 279 | default: |
diff --git a/drivers/char/random.c b/drivers/char/random.c index 82759cef9043..04645c09fe5e 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
| @@ -1106,7 +1106,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out) | |||
| 1106 | __mix_pool_bytes(r, hash.w, sizeof(hash.w)); | 1106 | __mix_pool_bytes(r, hash.w, sizeof(hash.w)); |
| 1107 | spin_unlock_irqrestore(&r->lock, flags); | 1107 | spin_unlock_irqrestore(&r->lock, flags); |
| 1108 | 1108 | ||
| 1109 | memset(workspace, 0, sizeof(workspace)); | 1109 | memzero_explicit(workspace, sizeof(workspace)); |
| 1110 | 1110 | ||
| 1111 | /* | 1111 | /* |
| 1112 | * In case the hash function has some recognizable output | 1112 | * In case the hash function has some recognizable output |
| @@ -1118,7 +1118,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out) | |||
| 1118 | hash.w[2] ^= rol32(hash.w[2], 16); | 1118 | hash.w[2] ^= rol32(hash.w[2], 16); |
| 1119 | 1119 | ||
| 1120 | memcpy(out, &hash, EXTRACT_SIZE); | 1120 | memcpy(out, &hash, EXTRACT_SIZE); |
| 1121 | memset(&hash, 0, sizeof(hash)); | 1121 | memzero_explicit(&hash, sizeof(hash)); |
| 1122 | } | 1122 | } |
| 1123 | 1123 | ||
| 1124 | /* | 1124 | /* |
| @@ -1175,7 +1175,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, | |||
| 1175 | } | 1175 | } |
| 1176 | 1176 | ||
| 1177 | /* Wipe data just returned from memory */ | 1177 | /* Wipe data just returned from memory */ |
| 1178 | memset(tmp, 0, sizeof(tmp)); | 1178 | memzero_explicit(tmp, sizeof(tmp)); |
| 1179 | 1179 | ||
| 1180 | return ret; | 1180 | return ret; |
| 1181 | } | 1181 | } |
| @@ -1218,7 +1218,7 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, | |||
| 1218 | } | 1218 | } |
| 1219 | 1219 | ||
| 1220 | /* Wipe data just returned from memory */ | 1220 | /* Wipe data just returned from memory */ |
| 1221 | memset(tmp, 0, sizeof(tmp)); | 1221 | memzero_explicit(tmp, sizeof(tmp)); |
| 1222 | 1222 | ||
| 1223 | return ret; | 1223 | return ret; |
| 1224 | } | 1224 | } |
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 6bbb8b913446..92c162af5045 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/cpu.h> | 18 | #include <linux/cpu.h> |
| 19 | #include <linux/cpu_cooling.h> | 19 | #include <linux/cpu_cooling.h> |
| 20 | #include <linux/cpufreq.h> | 20 | #include <linux/cpufreq.h> |
| 21 | #include <linux/cpufreq-dt.h> | ||
| 21 | #include <linux/cpumask.h> | 22 | #include <linux/cpumask.h> |
| 22 | #include <linux/err.h> | 23 | #include <linux/err.h> |
| 23 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| @@ -146,8 +147,8 @@ try_again: | |||
| 146 | goto try_again; | 147 | goto try_again; |
| 147 | } | 148 | } |
| 148 | 149 | ||
| 149 | dev_warn(cpu_dev, "failed to get cpu%d regulator: %ld\n", | 150 | dev_dbg(cpu_dev, "no regulator for cpu%d: %ld\n", |
| 150 | cpu, PTR_ERR(cpu_reg)); | 151 | cpu, PTR_ERR(cpu_reg)); |
| 151 | } | 152 | } |
| 152 | 153 | ||
| 153 | cpu_clk = clk_get(cpu_dev, NULL); | 154 | cpu_clk = clk_get(cpu_dev, NULL); |
| @@ -178,6 +179,7 @@ try_again: | |||
| 178 | 179 | ||
| 179 | static int cpufreq_init(struct cpufreq_policy *policy) | 180 | static int cpufreq_init(struct cpufreq_policy *policy) |
| 180 | { | 181 | { |
| 182 | struct cpufreq_dt_platform_data *pd; | ||
| 181 | struct cpufreq_frequency_table *freq_table; | 183 | struct cpufreq_frequency_table *freq_table; |
| 182 | struct thermal_cooling_device *cdev; | 184 | struct thermal_cooling_device *cdev; |
| 183 | struct device_node *np; | 185 | struct device_node *np; |
| @@ -265,9 +267,18 @@ static int cpufreq_init(struct cpufreq_policy *policy) | |||
| 265 | policy->driver_data = priv; | 267 | policy->driver_data = priv; |
| 266 | 268 | ||
| 267 | policy->clk = cpu_clk; | 269 | policy->clk = cpu_clk; |
| 268 | ret = cpufreq_generic_init(policy, freq_table, transition_latency); | 270 | ret = cpufreq_table_validate_and_show(policy, freq_table); |
| 269 | if (ret) | 271 | if (ret) { |
| 272 | dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, | ||
| 273 | ret); | ||
| 270 | goto out_cooling_unregister; | 274 | goto out_cooling_unregister; |
| 275 | } | ||
| 276 | |||
| 277 | policy->cpuinfo.transition_latency = transition_latency; | ||
| 278 | |||
| 279 | pd = cpufreq_get_driver_data(); | ||
| 280 | if (pd && !pd->independent_clocks) | ||
| 281 | cpumask_setall(policy->cpus); | ||
| 271 | 282 | ||
| 272 | of_node_put(np); | 283 | of_node_put(np); |
| 273 | 284 | ||
| @@ -335,6 +346,8 @@ static int dt_cpufreq_probe(struct platform_device *pdev) | |||
| 335 | if (!IS_ERR(cpu_reg)) | 346 | if (!IS_ERR(cpu_reg)) |
| 336 | regulator_put(cpu_reg); | 347 | regulator_put(cpu_reg); |
| 337 | 348 | ||
| 349 | dt_cpufreq_driver.driver_data = dev_get_platdata(&pdev->dev); | ||
| 350 | |||
| 338 | ret = cpufreq_register_driver(&dt_cpufreq_driver); | 351 | ret = cpufreq_register_driver(&dt_cpufreq_driver); |
| 339 | if (ret) | 352 | if (ret) |
| 340 | dev_err(cpu_dev, "failed register driver: %d\n", ret); | 353 | dev_err(cpu_dev, "failed register driver: %d\n", ret); |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 24bf76fba141..644b54e1e7d1 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
| @@ -512,7 +512,18 @@ show_one(cpuinfo_max_freq, cpuinfo.max_freq); | |||
| 512 | show_one(cpuinfo_transition_latency, cpuinfo.transition_latency); | 512 | show_one(cpuinfo_transition_latency, cpuinfo.transition_latency); |
| 513 | show_one(scaling_min_freq, min); | 513 | show_one(scaling_min_freq, min); |
| 514 | show_one(scaling_max_freq, max); | 514 | show_one(scaling_max_freq, max); |
| 515 | show_one(scaling_cur_freq, cur); | 515 | |
| 516 | static ssize_t show_scaling_cur_freq( | ||
| 517 | struct cpufreq_policy *policy, char *buf) | ||
| 518 | { | ||
| 519 | ssize_t ret; | ||
| 520 | |||
| 521 | if (cpufreq_driver && cpufreq_driver->setpolicy && cpufreq_driver->get) | ||
| 522 | ret = sprintf(buf, "%u\n", cpufreq_driver->get(policy->cpu)); | ||
| 523 | else | ||
| 524 | ret = sprintf(buf, "%u\n", policy->cur); | ||
| 525 | return ret; | ||
| 526 | } | ||
| 516 | 527 | ||
| 517 | static int cpufreq_set_policy(struct cpufreq_policy *policy, | 528 | static int cpufreq_set_policy(struct cpufreq_policy *policy, |
| 518 | struct cpufreq_policy *new_policy); | 529 | struct cpufreq_policy *new_policy); |
| @@ -906,11 +917,11 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, | |||
| 906 | if (ret) | 917 | if (ret) |
| 907 | goto err_out_kobj_put; | 918 | goto err_out_kobj_put; |
| 908 | } | 919 | } |
| 909 | if (has_target()) { | 920 | |
| 910 | ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); | 921 | ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); |
| 911 | if (ret) | 922 | if (ret) |
| 912 | goto err_out_kobj_put; | 923 | goto err_out_kobj_put; |
| 913 | } | 924 | |
| 914 | if (cpufreq_driver->bios_limit) { | 925 | if (cpufreq_driver->bios_limit) { |
| 915 | ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); | 926 | ret = sysfs_create_file(&policy->kobj, &bios_limit.attr); |
| 916 | if (ret) | 927 | if (ret) |
| @@ -1731,6 +1742,21 @@ const char *cpufreq_get_current_driver(void) | |||
| 1731 | } | 1742 | } |
| 1732 | EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); | 1743 | EXPORT_SYMBOL_GPL(cpufreq_get_current_driver); |
| 1733 | 1744 | ||
| 1745 | /** | ||
| 1746 | * cpufreq_get_driver_data - return current driver data | ||
| 1747 | * | ||
| 1748 | * Return the private data of the currently loaded cpufreq | ||
| 1749 | * driver, or NULL if no cpufreq driver is loaded. | ||
| 1750 | */ | ||
| 1751 | void *cpufreq_get_driver_data(void) | ||
| 1752 | { | ||
| 1753 | if (cpufreq_driver) | ||
| 1754 | return cpufreq_driver->driver_data; | ||
| 1755 | |||
| 1756 | return NULL; | ||
| 1757 | } | ||
| 1758 | EXPORT_SYMBOL_GPL(cpufreq_get_driver_data); | ||
| 1759 | |||
| 1734 | /********************************************************************* | 1760 | /********************************************************************* |
| 1735 | * NOTIFIER LISTS INTERFACE * | 1761 | * NOTIFIER LISTS INTERFACE * |
| 1736 | *********************************************************************/ | 1762 | *********************************************************************/ |
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 0668b389c516..27bb6d3877ed 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c | |||
| @@ -52,6 +52,17 @@ static inline int32_t div_fp(int32_t x, int32_t y) | |||
| 52 | return div_s64((int64_t)x << FRAC_BITS, y); | 52 | return div_s64((int64_t)x << FRAC_BITS, y); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | static inline int ceiling_fp(int32_t x) | ||
| 56 | { | ||
| 57 | int mask, ret; | ||
| 58 | |||
| 59 | ret = fp_toint(x); | ||
| 60 | mask = (1 << FRAC_BITS) - 1; | ||
| 61 | if (x & mask) | ||
| 62 | ret += 1; | ||
| 63 | return ret; | ||
| 64 | } | ||
| 65 | |||
| 55 | struct sample { | 66 | struct sample { |
| 56 | int32_t core_pct_busy; | 67 | int32_t core_pct_busy; |
| 57 | u64 aperf; | 68 | u64 aperf; |
| @@ -64,6 +75,7 @@ struct pstate_data { | |||
| 64 | int current_pstate; | 75 | int current_pstate; |
| 65 | int min_pstate; | 76 | int min_pstate; |
| 66 | int max_pstate; | 77 | int max_pstate; |
| 78 | int scaling; | ||
| 67 | int turbo_pstate; | 79 | int turbo_pstate; |
| 68 | }; | 80 | }; |
| 69 | 81 | ||
| @@ -113,6 +125,7 @@ struct pstate_funcs { | |||
| 113 | int (*get_max)(void); | 125 | int (*get_max)(void); |
| 114 | int (*get_min)(void); | 126 | int (*get_min)(void); |
| 115 | int (*get_turbo)(void); | 127 | int (*get_turbo)(void); |
| 128 | int (*get_scaling)(void); | ||
| 116 | void (*set)(struct cpudata*, int pstate); | 129 | void (*set)(struct cpudata*, int pstate); |
| 117 | void (*get_vid)(struct cpudata *); | 130 | void (*get_vid)(struct cpudata *); |
| 118 | }; | 131 | }; |
| @@ -138,6 +151,7 @@ struct perf_limits { | |||
| 138 | 151 | ||
| 139 | static struct perf_limits limits = { | 152 | static struct perf_limits limits = { |
| 140 | .no_turbo = 0, | 153 | .no_turbo = 0, |
| 154 | .turbo_disabled = 0, | ||
| 141 | .max_perf_pct = 100, | 155 | .max_perf_pct = 100, |
| 142 | .max_perf = int_tofp(1), | 156 | .max_perf = int_tofp(1), |
| 143 | .min_perf_pct = 0, | 157 | .min_perf_pct = 0, |
| @@ -218,6 +232,18 @@ static inline void intel_pstate_reset_all_pid(void) | |||
| 218 | } | 232 | } |
| 219 | } | 233 | } |
| 220 | 234 | ||
| 235 | static inline void update_turbo_state(void) | ||
| 236 | { | ||
| 237 | u64 misc_en; | ||
| 238 | struct cpudata *cpu; | ||
| 239 | |||
| 240 | cpu = all_cpu_data[0]; | ||
| 241 | rdmsrl(MSR_IA32_MISC_ENABLE, misc_en); | ||
| 242 | limits.turbo_disabled = | ||
| 243 | (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE || | ||
| 244 | cpu->pstate.max_pstate == cpu->pstate.turbo_pstate); | ||
| 245 | } | ||
| 246 | |||
| 221 | /************************** debugfs begin ************************/ | 247 | /************************** debugfs begin ************************/ |
| 222 | static int pid_param_set(void *data, u64 val) | 248 | static int pid_param_set(void *data, u64 val) |
| 223 | { | 249 | { |
| @@ -274,6 +300,20 @@ static void __init intel_pstate_debug_expose_params(void) | |||
| 274 | return sprintf(buf, "%u\n", limits.object); \ | 300 | return sprintf(buf, "%u\n", limits.object); \ |
| 275 | } | 301 | } |
| 276 | 302 | ||
| 303 | static ssize_t show_no_turbo(struct kobject *kobj, | ||
| 304 | struct attribute *attr, char *buf) | ||
| 305 | { | ||
| 306 | ssize_t ret; | ||
| 307 | |||
| 308 | update_turbo_state(); | ||
| 309 | if (limits.turbo_disabled) | ||
| 310 | ret = sprintf(buf, "%u\n", limits.turbo_disabled); | ||
| 311 | else | ||
| 312 | ret = sprintf(buf, "%u\n", limits.no_turbo); | ||
| 313 | |||
| 314 | return ret; | ||
| 315 | } | ||
| 316 | |||
| 277 | static ssize_t store_no_turbo(struct kobject *a, struct attribute *b, | 317 | static ssize_t store_no_turbo(struct kobject *a, struct attribute *b, |
| 278 | const char *buf, size_t count) | 318 | const char *buf, size_t count) |
| 279 | { | 319 | { |
| @@ -283,11 +323,14 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b, | |||
| 283 | ret = sscanf(buf, "%u", &input); | 323 | ret = sscanf(buf, "%u", &input); |
| 284 | if (ret != 1) | 324 | if (ret != 1) |
| 285 | return -EINVAL; | 325 | return -EINVAL; |
| 286 | limits.no_turbo = clamp_t(int, input, 0 , 1); | 326 | |
| 327 | update_turbo_state(); | ||
| 287 | if (limits.turbo_disabled) { | 328 | if (limits.turbo_disabled) { |
| 288 | pr_warn("Turbo disabled by BIOS or unavailable on processor\n"); | 329 | pr_warn("Turbo disabled by BIOS or unavailable on processor\n"); |
| 289 | limits.no_turbo = limits.turbo_disabled; | 330 | return -EPERM; |
| 290 | } | 331 | } |
| 332 | limits.no_turbo = clamp_t(int, input, 0, 1); | ||
| 333 | |||
| 291 | return count; | 334 | return count; |
| 292 | } | 335 | } |
| 293 | 336 | ||
| @@ -323,7 +366,6 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, | |||
| 323 | return count; | 366 | return count; |
| 324 | } | 367 | } |
| 325 | 368 | ||
| 326 | show_one(no_turbo, no_turbo); | ||
| 327 | show_one(max_perf_pct, max_perf_pct); | 369 | show_one(max_perf_pct, max_perf_pct); |
| 328 | show_one(min_perf_pct, min_perf_pct); | 370 | show_one(min_perf_pct, min_perf_pct); |
| 329 | 371 | ||
| @@ -394,7 +436,7 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate) | |||
| 394 | cpudata->vid.ratio); | 436 | cpudata->vid.ratio); |
| 395 | 437 | ||
| 396 | vid_fp = clamp_t(int32_t, vid_fp, cpudata->vid.min, cpudata->vid.max); | 438 | vid_fp = clamp_t(int32_t, vid_fp, cpudata->vid.min, cpudata->vid.max); |
| 397 | vid = fp_toint(vid_fp); | 439 | vid = ceiling_fp(vid_fp); |
| 398 | 440 | ||
| 399 | if (pstate > cpudata->pstate.max_pstate) | 441 | if (pstate > cpudata->pstate.max_pstate) |
| 400 | vid = cpudata->vid.turbo; | 442 | vid = cpudata->vid.turbo; |
| @@ -404,6 +446,22 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate) | |||
| 404 | wrmsrl(MSR_IA32_PERF_CTL, val); | 446 | wrmsrl(MSR_IA32_PERF_CTL, val); |
| 405 | } | 447 | } |
| 406 | 448 | ||
| 449 | #define BYT_BCLK_FREQS 5 | ||
| 450 | static int byt_freq_table[BYT_BCLK_FREQS] = { 833, 1000, 1333, 1167, 800}; | ||
| 451 | |||
| 452 | static int byt_get_scaling(void) | ||
| 453 | { | ||
| 454 | u64 value; | ||
| 455 | int i; | ||
| 456 | |||
| 457 | rdmsrl(MSR_FSB_FREQ, value); | ||
| 458 | i = value & 0x3; | ||
| 459 | |||
| 460 | BUG_ON(i > BYT_BCLK_FREQS); | ||
| 461 | |||
| 462 | return byt_freq_table[i] * 100; | ||
| 463 | } | ||
| 464 | |||
| 407 | static void byt_get_vid(struct cpudata *cpudata) | 465 | static void byt_get_vid(struct cpudata *cpudata) |
| 408 | { | 466 | { |
| 409 | u64 value; | 467 | u64 value; |
| @@ -449,6 +507,11 @@ static int core_get_turbo_pstate(void) | |||
| 449 | return ret; | 507 | return ret; |
| 450 | } | 508 | } |
| 451 | 509 | ||
| 510 | static inline int core_get_scaling(void) | ||
| 511 | { | ||
| 512 | return 100000; | ||
| 513 | } | ||
| 514 | |||
| 452 | static void core_set_pstate(struct cpudata *cpudata, int pstate) | 515 | static void core_set_pstate(struct cpudata *cpudata, int pstate) |
| 453 | { | 516 | { |
| 454 | u64 val; | 517 | u64 val; |
| @@ -473,6 +536,7 @@ static struct cpu_defaults core_params = { | |||
| 473 | .get_max = core_get_max_pstate, | 536 | .get_max = core_get_max_pstate, |
| 474 | .get_min = core_get_min_pstate, | 537 | .get_min = core_get_min_pstate, |
| 475 | .get_turbo = core_get_turbo_pstate, | 538 | .get_turbo = core_get_turbo_pstate, |
| 539 | .get_scaling = core_get_scaling, | ||
| 476 | .set = core_set_pstate, | 540 | .set = core_set_pstate, |
| 477 | }, | 541 | }, |
| 478 | }; | 542 | }; |
| @@ -491,6 +555,7 @@ static struct cpu_defaults byt_params = { | |||
| 491 | .get_min = byt_get_min_pstate, | 555 | .get_min = byt_get_min_pstate, |
| 492 | .get_turbo = byt_get_turbo_pstate, | 556 | .get_turbo = byt_get_turbo_pstate, |
| 493 | .set = byt_set_pstate, | 557 | .set = byt_set_pstate, |
| 558 | .get_scaling = byt_get_scaling, | ||
| 494 | .get_vid = byt_get_vid, | 559 | .get_vid = byt_get_vid, |
| 495 | }, | 560 | }, |
| 496 | }; | 561 | }; |
| @@ -501,7 +566,7 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) | |||
| 501 | int max_perf_adj; | 566 | int max_perf_adj; |
| 502 | int min_perf; | 567 | int min_perf; |
| 503 | 568 | ||
| 504 | if (limits.no_turbo) | 569 | if (limits.no_turbo || limits.turbo_disabled) |
| 505 | max_perf = cpu->pstate.max_pstate; | 570 | max_perf = cpu->pstate.max_pstate; |
| 506 | 571 | ||
| 507 | max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), limits.max_perf)); | 572 | max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), limits.max_perf)); |
| @@ -516,6 +581,8 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) | |||
| 516 | { | 581 | { |
| 517 | int max_perf, min_perf; | 582 | int max_perf, min_perf; |
| 518 | 583 | ||
| 584 | update_turbo_state(); | ||
| 585 | |||
| 519 | intel_pstate_get_min_max(cpu, &min_perf, &max_perf); | 586 | intel_pstate_get_min_max(cpu, &min_perf, &max_perf); |
| 520 | 587 | ||
| 521 | pstate = clamp_t(int, pstate, min_perf, max_perf); | 588 | pstate = clamp_t(int, pstate, min_perf, max_perf); |
| @@ -523,7 +590,7 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) | |||
| 523 | if (pstate == cpu->pstate.current_pstate) | 590 | if (pstate == cpu->pstate.current_pstate) |
| 524 | return; | 591 | return; |
| 525 | 592 | ||
| 526 | trace_cpu_frequency(pstate * 100000, cpu->cpu); | 593 | trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu); |
| 527 | 594 | ||
| 528 | cpu->pstate.current_pstate = pstate; | 595 | cpu->pstate.current_pstate = pstate; |
| 529 | 596 | ||
| @@ -535,6 +602,7 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) | |||
| 535 | cpu->pstate.min_pstate = pstate_funcs.get_min(); | 602 | cpu->pstate.min_pstate = pstate_funcs.get_min(); |
| 536 | cpu->pstate.max_pstate = pstate_funcs.get_max(); | 603 | cpu->pstate.max_pstate = pstate_funcs.get_max(); |
| 537 | cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); | 604 | cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); |
| 605 | cpu->pstate.scaling = pstate_funcs.get_scaling(); | ||
| 538 | 606 | ||
| 539 | if (pstate_funcs.get_vid) | 607 | if (pstate_funcs.get_vid) |
| 540 | pstate_funcs.get_vid(cpu); | 608 | pstate_funcs.get_vid(cpu); |
| @@ -550,7 +618,9 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu) | |||
| 550 | core_pct = div64_u64(core_pct, int_tofp(sample->mperf)); | 618 | core_pct = div64_u64(core_pct, int_tofp(sample->mperf)); |
| 551 | 619 | ||
| 552 | sample->freq = fp_toint( | 620 | sample->freq = fp_toint( |
| 553 | mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct)); | 621 | mul_fp(int_tofp( |
| 622 | cpu->pstate.max_pstate * cpu->pstate.scaling / 100), | ||
| 623 | core_pct)); | ||
| 554 | 624 | ||
| 555 | sample->core_pct_busy = (int32_t)core_pct; | 625 | sample->core_pct_busy = (int32_t)core_pct; |
| 556 | } | 626 | } |
| @@ -671,7 +741,9 @@ static int intel_pstate_init_cpu(unsigned int cpunum) | |||
| 671 | { | 741 | { |
| 672 | struct cpudata *cpu; | 742 | struct cpudata *cpu; |
| 673 | 743 | ||
| 674 | all_cpu_data[cpunum] = kzalloc(sizeof(struct cpudata), GFP_KERNEL); | 744 | if (!all_cpu_data[cpunum]) |
| 745 | all_cpu_data[cpunum] = kzalloc(sizeof(struct cpudata), | ||
| 746 | GFP_KERNEL); | ||
| 675 | if (!all_cpu_data[cpunum]) | 747 | if (!all_cpu_data[cpunum]) |
| 676 | return -ENOMEM; | 748 | return -ENOMEM; |
| 677 | 749 | ||
| @@ -714,9 +786,10 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) | |||
| 714 | if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { | 786 | if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { |
| 715 | limits.min_perf_pct = 100; | 787 | limits.min_perf_pct = 100; |
| 716 | limits.min_perf = int_tofp(1); | 788 | limits.min_perf = int_tofp(1); |
| 789 | limits.max_policy_pct = 100; | ||
| 717 | limits.max_perf_pct = 100; | 790 | limits.max_perf_pct = 100; |
| 718 | limits.max_perf = int_tofp(1); | 791 | limits.max_perf = int_tofp(1); |
| 719 | limits.no_turbo = limits.turbo_disabled; | 792 | limits.no_turbo = 0; |
| 720 | return 0; | 793 | return 0; |
| 721 | } | 794 | } |
| 722 | limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq; | 795 | limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq; |
| @@ -751,15 +824,12 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy) | |||
| 751 | 824 | ||
| 752 | del_timer_sync(&all_cpu_data[cpu_num]->timer); | 825 | del_timer_sync(&all_cpu_data[cpu_num]->timer); |
| 753 | intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate); | 826 | intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate); |
| 754 | kfree(all_cpu_data[cpu_num]); | ||
| 755 | all_cpu_data[cpu_num] = NULL; | ||
| 756 | } | 827 | } |
| 757 | 828 | ||
| 758 | static int intel_pstate_cpu_init(struct cpufreq_policy *policy) | 829 | static int intel_pstate_cpu_init(struct cpufreq_policy *policy) |
| 759 | { | 830 | { |
| 760 | struct cpudata *cpu; | 831 | struct cpudata *cpu; |
| 761 | int rc; | 832 | int rc; |
| 762 | u64 misc_en; | ||
| 763 | 833 | ||
| 764 | rc = intel_pstate_init_cpu(policy->cpu); | 834 | rc = intel_pstate_init_cpu(policy->cpu); |
| 765 | if (rc) | 835 | if (rc) |
| @@ -767,23 +837,18 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy) | |||
| 767 | 837 | ||
| 768 | cpu = all_cpu_data[policy->cpu]; | 838 | cpu = all_cpu_data[policy->cpu]; |
| 769 | 839 | ||
| 770 | rdmsrl(MSR_IA32_MISC_ENABLE, misc_en); | ||
| 771 | if (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE || | ||
| 772 | cpu->pstate.max_pstate == cpu->pstate.turbo_pstate) { | ||
| 773 | limits.turbo_disabled = 1; | ||
| 774 | limits.no_turbo = 1; | ||
| 775 | } | ||
| 776 | if (limits.min_perf_pct == 100 && limits.max_perf_pct == 100) | 840 | if (limits.min_perf_pct == 100 && limits.max_perf_pct == 100) |
| 777 | policy->policy = CPUFREQ_POLICY_PERFORMANCE; | 841 | policy->policy = CPUFREQ_POLICY_PERFORMANCE; |
| 778 | else | 842 | else |
| 779 | policy->policy = CPUFREQ_POLICY_POWERSAVE; | 843 | policy->policy = CPUFREQ_POLICY_POWERSAVE; |
| 780 | 844 | ||
| 781 | policy->min = cpu->pstate.min_pstate * 100000; | 845 | policy->min = cpu->pstate.min_pstate * cpu->pstate.scaling; |
| 782 | policy->max = cpu->pstate.turbo_pstate * 100000; | 846 | policy->max = cpu->pstate.turbo_pstate * cpu->pstate.scaling; |
| 783 | 847 | ||
| 784 | /* cpuinfo and default policy values */ | 848 | /* cpuinfo and default policy values */ |
| 785 | policy->cpuinfo.min_freq = cpu->pstate.min_pstate * 100000; | 849 | policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling; |
| 786 | policy->cpuinfo.max_freq = cpu->pstate.turbo_pstate * 100000; | 850 | policy->cpuinfo.max_freq = |
| 851 | cpu->pstate.turbo_pstate * cpu->pstate.scaling; | ||
| 787 | policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; | 852 | policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; |
| 788 | cpumask_set_cpu(policy->cpu, policy->cpus); | 853 | cpumask_set_cpu(policy->cpu, policy->cpus); |
| 789 | 854 | ||
| @@ -841,6 +906,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs) | |||
| 841 | pstate_funcs.get_max = funcs->get_max; | 906 | pstate_funcs.get_max = funcs->get_max; |
| 842 | pstate_funcs.get_min = funcs->get_min; | 907 | pstate_funcs.get_min = funcs->get_min; |
| 843 | pstate_funcs.get_turbo = funcs->get_turbo; | 908 | pstate_funcs.get_turbo = funcs->get_turbo; |
| 909 | pstate_funcs.get_scaling = funcs->get_scaling; | ||
| 844 | pstate_funcs.set = funcs->set; | 910 | pstate_funcs.set = funcs->set; |
| 845 | pstate_funcs.get_vid = funcs->get_vid; | 911 | pstate_funcs.get_vid = funcs->get_vid; |
| 846 | } | 912 | } |
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index a64be578dab2..7d3a3497dd4c 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c | |||
| @@ -163,7 +163,8 @@ static int powernv_add_idle_states(void) | |||
| 163 | int nr_idle_states = 1; /* Snooze */ | 163 | int nr_idle_states = 1; /* Snooze */ |
| 164 | int dt_idle_states; | 164 | int dt_idle_states; |
| 165 | const __be32 *idle_state_flags; | 165 | const __be32 *idle_state_flags; |
| 166 | u32 len_flags, flags; | 166 | const __be32 *idle_state_latency; |
| 167 | u32 len_flags, flags, latency_ns; | ||
| 167 | int i; | 168 | int i; |
| 168 | 169 | ||
| 169 | /* Currently we have snooze statically defined */ | 170 | /* Currently we have snooze statically defined */ |
| @@ -180,18 +181,32 @@ static int powernv_add_idle_states(void) | |||
| 180 | return nr_idle_states; | 181 | return nr_idle_states; |
| 181 | } | 182 | } |
| 182 | 183 | ||
| 184 | idle_state_latency = of_get_property(power_mgt, | ||
| 185 | "ibm,cpu-idle-state-latencies-ns", NULL); | ||
| 186 | if (!idle_state_latency) { | ||
| 187 | pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-latencies-ns\n"); | ||
| 188 | return nr_idle_states; | ||
| 189 | } | ||
| 190 | |||
| 183 | dt_idle_states = len_flags / sizeof(u32); | 191 | dt_idle_states = len_flags / sizeof(u32); |
| 184 | 192 | ||
| 185 | for (i = 0; i < dt_idle_states; i++) { | 193 | for (i = 0; i < dt_idle_states; i++) { |
| 186 | 194 | ||
| 187 | flags = be32_to_cpu(idle_state_flags[i]); | 195 | flags = be32_to_cpu(idle_state_flags[i]); |
| 196 | |||
| 197 | /* Cpuidle accepts exit_latency in us and we estimate | ||
| 198 | * target residency to be 10x exit_latency | ||
| 199 | */ | ||
| 200 | latency_ns = be32_to_cpu(idle_state_latency[i]); | ||
| 188 | if (flags & IDLE_USE_INST_NAP) { | 201 | if (flags & IDLE_USE_INST_NAP) { |
| 189 | /* Add NAP state */ | 202 | /* Add NAP state */ |
| 190 | strcpy(powernv_states[nr_idle_states].name, "Nap"); | 203 | strcpy(powernv_states[nr_idle_states].name, "Nap"); |
| 191 | strcpy(powernv_states[nr_idle_states].desc, "Nap"); | 204 | strcpy(powernv_states[nr_idle_states].desc, "Nap"); |
| 192 | powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIME_VALID; | 205 | powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIME_VALID; |
| 193 | powernv_states[nr_idle_states].exit_latency = 10; | 206 | powernv_states[nr_idle_states].exit_latency = |
| 194 | powernv_states[nr_idle_states].target_residency = 100; | 207 | ((unsigned int)latency_ns) / 1000; |
| 208 | powernv_states[nr_idle_states].target_residency = | ||
| 209 | ((unsigned int)latency_ns / 100); | ||
| 195 | powernv_states[nr_idle_states].enter = &nap_loop; | 210 | powernv_states[nr_idle_states].enter = &nap_loop; |
| 196 | nr_idle_states++; | 211 | nr_idle_states++; |
| 197 | } | 212 | } |
| @@ -202,8 +217,10 @@ static int powernv_add_idle_states(void) | |||
| 202 | strcpy(powernv_states[nr_idle_states].desc, "FastSleep"); | 217 | strcpy(powernv_states[nr_idle_states].desc, "FastSleep"); |
| 203 | powernv_states[nr_idle_states].flags = | 218 | powernv_states[nr_idle_states].flags = |
| 204 | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP; | 219 | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP; |
| 205 | powernv_states[nr_idle_states].exit_latency = 300; | 220 | powernv_states[nr_idle_states].exit_latency = |
| 206 | powernv_states[nr_idle_states].target_residency = 1000000; | 221 | ((unsigned int)latency_ns) / 1000; |
| 222 | powernv_states[nr_idle_states].target_residency = | ||
| 223 | ((unsigned int)latency_ns / 100); | ||
| 207 | powernv_states[nr_idle_states].enter = &fastsleep_loop; | 224 | powernv_states[nr_idle_states].enter = &fastsleep_loop; |
| 208 | nr_idle_states++; | 225 | nr_idle_states++; |
| 209 | } | 226 | } |
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 64ecbb501c50..8590099ac148 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
| @@ -41,6 +41,28 @@ struct efi __read_mostly efi = { | |||
| 41 | }; | 41 | }; |
| 42 | EXPORT_SYMBOL(efi); | 42 | EXPORT_SYMBOL(efi); |
| 43 | 43 | ||
| 44 | static bool disable_runtime; | ||
| 45 | static int __init setup_noefi(char *arg) | ||
| 46 | { | ||
| 47 | disable_runtime = true; | ||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | early_param("noefi", setup_noefi); | ||
| 51 | |||
| 52 | bool efi_runtime_disabled(void) | ||
| 53 | { | ||
| 54 | return disable_runtime; | ||
| 55 | } | ||
| 56 | |||
| 57 | static int __init parse_efi_cmdline(char *str) | ||
| 58 | { | ||
| 59 | if (parse_option_str(str, "noruntime")) | ||
| 60 | disable_runtime = true; | ||
| 61 | |||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | early_param("efi", parse_efi_cmdline); | ||
| 65 | |||
| 44 | static struct kobject *efi_kobj; | 66 | static struct kobject *efi_kobj; |
| 45 | static struct kobject *efivars_kobj; | 67 | static struct kobject *efivars_kobj; |
| 46 | 68 | ||
| @@ -423,3 +445,60 @@ int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose) | |||
| 423 | return ret; | 445 | return ret; |
| 424 | } | 446 | } |
| 425 | #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ | 447 | #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ |
| 448 | |||
| 449 | static __initdata char memory_type_name[][20] = { | ||
| 450 | "Reserved", | ||
| 451 | "Loader Code", | ||
| 452 | "Loader Data", | ||
| 453 | "Boot Code", | ||
| 454 | "Boot Data", | ||
| 455 | "Runtime Code", | ||
| 456 | "Runtime Data", | ||
| 457 | "Conventional Memory", | ||
| 458 | "Unusable Memory", | ||
| 459 | "ACPI Reclaim Memory", | ||
| 460 | "ACPI Memory NVS", | ||
| 461 | "Memory Mapped I/O", | ||
| 462 | "MMIO Port Space", | ||
| 463 | "PAL Code" | ||
| 464 | }; | ||
| 465 | |||
| 466 | char * __init efi_md_typeattr_format(char *buf, size_t size, | ||
| 467 | const efi_memory_desc_t *md) | ||
| 468 | { | ||
| 469 | char *pos; | ||
| 470 | int type_len; | ||
| 471 | u64 attr; | ||
| 472 | |||
| 473 | pos = buf; | ||
| 474 | if (md->type >= ARRAY_SIZE(memory_type_name)) | ||
| 475 | type_len = snprintf(pos, size, "[type=%u", md->type); | ||
| 476 | else | ||
| 477 | type_len = snprintf(pos, size, "[%-*s", | ||
| 478 | (int)(sizeof(memory_type_name[0]) - 1), | ||
| 479 | memory_type_name[md->type]); | ||
| 480 | if (type_len >= size) | ||
| 481 | return buf; | ||
| 482 | |||
| 483 | pos += type_len; | ||
| 484 | size -= type_len; | ||
| 485 | |||
| 486 | attr = md->attribute; | ||
| 487 | if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | | ||
| 488 | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP | | ||
| 489 | EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME)) | ||
| 490 | snprintf(pos, size, "|attr=0x%016llx]", | ||
| 491 | (unsigned long long)attr); | ||
| 492 | else | ||
| 493 | snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]", | ||
| 494 | attr & EFI_MEMORY_RUNTIME ? "RUN" : "", | ||
| 495 | attr & EFI_MEMORY_XP ? "XP" : "", | ||
| 496 | attr & EFI_MEMORY_RP ? "RP" : "", | ||
| 497 | attr & EFI_MEMORY_WP ? "WP" : "", | ||
| 498 | attr & EFI_MEMORY_UCE ? "UCE" : "", | ||
| 499 | attr & EFI_MEMORY_WB ? "WB" : "", | ||
| 500 | attr & EFI_MEMORY_WT ? "WT" : "", | ||
| 501 | attr & EFI_MEMORY_WC ? "WC" : "", | ||
| 502 | attr & EFI_MEMORY_UC ? "UC" : ""); | ||
| 503 | return buf; | ||
| 504 | } | ||
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 480339b6b110..75ee05964cbc 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c | |||
| @@ -226,6 +226,10 @@ unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table, | |||
| 226 | goto fail_free_image; | 226 | goto fail_free_image; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | status = efi_parse_options(cmdline_ptr); | ||
| 230 | if (status != EFI_SUCCESS) | ||
| 231 | pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n"); | ||
| 232 | |||
| 229 | /* | 233 | /* |
| 230 | * Unauthenticated device tree data is a security hazard, so | 234 | * Unauthenticated device tree data is a security hazard, so |
| 231 | * ignore 'dtb=' unless UEFI Secure Boot is disabled. | 235 | * ignore 'dtb=' unless UEFI Secure Boot is disabled. |
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 32d5cca30f49..a920fec8fe88 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c | |||
| @@ -15,8 +15,23 @@ | |||
| 15 | 15 | ||
| 16 | #include "efistub.h" | 16 | #include "efistub.h" |
| 17 | 17 | ||
| 18 | /* | ||
| 19 | * Some firmware implementations have problems reading files in one go. | ||
| 20 | * A read chunk size of 1MB seems to work for most platforms. | ||
| 21 | * | ||
| 22 | * Unfortunately, reading files in chunks triggers *other* bugs on some | ||
| 23 | * platforms, so we provide a way to disable this workaround, which can | ||
| 24 | * be done by passing "efi=nochunk" on the EFI boot stub command line. | ||
| 25 | * | ||
| 26 | * If you experience issues with initrd images being corrupt it's worth | ||
| 27 | * trying efi=nochunk, but chunking is enabled by default because there | ||
| 28 | * are far more machines that require the workaround than those that | ||
| 29 | * break with it enabled. | ||
| 30 | */ | ||
| 18 | #define EFI_READ_CHUNK_SIZE (1024 * 1024) | 31 | #define EFI_READ_CHUNK_SIZE (1024 * 1024) |
| 19 | 32 | ||
| 33 | static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; | ||
| 34 | |||
| 20 | struct file_info { | 35 | struct file_info { |
| 21 | efi_file_handle_t *handle; | 36 | efi_file_handle_t *handle; |
| 22 | u64 size; | 37 | u64 size; |
| @@ -281,6 +296,49 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, | |||
| 281 | efi_call_early(free_pages, addr, nr_pages); | 296 | efi_call_early(free_pages, addr, nr_pages); |
| 282 | } | 297 | } |
| 283 | 298 | ||
| 299 | /* | ||
| 300 | * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi= | ||
| 301 | * option, e.g. efi=nochunk. | ||
| 302 | * | ||
| 303 | * It should be noted that efi= is parsed in two very different | ||
| 304 | * environments, first in the early boot environment of the EFI boot | ||
| 305 | * stub, and subsequently during the kernel boot. | ||
| 306 | */ | ||
| 307 | efi_status_t efi_parse_options(char *cmdline) | ||
| 308 | { | ||
| 309 | char *str; | ||
| 310 | |||
| 311 | /* | ||
| 312 | * If no EFI parameters were specified on the cmdline we've got | ||
| 313 | * nothing to do. | ||
| 314 | */ | ||
| 315 | str = strstr(cmdline, "efi="); | ||
| 316 | if (!str) | ||
| 317 | return EFI_SUCCESS; | ||
| 318 | |||
| 319 | /* Skip ahead to first argument */ | ||
| 320 | str += strlen("efi="); | ||
| 321 | |||
| 322 | /* | ||
| 323 | * Remember, because efi= is also used by the kernel we need to | ||
| 324 | * skip over arguments we don't understand. | ||
| 325 | */ | ||
| 326 | while (*str) { | ||
| 327 | if (!strncmp(str, "nochunk", 7)) { | ||
| 328 | str += strlen("nochunk"); | ||
| 329 | __chunk_size = -1UL; | ||
| 330 | } | ||
| 331 | |||
| 332 | /* Group words together, delimited by "," */ | ||
| 333 | while (*str && *str != ',') | ||
| 334 | str++; | ||
| 335 | |||
| 336 | if (*str == ',') | ||
| 337 | str++; | ||
| 338 | } | ||
| 339 | |||
| 340 | return EFI_SUCCESS; | ||
| 341 | } | ||
| 284 | 342 | ||
| 285 | /* | 343 | /* |
| 286 | * Check the cmdline for a LILO-style file= arguments. | 344 | * Check the cmdline for a LILO-style file= arguments. |
| @@ -423,8 +481,8 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, | |||
| 423 | size = files[j].size; | 481 | size = files[j].size; |
| 424 | while (size) { | 482 | while (size) { |
| 425 | unsigned long chunksize; | 483 | unsigned long chunksize; |
| 426 | if (size > EFI_READ_CHUNK_SIZE) | 484 | if (size > __chunk_size) |
| 427 | chunksize = EFI_READ_CHUNK_SIZE; | 485 | chunksize = __chunk_size; |
| 428 | else | 486 | else |
| 429 | chunksize = size; | 487 | chunksize = size; |
| 430 | 488 | ||
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 10daa4bbb258..228bbf910461 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c | |||
| @@ -14,11 +14,80 @@ | |||
| 14 | * This file is released under the GPLv2. | 14 | * This file is released under the GPLv2. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/bug.h> | ||
| 17 | #include <linux/efi.h> | 18 | #include <linux/efi.h> |
| 18 | #include <linux/spinlock.h> /* spinlock_t */ | 19 | #include <linux/mutex.h> |
| 20 | #include <linux/spinlock.h> | ||
| 19 | #include <asm/efi.h> | 21 | #include <asm/efi.h> |
| 20 | 22 | ||
| 21 | /* | 23 | /* |
| 24 | * According to section 7.1 of the UEFI spec, Runtime Services are not fully | ||
| 25 | * reentrant, and there are particular combinations of calls that need to be | ||
| 26 | * serialized. (source: UEFI Specification v2.4A) | ||
| 27 | * | ||
| 28 | * Table 31. Rules for Reentry Into Runtime Services | ||
| 29 | * +------------------------------------+-------------------------------+ | ||
| 30 | * | If previous call is busy in | Forbidden to call | | ||
| 31 | * +------------------------------------+-------------------------------+ | ||
| 32 | * | Any | SetVirtualAddressMap() | | ||
| 33 | * +------------------------------------+-------------------------------+ | ||
| 34 | * | ConvertPointer() | ConvertPointer() | | ||
| 35 | * +------------------------------------+-------------------------------+ | ||
| 36 | * | SetVariable() | ResetSystem() | | ||
| 37 | * | UpdateCapsule() | | | ||
| 38 | * | SetTime() | | | ||
| 39 | * | SetWakeupTime() | | | ||
| 40 | * | GetNextHighMonotonicCount() | | | ||
| 41 | * +------------------------------------+-------------------------------+ | ||
| 42 | * | GetVariable() | GetVariable() | | ||
| 43 | * | GetNextVariableName() | GetNextVariableName() | | ||
| 44 | * | SetVariable() | SetVariable() | | ||
| 45 | * | QueryVariableInfo() | QueryVariableInfo() | | ||
| 46 | * | UpdateCapsule() | UpdateCapsule() | | ||
| 47 | * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | | ||
| 48 | * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | | ||
| 49 | * +------------------------------------+-------------------------------+ | ||
| 50 | * | GetTime() | GetTime() | | ||
| 51 | * | SetTime() | SetTime() | | ||
| 52 | * | GetWakeupTime() | GetWakeupTime() | | ||
| 53 | * | SetWakeupTime() | SetWakeupTime() | | ||
| 54 | * +------------------------------------+-------------------------------+ | ||
| 55 | * | ||
| 56 | * Due to the fact that the EFI pstore may write to the variable store in | ||
| 57 | * interrupt context, we need to use a spinlock for at least the groups that | ||
| 58 | * contain SetVariable() and QueryVariableInfo(). That leaves little else, as | ||
| 59 | * none of the remaining functions are actually ever called at runtime. | ||
| 60 | * So let's just use a single spinlock to serialize all Runtime Services calls. | ||
| 61 | */ | ||
| 62 | static DEFINE_SPINLOCK(efi_runtime_lock); | ||
| 63 | |||
| 64 | /* | ||
| 65 | * Some runtime services calls can be reentrant under NMI, even if the table | ||
| 66 | * above says they are not. (source: UEFI Specification v2.4A) | ||
| 67 | * | ||
| 68 | * Table 32. Functions that may be called after Machine Check, INIT and NMI | ||
| 69 | * +----------------------------+------------------------------------------+ | ||
| 70 | * | Function | Called after Machine Check, INIT and NMI | | ||
| 71 | * +----------------------------+------------------------------------------+ | ||
| 72 | * | GetTime() | Yes, even if previously busy. | | ||
| 73 | * | GetVariable() | Yes, even if previously busy | | ||
| 74 | * | GetNextVariableName() | Yes, even if previously busy | | ||
| 75 | * | QueryVariableInfo() | Yes, even if previously busy | | ||
| 76 | * | SetVariable() | Yes, even if previously busy | | ||
| 77 | * | UpdateCapsule() | Yes, even if previously busy | | ||
| 78 | * | QueryCapsuleCapabilities() | Yes, even if previously busy | | ||
| 79 | * | ResetSystem() | Yes, even if previously busy | | ||
| 80 | * +----------------------------+------------------------------------------+ | ||
| 81 | * | ||
| 82 | * In order to prevent deadlocks under NMI, the wrappers for these functions | ||
| 83 | * may only grab the efi_runtime_lock or rtc_lock spinlocks if !efi_in_nmi(). | ||
| 84 | * However, not all of the services listed are reachable through NMI code paths, | ||
| 85 | * so the the special handling as suggested by the UEFI spec is only implemented | ||
| 86 | * for QueryVariableInfo() and SetVariable(), as these can be reached in NMI | ||
| 87 | * context through efi_pstore_write(). | ||
| 88 | */ | ||
| 89 | |||
| 90 | /* | ||
| 22 | * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), | 91 | * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), |
| 23 | * the EFI specification requires that callers of the time related runtime | 92 | * the EFI specification requires that callers of the time related runtime |
| 24 | * functions serialize with other CMOS accesses in the kernel, as the EFI time | 93 | * functions serialize with other CMOS accesses in the kernel, as the EFI time |
| @@ -32,7 +101,9 @@ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) | |||
| 32 | efi_status_t status; | 101 | efi_status_t status; |
| 33 | 102 | ||
| 34 | spin_lock_irqsave(&rtc_lock, flags); | 103 | spin_lock_irqsave(&rtc_lock, flags); |
| 104 | spin_lock(&efi_runtime_lock); | ||
| 35 | status = efi_call_virt(get_time, tm, tc); | 105 | status = efi_call_virt(get_time, tm, tc); |
| 106 | spin_unlock(&efi_runtime_lock); | ||
| 36 | spin_unlock_irqrestore(&rtc_lock, flags); | 107 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 37 | return status; | 108 | return status; |
| 38 | } | 109 | } |
| @@ -43,7 +114,9 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm) | |||
| 43 | efi_status_t status; | 114 | efi_status_t status; |
| 44 | 115 | ||
| 45 | spin_lock_irqsave(&rtc_lock, flags); | 116 | spin_lock_irqsave(&rtc_lock, flags); |
| 117 | spin_lock(&efi_runtime_lock); | ||
| 46 | status = efi_call_virt(set_time, tm); | 118 | status = efi_call_virt(set_time, tm); |
| 119 | spin_unlock(&efi_runtime_lock); | ||
| 47 | spin_unlock_irqrestore(&rtc_lock, flags); | 120 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 48 | return status; | 121 | return status; |
| 49 | } | 122 | } |
| @@ -56,7 +129,9 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, | |||
| 56 | efi_status_t status; | 129 | efi_status_t status; |
| 57 | 130 | ||
| 58 | spin_lock_irqsave(&rtc_lock, flags); | 131 | spin_lock_irqsave(&rtc_lock, flags); |
| 132 | spin_lock(&efi_runtime_lock); | ||
| 59 | status = efi_call_virt(get_wakeup_time, enabled, pending, tm); | 133 | status = efi_call_virt(get_wakeup_time, enabled, pending, tm); |
| 134 | spin_unlock(&efi_runtime_lock); | ||
| 60 | spin_unlock_irqrestore(&rtc_lock, flags); | 135 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 61 | return status; | 136 | return status; |
| 62 | } | 137 | } |
| @@ -67,7 +142,9 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) | |||
| 67 | efi_status_t status; | 142 | efi_status_t status; |
| 68 | 143 | ||
| 69 | spin_lock_irqsave(&rtc_lock, flags); | 144 | spin_lock_irqsave(&rtc_lock, flags); |
| 145 | spin_lock(&efi_runtime_lock); | ||
| 70 | status = efi_call_virt(set_wakeup_time, enabled, tm); | 146 | status = efi_call_virt(set_wakeup_time, enabled, tm); |
| 147 | spin_unlock(&efi_runtime_lock); | ||
| 71 | spin_unlock_irqrestore(&rtc_lock, flags); | 148 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 72 | return status; | 149 | return status; |
| 73 | } | 150 | } |
| @@ -78,14 +155,27 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name, | |||
| 78 | unsigned long *data_size, | 155 | unsigned long *data_size, |
| 79 | void *data) | 156 | void *data) |
| 80 | { | 157 | { |
| 81 | return efi_call_virt(get_variable, name, vendor, attr, data_size, data); | 158 | unsigned long flags; |
| 159 | efi_status_t status; | ||
| 160 | |||
| 161 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 162 | status = efi_call_virt(get_variable, name, vendor, attr, data_size, | ||
| 163 | data); | ||
| 164 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 165 | return status; | ||
| 82 | } | 166 | } |
| 83 | 167 | ||
| 84 | static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, | 168 | static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, |
| 85 | efi_char16_t *name, | 169 | efi_char16_t *name, |
| 86 | efi_guid_t *vendor) | 170 | efi_guid_t *vendor) |
| 87 | { | 171 | { |
| 88 | return efi_call_virt(get_next_variable, name_size, name, vendor); | 172 | unsigned long flags; |
| 173 | efi_status_t status; | ||
| 174 | |||
| 175 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 176 | status = efi_call_virt(get_next_variable, name_size, name, vendor); | ||
| 177 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 178 | return status; | ||
| 89 | } | 179 | } |
| 90 | 180 | ||
| 91 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, | 181 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, |
| @@ -94,24 +184,61 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, | |||
| 94 | unsigned long data_size, | 184 | unsigned long data_size, |
| 95 | void *data) | 185 | void *data) |
| 96 | { | 186 | { |
| 97 | return efi_call_virt(set_variable, name, vendor, attr, data_size, data); | 187 | unsigned long flags; |
| 188 | efi_status_t status; | ||
| 189 | |||
| 190 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 191 | status = efi_call_virt(set_variable, name, vendor, attr, data_size, | ||
| 192 | data); | ||
| 193 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 194 | return status; | ||
| 98 | } | 195 | } |
| 99 | 196 | ||
| 197 | static efi_status_t | ||
| 198 | virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, | ||
| 199 | u32 attr, unsigned long data_size, | ||
| 200 | void *data) | ||
| 201 | { | ||
| 202 | unsigned long flags; | ||
| 203 | efi_status_t status; | ||
| 204 | |||
| 205 | if (!spin_trylock_irqsave(&efi_runtime_lock, flags)) | ||
| 206 | return EFI_NOT_READY; | ||
| 207 | |||
| 208 | status = efi_call_virt(set_variable, name, vendor, attr, data_size, | ||
| 209 | data); | ||
| 210 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 211 | return status; | ||
| 212 | } | ||
| 213 | |||
| 214 | |||
| 100 | static efi_status_t virt_efi_query_variable_info(u32 attr, | 215 | static efi_status_t virt_efi_query_variable_info(u32 attr, |
| 101 | u64 *storage_space, | 216 | u64 *storage_space, |
| 102 | u64 *remaining_space, | 217 | u64 *remaining_space, |
| 103 | u64 *max_variable_size) | 218 | u64 *max_variable_size) |
| 104 | { | 219 | { |
| 220 | unsigned long flags; | ||
| 221 | efi_status_t status; | ||
| 222 | |||
| 105 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 223 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
| 106 | return EFI_UNSUPPORTED; | 224 | return EFI_UNSUPPORTED; |
| 107 | 225 | ||
| 108 | return efi_call_virt(query_variable_info, attr, storage_space, | 226 | spin_lock_irqsave(&efi_runtime_lock, flags); |
| 109 | remaining_space, max_variable_size); | 227 | status = efi_call_virt(query_variable_info, attr, storage_space, |
| 228 | remaining_space, max_variable_size); | ||
| 229 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 230 | return status; | ||
| 110 | } | 231 | } |
| 111 | 232 | ||
| 112 | static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) | 233 | static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) |
| 113 | { | 234 | { |
| 114 | return efi_call_virt(get_next_high_mono_count, count); | 235 | unsigned long flags; |
| 236 | efi_status_t status; | ||
| 237 | |||
| 238 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 239 | status = efi_call_virt(get_next_high_mono_count, count); | ||
| 240 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 241 | return status; | ||
| 115 | } | 242 | } |
| 116 | 243 | ||
| 117 | static void virt_efi_reset_system(int reset_type, | 244 | static void virt_efi_reset_system(int reset_type, |
| @@ -119,17 +246,27 @@ static void virt_efi_reset_system(int reset_type, | |||
| 119 | unsigned long data_size, | 246 | unsigned long data_size, |
| 120 | efi_char16_t *data) | 247 | efi_char16_t *data) |
| 121 | { | 248 | { |
| 249 | unsigned long flags; | ||
| 250 | |||
| 251 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 122 | __efi_call_virt(reset_system, reset_type, status, data_size, data); | 252 | __efi_call_virt(reset_system, reset_type, status, data_size, data); |
| 253 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 123 | } | 254 | } |
| 124 | 255 | ||
| 125 | static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, | 256 | static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, |
| 126 | unsigned long count, | 257 | unsigned long count, |
| 127 | unsigned long sg_list) | 258 | unsigned long sg_list) |
| 128 | { | 259 | { |
| 260 | unsigned long flags; | ||
| 261 | efi_status_t status; | ||
| 262 | |||
| 129 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 263 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
| 130 | return EFI_UNSUPPORTED; | 264 | return EFI_UNSUPPORTED; |
| 131 | 265 | ||
| 132 | return efi_call_virt(update_capsule, capsules, count, sg_list); | 266 | spin_lock_irqsave(&efi_runtime_lock, flags); |
| 267 | status = efi_call_virt(update_capsule, capsules, count, sg_list); | ||
| 268 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 269 | return status; | ||
| 133 | } | 270 | } |
| 134 | 271 | ||
| 135 | static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, | 272 | static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, |
| @@ -137,11 +274,17 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, | |||
| 137 | u64 *max_size, | 274 | u64 *max_size, |
| 138 | int *reset_type) | 275 | int *reset_type) |
| 139 | { | 276 | { |
| 277 | unsigned long flags; | ||
| 278 | efi_status_t status; | ||
| 279 | |||
| 140 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 280 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
| 141 | return EFI_UNSUPPORTED; | 281 | return EFI_UNSUPPORTED; |
| 142 | 282 | ||
| 143 | return efi_call_virt(query_capsule_caps, capsules, count, max_size, | 283 | spin_lock_irqsave(&efi_runtime_lock, flags); |
| 144 | reset_type); | 284 | status = efi_call_virt(query_capsule_caps, capsules, count, max_size, |
| 285 | reset_type); | ||
| 286 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 287 | return status; | ||
| 145 | } | 288 | } |
| 146 | 289 | ||
| 147 | void efi_native_runtime_setup(void) | 290 | void efi_native_runtime_setup(void) |
| @@ -153,6 +296,7 @@ void efi_native_runtime_setup(void) | |||
| 153 | efi.get_variable = virt_efi_get_variable; | 296 | efi.get_variable = virt_efi_get_variable; |
| 154 | efi.get_next_variable = virt_efi_get_next_variable; | 297 | efi.get_next_variable = virt_efi_get_next_variable; |
| 155 | efi.set_variable = virt_efi_set_variable; | 298 | efi.set_variable = virt_efi_set_variable; |
| 299 | efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; | ||
| 156 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; | 300 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; |
| 157 | efi.reset_system = virt_efi_reset_system; | 301 | efi.reset_system = virt_efi_reset_system; |
| 158 | efi.query_variable_info = virt_efi_query_variable_info; | 302 | efi.query_variable_info = virt_efi_query_variable_info; |
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 5abe943e3404..70a0fb10517f 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c | |||
| @@ -321,11 +321,11 @@ static unsigned long var_name_strnsize(efi_char16_t *variable_name, | |||
| 321 | * Print a warning when duplicate EFI variables are encountered and | 321 | * Print a warning when duplicate EFI variables are encountered and |
| 322 | * disable the sysfs workqueue since the firmware is buggy. | 322 | * disable the sysfs workqueue since the firmware is buggy. |
| 323 | */ | 323 | */ |
| 324 | static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | 324 | static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid, |
| 325 | unsigned long len16) | 325 | unsigned long len16) |
| 326 | { | 326 | { |
| 327 | size_t i, len8 = len16 / sizeof(efi_char16_t); | 327 | size_t i, len8 = len16 / sizeof(efi_char16_t); |
| 328 | char *s8; | 328 | char *str8; |
| 329 | 329 | ||
| 330 | /* | 330 | /* |
| 331 | * Disable the workqueue since the algorithm it uses for | 331 | * Disable the workqueue since the algorithm it uses for |
| @@ -334,16 +334,16 @@ static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | |||
| 334 | */ | 334 | */ |
| 335 | efivar_wq_enabled = false; | 335 | efivar_wq_enabled = false; |
| 336 | 336 | ||
| 337 | s8 = kzalloc(len8, GFP_KERNEL); | 337 | str8 = kzalloc(len8, GFP_KERNEL); |
| 338 | if (!s8) | 338 | if (!str8) |
| 339 | return; | 339 | return; |
| 340 | 340 | ||
| 341 | for (i = 0; i < len8; i++) | 341 | for (i = 0; i < len8; i++) |
| 342 | s8[i] = s16[i]; | 342 | str8[i] = str16[i]; |
| 343 | 343 | ||
| 344 | printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", | 344 | printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", |
| 345 | s8, vendor_guid); | 345 | str8, vendor_guid); |
| 346 | kfree(s8); | 346 | kfree(str8); |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | /** | 349 | /** |
| @@ -595,6 +595,39 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | |||
| 595 | } | 595 | } |
| 596 | EXPORT_SYMBOL_GPL(efivar_entry_set); | 596 | EXPORT_SYMBOL_GPL(efivar_entry_set); |
| 597 | 597 | ||
| 598 | /* | ||
| 599 | * efivar_entry_set_nonblocking - call set_variable_nonblocking() | ||
| 600 | * | ||
| 601 | * This function is guaranteed to not block and is suitable for calling | ||
| 602 | * from crash/panic handlers. | ||
| 603 | * | ||
| 604 | * Crucially, this function will not block if it cannot acquire | ||
| 605 | * __efivars->lock. Instead, it returns -EBUSY. | ||
| 606 | */ | ||
| 607 | static int | ||
| 608 | efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor, | ||
| 609 | u32 attributes, unsigned long size, void *data) | ||
| 610 | { | ||
| 611 | const struct efivar_operations *ops = __efivars->ops; | ||
| 612 | unsigned long flags; | ||
| 613 | efi_status_t status; | ||
| 614 | |||
| 615 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) | ||
| 616 | return -EBUSY; | ||
| 617 | |||
| 618 | status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); | ||
| 619 | if (status != EFI_SUCCESS) { | ||
| 620 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
| 621 | return -ENOSPC; | ||
| 622 | } | ||
| 623 | |||
| 624 | status = ops->set_variable_nonblocking(name, &vendor, attributes, | ||
| 625 | size, data); | ||
| 626 | |||
| 627 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
| 628 | return efi_status_to_err(status); | ||
| 629 | } | ||
| 630 | |||
| 598 | /** | 631 | /** |
| 599 | * efivar_entry_set_safe - call set_variable() if enough space in firmware | 632 | * efivar_entry_set_safe - call set_variable() if enough space in firmware |
| 600 | * @name: buffer containing the variable name | 633 | * @name: buffer containing the variable name |
| @@ -622,6 +655,20 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, | |||
| 622 | if (!ops->query_variable_store) | 655 | if (!ops->query_variable_store) |
| 623 | return -ENOSYS; | 656 | return -ENOSYS; |
| 624 | 657 | ||
| 658 | /* | ||
| 659 | * If the EFI variable backend provides a non-blocking | ||
| 660 | * ->set_variable() operation and we're in a context where we | ||
| 661 | * cannot block, then we need to use it to avoid live-locks, | ||
| 662 | * since the implication is that the regular ->set_variable() | ||
| 663 | * will block. | ||
| 664 | * | ||
| 665 | * If no ->set_variable_nonblocking() is provided then | ||
| 666 | * ->set_variable() is assumed to be non-blocking. | ||
| 667 | */ | ||
| 668 | if (!block && ops->set_variable_nonblocking) | ||
| 669 | return efivar_entry_set_nonblocking(name, vendor, attributes, | ||
| 670 | size, data); | ||
| 671 | |||
| 625 | if (!block) { | 672 | if (!block) { |
| 626 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) | 673 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) |
| 627 | return -EBUSY; | 674 | return -EBUSY; |
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c index e705335101a5..c2a1cba1e984 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c | |||
| @@ -32,6 +32,8 @@ static struct drm_driver driver; | |||
| 32 | static const struct pci_device_id pciidlist[] = { | 32 | static const struct pci_device_id pciidlist[] = { |
| 33 | { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, 0x1af4, 0x1100, 0, | 33 | { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, 0x1af4, 0x1100, 0, |
| 34 | 0, 0 }, | 34 | 0, 0 }, |
| 35 | { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, PCI_VENDOR_ID_XEN, | ||
| 36 | 0x0001, 0, 0, 0 }, | ||
| 35 | {0,} | 37 | {0,} |
| 36 | }; | 38 | }; |
| 37 | 39 | ||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3201986bf25e..f66392b6e287 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
| @@ -1711,7 +1711,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, | |||
| 1711 | #define HPD_STORM_DETECT_PERIOD 1000 | 1711 | #define HPD_STORM_DETECT_PERIOD 1000 |
| 1712 | #define HPD_STORM_THRESHOLD 5 | 1712 | #define HPD_STORM_THRESHOLD 5 |
| 1713 | 1713 | ||
| 1714 | static int ilk_port_to_hotplug_shift(enum port port) | 1714 | static int pch_port_to_hotplug_shift(enum port port) |
| 1715 | { | 1715 | { |
| 1716 | switch (port) { | 1716 | switch (port) { |
| 1717 | case PORT_A: | 1717 | case PORT_A: |
| @@ -1727,7 +1727,7 @@ static int ilk_port_to_hotplug_shift(enum port port) | |||
| 1727 | } | 1727 | } |
| 1728 | } | 1728 | } |
| 1729 | 1729 | ||
| 1730 | static int g4x_port_to_hotplug_shift(enum port port) | 1730 | static int i915_port_to_hotplug_shift(enum port port) |
| 1731 | { | 1731 | { |
| 1732 | switch (port) { | 1732 | switch (port) { |
| 1733 | case PORT_A: | 1733 | case PORT_A: |
| @@ -1785,12 +1785,12 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, | |||
| 1785 | if (port && dev_priv->hpd_irq_port[port]) { | 1785 | if (port && dev_priv->hpd_irq_port[port]) { |
| 1786 | bool long_hpd; | 1786 | bool long_hpd; |
| 1787 | 1787 | ||
| 1788 | if (IS_G4X(dev)) { | 1788 | if (HAS_PCH_SPLIT(dev)) { |
| 1789 | dig_shift = g4x_port_to_hotplug_shift(port); | 1789 | dig_shift = pch_port_to_hotplug_shift(port); |
| 1790 | long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; | ||
| 1791 | } else { | ||
| 1792 | dig_shift = ilk_port_to_hotplug_shift(port); | ||
| 1793 | long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; | 1790 | long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; |
| 1791 | } else { | ||
| 1792 | dig_shift = i915_port_to_hotplug_shift(port); | ||
| 1793 | long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; | ||
| 1794 | } | 1794 | } |
| 1795 | 1795 | ||
| 1796 | DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", | 1796 | DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", |
| @@ -3458,12 +3458,13 @@ static void gen8_irq_reset(struct drm_device *dev) | |||
| 3458 | void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv) | 3458 | void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv) |
| 3459 | { | 3459 | { |
| 3460 | unsigned long irqflags; | 3460 | unsigned long irqflags; |
| 3461 | uint32_t extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN; | ||
| 3461 | 3462 | ||
| 3462 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); | 3463 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
| 3463 | GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_B, dev_priv->de_irq_mask[PIPE_B], | 3464 | GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_B, dev_priv->de_irq_mask[PIPE_B], |
| 3464 | ~dev_priv->de_irq_mask[PIPE_B]); | 3465 | ~dev_priv->de_irq_mask[PIPE_B] | extra_ier); |
| 3465 | GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_C, dev_priv->de_irq_mask[PIPE_C], | 3466 | GEN8_IRQ_INIT_NDX(DE_PIPE, PIPE_C, dev_priv->de_irq_mask[PIPE_C], |
| 3466 | ~dev_priv->de_irq_mask[PIPE_C]); | 3467 | ~dev_priv->de_irq_mask[PIPE_C] | extra_ier); |
| 3467 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | 3468 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
| 3468 | } | 3469 | } |
| 3469 | 3470 | ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 507370513f3d..c9e220963a78 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -73,9 +73,6 @@ static const uint32_t intel_cursor_formats[] = { | |||
| 73 | DRM_FORMAT_ARGB8888, | 73 | DRM_FORMAT_ARGB8888, |
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| 76 | #define DIV_ROUND_CLOSEST_ULL(ll, d) \ | ||
| 77 | ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) | ||
| 78 | |||
| 79 | static void intel_increase_pllclock(struct drm_device *dev, | 76 | static void intel_increase_pllclock(struct drm_device *dev, |
| 80 | enum pipe pipe); | 77 | enum pipe pipe); |
| 81 | static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); | 78 | static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); |
| @@ -12357,27 +12354,36 @@ static void intel_setup_outputs(struct drm_device *dev) | |||
| 12357 | if (I915_READ(PCH_DP_D) & DP_DETECTED) | 12354 | if (I915_READ(PCH_DP_D) & DP_DETECTED) |
| 12358 | intel_dp_init(dev, PCH_DP_D, PORT_D); | 12355 | intel_dp_init(dev, PCH_DP_D, PORT_D); |
| 12359 | } else if (IS_VALLEYVIEW(dev)) { | 12356 | } else if (IS_VALLEYVIEW(dev)) { |
| 12360 | if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) { | 12357 | /* |
| 12358 | * The DP_DETECTED bit is the latched state of the DDC | ||
| 12359 | * SDA pin at boot. However since eDP doesn't require DDC | ||
| 12360 | * (no way to plug in a DP->HDMI dongle) the DDC pins for | ||
| 12361 | * eDP ports may have been muxed to an alternate function. | ||
| 12362 | * Thus we can't rely on the DP_DETECTED bit alone to detect | ||
| 12363 | * eDP ports. Consult the VBT as well as DP_DETECTED to | ||
| 12364 | * detect eDP ports. | ||
| 12365 | */ | ||
| 12366 | if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED) | ||
| 12361 | intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, | 12367 | intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB, |
| 12362 | PORT_B); | 12368 | PORT_B); |
| 12363 | if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) | 12369 | if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED || |
| 12364 | intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); | 12370 | intel_dp_is_edp(dev, PORT_B)) |
| 12365 | } | 12371 | intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); |
| 12366 | 12372 | ||
| 12367 | if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) { | 12373 | if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) |
| 12368 | intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC, | 12374 | intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC, |
| 12369 | PORT_C); | 12375 | PORT_C); |
| 12370 | if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED) | 12376 | if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED || |
| 12371 | intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); | 12377 | intel_dp_is_edp(dev, PORT_C)) |
| 12372 | } | 12378 | intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); |
| 12373 | 12379 | ||
| 12374 | if (IS_CHERRYVIEW(dev)) { | 12380 | if (IS_CHERRYVIEW(dev)) { |
| 12375 | if (I915_READ(VLV_DISPLAY_BASE + CHV_HDMID) & SDVO_DETECTED) { | 12381 | if (I915_READ(VLV_DISPLAY_BASE + CHV_HDMID) & SDVO_DETECTED) |
| 12376 | intel_hdmi_init(dev, VLV_DISPLAY_BASE + CHV_HDMID, | 12382 | intel_hdmi_init(dev, VLV_DISPLAY_BASE + CHV_HDMID, |
| 12377 | PORT_D); | 12383 | PORT_D); |
| 12378 | if (I915_READ(VLV_DISPLAY_BASE + DP_D) & DP_DETECTED) | 12384 | /* eDP not supported on port D, so don't check VBT */ |
| 12379 | intel_dp_init(dev, VLV_DISPLAY_BASE + DP_D, PORT_D); | 12385 | if (I915_READ(VLV_DISPLAY_BASE + DP_D) & DP_DETECTED) |
| 12380 | } | 12386 | intel_dp_init(dev, VLV_DISPLAY_BASE + DP_D, PORT_D); |
| 12381 | } | 12387 | } |
| 12382 | 12388 | ||
| 12383 | intel_dsi_init(dev); | 12389 | intel_dsi_init(dev); |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 07ce04683c30..ba715229a540 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -35,6 +35,9 @@ | |||
| 35 | #include <drm/drm_fb_helper.h> | 35 | #include <drm/drm_fb_helper.h> |
| 36 | #include <drm/drm_dp_mst_helper.h> | 36 | #include <drm/drm_dp_mst_helper.h> |
| 37 | 37 | ||
| 38 | #define DIV_ROUND_CLOSEST_ULL(ll, d) \ | ||
| 39 | ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; }) | ||
| 40 | |||
| 38 | /** | 41 | /** |
| 39 | * _wait_for - magic (register) wait macro | 42 | * _wait_for - magic (register) wait macro |
| 40 | * | 43 | * |
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 18784470a760..0e018cb49147 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
| @@ -419,9 +419,8 @@ static uint32_t scale(uint32_t source_val, | |||
| 419 | source_val = clamp(source_val, source_min, source_max); | 419 | source_val = clamp(source_val, source_min, source_max); |
| 420 | 420 | ||
| 421 | /* avoid overflows */ | 421 | /* avoid overflows */ |
| 422 | target_val = (uint64_t)(source_val - source_min) * | 422 | target_val = DIV_ROUND_CLOSEST_ULL((uint64_t)(source_val - source_min) * |
| 423 | (target_max - target_min); | 423 | (target_max - target_min), source_max - source_min); |
| 424 | do_div(target_val, source_max - source_min); | ||
| 425 | target_val += target_min; | 424 | target_val += target_min; |
| 426 | 425 | ||
| 427 | return target_val; | 426 | return target_val; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c index 552fdbd45ebe..1d0e33fb5f61 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c | |||
| @@ -113,6 +113,8 @@ | |||
| 113 | #define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf) | 113 | #define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf) |
| 114 | #define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac) | 114 | #define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac) |
| 115 | 115 | ||
| 116 | #include <subdev/fb.h> | ||
| 117 | |||
| 116 | /* | 118 | /* |
| 117 | * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's | 119 | * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's |
| 118 | * the GPU itself that does context-switching, but it needs a special | 120 | * the GPU itself that does context-switching, but it needs a special |
| @@ -569,8 +571,12 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) | |||
| 569 | gr_def(ctx, 0x407d08, 0x00010040); | 571 | gr_def(ctx, 0x407d08, 0x00010040); |
| 570 | else if (device->chipset < 0xa0) | 572 | else if (device->chipset < 0xa0) |
| 571 | gr_def(ctx, 0x407d08, 0x00390040); | 573 | gr_def(ctx, 0x407d08, 0x00390040); |
| 572 | else | 574 | else { |
| 573 | gr_def(ctx, 0x407d08, 0x003d0040); | 575 | if (nouveau_fb(device)->ram->type != NV_MEM_TYPE_GDDR5) |
| 576 | gr_def(ctx, 0x407d08, 0x003d0040); | ||
| 577 | else | ||
| 578 | gr_def(ctx, 0x407d08, 0x003c0040); | ||
| 579 | } | ||
| 574 | gr_def(ctx, 0x407d0c, 0x00000022); | 580 | gr_def(ctx, 0x407d0c, 0x00000022); |
| 575 | } | 581 | } |
| 576 | 582 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 589dbb582da2..fd3dbd59d73e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c | |||
| @@ -400,15 +400,20 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, | |||
| 400 | struct nouveau_channel **pchan) | 400 | struct nouveau_channel **pchan) |
| 401 | { | 401 | { |
| 402 | struct nouveau_cli *cli = (void *)nvif_client(&device->base); | 402 | struct nouveau_cli *cli = (void *)nvif_client(&device->base); |
| 403 | bool super; | ||
| 403 | int ret; | 404 | int ret; |
| 404 | 405 | ||
| 406 | /* hack until fencenv50 is fixed, and agp access relaxed */ | ||
| 407 | super = cli->base.super; | ||
| 408 | cli->base.super = true; | ||
| 409 | |||
| 405 | ret = nouveau_channel_ind(drm, device, handle, arg0, pchan); | 410 | ret = nouveau_channel_ind(drm, device, handle, arg0, pchan); |
| 406 | if (ret) { | 411 | if (ret) { |
| 407 | NV_PRINTK(debug, cli, "ib channel create, %d\n", ret); | 412 | NV_PRINTK(debug, cli, "ib channel create, %d\n", ret); |
| 408 | ret = nouveau_channel_dma(drm, device, handle, pchan); | 413 | ret = nouveau_channel_dma(drm, device, handle, pchan); |
| 409 | if (ret) { | 414 | if (ret) { |
| 410 | NV_PRINTK(debug, cli, "dma channel create, %d\n", ret); | 415 | NV_PRINTK(debug, cli, "dma channel create, %d\n", ret); |
| 411 | return ret; | 416 | goto done; |
| 412 | } | 417 | } |
| 413 | } | 418 | } |
| 414 | 419 | ||
| @@ -416,8 +421,9 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, | |||
| 416 | if (ret) { | 421 | if (ret) { |
| 417 | NV_PRINTK(error, cli, "channel failed to initialise, %d\n", ret); | 422 | NV_PRINTK(error, cli, "channel failed to initialise, %d\n", ret); |
| 418 | nouveau_channel_del(pchan); | 423 | nouveau_channel_del(pchan); |
| 419 | return ret; | ||
| 420 | } | 424 | } |
| 421 | 425 | ||
| 422 | return 0; | 426 | done: |
| 427 | cli->base.super = super; | ||
| 428 | return ret; | ||
| 423 | } | 429 | } |
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index af9e78546688..0d1396266857 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c | |||
| @@ -572,7 +572,6 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, | |||
| 572 | struct qxl_framebuffer *qfb; | 572 | struct qxl_framebuffer *qfb; |
| 573 | struct qxl_bo *bo, *old_bo = NULL; | 573 | struct qxl_bo *bo, *old_bo = NULL; |
| 574 | struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); | 574 | struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); |
| 575 | uint32_t width, height, base_offset; | ||
| 576 | bool recreate_primary = false; | 575 | bool recreate_primary = false; |
| 577 | int ret; | 576 | int ret; |
| 578 | int surf_id; | 577 | int surf_id; |
| @@ -602,9 +601,10 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, | |||
| 602 | if (qcrtc->index == 0) | 601 | if (qcrtc->index == 0) |
| 603 | recreate_primary = true; | 602 | recreate_primary = true; |
| 604 | 603 | ||
| 605 | width = mode->hdisplay; | 604 | if (bo->surf.stride * bo->surf.height > qdev->vram_size) { |
| 606 | height = mode->vdisplay; | 605 | DRM_ERROR("Mode doesn't fit in vram size (vgamem)"); |
| 607 | base_offset = 0; | 606 | return -EINVAL; |
| 607 | } | ||
| 608 | 608 | ||
| 609 | ret = qxl_bo_reserve(bo, false); | 609 | ret = qxl_bo_reserve(bo, false); |
| 610 | if (ret != 0) | 610 | if (ret != 0) |
| @@ -618,10 +618,10 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, | |||
| 618 | if (recreate_primary) { | 618 | if (recreate_primary) { |
| 619 | qxl_io_destroy_primary(qdev); | 619 | qxl_io_destroy_primary(qdev); |
| 620 | qxl_io_log(qdev, | 620 | qxl_io_log(qdev, |
| 621 | "recreate primary: %dx%d (was %dx%d,%d,%d)\n", | 621 | "recreate primary: %dx%d,%d,%d\n", |
| 622 | width, height, bo->surf.width, | 622 | bo->surf.width, bo->surf.height, |
| 623 | bo->surf.height, bo->surf.stride, bo->surf.format); | 623 | bo->surf.stride, bo->surf.format); |
| 624 | qxl_io_create_primary(qdev, base_offset, bo); | 624 | qxl_io_create_primary(qdev, 0, bo); |
| 625 | bo->is_primary = true; | 625 | bo->is_primary = true; |
| 626 | } | 626 | } |
| 627 | 627 | ||
diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index 300d971187c4..0b2929de9f41 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include "drmP.h" | 25 | #include "drmP.h" |
| 26 | #include "radeon.h" | 26 | #include "radeon.h" |
| 27 | #include "radeon_asic.h" | ||
| 27 | #include "btcd.h" | 28 | #include "btcd.h" |
| 28 | #include "r600_dpm.h" | 29 | #include "r600_dpm.h" |
| 29 | #include "cypress_dpm.h" | 30 | #include "cypress_dpm.h" |
| @@ -1170,6 +1171,23 @@ static const struct radeon_blacklist_clocks btc_blacklist_clocks[] = | |||
| 1170 | { 25000, 30000, RADEON_SCLK_UP } | 1171 | { 25000, 30000, RADEON_SCLK_UP } |
| 1171 | }; | 1172 | }; |
| 1172 | 1173 | ||
| 1174 | void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table, | ||
| 1175 | u32 *max_clock) | ||
| 1176 | { | ||
| 1177 | u32 i, clock = 0; | ||
| 1178 | |||
| 1179 | if ((table == NULL) || (table->count == 0)) { | ||
| 1180 | *max_clock = clock; | ||
| 1181 | return; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | for (i = 0; i < table->count; i++) { | ||
| 1185 | if (clock < table->entries[i].clk) | ||
| 1186 | clock = table->entries[i].clk; | ||
| 1187 | } | ||
| 1188 | *max_clock = clock; | ||
| 1189 | } | ||
| 1190 | |||
| 1173 | void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table, | 1191 | void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table, |
| 1174 | u32 clock, u16 max_voltage, u16 *voltage) | 1192 | u32 clock, u16 max_voltage, u16 *voltage) |
| 1175 | { | 1193 | { |
diff --git a/drivers/gpu/drm/radeon/btc_dpm.h b/drivers/gpu/drm/radeon/btc_dpm.h index 1a15e0e41950..3b6f12b7760b 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.h +++ b/drivers/gpu/drm/radeon/btc_dpm.h | |||
| @@ -46,6 +46,8 @@ void btc_adjust_clock_combinations(struct radeon_device *rdev, | |||
| 46 | struct rv7xx_pl *pl); | 46 | struct rv7xx_pl *pl); |
| 47 | void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table, | 47 | void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table, |
| 48 | u32 clock, u16 max_voltage, u16 *voltage); | 48 | u32 clock, u16 max_voltage, u16 *voltage); |
| 49 | void btc_get_max_clock_from_voltage_dependency_table(struct radeon_clock_voltage_dependency_table *table, | ||
| 50 | u32 *max_clock); | ||
| 49 | void btc_apply_voltage_delta_rules(struct radeon_device *rdev, | 51 | void btc_apply_voltage_delta_rules(struct radeon_device *rdev, |
| 50 | u16 max_vddc, u16 max_vddci, | 52 | u16 max_vddc, u16 max_vddci, |
| 51 | u16 *vddc, u16 *vddci); | 53 | u16 *vddc, u16 *vddci); |
diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index f5c8c0445a94..11a55e9dad7f 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
| 25 | #include "drmP.h" | 25 | #include "drmP.h" |
| 26 | #include "radeon.h" | 26 | #include "radeon.h" |
| 27 | #include "radeon_asic.h" | ||
| 27 | #include "radeon_ucode.h" | 28 | #include "radeon_ucode.h" |
| 28 | #include "cikd.h" | 29 | #include "cikd.h" |
| 29 | #include "r600_dpm.h" | 30 | #include "r600_dpm.h" |
diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index c77dad1a4576..4e8432d07f15 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c | |||
| @@ -611,16 +611,19 @@ int cik_sdma_ring_test(struct radeon_device *rdev, | |||
| 611 | { | 611 | { |
| 612 | unsigned i; | 612 | unsigned i; |
| 613 | int r; | 613 | int r; |
| 614 | void __iomem *ptr = (void *)rdev->vram_scratch.ptr; | 614 | unsigned index; |
| 615 | u32 tmp; | 615 | u32 tmp; |
| 616 | u64 gpu_addr; | ||
| 616 | 617 | ||
| 617 | if (!ptr) { | 618 | if (ring->idx == R600_RING_TYPE_DMA_INDEX) |
| 618 | DRM_ERROR("invalid vram scratch pointer\n"); | 619 | index = R600_WB_DMA_RING_TEST_OFFSET; |
| 619 | return -EINVAL; | 620 | else |
| 620 | } | 621 | index = CAYMAN_WB_DMA1_RING_TEST_OFFSET; |
| 622 | |||
| 623 | gpu_addr = rdev->wb.gpu_addr + index; | ||
| 621 | 624 | ||
| 622 | tmp = 0xCAFEDEAD; | 625 | tmp = 0xCAFEDEAD; |
| 623 | writel(tmp, ptr); | 626 | rdev->wb.wb[index/4] = cpu_to_le32(tmp); |
| 624 | 627 | ||
| 625 | r = radeon_ring_lock(rdev, ring, 5); | 628 | r = radeon_ring_lock(rdev, ring, 5); |
| 626 | if (r) { | 629 | if (r) { |
| @@ -628,14 +631,14 @@ int cik_sdma_ring_test(struct radeon_device *rdev, | |||
| 628 | return r; | 631 | return r; |
| 629 | } | 632 | } |
| 630 | radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0)); | 633 | radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0)); |
| 631 | radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc); | 634 | radeon_ring_write(ring, lower_32_bits(gpu_addr)); |
| 632 | radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr)); | 635 | radeon_ring_write(ring, upper_32_bits(gpu_addr)); |
| 633 | radeon_ring_write(ring, 1); /* number of DWs to follow */ | 636 | radeon_ring_write(ring, 1); /* number of DWs to follow */ |
| 634 | radeon_ring_write(ring, 0xDEADBEEF); | 637 | radeon_ring_write(ring, 0xDEADBEEF); |
| 635 | radeon_ring_unlock_commit(rdev, ring, false); | 638 | radeon_ring_unlock_commit(rdev, ring, false); |
| 636 | 639 | ||
| 637 | for (i = 0; i < rdev->usec_timeout; i++) { | 640 | for (i = 0; i < rdev->usec_timeout; i++) { |
| 638 | tmp = readl(ptr); | 641 | tmp = le32_to_cpu(rdev->wb.wb[index/4]); |
| 639 | if (tmp == 0xDEADBEEF) | 642 | if (tmp == 0xDEADBEEF) |
| 640 | break; | 643 | break; |
| 641 | DRM_UDELAY(1); | 644 | DRM_UDELAY(1); |
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c index 47d31e915758..9aad0327e4d1 100644 --- a/drivers/gpu/drm/radeon/cypress_dpm.c +++ b/drivers/gpu/drm/radeon/cypress_dpm.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include "drmP.h" | 25 | #include "drmP.h" |
| 26 | #include "radeon.h" | 26 | #include "radeon.h" |
| 27 | #include "radeon_asic.h" | ||
| 27 | #include "evergreend.h" | 28 | #include "evergreend.h" |
| 28 | #include "r600_dpm.h" | 29 | #include "r600_dpm.h" |
| 29 | #include "cypress_dpm.h" | 30 | #include "cypress_dpm.h" |
diff --git a/drivers/gpu/drm/radeon/dce3_1_afmt.c b/drivers/gpu/drm/radeon/dce3_1_afmt.c index 950af153f30e..2fe8cfc966d9 100644 --- a/drivers/gpu/drm/radeon/dce3_1_afmt.c +++ b/drivers/gpu/drm/radeon/dce3_1_afmt.c | |||
| @@ -32,7 +32,7 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) | |||
| 32 | struct drm_connector *connector; | 32 | struct drm_connector *connector; |
| 33 | struct radeon_connector *radeon_connector = NULL; | 33 | struct radeon_connector *radeon_connector = NULL; |
| 34 | u32 tmp; | 34 | u32 tmp; |
| 35 | u8 *sadb; | 35 | u8 *sadb = NULL; |
| 36 | int sad_count; | 36 | int sad_count; |
| 37 | 37 | ||
| 38 | list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { | 38 | list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { |
| @@ -49,8 +49,8 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) | |||
| 49 | 49 | ||
| 50 | sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); | 50 | sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb); |
| 51 | if (sad_count < 0) { | 51 | if (sad_count < 0) { |
| 52 | DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); | 52 | DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); |
| 53 | return; | 53 | sad_count = 0; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | /* program the speaker allocation */ | 56 | /* program the speaker allocation */ |
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index c0bbf68dbc27..f312edf4d50e 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c | |||
| @@ -155,7 +155,7 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder) | |||
| 155 | struct drm_connector *connector; | 155 | struct drm_connector *connector; |
| 156 | struct radeon_connector *radeon_connector = NULL; | 156 | struct radeon_connector *radeon_connector = NULL; |
| 157 | u32 offset, tmp; | 157 | u32 offset, tmp; |
| 158 | u8 *sadb; | 158 | u8 *sadb = NULL; |
| 159 | int sad_count; | 159 | int sad_count; |
| 160 | 160 | ||
| 161 | if (!dig || !dig->afmt || !dig->afmt->pin) | 161 | if (!dig || !dig->afmt || !dig->afmt->pin) |
| @@ -176,9 +176,9 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder) | |||
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); | 178 | sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); |
| 179 | if (sad_count <= 0) { | 179 | if (sad_count < 0) { |
| 180 | DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); | 180 | DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); |
| 181 | return; | 181 | sad_count = 0; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | /* program the speaker allocation */ | 184 | /* program the speaker allocation */ |
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index 2514d659b1ba..53abd9b17a50 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c | |||
| @@ -133,7 +133,7 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder) | |||
| 133 | struct drm_connector *connector; | 133 | struct drm_connector *connector; |
| 134 | struct radeon_connector *radeon_connector = NULL; | 134 | struct radeon_connector *radeon_connector = NULL; |
| 135 | u32 tmp; | 135 | u32 tmp; |
| 136 | u8 *sadb; | 136 | u8 *sadb = NULL; |
| 137 | int sad_count; | 137 | int sad_count; |
| 138 | 138 | ||
| 139 | list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { | 139 | list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { |
| @@ -149,9 +149,9 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder) | |||
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); | 151 | sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb); |
| 152 | if (sad_count <= 0) { | 152 | if (sad_count < 0) { |
| 153 | DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); | 153 | DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count); |
| 154 | return; | 154 | sad_count = 0; |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | /* program the speaker allocation */ | 157 | /* program the speaker allocation */ |
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 715b181c6243..6d2f16cf2c1c 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | 23 | ||
| 24 | #include "drmP.h" | 24 | #include "drmP.h" |
| 25 | #include "radeon.h" | 25 | #include "radeon.h" |
| 26 | #include "radeon_asic.h" | ||
| 26 | #include "nid.h" | 27 | #include "nid.h" |
| 27 | #include "r600_dpm.h" | 28 | #include "r600_dpm.h" |
| 28 | #include "ni_dpm.h" | 29 | #include "ni_dpm.h" |
diff --git a/drivers/gpu/drm/radeon/r600_dma.c b/drivers/gpu/drm/radeon/r600_dma.c index 100189ec5fa8..aabc343b9a8f 100644 --- a/drivers/gpu/drm/radeon/r600_dma.c +++ b/drivers/gpu/drm/radeon/r600_dma.c | |||
| @@ -232,16 +232,19 @@ int r600_dma_ring_test(struct radeon_device *rdev, | |||
| 232 | { | 232 | { |
| 233 | unsigned i; | 233 | unsigned i; |
| 234 | int r; | 234 | int r; |
| 235 | void __iomem *ptr = (void *)rdev->vram_scratch.ptr; | 235 | unsigned index; |
| 236 | u32 tmp; | 236 | u32 tmp; |
| 237 | u64 gpu_addr; | ||
| 237 | 238 | ||
| 238 | if (!ptr) { | 239 | if (ring->idx == R600_RING_TYPE_DMA_INDEX) |
| 239 | DRM_ERROR("invalid vram scratch pointer\n"); | 240 | index = R600_WB_DMA_RING_TEST_OFFSET; |
| 240 | return -EINVAL; | 241 | else |
| 241 | } | 242 | index = CAYMAN_WB_DMA1_RING_TEST_OFFSET; |
| 243 | |||
| 244 | gpu_addr = rdev->wb.gpu_addr + index; | ||
| 242 | 245 | ||
| 243 | tmp = 0xCAFEDEAD; | 246 | tmp = 0xCAFEDEAD; |
| 244 | writel(tmp, ptr); | 247 | rdev->wb.wb[index/4] = cpu_to_le32(tmp); |
| 245 | 248 | ||
| 246 | r = radeon_ring_lock(rdev, ring, 4); | 249 | r = radeon_ring_lock(rdev, ring, 4); |
| 247 | if (r) { | 250 | if (r) { |
| @@ -249,13 +252,13 @@ int r600_dma_ring_test(struct radeon_device *rdev, | |||
| 249 | return r; | 252 | return r; |
| 250 | } | 253 | } |
| 251 | radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); | 254 | radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1)); |
| 252 | radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc); | 255 | radeon_ring_write(ring, lower_32_bits(gpu_addr)); |
| 253 | radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff); | 256 | radeon_ring_write(ring, upper_32_bits(gpu_addr) & 0xff); |
| 254 | radeon_ring_write(ring, 0xDEADBEEF); | 257 | radeon_ring_write(ring, 0xDEADBEEF); |
| 255 | radeon_ring_unlock_commit(rdev, ring, false); | 258 | radeon_ring_unlock_commit(rdev, ring, false); |
| 256 | 259 | ||
| 257 | for (i = 0; i < rdev->usec_timeout; i++) { | 260 | for (i = 0; i < rdev->usec_timeout; i++) { |
| 258 | tmp = readl(ptr); | 261 | tmp = le32_to_cpu(rdev->wb.wb[index/4]); |
| 259 | if (tmp == 0xDEADBEEF) | 262 | if (tmp == 0xDEADBEEF) |
| 260 | break; | 263 | break; |
| 261 | DRM_UDELAY(1); | 264 | DRM_UDELAY(1); |
diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 9c61b74ef441..f6309bd23e01 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include "drmP.h" | 25 | #include "drmP.h" |
| 26 | #include "radeon.h" | 26 | #include "radeon.h" |
| 27 | #include "radeon_asic.h" | ||
| 27 | #include "r600d.h" | 28 | #include "r600d.h" |
| 28 | #include "r600_dpm.h" | 29 | #include "r600_dpm.h" |
| 29 | #include "atom.h" | 30 | #include "atom.h" |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index f7c4b226a284..a9717b3fbf1b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
| @@ -1133,6 +1133,8 @@ struct radeon_wb { | |||
| 1133 | #define R600_WB_EVENT_OFFSET 3072 | 1133 | #define R600_WB_EVENT_OFFSET 3072 |
| 1134 | #define CIK_WB_CP1_WPTR_OFFSET 3328 | 1134 | #define CIK_WB_CP1_WPTR_OFFSET 3328 |
| 1135 | #define CIK_WB_CP2_WPTR_OFFSET 3584 | 1135 | #define CIK_WB_CP2_WPTR_OFFSET 3584 |
| 1136 | #define R600_WB_DMA_RING_TEST_OFFSET 3588 | ||
| 1137 | #define CAYMAN_WB_DMA1_RING_TEST_OFFSET 3592 | ||
| 1136 | 1138 | ||
| 1137 | /** | 1139 | /** |
| 1138 | * struct radeon_pm - power management datas | 1140 | * struct radeon_pm - power management datas |
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index f41cc1538e48..ea2676954dde 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c | |||
| @@ -1130,7 +1130,7 @@ static void radeon_check_arguments(struct radeon_device *rdev) | |||
| 1130 | if (radeon_vm_block_size == -1) { | 1130 | if (radeon_vm_block_size == -1) { |
| 1131 | 1131 | ||
| 1132 | /* Total bits covered by PD + PTs */ | 1132 | /* Total bits covered by PD + PTs */ |
| 1133 | unsigned bits = ilog2(radeon_vm_size) + 17; | 1133 | unsigned bits = ilog2(radeon_vm_size) + 18; |
| 1134 | 1134 | ||
| 1135 | /* Make sure the PD is 4K in size up to 8GB address space. | 1135 | /* Make sure the PD is 4K in size up to 8GB address space. |
| 1136 | Above that split equal between PD and PTs */ | 1136 | Above that split equal between PD and PTs */ |
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c index 02f7710de470..9031f4b69824 100644 --- a/drivers/gpu/drm/radeon/rs780_dpm.c +++ b/drivers/gpu/drm/radeon/rs780_dpm.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include "drmP.h" | 25 | #include "drmP.h" |
| 26 | #include "radeon.h" | 26 | #include "radeon.h" |
| 27 | #include "radeon_asic.h" | ||
| 27 | #include "rs780d.h" | 28 | #include "rs780d.h" |
| 28 | #include "r600_dpm.h" | 29 | #include "r600_dpm.h" |
| 29 | #include "rs780_dpm.h" | 30 | #include "rs780_dpm.h" |
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index e7045b085715..6a5c233361e9 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include "drmP.h" | 25 | #include "drmP.h" |
| 26 | #include "radeon.h" | 26 | #include "radeon.h" |
| 27 | #include "radeon_asic.h" | ||
| 27 | #include "rv6xxd.h" | 28 | #include "rv6xxd.h" |
| 28 | #include "r600_dpm.h" | 29 | #include "r600_dpm.h" |
| 29 | #include "rv6xx_dpm.h" | 30 | #include "rv6xx_dpm.h" |
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 3c76e1dcdf04..755a8f96fe46 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include "drmP.h" | 25 | #include "drmP.h" |
| 26 | #include "radeon.h" | 26 | #include "radeon.h" |
| 27 | #include "radeon_asic.h" | ||
| 27 | #include "rv770d.h" | 28 | #include "rv770d.h" |
| 28 | #include "r600_dpm.h" | 29 | #include "r600_dpm.h" |
| 29 | #include "rv770_dpm.h" | 30 | #include "rv770_dpm.h" |
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 9e4d5d7d348f..a53c2e79d9cb 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | 23 | ||
| 24 | #include "drmP.h" | 24 | #include "drmP.h" |
| 25 | #include "radeon.h" | 25 | #include "radeon.h" |
| 26 | #include "radeon_asic.h" | ||
| 26 | #include "sid.h" | 27 | #include "sid.h" |
| 27 | #include "r600_dpm.h" | 28 | #include "r600_dpm.h" |
| 28 | #include "si_dpm.h" | 29 | #include "si_dpm.h" |
| @@ -2916,6 +2917,7 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, | |||
| 2916 | bool disable_sclk_switching = false; | 2917 | bool disable_sclk_switching = false; |
| 2917 | u32 mclk, sclk; | 2918 | u32 mclk, sclk; |
| 2918 | u16 vddc, vddci; | 2919 | u16 vddc, vddci; |
| 2920 | u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; | ||
| 2919 | int i; | 2921 | int i; |
| 2920 | 2922 | ||
| 2921 | if ((rdev->pm.dpm.new_active_crtc_count > 1) || | 2923 | if ((rdev->pm.dpm.new_active_crtc_count > 1) || |
| @@ -2949,6 +2951,29 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, | |||
| 2949 | } | 2951 | } |
| 2950 | } | 2952 | } |
| 2951 | 2953 | ||
| 2954 | /* limit clocks to max supported clocks based on voltage dependency tables */ | ||
| 2955 | btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk, | ||
| 2956 | &max_sclk_vddc); | ||
| 2957 | btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, | ||
| 2958 | &max_mclk_vddci); | ||
| 2959 | btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, | ||
| 2960 | &max_mclk_vddc); | ||
| 2961 | |||
| 2962 | for (i = 0; i < ps->performance_level_count; i++) { | ||
| 2963 | if (max_sclk_vddc) { | ||
| 2964 | if (ps->performance_levels[i].sclk > max_sclk_vddc) | ||
| 2965 | ps->performance_levels[i].sclk = max_sclk_vddc; | ||
| 2966 | } | ||
| 2967 | if (max_mclk_vddci) { | ||
| 2968 | if (ps->performance_levels[i].mclk > max_mclk_vddci) | ||
| 2969 | ps->performance_levels[i].mclk = max_mclk_vddci; | ||
| 2970 | } | ||
| 2971 | if (max_mclk_vddc) { | ||
| 2972 | if (ps->performance_levels[i].mclk > max_mclk_vddc) | ||
| 2973 | ps->performance_levels[i].mclk = max_mclk_vddc; | ||
| 2974 | } | ||
| 2975 | } | ||
| 2976 | |||
| 2952 | /* XXX validate the min clocks required for display */ | 2977 | /* XXX validate the min clocks required for display */ |
| 2953 | 2978 | ||
| 2954 | if (disable_mclk_switching) { | 2979 | if (disable_mclk_switching) { |
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index 3f0e8d7b8dbe..1f8a8833e1be 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | 23 | ||
| 24 | #include "drmP.h" | 24 | #include "drmP.h" |
| 25 | #include "radeon.h" | 25 | #include "radeon.h" |
| 26 | #include "radeon_asic.h" | ||
| 26 | #include "sumod.h" | 27 | #include "sumod.h" |
| 27 | #include "r600_dpm.h" | 28 | #include "r600_dpm.h" |
| 28 | #include "cypress_dpm.h" | 29 | #include "cypress_dpm.h" |
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 57f780053b3e..b4ec5c4e7969 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | 23 | ||
| 24 | #include "drmP.h" | 24 | #include "drmP.h" |
| 25 | #include "radeon.h" | 25 | #include "radeon.h" |
| 26 | #include "radeon_asic.h" | ||
| 26 | #include "trinityd.h" | 27 | #include "trinityd.h" |
| 27 | #include "r600_dpm.h" | 28 | #include "r600_dpm.h" |
| 28 | #include "trinity_dpm.h" | 29 | #include "trinity_dpm.h" |
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 8f5cec67c47d..d395b0bef73b 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c | |||
| @@ -709,6 +709,7 @@ out: | |||
| 709 | 709 | ||
| 710 | static int ttm_mem_evict_first(struct ttm_bo_device *bdev, | 710 | static int ttm_mem_evict_first(struct ttm_bo_device *bdev, |
| 711 | uint32_t mem_type, | 711 | uint32_t mem_type, |
| 712 | const struct ttm_place *place, | ||
| 712 | bool interruptible, | 713 | bool interruptible, |
| 713 | bool no_wait_gpu) | 714 | bool no_wait_gpu) |
| 714 | { | 715 | { |
| @@ -720,8 +721,21 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, | |||
| 720 | spin_lock(&glob->lru_lock); | 721 | spin_lock(&glob->lru_lock); |
| 721 | list_for_each_entry(bo, &man->lru, lru) { | 722 | list_for_each_entry(bo, &man->lru, lru) { |
| 722 | ret = __ttm_bo_reserve(bo, false, true, false, NULL); | 723 | ret = __ttm_bo_reserve(bo, false, true, false, NULL); |
| 723 | if (!ret) | 724 | if (!ret) { |
| 725 | if (place && (place->fpfn || place->lpfn)) { | ||
| 726 | /* Don't evict this BO if it's outside of the | ||
| 727 | * requested placement range | ||
| 728 | */ | ||
| 729 | if (place->fpfn >= (bo->mem.start + bo->mem.size) || | ||
| 730 | (place->lpfn && place->lpfn <= bo->mem.start)) { | ||
| 731 | __ttm_bo_unreserve(bo); | ||
| 732 | ret = -EBUSY; | ||
| 733 | continue; | ||
| 734 | } | ||
| 735 | } | ||
| 736 | |||
| 724 | break; | 737 | break; |
| 738 | } | ||
| 725 | } | 739 | } |
| 726 | 740 | ||
| 727 | if (ret) { | 741 | if (ret) { |
| @@ -782,7 +796,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, | |||
| 782 | return ret; | 796 | return ret; |
| 783 | if (mem->mm_node) | 797 | if (mem->mm_node) |
| 784 | break; | 798 | break; |
| 785 | ret = ttm_mem_evict_first(bdev, mem_type, | 799 | ret = ttm_mem_evict_first(bdev, mem_type, place, |
| 786 | interruptible, no_wait_gpu); | 800 | interruptible, no_wait_gpu); |
| 787 | if (unlikely(ret != 0)) | 801 | if (unlikely(ret != 0)) |
| 788 | return ret; | 802 | return ret; |
| @@ -994,9 +1008,9 @@ static bool ttm_bo_mem_compat(struct ttm_placement *placement, | |||
| 994 | 1008 | ||
| 995 | for (i = 0; i < placement->num_placement; i++) { | 1009 | for (i = 0; i < placement->num_placement; i++) { |
| 996 | const struct ttm_place *heap = &placement->placement[i]; | 1010 | const struct ttm_place *heap = &placement->placement[i]; |
| 997 | if (mem->mm_node && heap->lpfn != 0 && | 1011 | if (mem->mm_node && |
| 998 | (mem->start < heap->fpfn || | 1012 | (mem->start < heap->fpfn || |
| 999 | mem->start + mem->num_pages > heap->lpfn)) | 1013 | (heap->lpfn != 0 && (mem->start + mem->num_pages) > heap->lpfn))) |
| 1000 | continue; | 1014 | continue; |
| 1001 | 1015 | ||
| 1002 | *new_flags = heap->flags; | 1016 | *new_flags = heap->flags; |
| @@ -1007,9 +1021,9 @@ static bool ttm_bo_mem_compat(struct ttm_placement *placement, | |||
| 1007 | 1021 | ||
| 1008 | for (i = 0; i < placement->num_busy_placement; i++) { | 1022 | for (i = 0; i < placement->num_busy_placement; i++) { |
| 1009 | const struct ttm_place *heap = &placement->busy_placement[i]; | 1023 | const struct ttm_place *heap = &placement->busy_placement[i]; |
| 1010 | if (mem->mm_node && heap->lpfn != 0 && | 1024 | if (mem->mm_node && |
| 1011 | (mem->start < heap->fpfn || | 1025 | (mem->start < heap->fpfn || |
| 1012 | mem->start + mem->num_pages > heap->lpfn)) | 1026 | (heap->lpfn != 0 && (mem->start + mem->num_pages) > heap->lpfn))) |
| 1013 | continue; | 1027 | continue; |
| 1014 | 1028 | ||
| 1015 | *new_flags = heap->flags; | 1029 | *new_flags = heap->flags; |
| @@ -1233,7 +1247,7 @@ static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev, | |||
| 1233 | spin_lock(&glob->lru_lock); | 1247 | spin_lock(&glob->lru_lock); |
| 1234 | while (!list_empty(&man->lru)) { | 1248 | while (!list_empty(&man->lru)) { |
| 1235 | spin_unlock(&glob->lru_lock); | 1249 | spin_unlock(&glob->lru_lock); |
| 1236 | ret = ttm_mem_evict_first(bdev, mem_type, false, false); | 1250 | ret = ttm_mem_evict_first(bdev, mem_type, NULL, false, false); |
| 1237 | if (ret) { | 1251 | if (ret) { |
| 1238 | if (allow_errors) { | 1252 | if (allow_errors) { |
| 1239 | return ret; | 1253 | return ret; |
diff --git a/drivers/hwmon/menf21bmc_hwmon.c b/drivers/hwmon/menf21bmc_hwmon.c index c92229d321c9..afc6b58eaa62 100644 --- a/drivers/hwmon/menf21bmc_hwmon.c +++ b/drivers/hwmon/menf21bmc_hwmon.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/jiffies.h> | 21 | #include <linux/jiffies.h> |
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
| 24 | #include <linux/err.h> | ||
| 24 | 25 | ||
| 25 | #define DRV_NAME "menf21bmc_hwmon" | 26 | #define DRV_NAME "menf21bmc_hwmon" |
| 26 | 27 | ||
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index a9f9c46e5022..63fc63911295 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c | |||
| @@ -397,6 +397,7 @@ static int pcie_pme_suspend(struct pcie_device *srv) | |||
| 397 | struct pcie_pme_service_data *data = get_service_data(srv); | 397 | struct pcie_pme_service_data *data = get_service_data(srv); |
| 398 | struct pci_dev *port = srv->port; | 398 | struct pci_dev *port = srv->port; |
| 399 | bool wakeup; | 399 | bool wakeup; |
| 400 | int ret; | ||
| 400 | 401 | ||
| 401 | if (device_may_wakeup(&port->dev)) { | 402 | if (device_may_wakeup(&port->dev)) { |
| 402 | wakeup = true; | 403 | wakeup = true; |
| @@ -407,9 +408,10 @@ static int pcie_pme_suspend(struct pcie_device *srv) | |||
| 407 | } | 408 | } |
| 408 | spin_lock_irq(&data->lock); | 409 | spin_lock_irq(&data->lock); |
| 409 | if (wakeup) { | 410 | if (wakeup) { |
| 410 | enable_irq_wake(srv->irq); | 411 | ret = enable_irq_wake(srv->irq); |
| 411 | data->suspend_level = PME_SUSPEND_WAKEUP; | 412 | data->suspend_level = PME_SUSPEND_WAKEUP; |
| 412 | } else { | 413 | } |
| 414 | if (!wakeup || ret) { | ||
| 413 | struct pci_dev *port = srv->port; | 415 | struct pci_dev *port = srv->port; |
| 414 | 416 | ||
| 415 | pcie_pme_interrupt_enable(port, false); | 417 | pcie_pme_interrupt_enable(port, false); |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 8cd0beebdc3f..94ae1798d48a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -830,7 +830,7 @@ config RTC_DRV_DA9063 | |||
| 830 | 830 | ||
| 831 | config RTC_DRV_EFI | 831 | config RTC_DRV_EFI |
| 832 | tristate "EFI RTC" | 832 | tristate "EFI RTC" |
| 833 | depends on EFI | 833 | depends on EFI && !X86 |
| 834 | help | 834 | help |
| 835 | If you say yes here you will get support for the EFI | 835 | If you say yes here you will get support for the EFI |
| 836 | Real Time Clock. | 836 | Real Time Clock. |
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index c384fec6d173..53b589dc34eb 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c | |||
| @@ -236,3 +236,4 @@ MODULE_ALIAS("platform:rtc-efi"); | |||
| 236 | MODULE_AUTHOR("dann frazier <dannf@hp.com>"); | 236 | MODULE_AUTHOR("dann frazier <dannf@hp.com>"); |
| 237 | MODULE_LICENSE("GPL"); | 237 | MODULE_LICENSE("GPL"); |
| 238 | MODULE_DESCRIPTION("EFI RTC driver"); | 238 | MODULE_DESCRIPTION("EFI RTC driver"); |
| 239 | MODULE_ALIAS("platform:rtc-efi"); | ||
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index ef5587fe2c69..f554d25b4399 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
| @@ -84,6 +84,16 @@ config THERMAL_GOV_STEP_WISE | |||
| 84 | Enable this to manage platform thermals using a simple linear | 84 | Enable this to manage platform thermals using a simple linear |
| 85 | governor. | 85 | governor. |
| 86 | 86 | ||
| 87 | config THERMAL_GOV_BANG_BANG | ||
| 88 | bool "Bang Bang thermal governor" | ||
| 89 | default n | ||
| 90 | help | ||
| 91 | Enable this to manage platform thermals using bang bang governor. | ||
| 92 | |||
| 93 | Say 'Y' here if you want to use two point temperature regulation | ||
| 94 | used for fans without throttling. Some fan drivers depend on this | ||
| 95 | governor to be enabled (e.g. acerhdf). | ||
| 96 | |||
| 87 | config THERMAL_GOV_USER_SPACE | 97 | config THERMAL_GOV_USER_SPACE |
| 88 | bool "User_space thermal governor" | 98 | bool "User_space thermal governor" |
| 89 | help | 99 | help |
| @@ -207,21 +217,6 @@ config X86_PKG_TEMP_THERMAL | |||
| 207 | two trip points which can be set by user to get notifications via thermal | 217 | two trip points which can be set by user to get notifications via thermal |
| 208 | notification methods. | 218 | notification methods. |
| 209 | 219 | ||
| 210 | config ACPI_INT3403_THERMAL | ||
| 211 | tristate "ACPI INT3403 thermal driver" | ||
| 212 | depends on X86 && ACPI | ||
| 213 | help | ||
| 214 | Newer laptops and tablets that use ACPI may have thermal sensors | ||
| 215 | outside the core CPU/SOC for thermal safety reasons. These | ||
| 216 | temperature sensors are also exposed for the OS to use via the so | ||
| 217 | called INT3403 ACPI object. This driver will, on devices that have | ||
| 218 | such sensors, expose the temperature information from these sensors | ||
| 219 | to userspace via the normal thermal framework. This means that a wide | ||
| 220 | range of applications and GUI widgets can show this information to | ||
| 221 | the user or use this information for making decisions. For example, | ||
| 222 | the Intel Thermal Daemon can use this information to allow the user | ||
| 223 | to select his laptop to run without turning on the fans. | ||
| 224 | |||
| 225 | config INTEL_SOC_DTS_THERMAL | 220 | config INTEL_SOC_DTS_THERMAL |
| 226 | tristate "Intel SoCs DTS thermal driver" | 221 | tristate "Intel SoCs DTS thermal driver" |
| 227 | depends on X86 && IOSF_MBI | 222 | depends on X86 && IOSF_MBI |
| @@ -234,6 +229,30 @@ config INTEL_SOC_DTS_THERMAL | |||
| 234 | notification methods.The other trip is a critical trip point, which | 229 | notification methods.The other trip is a critical trip point, which |
| 235 | was set by the driver based on the TJ MAX temperature. | 230 | was set by the driver based on the TJ MAX temperature. |
| 236 | 231 | ||
| 232 | config INT340X_THERMAL | ||
| 233 | tristate "ACPI INT340X thermal drivers" | ||
| 234 | depends on X86 && ACPI | ||
| 235 | select THERMAL_GOV_USER_SPACE | ||
| 236 | select ACPI_THERMAL_REL | ||
| 237 | select ACPI_FAN | ||
| 238 | help | ||
| 239 | Newer laptops and tablets that use ACPI may have thermal sensors and | ||
| 240 | other devices with thermal control capabilities outside the core | ||
| 241 | CPU/SOC, for thermal safety reasons. | ||
| 242 | They are exposed for the OS to use via the INT3400 ACPI device object | ||
| 243 | as the master, and INT3401~INT340B ACPI device objects as the slaves. | ||
| 244 | Enable this to expose the temperature information and cooling ability | ||
| 245 | from these objects to userspace via the normal thermal framework. | ||
| 246 | This means that a wide range of applications and GUI widgets can show | ||
| 247 | the information to the user or use this information for making | ||
| 248 | decisions. For example, the Intel Thermal Daemon can use this | ||
| 249 | information to allow the user to select his laptop to run without | ||
| 250 | turning on the fans. | ||
| 251 | |||
| 252 | config ACPI_THERMAL_REL | ||
| 253 | tristate | ||
| 254 | depends on ACPI | ||
| 255 | |||
| 237 | menu "Texas Instruments thermal drivers" | 256 | menu "Texas Instruments thermal drivers" |
| 238 | source "drivers/thermal/ti-soc-thermal/Kconfig" | 257 | source "drivers/thermal/ti-soc-thermal/Kconfig" |
| 239 | endmenu | 258 | endmenu |
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 31e232f84b6b..39c4fe87da2f 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile | |||
| @@ -11,6 +11,7 @@ thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o | |||
| 11 | 11 | ||
| 12 | # governors | 12 | # governors |
| 13 | thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o | 13 | thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o |
| 14 | thermal_sys-$(CONFIG_THERMAL_GOV_BANG_BANG) += gov_bang_bang.o | ||
| 14 | thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o | 15 | thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o |
| 15 | thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o | 16 | thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o |
| 16 | 17 | ||
| @@ -31,5 +32,5 @@ obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o | |||
| 31 | obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o | 32 | obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o |
| 32 | obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o | 33 | obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o |
| 33 | obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ | 34 | obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ |
| 34 | obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o | 35 | obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ |
| 35 | obj-$(CONFIG_ST_THERMAL) += st/ | 36 | obj-$(CONFIG_ST_THERMAL) += st/ |
diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c index 944ba2f340c8..6e0a3fbfae86 100644 --- a/drivers/thermal/fair_share.c +++ b/drivers/thermal/fair_share.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <linux/thermal.h> | 25 | #include <linux/thermal.h> |
| 26 | #include <trace/events/thermal.h> | ||
| 26 | 27 | ||
| 27 | #include "thermal_core.h" | 28 | #include "thermal_core.h" |
| 28 | 29 | ||
| @@ -34,6 +35,7 @@ static int get_trip_level(struct thermal_zone_device *tz) | |||
| 34 | { | 35 | { |
| 35 | int count = 0; | 36 | int count = 0; |
| 36 | unsigned long trip_temp; | 37 | unsigned long trip_temp; |
| 38 | enum thermal_trip_type trip_type; | ||
| 37 | 39 | ||
| 38 | if (tz->trips == 0 || !tz->ops->get_trip_temp) | 40 | if (tz->trips == 0 || !tz->ops->get_trip_temp) |
| 39 | return 0; | 41 | return 0; |
| @@ -43,6 +45,16 @@ static int get_trip_level(struct thermal_zone_device *tz) | |||
| 43 | if (tz->temperature < trip_temp) | 45 | if (tz->temperature < trip_temp) |
| 44 | break; | 46 | break; |
| 45 | } | 47 | } |
| 48 | |||
| 49 | /* | ||
| 50 | * count > 0 only if temperature is greater than first trip | ||
| 51 | * point, in which case, trip_point = count - 1 | ||
| 52 | */ | ||
| 53 | if (count > 0) { | ||
| 54 | tz->ops->get_trip_type(tz, count - 1, &trip_type); | ||
| 55 | trace_thermal_zone_trip(tz, count - 1, trip_type); | ||
| 56 | } | ||
| 57 | |||
| 46 | return count; | 58 | return count; |
| 47 | } | 59 | } |
| 48 | 60 | ||
diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c new file mode 100644 index 000000000000..c5dd76b2ee74 --- /dev/null +++ b/drivers/thermal/gov_bang_bang.c | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | /* | ||
| 2 | * gov_bang_bang.c - A simple thermal throttling governor using hysteresis | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Peter Feuerer <peter@piie.net> | ||
| 5 | * | ||
| 6 | * Based on step_wise.c with following Copyrights: | ||
| 7 | * Copyright (C) 2012 Intel Corp | ||
| 8 | * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> | ||
| 9 | * | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License as published by | ||
| 13 | * the Free Software Foundation, version 2. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 18 | * the GNU General Public License for more details. | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/thermal.h> | ||
| 23 | |||
| 24 | #include "thermal_core.h" | ||
| 25 | |||
| 26 | static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) | ||
| 27 | { | ||
| 28 | long trip_temp; | ||
| 29 | unsigned long trip_hyst; | ||
| 30 | struct thermal_instance *instance; | ||
| 31 | |||
| 32 | tz->ops->get_trip_temp(tz, trip, &trip_temp); | ||
| 33 | tz->ops->get_trip_hyst(tz, trip, &trip_hyst); | ||
| 34 | |||
| 35 | dev_dbg(&tz->device, "Trip%d[temp=%ld]:temp=%d:hyst=%ld\n", | ||
| 36 | trip, trip_temp, tz->temperature, | ||
| 37 | trip_hyst); | ||
| 38 | |||
| 39 | mutex_lock(&tz->lock); | ||
| 40 | |||
| 41 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { | ||
| 42 | if (instance->trip != trip) | ||
| 43 | continue; | ||
| 44 | |||
| 45 | /* in case fan is in initial state, switch the fan off */ | ||
| 46 | if (instance->target == THERMAL_NO_TARGET) | ||
| 47 | instance->target = 0; | ||
| 48 | |||
| 49 | /* in case fan is neither on nor off set the fan to active */ | ||
| 50 | if (instance->target != 0 && instance->target != 1) { | ||
| 51 | pr_warn("Thermal instance %s controlled by bang-bang has unexpected state: %ld\n", | ||
| 52 | instance->name, instance->target); | ||
| 53 | instance->target = 1; | ||
| 54 | } | ||
| 55 | |||
| 56 | /* | ||
| 57 | * enable fan when temperature exceeds trip_temp and disable | ||
| 58 | * the fan in case it falls below trip_temp minus hysteresis | ||
| 59 | */ | ||
| 60 | if (instance->target == 0 && tz->temperature >= trip_temp) | ||
| 61 | instance->target = 1; | ||
| 62 | else if (instance->target == 1 && | ||
| 63 | tz->temperature < trip_temp - trip_hyst) | ||
| 64 | instance->target = 0; | ||
| 65 | |||
| 66 | dev_dbg(&instance->cdev->device, "target=%d\n", | ||
| 67 | (int)instance->target); | ||
| 68 | |||
| 69 | instance->cdev->updated = false; /* cdev needs update */ | ||
| 70 | } | ||
| 71 | |||
| 72 | mutex_unlock(&tz->lock); | ||
| 73 | } | ||
| 74 | |||
| 75 | /** | ||
| 76 | * bang_bang_control - controls devices associated with the given zone | ||
| 77 | * @tz - thermal_zone_device | ||
| 78 | * @trip - the trip point | ||
| 79 | * | ||
| 80 | * Regulation Logic: a two point regulation, deliver cooling state depending | ||
| 81 | * on the previous state shown in this diagram: | ||
| 82 | * | ||
| 83 | * Fan: OFF ON | ||
| 84 | * | ||
| 85 | * | | ||
| 86 | * | | ||
| 87 | * trip_temp: +---->+ | ||
| 88 | * | | ^ | ||
| 89 | * | | | | ||
| 90 | * | | Temperature | ||
| 91 | * (trip_temp - hyst): +<----+ | ||
| 92 | * | | ||
| 93 | * | | ||
| 94 | * | | ||
| 95 | * | ||
| 96 | * * If the fan is not running and temperature exceeds trip_temp, the fan | ||
| 97 | * gets turned on. | ||
| 98 | * * In case the fan is running, temperature must fall below | ||
| 99 | * (trip_temp - hyst) so that the fan gets turned off again. | ||
| 100 | * | ||
| 101 | */ | ||
| 102 | static int bang_bang_control(struct thermal_zone_device *tz, int trip) | ||
| 103 | { | ||
| 104 | struct thermal_instance *instance; | ||
| 105 | |||
| 106 | thermal_zone_trip_update(tz, trip); | ||
| 107 | |||
| 108 | mutex_lock(&tz->lock); | ||
| 109 | |||
| 110 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) | ||
| 111 | thermal_cdev_update(instance->cdev); | ||
| 112 | |||
| 113 | mutex_unlock(&tz->lock); | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | static struct thermal_governor thermal_gov_bang_bang = { | ||
| 119 | .name = "bang_bang", | ||
| 120 | .throttle = bang_bang_control, | ||
| 121 | }; | ||
| 122 | |||
| 123 | int thermal_gov_bang_bang_register(void) | ||
| 124 | { | ||
| 125 | return thermal_register_governor(&thermal_gov_bang_bang); | ||
| 126 | } | ||
| 127 | |||
| 128 | void thermal_gov_bang_bang_unregister(void) | ||
| 129 | { | ||
| 130 | thermal_unregister_governor(&thermal_gov_bang_bang); | ||
| 131 | } | ||
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 2c516f2eebed..461bf3d033a0 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/mfd/syscon.h> | 19 | #include <linux/mfd/syscon.h> |
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
| 22 | #include <linux/of_device.h> | ||
| 22 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
| 23 | #include <linux/regmap.h> | 24 | #include <linux/regmap.h> |
| 24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| @@ -31,6 +32,11 @@ | |||
| 31 | 32 | ||
| 32 | #define MISC0 0x0150 | 33 | #define MISC0 0x0150 |
| 33 | #define MISC0_REFTOP_SELBIASOFF (1 << 3) | 34 | #define MISC0_REFTOP_SELBIASOFF (1 << 3) |
| 35 | #define MISC1 0x0160 | ||
| 36 | #define MISC1_IRQ_TEMPHIGH (1 << 29) | ||
| 37 | /* Below LOW and PANIC bits are only for TEMPMON_IMX6SX */ | ||
| 38 | #define MISC1_IRQ_TEMPLOW (1 << 28) | ||
| 39 | #define MISC1_IRQ_TEMPPANIC (1 << 27) | ||
| 34 | 40 | ||
| 35 | #define TEMPSENSE0 0x0180 | 41 | #define TEMPSENSE0 0x0180 |
| 36 | #define TEMPSENSE0_ALARM_VALUE_SHIFT 20 | 42 | #define TEMPSENSE0_ALARM_VALUE_SHIFT 20 |
| @@ -43,6 +49,12 @@ | |||
| 43 | 49 | ||
| 44 | #define TEMPSENSE1 0x0190 | 50 | #define TEMPSENSE1 0x0190 |
| 45 | #define TEMPSENSE1_MEASURE_FREQ 0xffff | 51 | #define TEMPSENSE1_MEASURE_FREQ 0xffff |
| 52 | /* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */ | ||
| 53 | #define TEMPSENSE2 0x0290 | ||
| 54 | #define TEMPSENSE2_LOW_VALUE_SHIFT 0 | ||
| 55 | #define TEMPSENSE2_LOW_VALUE_MASK 0xfff | ||
| 56 | #define TEMPSENSE2_PANIC_VALUE_SHIFT 16 | ||
| 57 | #define TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000 | ||
| 46 | 58 | ||
| 47 | #define OCOTP_ANA1 0x04e0 | 59 | #define OCOTP_ANA1 0x04e0 |
| 48 | 60 | ||
| @@ -66,6 +78,21 @@ enum imx_thermal_trip { | |||
| 66 | #define FACTOR1 15976 | 78 | #define FACTOR1 15976 |
| 67 | #define FACTOR2 4297157 | 79 | #define FACTOR2 4297157 |
| 68 | 80 | ||
| 81 | #define TEMPMON_IMX6Q 1 | ||
| 82 | #define TEMPMON_IMX6SX 2 | ||
| 83 | |||
| 84 | struct thermal_soc_data { | ||
| 85 | u32 version; | ||
| 86 | }; | ||
| 87 | |||
| 88 | static struct thermal_soc_data thermal_imx6q_data = { | ||
| 89 | .version = TEMPMON_IMX6Q, | ||
| 90 | }; | ||
| 91 | |||
| 92 | static struct thermal_soc_data thermal_imx6sx_data = { | ||
| 93 | .version = TEMPMON_IMX6SX, | ||
| 94 | }; | ||
| 95 | |||
| 69 | struct imx_thermal_data { | 96 | struct imx_thermal_data { |
| 70 | struct thermal_zone_device *tz; | 97 | struct thermal_zone_device *tz; |
| 71 | struct thermal_cooling_device *cdev; | 98 | struct thermal_cooling_device *cdev; |
| @@ -79,8 +106,21 @@ struct imx_thermal_data { | |||
| 79 | bool irq_enabled; | 106 | bool irq_enabled; |
| 80 | int irq; | 107 | int irq; |
| 81 | struct clk *thermal_clk; | 108 | struct clk *thermal_clk; |
| 109 | const struct thermal_soc_data *socdata; | ||
| 82 | }; | 110 | }; |
| 83 | 111 | ||
| 112 | static void imx_set_panic_temp(struct imx_thermal_data *data, | ||
| 113 | signed long panic_temp) | ||
| 114 | { | ||
| 115 | struct regmap *map = data->tempmon; | ||
| 116 | int critical_value; | ||
| 117 | |||
| 118 | critical_value = (data->c2 - panic_temp) / data->c1; | ||
| 119 | regmap_write(map, TEMPSENSE2 + REG_CLR, TEMPSENSE2_PANIC_VALUE_MASK); | ||
| 120 | regmap_write(map, TEMPSENSE2 + REG_SET, critical_value << | ||
| 121 | TEMPSENSE2_PANIC_VALUE_SHIFT); | ||
| 122 | } | ||
| 123 | |||
| 84 | static void imx_set_alarm_temp(struct imx_thermal_data *data, | 124 | static void imx_set_alarm_temp(struct imx_thermal_data *data, |
| 85 | signed long alarm_temp) | 125 | signed long alarm_temp) |
| 86 | { | 126 | { |
| @@ -142,13 +182,17 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp) | |||
| 142 | /* See imx_get_sensor_data() for formula derivation */ | 182 | /* See imx_get_sensor_data() for formula derivation */ |
| 143 | *temp = data->c2 - n_meas * data->c1; | 183 | *temp = data->c2 - n_meas * data->c1; |
| 144 | 184 | ||
| 145 | /* Update alarm value to next higher trip point */ | 185 | /* Update alarm value to next higher trip point for TEMPMON_IMX6Q */ |
| 146 | if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive) | 186 | if (data->socdata->version == TEMPMON_IMX6Q) { |
| 147 | imx_set_alarm_temp(data, data->temp_critical); | 187 | if (data->alarm_temp == data->temp_passive && |
| 148 | if (data->alarm_temp == data->temp_critical && *temp < data->temp_passive) { | 188 | *temp >= data->temp_passive) |
| 149 | imx_set_alarm_temp(data, data->temp_passive); | 189 | imx_set_alarm_temp(data, data->temp_critical); |
| 150 | dev_dbg(&tz->device, "thermal alarm off: T < %lu\n", | 190 | if (data->alarm_temp == data->temp_critical && |
| 151 | data->alarm_temp / 1000); | 191 | *temp < data->temp_passive) { |
| 192 | imx_set_alarm_temp(data, data->temp_passive); | ||
| 193 | dev_dbg(&tz->device, "thermal alarm off: T < %lu\n", | ||
| 194 | data->alarm_temp / 1000); | ||
| 195 | } | ||
| 152 | } | 196 | } |
| 153 | 197 | ||
| 154 | if (*temp != data->last_temp) { | 198 | if (*temp != data->last_temp) { |
| @@ -398,8 +442,17 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev) | |||
| 398 | return IRQ_HANDLED; | 442 | return IRQ_HANDLED; |
| 399 | } | 443 | } |
| 400 | 444 | ||
| 445 | static const struct of_device_id of_imx_thermal_match[] = { | ||
| 446 | { .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, }, | ||
| 447 | { .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, }, | ||
| 448 | { /* end */ } | ||
| 449 | }; | ||
| 450 | MODULE_DEVICE_TABLE(of, of_imx_thermal_match); | ||
| 451 | |||
| 401 | static int imx_thermal_probe(struct platform_device *pdev) | 452 | static int imx_thermal_probe(struct platform_device *pdev) |
| 402 | { | 453 | { |
| 454 | const struct of_device_id *of_id = | ||
| 455 | of_match_device(of_imx_thermal_match, &pdev->dev); | ||
| 403 | struct imx_thermal_data *data; | 456 | struct imx_thermal_data *data; |
| 404 | struct cpumask clip_cpus; | 457 | struct cpumask clip_cpus; |
| 405 | struct regmap *map; | 458 | struct regmap *map; |
| @@ -418,6 +471,20 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
| 418 | } | 471 | } |
| 419 | data->tempmon = map; | 472 | data->tempmon = map; |
| 420 | 473 | ||
| 474 | data->socdata = of_id->data; | ||
| 475 | |||
| 476 | /* make sure the IRQ flag is clear before enabling irq on i.MX6SX */ | ||
| 477 | if (data->socdata->version == TEMPMON_IMX6SX) { | ||
| 478 | regmap_write(map, MISC1 + REG_CLR, MISC1_IRQ_TEMPHIGH | | ||
| 479 | MISC1_IRQ_TEMPLOW | MISC1_IRQ_TEMPPANIC); | ||
| 480 | /* | ||
| 481 | * reset value of LOW ALARM is incorrect, set it to lowest | ||
| 482 | * value to avoid false trigger of low alarm. | ||
| 483 | */ | ||
| 484 | regmap_write(map, TEMPSENSE2 + REG_SET, | ||
| 485 | TEMPSENSE2_LOW_VALUE_MASK); | ||
| 486 | } | ||
| 487 | |||
| 421 | data->irq = platform_get_irq(pdev, 0); | 488 | data->irq = platform_get_irq(pdev, 0); |
| 422 | if (data->irq < 0) | 489 | if (data->irq < 0) |
| 423 | return data->irq; | 490 | return data->irq; |
| @@ -489,6 +556,10 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
| 489 | measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */ | 556 | measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */ |
| 490 | regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq); | 557 | regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq); |
| 491 | imx_set_alarm_temp(data, data->temp_passive); | 558 | imx_set_alarm_temp(data, data->temp_passive); |
| 559 | |||
| 560 | if (data->socdata->version == TEMPMON_IMX6SX) | ||
| 561 | imx_set_panic_temp(data, data->temp_critical); | ||
| 562 | |||
| 492 | regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); | 563 | regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); |
| 493 | regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); | 564 | regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); |
| 494 | 565 | ||
| @@ -550,12 +621,6 @@ static int imx_thermal_resume(struct device *dev) | |||
| 550 | static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops, | 621 | static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops, |
| 551 | imx_thermal_suspend, imx_thermal_resume); | 622 | imx_thermal_suspend, imx_thermal_resume); |
| 552 | 623 | ||
| 553 | static const struct of_device_id of_imx_thermal_match[] = { | ||
| 554 | { .compatible = "fsl,imx6q-tempmon", }, | ||
| 555 | { /* end */ } | ||
| 556 | }; | ||
| 557 | MODULE_DEVICE_TABLE(of, of_imx_thermal_match); | ||
| 558 | |||
| 559 | static struct platform_driver imx_thermal = { | 624 | static struct platform_driver imx_thermal = { |
| 560 | .driver = { | 625 | .driver = { |
| 561 | .name = "imx_thermal", | 626 | .name = "imx_thermal", |
diff --git a/drivers/thermal/int3403_thermal.c b/drivers/thermal/int3403_thermal.c deleted file mode 100644 index 17554eeb3953..000000000000 --- a/drivers/thermal/int3403_thermal.c +++ /dev/null | |||
| @@ -1,296 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * ACPI INT3403 thermal driver | ||
| 3 | * Copyright (c) 2013, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/types.h> | ||
| 19 | #include <linux/acpi.h> | ||
| 20 | #include <linux/thermal.h> | ||
| 21 | |||
| 22 | #define INT3403_TYPE_SENSOR 0x03 | ||
| 23 | #define INT3403_PERF_CHANGED_EVENT 0x80 | ||
| 24 | #define INT3403_THERMAL_EVENT 0x90 | ||
| 25 | |||
| 26 | #define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100) | ||
| 27 | #define KELVIN_OFFSET 2732 | ||
| 28 | #define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off)) | ||
| 29 | |||
| 30 | #define ACPI_INT3403_CLASS "int3403" | ||
| 31 | #define ACPI_INT3403_FILE_STATE "state" | ||
| 32 | |||
| 33 | struct int3403_sensor { | ||
| 34 | struct thermal_zone_device *tzone; | ||
| 35 | unsigned long *thresholds; | ||
| 36 | unsigned long crit_temp; | ||
| 37 | int crit_trip_id; | ||
| 38 | unsigned long psv_temp; | ||
| 39 | int psv_trip_id; | ||
| 40 | }; | ||
| 41 | |||
| 42 | static int sys_get_curr_temp(struct thermal_zone_device *tzone, | ||
| 43 | unsigned long *temp) | ||
| 44 | { | ||
| 45 | struct acpi_device *device = tzone->devdata; | ||
| 46 | unsigned long long tmp; | ||
| 47 | acpi_status status; | ||
| 48 | |||
| 49 | status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp); | ||
| 50 | if (ACPI_FAILURE(status)) | ||
| 51 | return -EIO; | ||
| 52 | |||
| 53 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET); | ||
| 54 | |||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | static int sys_get_trip_hyst(struct thermal_zone_device *tzone, | ||
| 59 | int trip, unsigned long *temp) | ||
| 60 | { | ||
| 61 | struct acpi_device *device = tzone->devdata; | ||
| 62 | unsigned long long hyst; | ||
| 63 | acpi_status status; | ||
| 64 | |||
| 65 | status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst); | ||
| 66 | if (ACPI_FAILURE(status)) | ||
| 67 | return -EIO; | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Thermal hysteresis represents a temperature difference. | ||
| 71 | * Kelvin and Celsius have same degree size. So the | ||
| 72 | * conversion here between tenths of degree Kelvin unit | ||
| 73 | * and Milli-Celsius unit is just to multiply 100. | ||
| 74 | */ | ||
| 75 | *temp = hyst * 100; | ||
| 76 | |||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int sys_get_trip_temp(struct thermal_zone_device *tzone, | ||
| 81 | int trip, unsigned long *temp) | ||
| 82 | { | ||
| 83 | struct acpi_device *device = tzone->devdata; | ||
| 84 | struct int3403_sensor *obj = acpi_driver_data(device); | ||
| 85 | |||
| 86 | if (trip == obj->crit_trip_id) | ||
| 87 | *temp = obj->crit_temp; | ||
| 88 | else if (trip == obj->psv_trip_id) | ||
| 89 | *temp = obj->psv_temp; | ||
| 90 | else { | ||
| 91 | /* | ||
| 92 | * get_trip_temp is a mandatory callback but | ||
| 93 | * PATx method doesn't return any value, so return | ||
| 94 | * cached value, which was last set from user space. | ||
| 95 | */ | ||
| 96 | *temp = obj->thresholds[trip]; | ||
| 97 | } | ||
| 98 | |||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static int sys_get_trip_type(struct thermal_zone_device *thermal, | ||
| 103 | int trip, enum thermal_trip_type *type) | ||
| 104 | { | ||
| 105 | struct acpi_device *device = thermal->devdata; | ||
| 106 | struct int3403_sensor *obj = acpi_driver_data(device); | ||
| 107 | |||
| 108 | /* Mandatory callback, may not mean much here */ | ||
| 109 | if (trip == obj->crit_trip_id) | ||
| 110 | *type = THERMAL_TRIP_CRITICAL; | ||
| 111 | else | ||
| 112 | *type = THERMAL_TRIP_PASSIVE; | ||
| 113 | |||
| 114 | return 0; | ||
| 115 | } | ||
| 116 | |||
| 117 | int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip, | ||
| 118 | unsigned long temp) | ||
| 119 | { | ||
| 120 | struct acpi_device *device = tzone->devdata; | ||
| 121 | acpi_status status; | ||
| 122 | char name[10]; | ||
| 123 | int ret = 0; | ||
| 124 | struct int3403_sensor *obj = acpi_driver_data(device); | ||
| 125 | |||
| 126 | snprintf(name, sizeof(name), "PAT%d", trip); | ||
| 127 | if (acpi_has_method(device->handle, name)) { | ||
| 128 | status = acpi_execute_simple_method(device->handle, name, | ||
| 129 | MILLI_CELSIUS_TO_DECI_KELVIN(temp, | ||
| 130 | KELVIN_OFFSET)); | ||
| 131 | if (ACPI_FAILURE(status)) | ||
| 132 | ret = -EIO; | ||
| 133 | else | ||
| 134 | obj->thresholds[trip] = temp; | ||
| 135 | } else { | ||
| 136 | ret = -EIO; | ||
| 137 | dev_err(&device->dev, "sys_set_trip_temp: method not found\n"); | ||
| 138 | } | ||
| 139 | |||
| 140 | return ret; | ||
| 141 | } | ||
| 142 | |||
| 143 | static struct thermal_zone_device_ops tzone_ops = { | ||
| 144 | .get_temp = sys_get_curr_temp, | ||
| 145 | .get_trip_temp = sys_get_trip_temp, | ||
| 146 | .get_trip_type = sys_get_trip_type, | ||
| 147 | .set_trip_temp = sys_set_trip_temp, | ||
| 148 | .get_trip_hyst = sys_get_trip_hyst, | ||
| 149 | }; | ||
| 150 | |||
| 151 | static void acpi_thermal_notify(struct acpi_device *device, u32 event) | ||
| 152 | { | ||
| 153 | struct int3403_sensor *obj; | ||
| 154 | |||
| 155 | if (!device) | ||
| 156 | return; | ||
| 157 | |||
| 158 | obj = acpi_driver_data(device); | ||
| 159 | if (!obj) | ||
| 160 | return; | ||
| 161 | |||
| 162 | switch (event) { | ||
| 163 | case INT3403_PERF_CHANGED_EVENT: | ||
| 164 | break; | ||
| 165 | case INT3403_THERMAL_EVENT: | ||
| 166 | thermal_zone_device_update(obj->tzone); | ||
| 167 | break; | ||
| 168 | default: | ||
| 169 | dev_err(&device->dev, "Unsupported event [0x%x]\n", event); | ||
| 170 | break; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp) | ||
| 175 | { | ||
| 176 | unsigned long long crt; | ||
| 177 | acpi_status status; | ||
| 178 | |||
| 179 | status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt); | ||
| 180 | if (ACPI_FAILURE(status)) | ||
| 181 | return -EIO; | ||
| 182 | |||
| 183 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET); | ||
| 184 | |||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 188 | static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp) | ||
| 189 | { | ||
| 190 | unsigned long long psv; | ||
| 191 | acpi_status status; | ||
| 192 | |||
| 193 | status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv); | ||
| 194 | if (ACPI_FAILURE(status)) | ||
| 195 | return -EIO; | ||
| 196 | |||
| 197 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET); | ||
| 198 | |||
| 199 | return 0; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int acpi_int3403_add(struct acpi_device *device) | ||
| 203 | { | ||
| 204 | int result = 0; | ||
| 205 | unsigned long long ptyp; | ||
| 206 | acpi_status status; | ||
| 207 | struct int3403_sensor *obj; | ||
| 208 | unsigned long long trip_cnt; | ||
| 209 | int trip_mask = 0; | ||
| 210 | |||
| 211 | if (!device) | ||
| 212 | return -EINVAL; | ||
| 213 | |||
| 214 | status = acpi_evaluate_integer(device->handle, "PTYP", NULL, &ptyp); | ||
| 215 | if (ACPI_FAILURE(status)) | ||
| 216 | return -EINVAL; | ||
| 217 | |||
| 218 | if (ptyp != INT3403_TYPE_SENSOR) | ||
| 219 | return -EINVAL; | ||
| 220 | |||
| 221 | obj = devm_kzalloc(&device->dev, sizeof(*obj), GFP_KERNEL); | ||
| 222 | if (!obj) | ||
| 223 | return -ENOMEM; | ||
| 224 | |||
| 225 | device->driver_data = obj; | ||
| 226 | |||
| 227 | status = acpi_evaluate_integer(device->handle, "PATC", NULL, | ||
| 228 | &trip_cnt); | ||
| 229 | if (ACPI_FAILURE(status)) | ||
| 230 | trip_cnt = 0; | ||
| 231 | |||
| 232 | if (trip_cnt) { | ||
| 233 | /* We have to cache, thresholds can't be readback */ | ||
| 234 | obj->thresholds = devm_kzalloc(&device->dev, | ||
| 235 | sizeof(*obj->thresholds) * trip_cnt, | ||
| 236 | GFP_KERNEL); | ||
| 237 | if (!obj->thresholds) | ||
| 238 | return -ENOMEM; | ||
| 239 | trip_mask = BIT(trip_cnt) - 1; | ||
| 240 | } | ||
| 241 | |||
| 242 | obj->psv_trip_id = -1; | ||
| 243 | if (!sys_get_trip_psv(device, &obj->psv_temp)) | ||
| 244 | obj->psv_trip_id = trip_cnt++; | ||
| 245 | |||
| 246 | obj->crit_trip_id = -1; | ||
| 247 | if (!sys_get_trip_crt(device, &obj->crit_temp)) | ||
| 248 | obj->crit_trip_id = trip_cnt++; | ||
| 249 | |||
| 250 | obj->tzone = thermal_zone_device_register(acpi_device_bid(device), | ||
| 251 | trip_cnt, trip_mask, device, &tzone_ops, | ||
| 252 | NULL, 0, 0); | ||
| 253 | if (IS_ERR(obj->tzone)) { | ||
| 254 | result = PTR_ERR(obj->tzone); | ||
| 255 | return result; | ||
| 256 | } | ||
| 257 | |||
| 258 | strcpy(acpi_device_name(device), "INT3403"); | ||
| 259 | strcpy(acpi_device_class(device), ACPI_INT3403_CLASS); | ||
| 260 | |||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 264 | static int acpi_int3403_remove(struct acpi_device *device) | ||
| 265 | { | ||
| 266 | struct int3403_sensor *obj; | ||
| 267 | |||
| 268 | obj = acpi_driver_data(device); | ||
| 269 | thermal_zone_device_unregister(obj->tzone); | ||
| 270 | |||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | ACPI_MODULE_NAME("int3403"); | ||
| 275 | static const struct acpi_device_id int3403_device_ids[] = { | ||
| 276 | {"INT3403", 0}, | ||
| 277 | {"", 0}, | ||
| 278 | }; | ||
| 279 | MODULE_DEVICE_TABLE(acpi, int3403_device_ids); | ||
| 280 | |||
| 281 | static struct acpi_driver acpi_int3403_driver = { | ||
| 282 | .name = "INT3403", | ||
| 283 | .class = ACPI_INT3403_CLASS, | ||
| 284 | .ids = int3403_device_ids, | ||
| 285 | .ops = { | ||
| 286 | .add = acpi_int3403_add, | ||
| 287 | .remove = acpi_int3403_remove, | ||
| 288 | .notify = acpi_thermal_notify, | ||
| 289 | }, | ||
| 290 | }; | ||
| 291 | |||
| 292 | module_acpi_driver(acpi_int3403_driver); | ||
| 293 | |||
| 294 | MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); | ||
| 295 | MODULE_LICENSE("GPL v2"); | ||
| 296 | MODULE_DESCRIPTION("ACPI INT3403 thermal driver"); | ||
diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile new file mode 100644 index 000000000000..ffe40bffaf1a --- /dev/null +++ b/drivers/thermal/int340x_thermal/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o | ||
| 2 | obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o | ||
| 3 | obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o | ||
| 4 | obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o | ||
diff --git a/drivers/thermal/int340x_thermal/acpi_thermal_rel.c b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c new file mode 100644 index 000000000000..0d8db808f0ae --- /dev/null +++ b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c | |||
| @@ -0,0 +1,400 @@ | |||
| 1 | /* acpi_thermal_rel.c driver for exporting ACPI thermal relationship | ||
| 2 | * | ||
| 3 | * Copyright (c) 2014 Intel Corp | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * Two functionalities included: | ||
| 13 | * 1. Export _TRT, _ART, via misc device interface to the userspace. | ||
| 14 | * 2. Provide parsing result to kernel drivers | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/export.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/device.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/io.h> | ||
| 23 | #include <linux/acpi.h> | ||
| 24 | #include <linux/uaccess.h> | ||
| 25 | #include <linux/miscdevice.h> | ||
| 26 | #include "acpi_thermal_rel.h" | ||
| 27 | |||
| 28 | static acpi_handle acpi_thermal_rel_handle; | ||
| 29 | static DEFINE_SPINLOCK(acpi_thermal_rel_chrdev_lock); | ||
| 30 | static int acpi_thermal_rel_chrdev_count; /* #times opened */ | ||
| 31 | static int acpi_thermal_rel_chrdev_exclu; /* already open exclusive? */ | ||
| 32 | |||
| 33 | static int acpi_thermal_rel_open(struct inode *inode, struct file *file) | ||
| 34 | { | ||
| 35 | spin_lock(&acpi_thermal_rel_chrdev_lock); | ||
| 36 | if (acpi_thermal_rel_chrdev_exclu || | ||
| 37 | (acpi_thermal_rel_chrdev_count && (file->f_flags & O_EXCL))) { | ||
| 38 | spin_unlock(&acpi_thermal_rel_chrdev_lock); | ||
| 39 | return -EBUSY; | ||
| 40 | } | ||
| 41 | |||
| 42 | if (file->f_flags & O_EXCL) | ||
| 43 | acpi_thermal_rel_chrdev_exclu = 1; | ||
| 44 | acpi_thermal_rel_chrdev_count++; | ||
| 45 | |||
| 46 | spin_unlock(&acpi_thermal_rel_chrdev_lock); | ||
| 47 | |||
| 48 | return nonseekable_open(inode, file); | ||
| 49 | } | ||
| 50 | |||
| 51 | static int acpi_thermal_rel_release(struct inode *inode, struct file *file) | ||
| 52 | { | ||
| 53 | spin_lock(&acpi_thermal_rel_chrdev_lock); | ||
| 54 | acpi_thermal_rel_chrdev_count--; | ||
| 55 | acpi_thermal_rel_chrdev_exclu = 0; | ||
| 56 | spin_unlock(&acpi_thermal_rel_chrdev_lock); | ||
| 57 | |||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | /** | ||
| 62 | * acpi_parse_trt - Thermal Relationship Table _TRT for passive cooling | ||
| 63 | * | ||
| 64 | * @handle: ACPI handle of the device contains _TRT | ||
| 65 | * @art_count: the number of valid entries resulted from parsing _TRT | ||
| 66 | * @artp: pointer to pointer of array of art entries in parsing result | ||
| 67 | * @create_dev: whether to create platform devices for target and source | ||
| 68 | * | ||
| 69 | */ | ||
| 70 | int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp, | ||
| 71 | bool create_dev) | ||
| 72 | { | ||
| 73 | acpi_status status; | ||
| 74 | int result = 0; | ||
| 75 | int i; | ||
| 76 | int nr_bad_entries = 0; | ||
| 77 | struct trt *trts; | ||
| 78 | struct acpi_device *adev; | ||
| 79 | union acpi_object *p; | ||
| 80 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 81 | struct acpi_buffer element = { 0, NULL }; | ||
| 82 | struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" }; | ||
| 83 | |||
| 84 | if (!acpi_has_method(handle, "_TRT")) | ||
| 85 | return 0; | ||
| 86 | |||
| 87 | status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer); | ||
| 88 | if (ACPI_FAILURE(status)) | ||
| 89 | return -ENODEV; | ||
| 90 | |||
| 91 | p = buffer.pointer; | ||
| 92 | if (!p || (p->type != ACPI_TYPE_PACKAGE)) { | ||
| 93 | pr_err("Invalid _TRT data\n"); | ||
| 94 | result = -EFAULT; | ||
| 95 | goto end; | ||
| 96 | } | ||
| 97 | |||
| 98 | *trt_count = p->package.count; | ||
| 99 | trts = kzalloc(*trt_count * sizeof(struct trt), GFP_KERNEL); | ||
| 100 | if (!trts) { | ||
| 101 | result = -ENOMEM; | ||
| 102 | goto end; | ||
| 103 | } | ||
| 104 | |||
| 105 | for (i = 0; i < *trt_count; i++) { | ||
| 106 | struct trt *trt = &trts[i - nr_bad_entries]; | ||
| 107 | |||
| 108 | element.length = sizeof(struct trt); | ||
| 109 | element.pointer = trt; | ||
| 110 | |||
| 111 | status = acpi_extract_package(&(p->package.elements[i]), | ||
| 112 | &trt_format, &element); | ||
| 113 | if (ACPI_FAILURE(status)) { | ||
| 114 | nr_bad_entries++; | ||
| 115 | pr_warn("_TRT package %d is invalid, ignored\n", i); | ||
| 116 | continue; | ||
| 117 | } | ||
| 118 | if (!create_dev) | ||
| 119 | continue; | ||
| 120 | |||
| 121 | result = acpi_bus_get_device(trt->source, &adev); | ||
| 122 | if (!result) | ||
| 123 | acpi_create_platform_device(adev); | ||
| 124 | else | ||
| 125 | pr_warn("Failed to get source ACPI device\n"); | ||
| 126 | |||
| 127 | result = acpi_bus_get_device(trt->target, &adev); | ||
| 128 | if (!result) | ||
| 129 | acpi_create_platform_device(adev); | ||
| 130 | else | ||
| 131 | pr_warn("Failed to get target ACPI device\n"); | ||
| 132 | } | ||
| 133 | |||
| 134 | *trtp = trts; | ||
| 135 | /* don't count bad entries */ | ||
| 136 | *trt_count -= nr_bad_entries; | ||
| 137 | end: | ||
| 138 | kfree(buffer.pointer); | ||
| 139 | return result; | ||
| 140 | } | ||
| 141 | EXPORT_SYMBOL(acpi_parse_trt); | ||
| 142 | |||
| 143 | /** | ||
| 144 | * acpi_parse_art - Parse Active Relationship Table _ART | ||
| 145 | * | ||
| 146 | * @handle: ACPI handle of the device contains _ART | ||
| 147 | * @art_count: the number of valid entries resulted from parsing _ART | ||
| 148 | * @artp: pointer to pointer of array of art entries in parsing result | ||
| 149 | * @create_dev: whether to create platform devices for target and source | ||
| 150 | * | ||
| 151 | */ | ||
| 152 | int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, | ||
| 153 | bool create_dev) | ||
| 154 | { | ||
| 155 | acpi_status status; | ||
| 156 | int result = 0; | ||
| 157 | int i; | ||
| 158 | int nr_bad_entries = 0; | ||
| 159 | struct art *arts; | ||
| 160 | struct acpi_device *adev; | ||
| 161 | union acpi_object *p; | ||
| 162 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 163 | struct acpi_buffer element = { 0, NULL }; | ||
| 164 | struct acpi_buffer art_format = { | ||
| 165 | sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" }; | ||
| 166 | |||
| 167 | if (!acpi_has_method(handle, "_ART")) | ||
| 168 | return 0; | ||
| 169 | |||
| 170 | status = acpi_evaluate_object(handle, "_ART", NULL, &buffer); | ||
| 171 | if (ACPI_FAILURE(status)) | ||
| 172 | return -ENODEV; | ||
| 173 | |||
| 174 | p = buffer.pointer; | ||
| 175 | if (!p || (p->type != ACPI_TYPE_PACKAGE)) { | ||
| 176 | pr_err("Invalid _ART data\n"); | ||
| 177 | result = -EFAULT; | ||
| 178 | goto end; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* ignore p->package.elements[0], as this is _ART Revision field */ | ||
| 182 | *art_count = p->package.count - 1; | ||
| 183 | arts = kzalloc(*art_count * sizeof(struct art), GFP_KERNEL); | ||
| 184 | if (!arts) { | ||
| 185 | result = -ENOMEM; | ||
| 186 | goto end; | ||
| 187 | } | ||
| 188 | |||
| 189 | for (i = 0; i < *art_count; i++) { | ||
| 190 | struct art *art = &arts[i - nr_bad_entries]; | ||
| 191 | |||
| 192 | element.length = sizeof(struct art); | ||
| 193 | element.pointer = art; | ||
| 194 | |||
| 195 | status = acpi_extract_package(&(p->package.elements[i + 1]), | ||
| 196 | &art_format, &element); | ||
| 197 | if (ACPI_FAILURE(status)) { | ||
| 198 | pr_warn("_ART package %d is invalid, ignored", i); | ||
| 199 | nr_bad_entries++; | ||
| 200 | continue; | ||
| 201 | } | ||
| 202 | if (!create_dev) | ||
| 203 | continue; | ||
| 204 | |||
| 205 | if (art->source) { | ||
| 206 | result = acpi_bus_get_device(art->source, &adev); | ||
| 207 | if (!result) | ||
| 208 | acpi_create_platform_device(adev); | ||
| 209 | else | ||
| 210 | pr_warn("Failed to get source ACPI device\n"); | ||
| 211 | } | ||
| 212 | if (art->target) { | ||
| 213 | result = acpi_bus_get_device(art->target, &adev); | ||
| 214 | if (!result) | ||
| 215 | acpi_create_platform_device(adev); | ||
| 216 | else | ||
| 217 | pr_warn("Failed to get source ACPI device\n"); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | *artp = arts; | ||
| 222 | /* don't count bad entries */ | ||
| 223 | *art_count -= nr_bad_entries; | ||
| 224 | end: | ||
| 225 | kfree(buffer.pointer); | ||
| 226 | return result; | ||
| 227 | } | ||
| 228 | EXPORT_SYMBOL(acpi_parse_art); | ||
| 229 | |||
| 230 | |||
| 231 | /* get device name from acpi handle */ | ||
| 232 | static void get_single_name(acpi_handle handle, char *name) | ||
| 233 | { | ||
| 234 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER}; | ||
| 235 | |||
| 236 | if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer))) | ||
| 237 | pr_warn("Failed get name from handle\n"); | ||
| 238 | else { | ||
| 239 | memcpy(name, buffer.pointer, ACPI_NAME_SIZE); | ||
| 240 | kfree(buffer.pointer); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | static int fill_art(char __user *ubuf) | ||
| 245 | { | ||
| 246 | int i; | ||
| 247 | int ret; | ||
| 248 | int count; | ||
| 249 | int art_len; | ||
| 250 | struct art *arts = NULL; | ||
| 251 | union art_object *art_user; | ||
| 252 | |||
| 253 | ret = acpi_parse_art(acpi_thermal_rel_handle, &count, &arts, false); | ||
| 254 | if (ret) | ||
| 255 | goto free_art; | ||
| 256 | art_len = count * sizeof(union art_object); | ||
| 257 | art_user = kzalloc(art_len, GFP_KERNEL); | ||
| 258 | if (!art_user) { | ||
| 259 | ret = -ENOMEM; | ||
| 260 | goto free_art; | ||
| 261 | } | ||
| 262 | /* now fill in user art data */ | ||
| 263 | for (i = 0; i < count; i++) { | ||
| 264 | /* userspace art needs device name instead of acpi reference */ | ||
| 265 | get_single_name(arts[i].source, art_user[i].source_device); | ||
| 266 | get_single_name(arts[i].target, art_user[i].target_device); | ||
| 267 | /* copy the rest int data in addition to source and target */ | ||
| 268 | memcpy(&art_user[i].weight, &arts[i].weight, | ||
| 269 | sizeof(u64) * (ACPI_NR_ART_ELEMENTS - 2)); | ||
| 270 | } | ||
| 271 | |||
| 272 | if (copy_to_user(ubuf, art_user, art_len)) | ||
| 273 | ret = -EFAULT; | ||
| 274 | kfree(art_user); | ||
| 275 | free_art: | ||
| 276 | kfree(arts); | ||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | |||
| 280 | static int fill_trt(char __user *ubuf) | ||
| 281 | { | ||
| 282 | int i; | ||
| 283 | int ret; | ||
| 284 | int count; | ||
| 285 | int trt_len; | ||
| 286 | struct trt *trts = NULL; | ||
| 287 | union trt_object *trt_user; | ||
| 288 | |||
| 289 | ret = acpi_parse_trt(acpi_thermal_rel_handle, &count, &trts, false); | ||
| 290 | if (ret) | ||
| 291 | goto free_trt; | ||
| 292 | trt_len = count * sizeof(union trt_object); | ||
| 293 | trt_user = kzalloc(trt_len, GFP_KERNEL); | ||
| 294 | if (!trt_user) { | ||
| 295 | ret = -ENOMEM; | ||
| 296 | goto free_trt; | ||
| 297 | } | ||
| 298 | /* now fill in user trt data */ | ||
| 299 | for (i = 0; i < count; i++) { | ||
| 300 | /* userspace trt needs device name instead of acpi reference */ | ||
| 301 | get_single_name(trts[i].source, trt_user[i].source_device); | ||
| 302 | get_single_name(trts[i].target, trt_user[i].target_device); | ||
| 303 | trt_user[i].sample_period = trts[i].sample_period; | ||
| 304 | trt_user[i].influence = trts[i].influence; | ||
| 305 | } | ||
| 306 | |||
| 307 | if (copy_to_user(ubuf, trt_user, trt_len)) | ||
| 308 | ret = -EFAULT; | ||
| 309 | kfree(trt_user); | ||
| 310 | free_trt: | ||
| 311 | kfree(trts); | ||
| 312 | return ret; | ||
| 313 | } | ||
| 314 | |||
| 315 | static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd, | ||
| 316 | unsigned long __arg) | ||
| 317 | { | ||
| 318 | int ret = 0; | ||
| 319 | unsigned long length = 0; | ||
| 320 | unsigned long count = 0; | ||
| 321 | char __user *arg = (void __user *)__arg; | ||
| 322 | struct trt *trts; | ||
| 323 | struct art *arts; | ||
| 324 | |||
| 325 | switch (cmd) { | ||
| 326 | case ACPI_THERMAL_GET_TRT_COUNT: | ||
| 327 | ret = acpi_parse_trt(acpi_thermal_rel_handle, (int *)&count, | ||
| 328 | &trts, false); | ||
| 329 | kfree(trts); | ||
| 330 | if (!ret) | ||
| 331 | return put_user(count, (unsigned long __user *)__arg); | ||
| 332 | return ret; | ||
| 333 | case ACPI_THERMAL_GET_TRT_LEN: | ||
| 334 | ret = acpi_parse_trt(acpi_thermal_rel_handle, (int *)&count, | ||
| 335 | &trts, false); | ||
| 336 | kfree(trts); | ||
| 337 | length = count * sizeof(union trt_object); | ||
| 338 | if (!ret) | ||
| 339 | return put_user(length, (unsigned long __user *)__arg); | ||
| 340 | return ret; | ||
| 341 | case ACPI_THERMAL_GET_TRT: | ||
| 342 | return fill_trt(arg); | ||
| 343 | case ACPI_THERMAL_GET_ART_COUNT: | ||
| 344 | ret = acpi_parse_art(acpi_thermal_rel_handle, (int *)&count, | ||
| 345 | &arts, false); | ||
| 346 | kfree(arts); | ||
| 347 | if (!ret) | ||
| 348 | return put_user(count, (unsigned long __user *)__arg); | ||
| 349 | return ret; | ||
| 350 | case ACPI_THERMAL_GET_ART_LEN: | ||
| 351 | ret = acpi_parse_art(acpi_thermal_rel_handle, (int *)&count, | ||
| 352 | &arts, false); | ||
| 353 | kfree(arts); | ||
| 354 | length = count * sizeof(union art_object); | ||
| 355 | if (!ret) | ||
| 356 | return put_user(length, (unsigned long __user *)__arg); | ||
| 357 | return ret; | ||
| 358 | |||
| 359 | case ACPI_THERMAL_GET_ART: | ||
| 360 | return fill_art(arg); | ||
| 361 | |||
| 362 | default: | ||
| 363 | return -ENOTTY; | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | static const struct file_operations acpi_thermal_rel_fops = { | ||
| 368 | .owner = THIS_MODULE, | ||
| 369 | .open = acpi_thermal_rel_open, | ||
| 370 | .release = acpi_thermal_rel_release, | ||
| 371 | .unlocked_ioctl = acpi_thermal_rel_ioctl, | ||
| 372 | .llseek = no_llseek, | ||
| 373 | }; | ||
| 374 | |||
| 375 | static struct miscdevice acpi_thermal_rel_misc_device = { | ||
| 376 | .minor = MISC_DYNAMIC_MINOR, | ||
| 377 | "acpi_thermal_rel", | ||
| 378 | &acpi_thermal_rel_fops | ||
| 379 | }; | ||
| 380 | |||
| 381 | int acpi_thermal_rel_misc_device_add(acpi_handle handle) | ||
| 382 | { | ||
| 383 | acpi_thermal_rel_handle = handle; | ||
| 384 | |||
| 385 | return misc_register(&acpi_thermal_rel_misc_device); | ||
| 386 | } | ||
| 387 | EXPORT_SYMBOL(acpi_thermal_rel_misc_device_add); | ||
| 388 | |||
| 389 | int acpi_thermal_rel_misc_device_remove(acpi_handle handle) | ||
| 390 | { | ||
| 391 | misc_deregister(&acpi_thermal_rel_misc_device); | ||
| 392 | |||
| 393 | return 0; | ||
| 394 | } | ||
| 395 | EXPORT_SYMBOL(acpi_thermal_rel_misc_device_remove); | ||
| 396 | |||
| 397 | MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>"); | ||
| 398 | MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com"); | ||
| 399 | MODULE_DESCRIPTION("Intel acpi thermal rel misc dev driver"); | ||
| 400 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/thermal/int340x_thermal/acpi_thermal_rel.h b/drivers/thermal/int340x_thermal/acpi_thermal_rel.h new file mode 100644 index 000000000000..f00700bc9d79 --- /dev/null +++ b/drivers/thermal/int340x_thermal/acpi_thermal_rel.h | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | #ifndef __ACPI_ACPI_THERMAL_H | ||
| 2 | #define __ACPI_ACPI_THERMAL_H | ||
| 3 | |||
| 4 | #include <asm/ioctl.h> | ||
| 5 | |||
| 6 | #define ACPI_THERMAL_MAGIC 's' | ||
| 7 | |||
| 8 | #define ACPI_THERMAL_GET_TRT_LEN _IOR(ACPI_THERMAL_MAGIC, 1, unsigned long) | ||
| 9 | #define ACPI_THERMAL_GET_ART_LEN _IOR(ACPI_THERMAL_MAGIC, 2, unsigned long) | ||
| 10 | #define ACPI_THERMAL_GET_TRT_COUNT _IOR(ACPI_THERMAL_MAGIC, 3, unsigned long) | ||
| 11 | #define ACPI_THERMAL_GET_ART_COUNT _IOR(ACPI_THERMAL_MAGIC, 4, unsigned long) | ||
| 12 | |||
| 13 | #define ACPI_THERMAL_GET_TRT _IOR(ACPI_THERMAL_MAGIC, 5, unsigned long) | ||
| 14 | #define ACPI_THERMAL_GET_ART _IOR(ACPI_THERMAL_MAGIC, 6, unsigned long) | ||
| 15 | |||
| 16 | struct art { | ||
| 17 | acpi_handle source; | ||
| 18 | acpi_handle target; | ||
| 19 | u64 weight; | ||
| 20 | u64 ac0_max; | ||
| 21 | u64 ac1_max; | ||
| 22 | u64 ac2_max; | ||
| 23 | u64 ac3_max; | ||
| 24 | u64 ac4_max; | ||
| 25 | u64 ac5_max; | ||
| 26 | u64 ac6_max; | ||
| 27 | u64 ac7_max; | ||
| 28 | u64 ac8_max; | ||
| 29 | u64 ac9_max; | ||
| 30 | } __packed; | ||
| 31 | |||
| 32 | struct trt { | ||
| 33 | acpi_handle source; | ||
| 34 | acpi_handle target; | ||
| 35 | u64 influence; | ||
| 36 | u64 sample_period; | ||
| 37 | u64 reverved1; | ||
| 38 | u64 reverved2; | ||
| 39 | u64 reverved3; | ||
| 40 | u64 reverved4; | ||
| 41 | } __packed; | ||
| 42 | |||
| 43 | #define ACPI_NR_ART_ELEMENTS 13 | ||
| 44 | /* for usrspace */ | ||
| 45 | union art_object { | ||
| 46 | struct { | ||
| 47 | char source_device[8]; /* ACPI single name */ | ||
| 48 | char target_device[8]; /* ACPI single name */ | ||
| 49 | u64 weight; | ||
| 50 | u64 ac0_max_level; | ||
| 51 | u64 ac1_max_level; | ||
| 52 | u64 ac2_max_level; | ||
| 53 | u64 ac3_max_level; | ||
| 54 | u64 ac4_max_level; | ||
| 55 | u64 ac5_max_level; | ||
| 56 | u64 ac6_max_level; | ||
| 57 | u64 ac7_max_level; | ||
| 58 | u64 ac8_max_level; | ||
| 59 | u64 ac9_max_level; | ||
| 60 | }; | ||
| 61 | u64 __data[ACPI_NR_ART_ELEMENTS]; | ||
| 62 | }; | ||
| 63 | |||
| 64 | union trt_object { | ||
| 65 | struct { | ||
| 66 | char source_device[8]; /* ACPI single name */ | ||
| 67 | char target_device[8]; /* ACPI single name */ | ||
| 68 | u64 influence; | ||
| 69 | u64 sample_period; | ||
| 70 | u64 reserved[4]; | ||
| 71 | }; | ||
| 72 | u64 __data[8]; | ||
| 73 | }; | ||
| 74 | |||
| 75 | #ifdef __KERNEL__ | ||
| 76 | int acpi_thermal_rel_misc_device_add(acpi_handle handle); | ||
| 77 | int acpi_thermal_rel_misc_device_remove(acpi_handle handle); | ||
| 78 | int acpi_parse_art(acpi_handle handle, int *art_count, struct art **arts, | ||
| 79 | bool create_dev); | ||
| 80 | int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trts, | ||
| 81 | bool create_dev); | ||
| 82 | #endif | ||
| 83 | |||
| 84 | #endif /* __ACPI_ACPI_THERMAL_H */ | ||
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c new file mode 100644 index 000000000000..edc1cce117ba --- /dev/null +++ b/drivers/thermal/int340x_thermal/int3400_thermal.c | |||
| @@ -0,0 +1,271 @@ | |||
| 1 | /* | ||
| 2 | * INT3400 thermal driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014, Intel Corporation | ||
| 5 | * Authors: Zhang Rui <rui.zhang@intel.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | #include <linux/acpi.h> | ||
| 16 | #include <linux/thermal.h> | ||
| 17 | #include "acpi_thermal_rel.h" | ||
| 18 | |||
| 19 | enum int3400_thermal_uuid { | ||
| 20 | INT3400_THERMAL_PASSIVE_1, | ||
| 21 | INT3400_THERMAL_PASSIVE_2, | ||
| 22 | INT3400_THERMAL_ACTIVE, | ||
| 23 | INT3400_THERMAL_CRITICAL, | ||
| 24 | INT3400_THERMAL_COOLING_MODE, | ||
| 25 | INT3400_THERMAL_MAXIMUM_UUID, | ||
| 26 | }; | ||
| 27 | |||
| 28 | static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { | ||
| 29 | "42A441D6-AE6A-462b-A84B-4A8CE79027D3", | ||
| 30 | "9E04115A-AE87-4D1C-9500-0F3E340BFE75", | ||
| 31 | "3A95C389-E4B8-4629-A526-C52C88626BAE", | ||
| 32 | "97C68AE7-15FA-499c-B8C9-5DA81D606E0A", | ||
| 33 | "16CAF1B7-DD38-40ed-B1C1-1B8A1913D531", | ||
| 34 | }; | ||
| 35 | |||
| 36 | struct int3400_thermal_priv { | ||
| 37 | struct acpi_device *adev; | ||
| 38 | struct thermal_zone_device *thermal; | ||
| 39 | int mode; | ||
| 40 | int art_count; | ||
| 41 | struct art *arts; | ||
| 42 | int trt_count; | ||
| 43 | struct trt *trts; | ||
| 44 | u8 uuid_bitmap; | ||
| 45 | int rel_misc_dev_res; | ||
| 46 | }; | ||
| 47 | |||
| 48 | static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv) | ||
| 49 | { | ||
| 50 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL}; | ||
| 51 | union acpi_object *obja, *objb; | ||
| 52 | int i, j; | ||
| 53 | int result = 0; | ||
| 54 | acpi_status status; | ||
| 55 | |||
| 56 | status = acpi_evaluate_object(priv->adev->handle, "IDSP", NULL, &buf); | ||
| 57 | if (ACPI_FAILURE(status)) | ||
| 58 | return -ENODEV; | ||
| 59 | |||
| 60 | obja = (union acpi_object *)buf.pointer; | ||
| 61 | if (obja->type != ACPI_TYPE_PACKAGE) { | ||
| 62 | result = -EINVAL; | ||
| 63 | goto end; | ||
| 64 | } | ||
| 65 | |||
| 66 | for (i = 0; i < obja->package.count; i++) { | ||
| 67 | objb = &obja->package.elements[i]; | ||
| 68 | if (objb->type != ACPI_TYPE_BUFFER) { | ||
| 69 | result = -EINVAL; | ||
| 70 | goto end; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* UUID must be 16 bytes */ | ||
| 74 | if (objb->buffer.length != 16) { | ||
| 75 | result = -EINVAL; | ||
| 76 | goto end; | ||
| 77 | } | ||
| 78 | |||
| 79 | for (j = 0; j < INT3400_THERMAL_MAXIMUM_UUID; j++) { | ||
| 80 | u8 uuid[16]; | ||
| 81 | |||
| 82 | acpi_str_to_uuid(int3400_thermal_uuids[j], uuid); | ||
| 83 | if (!strncmp(uuid, objb->buffer.pointer, 16)) { | ||
| 84 | priv->uuid_bitmap |= (1 << j); | ||
| 85 | break; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | end: | ||
| 91 | kfree(buf.pointer); | ||
| 92 | return result; | ||
| 93 | } | ||
| 94 | |||
| 95 | static int int3400_thermal_run_osc(acpi_handle handle, | ||
| 96 | enum int3400_thermal_uuid uuid, bool enable) | ||
| 97 | { | ||
| 98 | u32 ret, buf[2]; | ||
| 99 | acpi_status status; | ||
| 100 | int result = 0; | ||
| 101 | struct acpi_osc_context context = { | ||
| 102 | .uuid_str = int3400_thermal_uuids[uuid], | ||
| 103 | .rev = 1, | ||
| 104 | .cap.length = 8, | ||
| 105 | }; | ||
| 106 | |||
| 107 | buf[OSC_QUERY_DWORD] = 0; | ||
| 108 | buf[OSC_SUPPORT_DWORD] = enable; | ||
| 109 | |||
| 110 | context.cap.pointer = buf; | ||
| 111 | |||
| 112 | status = acpi_run_osc(handle, &context); | ||
| 113 | if (ACPI_SUCCESS(status)) { | ||
| 114 | ret = *((u32 *)(context.ret.pointer + 4)); | ||
| 115 | if (ret != enable) | ||
| 116 | result = -EPERM; | ||
| 117 | } else | ||
| 118 | result = -EPERM; | ||
| 119 | |||
| 120 | kfree(context.ret.pointer); | ||
| 121 | return result; | ||
| 122 | } | ||
| 123 | |||
| 124 | static int int3400_thermal_get_temp(struct thermal_zone_device *thermal, | ||
| 125 | unsigned long *temp) | ||
| 126 | { | ||
| 127 | *temp = 20 * 1000; /* faked temp sensor with 20C */ | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int int3400_thermal_get_mode(struct thermal_zone_device *thermal, | ||
| 132 | enum thermal_device_mode *mode) | ||
| 133 | { | ||
| 134 | struct int3400_thermal_priv *priv = thermal->devdata; | ||
| 135 | |||
| 136 | if (!priv) | ||
| 137 | return -EINVAL; | ||
| 138 | |||
| 139 | *mode = priv->mode; | ||
| 140 | |||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | static int int3400_thermal_set_mode(struct thermal_zone_device *thermal, | ||
| 145 | enum thermal_device_mode mode) | ||
| 146 | { | ||
| 147 | struct int3400_thermal_priv *priv = thermal->devdata; | ||
| 148 | bool enable; | ||
| 149 | int result = 0; | ||
| 150 | |||
| 151 | if (!priv) | ||
| 152 | return -EINVAL; | ||
| 153 | |||
| 154 | if (mode == THERMAL_DEVICE_ENABLED) | ||
| 155 | enable = true; | ||
| 156 | else if (mode == THERMAL_DEVICE_DISABLED) | ||
| 157 | enable = false; | ||
| 158 | else | ||
| 159 | return -EINVAL; | ||
| 160 | |||
| 161 | if (enable != priv->mode) { | ||
| 162 | priv->mode = enable; | ||
| 163 | /* currently, only PASSIVE COOLING is supported */ | ||
| 164 | result = int3400_thermal_run_osc(priv->adev->handle, | ||
| 165 | INT3400_THERMAL_PASSIVE_1, enable); | ||
| 166 | } | ||
| 167 | return result; | ||
| 168 | } | ||
| 169 | |||
| 170 | static struct thermal_zone_device_ops int3400_thermal_ops = { | ||
| 171 | .get_temp = int3400_thermal_get_temp, | ||
| 172 | }; | ||
| 173 | |||
| 174 | static struct thermal_zone_params int3400_thermal_params = { | ||
| 175 | .governor_name = "user_space", | ||
| 176 | .no_hwmon = true, | ||
| 177 | }; | ||
| 178 | |||
| 179 | static int int3400_thermal_probe(struct platform_device *pdev) | ||
| 180 | { | ||
| 181 | struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); | ||
| 182 | struct int3400_thermal_priv *priv; | ||
| 183 | int result; | ||
| 184 | |||
| 185 | if (!adev) | ||
| 186 | return -ENODEV; | ||
| 187 | |||
| 188 | priv = kzalloc(sizeof(struct int3400_thermal_priv), GFP_KERNEL); | ||
| 189 | if (!priv) | ||
| 190 | return -ENOMEM; | ||
| 191 | |||
| 192 | priv->adev = adev; | ||
| 193 | |||
| 194 | result = int3400_thermal_get_uuids(priv); | ||
| 195 | if (result) | ||
| 196 | goto free_priv; | ||
| 197 | |||
| 198 | result = acpi_parse_art(priv->adev->handle, &priv->art_count, | ||
| 199 | &priv->arts, true); | ||
| 200 | if (result) | ||
| 201 | goto free_priv; | ||
| 202 | |||
| 203 | |||
| 204 | result = acpi_parse_trt(priv->adev->handle, &priv->trt_count, | ||
| 205 | &priv->trts, true); | ||
| 206 | if (result) | ||
| 207 | goto free_art; | ||
| 208 | |||
| 209 | platform_set_drvdata(pdev, priv); | ||
| 210 | |||
| 211 | if (priv->uuid_bitmap & 1 << INT3400_THERMAL_PASSIVE_1) { | ||
| 212 | int3400_thermal_ops.get_mode = int3400_thermal_get_mode; | ||
| 213 | int3400_thermal_ops.set_mode = int3400_thermal_set_mode; | ||
| 214 | } | ||
| 215 | priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0, | ||
| 216 | priv, &int3400_thermal_ops, | ||
| 217 | &int3400_thermal_params, 0, 0); | ||
| 218 | if (IS_ERR(priv->thermal)) { | ||
| 219 | result = PTR_ERR(priv->thermal); | ||
| 220 | goto free_trt; | ||
| 221 | } | ||
| 222 | |||
| 223 | priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add( | ||
| 224 | priv->adev->handle); | ||
| 225 | |||
| 226 | return 0; | ||
| 227 | free_trt: | ||
| 228 | kfree(priv->trts); | ||
| 229 | free_art: | ||
| 230 | kfree(priv->arts); | ||
| 231 | free_priv: | ||
| 232 | kfree(priv); | ||
| 233 | return result; | ||
| 234 | } | ||
| 235 | |||
| 236 | static int int3400_thermal_remove(struct platform_device *pdev) | ||
| 237 | { | ||
| 238 | struct int3400_thermal_priv *priv = platform_get_drvdata(pdev); | ||
| 239 | |||
| 240 | if (!priv->rel_misc_dev_res) | ||
| 241 | acpi_thermal_rel_misc_device_remove(priv->adev->handle); | ||
| 242 | |||
| 243 | thermal_zone_device_unregister(priv->thermal); | ||
| 244 | kfree(priv->trts); | ||
| 245 | kfree(priv->arts); | ||
| 246 | kfree(priv); | ||
| 247 | return 0; | ||
| 248 | } | ||
| 249 | |||
| 250 | static const struct acpi_device_id int3400_thermal_match[] = { | ||
| 251 | {"INT3400", 0}, | ||
| 252 | {} | ||
| 253 | }; | ||
| 254 | |||
| 255 | MODULE_DEVICE_TABLE(acpi, int3400_thermal_match); | ||
| 256 | |||
| 257 | static struct platform_driver int3400_thermal_driver = { | ||
| 258 | .probe = int3400_thermal_probe, | ||
| 259 | .remove = int3400_thermal_remove, | ||
| 260 | .driver = { | ||
| 261 | .name = "int3400 thermal", | ||
| 262 | .owner = THIS_MODULE, | ||
| 263 | .acpi_match_table = ACPI_PTR(int3400_thermal_match), | ||
| 264 | }, | ||
| 265 | }; | ||
| 266 | |||
| 267 | module_platform_driver(int3400_thermal_driver); | ||
| 268 | |||
| 269 | MODULE_DESCRIPTION("INT3400 Thermal driver"); | ||
| 270 | MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>"); | ||
| 271 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c new file mode 100644 index 000000000000..a5d08c14ba24 --- /dev/null +++ b/drivers/thermal/int340x_thermal/int3402_thermal.c | |||
| @@ -0,0 +1,242 @@ | |||
| 1 | /* | ||
| 2 | * INT3402 thermal driver for memory temperature reporting | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014, Intel Corporation | ||
| 5 | * Authors: Aaron Lu <aaron.lu@intel.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | #include <linux/acpi.h> | ||
| 16 | #include <linux/thermal.h> | ||
| 17 | |||
| 18 | #define ACPI_ACTIVE_COOLING_MAX_NR 10 | ||
| 19 | |||
| 20 | struct active_trip { | ||
| 21 | unsigned long temp; | ||
| 22 | int id; | ||
| 23 | bool valid; | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct int3402_thermal_data { | ||
| 27 | unsigned long *aux_trips; | ||
| 28 | int aux_trip_nr; | ||
| 29 | unsigned long psv_temp; | ||
| 30 | int psv_trip_id; | ||
| 31 | unsigned long crt_temp; | ||
| 32 | int crt_trip_id; | ||
| 33 | unsigned long hot_temp; | ||
| 34 | int hot_trip_id; | ||
| 35 | struct active_trip act_trips[ACPI_ACTIVE_COOLING_MAX_NR]; | ||
| 36 | acpi_handle *handle; | ||
| 37 | }; | ||
| 38 | |||
| 39 | static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone, | ||
| 40 | unsigned long *temp) | ||
| 41 | { | ||
| 42 | struct int3402_thermal_data *d = zone->devdata; | ||
| 43 | unsigned long long tmp; | ||
| 44 | acpi_status status; | ||
| 45 | |||
| 46 | status = acpi_evaluate_integer(d->handle, "_TMP", NULL, &tmp); | ||
| 47 | if (ACPI_FAILURE(status)) | ||
| 48 | return -ENODEV; | ||
| 49 | |||
| 50 | /* _TMP returns the temperature in tenths of degrees Kelvin */ | ||
| 51 | *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); | ||
| 52 | |||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | static int int3402_thermal_get_trip_temp(struct thermal_zone_device *zone, | ||
| 57 | int trip, unsigned long *temp) | ||
| 58 | { | ||
| 59 | struct int3402_thermal_data *d = zone->devdata; | ||
| 60 | int i; | ||
| 61 | |||
| 62 | if (trip < d->aux_trip_nr) | ||
| 63 | *temp = d->aux_trips[trip]; | ||
| 64 | else if (trip == d->crt_trip_id) | ||
| 65 | *temp = d->crt_temp; | ||
| 66 | else if (trip == d->psv_trip_id) | ||
| 67 | *temp = d->psv_temp; | ||
| 68 | else if (trip == d->hot_trip_id) | ||
| 69 | *temp = d->hot_temp; | ||
| 70 | else { | ||
| 71 | for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { | ||
| 72 | if (d->act_trips[i].valid && | ||
| 73 | d->act_trips[i].id == trip) { | ||
| 74 | *temp = d->act_trips[i].temp; | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | if (i == ACPI_ACTIVE_COOLING_MAX_NR) | ||
| 79 | return -EINVAL; | ||
| 80 | } | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | static int int3402_thermal_get_trip_type(struct thermal_zone_device *zone, | ||
| 85 | int trip, enum thermal_trip_type *type) | ||
| 86 | { | ||
| 87 | struct int3402_thermal_data *d = zone->devdata; | ||
| 88 | int i; | ||
| 89 | |||
| 90 | if (trip < d->aux_trip_nr) | ||
| 91 | *type = THERMAL_TRIP_PASSIVE; | ||
| 92 | else if (trip == d->crt_trip_id) | ||
| 93 | *type = THERMAL_TRIP_CRITICAL; | ||
| 94 | else if (trip == d->hot_trip_id) | ||
| 95 | *type = THERMAL_TRIP_HOT; | ||
| 96 | else if (trip == d->psv_trip_id) | ||
| 97 | *type = THERMAL_TRIP_PASSIVE; | ||
| 98 | else { | ||
| 99 | for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { | ||
| 100 | if (d->act_trips[i].valid && | ||
| 101 | d->act_trips[i].id == trip) { | ||
| 102 | *type = THERMAL_TRIP_ACTIVE; | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | if (i == ACPI_ACTIVE_COOLING_MAX_NR) | ||
| 107 | return -EINVAL; | ||
| 108 | } | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int int3402_thermal_set_trip_temp(struct thermal_zone_device *zone, int trip, | ||
| 113 | unsigned long temp) | ||
| 114 | { | ||
| 115 | struct int3402_thermal_data *d = zone->devdata; | ||
| 116 | acpi_status status; | ||
| 117 | char name[10]; | ||
| 118 | |||
| 119 | snprintf(name, sizeof(name), "PAT%d", trip); | ||
| 120 | status = acpi_execute_simple_method(d->handle, name, | ||
| 121 | MILLICELSIUS_TO_DECI_KELVIN(temp)); | ||
| 122 | if (ACPI_FAILURE(status)) | ||
| 123 | return -EIO; | ||
| 124 | |||
| 125 | d->aux_trips[trip] = temp; | ||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | static struct thermal_zone_device_ops int3402_thermal_zone_ops = { | ||
| 130 | .get_temp = int3402_thermal_get_zone_temp, | ||
| 131 | .get_trip_temp = int3402_thermal_get_trip_temp, | ||
| 132 | .get_trip_type = int3402_thermal_get_trip_type, | ||
| 133 | .set_trip_temp = int3402_thermal_set_trip_temp, | ||
| 134 | }; | ||
| 135 | |||
| 136 | static struct thermal_zone_params int3402_thermal_params = { | ||
| 137 | .governor_name = "user_space", | ||
| 138 | .no_hwmon = true, | ||
| 139 | }; | ||
| 140 | |||
| 141 | static int int3402_thermal_get_temp(acpi_handle handle, char *name, | ||
| 142 | unsigned long *temp) | ||
| 143 | { | ||
| 144 | unsigned long long r; | ||
| 145 | acpi_status status; | ||
| 146 | |||
| 147 | status = acpi_evaluate_integer(handle, name, NULL, &r); | ||
| 148 | if (ACPI_FAILURE(status)) | ||
| 149 | return -EIO; | ||
| 150 | |||
| 151 | *temp = DECI_KELVIN_TO_MILLICELSIUS(r); | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | static int int3402_thermal_probe(struct platform_device *pdev) | ||
| 156 | { | ||
| 157 | struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); | ||
| 158 | struct int3402_thermal_data *d; | ||
| 159 | struct thermal_zone_device *zone; | ||
| 160 | acpi_status status; | ||
| 161 | unsigned long long trip_cnt; | ||
| 162 | int trip_mask = 0, i; | ||
| 163 | |||
| 164 | if (!acpi_has_method(adev->handle, "_TMP")) | ||
| 165 | return -ENODEV; | ||
| 166 | |||
| 167 | d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL); | ||
| 168 | if (!d) | ||
| 169 | return -ENOMEM; | ||
| 170 | |||
| 171 | status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); | ||
| 172 | if (ACPI_FAILURE(status)) | ||
| 173 | trip_cnt = 0; | ||
| 174 | else { | ||
| 175 | d->aux_trips = devm_kzalloc(&pdev->dev, | ||
| 176 | sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL); | ||
| 177 | if (!d->aux_trips) | ||
| 178 | return -ENOMEM; | ||
| 179 | trip_mask = trip_cnt - 1; | ||
| 180 | d->handle = adev->handle; | ||
| 181 | d->aux_trip_nr = trip_cnt; | ||
| 182 | } | ||
| 183 | |||
| 184 | d->crt_trip_id = -1; | ||
| 185 | if (!int3402_thermal_get_temp(adev->handle, "_CRT", &d->crt_temp)) | ||
| 186 | d->crt_trip_id = trip_cnt++; | ||
| 187 | d->hot_trip_id = -1; | ||
| 188 | if (!int3402_thermal_get_temp(adev->handle, "_HOT", &d->hot_temp)) | ||
| 189 | d->hot_trip_id = trip_cnt++; | ||
| 190 | d->psv_trip_id = -1; | ||
| 191 | if (!int3402_thermal_get_temp(adev->handle, "_PSV", &d->psv_temp)) | ||
| 192 | d->psv_trip_id = trip_cnt++; | ||
| 193 | for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { | ||
| 194 | char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; | ||
| 195 | if (int3402_thermal_get_temp(adev->handle, name, | ||
| 196 | &d->act_trips[i].temp)) | ||
| 197 | break; | ||
| 198 | d->act_trips[i].id = trip_cnt++; | ||
| 199 | d->act_trips[i].valid = true; | ||
| 200 | } | ||
| 201 | |||
| 202 | zone = thermal_zone_device_register(acpi_device_bid(adev), trip_cnt, | ||
| 203 | trip_mask, d, | ||
| 204 | &int3402_thermal_zone_ops, | ||
| 205 | &int3402_thermal_params, | ||
| 206 | 0, 0); | ||
| 207 | if (IS_ERR(zone)) | ||
| 208 | return PTR_ERR(zone); | ||
| 209 | platform_set_drvdata(pdev, zone); | ||
| 210 | |||
| 211 | return 0; | ||
| 212 | } | ||
| 213 | |||
| 214 | static int int3402_thermal_remove(struct platform_device *pdev) | ||
| 215 | { | ||
| 216 | struct thermal_zone_device *zone = platform_get_drvdata(pdev); | ||
| 217 | |||
| 218 | thermal_zone_device_unregister(zone); | ||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | static const struct acpi_device_id int3402_thermal_match[] = { | ||
| 223 | {"INT3402", 0}, | ||
| 224 | {} | ||
| 225 | }; | ||
| 226 | |||
| 227 | MODULE_DEVICE_TABLE(acpi, int3402_thermal_match); | ||
| 228 | |||
| 229 | static struct platform_driver int3402_thermal_driver = { | ||
| 230 | .probe = int3402_thermal_probe, | ||
| 231 | .remove = int3402_thermal_remove, | ||
| 232 | .driver = { | ||
| 233 | .name = "int3402 thermal", | ||
| 234 | .owner = THIS_MODULE, | ||
| 235 | .acpi_match_table = int3402_thermal_match, | ||
| 236 | }, | ||
| 237 | }; | ||
| 238 | |||
| 239 | module_platform_driver(int3402_thermal_driver); | ||
| 240 | |||
| 241 | MODULE_DESCRIPTION("INT3402 Thermal driver"); | ||
| 242 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c new file mode 100644 index 000000000000..d20dba986f0f --- /dev/null +++ b/drivers/thermal/int340x_thermal/int3403_thermal.c | |||
| @@ -0,0 +1,477 @@ | |||
| 1 | /* | ||
| 2 | * ACPI INT3403 thermal driver | ||
| 3 | * Copyright (c) 2013, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/types.h> | ||
| 19 | #include <linux/acpi.h> | ||
| 20 | #include <linux/thermal.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | |||
| 23 | #define INT3403_TYPE_SENSOR 0x03 | ||
| 24 | #define INT3403_TYPE_CHARGER 0x0B | ||
| 25 | #define INT3403_TYPE_BATTERY 0x0C | ||
| 26 | #define INT3403_PERF_CHANGED_EVENT 0x80 | ||
| 27 | #define INT3403_THERMAL_EVENT 0x90 | ||
| 28 | |||
| 29 | #define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100) | ||
| 30 | #define KELVIN_OFFSET 2732 | ||
| 31 | #define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off)) | ||
| 32 | |||
| 33 | struct int3403_sensor { | ||
| 34 | struct thermal_zone_device *tzone; | ||
| 35 | unsigned long *thresholds; | ||
| 36 | unsigned long crit_temp; | ||
| 37 | int crit_trip_id; | ||
| 38 | unsigned long psv_temp; | ||
| 39 | int psv_trip_id; | ||
| 40 | |||
| 41 | }; | ||
| 42 | |||
| 43 | struct int3403_performance_state { | ||
| 44 | u64 performance; | ||
| 45 | u64 power; | ||
| 46 | u64 latency; | ||
| 47 | u64 linear; | ||
| 48 | u64 control; | ||
| 49 | u64 raw_performace; | ||
| 50 | char *raw_unit; | ||
| 51 | int reserved; | ||
| 52 | }; | ||
| 53 | |||
| 54 | struct int3403_cdev { | ||
| 55 | struct thermal_cooling_device *cdev; | ||
| 56 | unsigned long max_state; | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct int3403_priv { | ||
| 60 | struct platform_device *pdev; | ||
| 61 | struct acpi_device *adev; | ||
| 62 | unsigned long long type; | ||
| 63 | void *priv; | ||
| 64 | }; | ||
| 65 | |||
| 66 | static int sys_get_curr_temp(struct thermal_zone_device *tzone, | ||
| 67 | unsigned long *temp) | ||
| 68 | { | ||
| 69 | struct int3403_priv *priv = tzone->devdata; | ||
| 70 | struct acpi_device *device = priv->adev; | ||
| 71 | unsigned long long tmp; | ||
| 72 | acpi_status status; | ||
| 73 | |||
| 74 | status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp); | ||
| 75 | if (ACPI_FAILURE(status)) | ||
| 76 | return -EIO; | ||
| 77 | |||
| 78 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET); | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int sys_get_trip_hyst(struct thermal_zone_device *tzone, | ||
| 84 | int trip, unsigned long *temp) | ||
| 85 | { | ||
| 86 | struct int3403_priv *priv = tzone->devdata; | ||
| 87 | struct acpi_device *device = priv->adev; | ||
| 88 | unsigned long long hyst; | ||
| 89 | acpi_status status; | ||
| 90 | |||
| 91 | status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst); | ||
| 92 | if (ACPI_FAILURE(status)) | ||
| 93 | return -EIO; | ||
| 94 | |||
| 95 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(hyst, KELVIN_OFFSET); | ||
| 96 | |||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int sys_get_trip_temp(struct thermal_zone_device *tzone, | ||
| 101 | int trip, unsigned long *temp) | ||
| 102 | { | ||
| 103 | struct int3403_priv *priv = tzone->devdata; | ||
| 104 | struct int3403_sensor *obj = priv->priv; | ||
| 105 | |||
| 106 | if (priv->type != INT3403_TYPE_SENSOR || !obj) | ||
| 107 | return -EINVAL; | ||
| 108 | |||
| 109 | if (trip == obj->crit_trip_id) | ||
| 110 | *temp = obj->crit_temp; | ||
| 111 | else if (trip == obj->psv_trip_id) | ||
| 112 | *temp = obj->psv_temp; | ||
| 113 | else { | ||
| 114 | /* | ||
| 115 | * get_trip_temp is a mandatory callback but | ||
| 116 | * PATx method doesn't return any value, so return | ||
| 117 | * cached value, which was last set from user space | ||
| 118 | */ | ||
| 119 | *temp = obj->thresholds[trip]; | ||
| 120 | } | ||
| 121 | |||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | static int sys_get_trip_type(struct thermal_zone_device *thermal, | ||
| 126 | int trip, enum thermal_trip_type *type) | ||
| 127 | { | ||
| 128 | struct int3403_priv *priv = thermal->devdata; | ||
| 129 | struct int3403_sensor *obj = priv->priv; | ||
| 130 | |||
| 131 | /* Mandatory callback, may not mean much here */ | ||
| 132 | if (trip == obj->crit_trip_id) | ||
| 133 | *type = THERMAL_TRIP_CRITICAL; | ||
| 134 | else | ||
| 135 | *type = THERMAL_TRIP_PASSIVE; | ||
| 136 | |||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip, | ||
| 141 | unsigned long temp) | ||
| 142 | { | ||
| 143 | struct int3403_priv *priv = tzone->devdata; | ||
| 144 | struct acpi_device *device = priv->adev; | ||
| 145 | struct int3403_sensor *obj = priv->priv; | ||
| 146 | acpi_status status; | ||
| 147 | char name[10]; | ||
| 148 | int ret = 0; | ||
| 149 | |||
| 150 | snprintf(name, sizeof(name), "PAT%d", trip); | ||
| 151 | if (acpi_has_method(device->handle, name)) { | ||
| 152 | status = acpi_execute_simple_method(device->handle, name, | ||
| 153 | MILLI_CELSIUS_TO_DECI_KELVIN(temp, | ||
| 154 | KELVIN_OFFSET)); | ||
| 155 | if (ACPI_FAILURE(status)) | ||
| 156 | ret = -EIO; | ||
| 157 | else | ||
| 158 | obj->thresholds[trip] = temp; | ||
| 159 | } else { | ||
| 160 | ret = -EIO; | ||
| 161 | dev_err(&device->dev, "sys_set_trip_temp: method not found\n"); | ||
| 162 | } | ||
| 163 | |||
| 164 | return ret; | ||
| 165 | } | ||
| 166 | |||
| 167 | static struct thermal_zone_device_ops tzone_ops = { | ||
| 168 | .get_temp = sys_get_curr_temp, | ||
| 169 | .get_trip_temp = sys_get_trip_temp, | ||
| 170 | .get_trip_type = sys_get_trip_type, | ||
| 171 | .set_trip_temp = sys_set_trip_temp, | ||
| 172 | .get_trip_hyst = sys_get_trip_hyst, | ||
| 173 | }; | ||
| 174 | |||
| 175 | static struct thermal_zone_params int3403_thermal_params = { | ||
| 176 | .governor_name = "user_space", | ||
| 177 | .no_hwmon = true, | ||
| 178 | }; | ||
| 179 | |||
| 180 | static void int3403_notify(acpi_handle handle, | ||
| 181 | u32 event, void *data) | ||
| 182 | { | ||
| 183 | struct int3403_priv *priv = data; | ||
| 184 | struct int3403_sensor *obj; | ||
| 185 | |||
| 186 | if (!priv) | ||
| 187 | return; | ||
| 188 | |||
| 189 | obj = priv->priv; | ||
| 190 | if (priv->type != INT3403_TYPE_SENSOR || !obj) | ||
| 191 | return; | ||
| 192 | |||
| 193 | switch (event) { | ||
| 194 | case INT3403_PERF_CHANGED_EVENT: | ||
| 195 | break; | ||
| 196 | case INT3403_THERMAL_EVENT: | ||
| 197 | thermal_zone_device_update(obj->tzone); | ||
| 198 | break; | ||
| 199 | default: | ||
| 200 | dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); | ||
| 201 | break; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp) | ||
| 206 | { | ||
| 207 | unsigned long long crt; | ||
| 208 | acpi_status status; | ||
| 209 | |||
| 210 | status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt); | ||
| 211 | if (ACPI_FAILURE(status)) | ||
| 212 | return -EIO; | ||
| 213 | |||
| 214 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET); | ||
| 215 | |||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | |||
| 219 | static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp) | ||
| 220 | { | ||
| 221 | unsigned long long psv; | ||
| 222 | acpi_status status; | ||
| 223 | |||
| 224 | status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv); | ||
| 225 | if (ACPI_FAILURE(status)) | ||
| 226 | return -EIO; | ||
| 227 | |||
| 228 | *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET); | ||
| 229 | |||
| 230 | return 0; | ||
| 231 | } | ||
| 232 | |||
| 233 | static int int3403_sensor_add(struct int3403_priv *priv) | ||
| 234 | { | ||
| 235 | int result = 0; | ||
| 236 | acpi_status status; | ||
| 237 | struct int3403_sensor *obj; | ||
| 238 | unsigned long long trip_cnt; | ||
| 239 | int trip_mask = 0; | ||
| 240 | |||
| 241 | obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); | ||
| 242 | if (!obj) | ||
| 243 | return -ENOMEM; | ||
| 244 | |||
| 245 | priv->priv = obj; | ||
| 246 | |||
| 247 | status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL, | ||
| 248 | &trip_cnt); | ||
| 249 | if (ACPI_FAILURE(status)) | ||
| 250 | trip_cnt = 0; | ||
| 251 | |||
| 252 | if (trip_cnt) { | ||
| 253 | /* We have to cache, thresholds can't be readback */ | ||
| 254 | obj->thresholds = devm_kzalloc(&priv->pdev->dev, | ||
| 255 | sizeof(*obj->thresholds) * trip_cnt, | ||
| 256 | GFP_KERNEL); | ||
| 257 | if (!obj->thresholds) { | ||
| 258 | result = -ENOMEM; | ||
| 259 | goto err_free_obj; | ||
| 260 | } | ||
| 261 | trip_mask = BIT(trip_cnt) - 1; | ||
| 262 | } | ||
| 263 | |||
| 264 | obj->psv_trip_id = -1; | ||
| 265 | if (!sys_get_trip_psv(priv->adev, &obj->psv_temp)) | ||
| 266 | obj->psv_trip_id = trip_cnt++; | ||
| 267 | |||
| 268 | obj->crit_trip_id = -1; | ||
| 269 | if (!sys_get_trip_crt(priv->adev, &obj->crit_temp)) | ||
| 270 | obj->crit_trip_id = trip_cnt++; | ||
| 271 | |||
| 272 | obj->tzone = thermal_zone_device_register(acpi_device_bid(priv->adev), | ||
| 273 | trip_cnt, trip_mask, priv, &tzone_ops, | ||
| 274 | &int3403_thermal_params, 0, 0); | ||
| 275 | if (IS_ERR(obj->tzone)) { | ||
| 276 | result = PTR_ERR(obj->tzone); | ||
| 277 | obj->tzone = NULL; | ||
| 278 | goto err_free_obj; | ||
| 279 | } | ||
| 280 | |||
| 281 | result = acpi_install_notify_handler(priv->adev->handle, | ||
| 282 | ACPI_DEVICE_NOTIFY, int3403_notify, | ||
| 283 | (void *)priv); | ||
| 284 | if (result) | ||
| 285 | goto err_free_obj; | ||
| 286 | |||
| 287 | return 0; | ||
| 288 | |||
| 289 | err_free_obj: | ||
| 290 | if (obj->tzone) | ||
| 291 | thermal_zone_device_unregister(obj->tzone); | ||
| 292 | return result; | ||
| 293 | } | ||
| 294 | |||
| 295 | static int int3403_sensor_remove(struct int3403_priv *priv) | ||
| 296 | { | ||
| 297 | struct int3403_sensor *obj = priv->priv; | ||
| 298 | |||
| 299 | thermal_zone_device_unregister(obj->tzone); | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | |||
| 303 | /* INT3403 Cooling devices */ | ||
| 304 | static int int3403_get_max_state(struct thermal_cooling_device *cdev, | ||
| 305 | unsigned long *state) | ||
| 306 | { | ||
| 307 | struct int3403_priv *priv = cdev->devdata; | ||
| 308 | struct int3403_cdev *obj = priv->priv; | ||
| 309 | |||
| 310 | *state = obj->max_state; | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | static int int3403_get_cur_state(struct thermal_cooling_device *cdev, | ||
| 315 | unsigned long *state) | ||
| 316 | { | ||
| 317 | struct int3403_priv *priv = cdev->devdata; | ||
| 318 | unsigned long long level; | ||
| 319 | acpi_status status; | ||
| 320 | |||
| 321 | status = acpi_evaluate_integer(priv->adev->handle, "PPPC", NULL, &level); | ||
| 322 | if (ACPI_SUCCESS(status)) { | ||
| 323 | *state = level; | ||
| 324 | return 0; | ||
| 325 | } else | ||
| 326 | return -EINVAL; | ||
| 327 | } | ||
| 328 | |||
| 329 | static int | ||
| 330 | int3403_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) | ||
| 331 | { | ||
| 332 | struct int3403_priv *priv = cdev->devdata; | ||
| 333 | acpi_status status; | ||
| 334 | |||
| 335 | status = acpi_execute_simple_method(priv->adev->handle, "SPPC", state); | ||
| 336 | if (ACPI_SUCCESS(status)) | ||
| 337 | return 0; | ||
| 338 | else | ||
| 339 | return -EINVAL; | ||
| 340 | } | ||
| 341 | |||
| 342 | static const struct thermal_cooling_device_ops int3403_cooling_ops = { | ||
| 343 | .get_max_state = int3403_get_max_state, | ||
| 344 | .get_cur_state = int3403_get_cur_state, | ||
| 345 | .set_cur_state = int3403_set_cur_state, | ||
| 346 | }; | ||
| 347 | |||
| 348 | static int int3403_cdev_add(struct int3403_priv *priv) | ||
| 349 | { | ||
| 350 | int result = 0; | ||
| 351 | acpi_status status; | ||
| 352 | struct int3403_cdev *obj; | ||
| 353 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 354 | union acpi_object *p; | ||
| 355 | |||
| 356 | obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); | ||
| 357 | if (!obj) | ||
| 358 | return -ENOMEM; | ||
| 359 | |||
| 360 | status = acpi_evaluate_object(priv->adev->handle, "PPSS", NULL, &buf); | ||
| 361 | if (ACPI_FAILURE(status)) | ||
| 362 | return -ENODEV; | ||
| 363 | |||
| 364 | p = buf.pointer; | ||
| 365 | if (!p || (p->type != ACPI_TYPE_PACKAGE)) { | ||
| 366 | printk(KERN_WARNING "Invalid PPSS data\n"); | ||
| 367 | return -EFAULT; | ||
| 368 | } | ||
| 369 | |||
| 370 | obj->max_state = p->package.count - 1; | ||
| 371 | obj->cdev = | ||
| 372 | thermal_cooling_device_register(acpi_device_bid(priv->adev), | ||
| 373 | priv, &int3403_cooling_ops); | ||
| 374 | if (IS_ERR(obj->cdev)) | ||
| 375 | result = PTR_ERR(obj->cdev); | ||
| 376 | |||
| 377 | priv->priv = obj; | ||
| 378 | |||
| 379 | /* TODO: add ACPI notification support */ | ||
| 380 | |||
| 381 | return result; | ||
| 382 | } | ||
| 383 | |||
| 384 | static int int3403_cdev_remove(struct int3403_priv *priv) | ||
| 385 | { | ||
| 386 | struct int3403_cdev *obj = priv->priv; | ||
| 387 | |||
| 388 | thermal_cooling_device_unregister(obj->cdev); | ||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 392 | static int int3403_add(struct platform_device *pdev) | ||
| 393 | { | ||
| 394 | struct int3403_priv *priv; | ||
| 395 | int result = 0; | ||
| 396 | acpi_status status; | ||
| 397 | |||
| 398 | priv = devm_kzalloc(&pdev->dev, sizeof(struct int3403_priv), | ||
| 399 | GFP_KERNEL); | ||
| 400 | if (!priv) | ||
| 401 | return -ENOMEM; | ||
| 402 | |||
| 403 | priv->pdev = pdev; | ||
| 404 | priv->adev = ACPI_COMPANION(&(pdev->dev)); | ||
| 405 | if (!priv->adev) { | ||
| 406 | result = -EINVAL; | ||
| 407 | goto err; | ||
| 408 | } | ||
| 409 | |||
| 410 | status = acpi_evaluate_integer(priv->adev->handle, "PTYP", | ||
| 411 | NULL, &priv->type); | ||
| 412 | if (ACPI_FAILURE(status)) { | ||
| 413 | result = -EINVAL; | ||
| 414 | goto err; | ||
| 415 | } | ||
| 416 | |||
| 417 | platform_set_drvdata(pdev, priv); | ||
| 418 | switch (priv->type) { | ||
| 419 | case INT3403_TYPE_SENSOR: | ||
| 420 | result = int3403_sensor_add(priv); | ||
| 421 | break; | ||
| 422 | case INT3403_TYPE_CHARGER: | ||
| 423 | case INT3403_TYPE_BATTERY: | ||
| 424 | result = int3403_cdev_add(priv); | ||
| 425 | break; | ||
| 426 | default: | ||
| 427 | result = -EINVAL; | ||
| 428 | } | ||
| 429 | |||
| 430 | if (result) | ||
| 431 | goto err; | ||
| 432 | return result; | ||
| 433 | |||
| 434 | err: | ||
| 435 | return result; | ||
| 436 | } | ||
| 437 | |||
| 438 | static int int3403_remove(struct platform_device *pdev) | ||
| 439 | { | ||
| 440 | struct int3403_priv *priv = platform_get_drvdata(pdev); | ||
| 441 | |||
| 442 | switch (priv->type) { | ||
| 443 | case INT3403_TYPE_SENSOR: | ||
| 444 | int3403_sensor_remove(priv); | ||
| 445 | break; | ||
| 446 | case INT3403_TYPE_CHARGER: | ||
| 447 | case INT3403_TYPE_BATTERY: | ||
| 448 | int3403_cdev_remove(priv); | ||
| 449 | break; | ||
| 450 | default: | ||
| 451 | break; | ||
| 452 | } | ||
| 453 | |||
| 454 | return 0; | ||
| 455 | } | ||
| 456 | |||
| 457 | static const struct acpi_device_id int3403_device_ids[] = { | ||
| 458 | {"INT3403", 0}, | ||
| 459 | {"", 0}, | ||
| 460 | }; | ||
| 461 | MODULE_DEVICE_TABLE(acpi, int3403_device_ids); | ||
| 462 | |||
| 463 | static struct platform_driver int3403_driver = { | ||
| 464 | .probe = int3403_add, | ||
| 465 | .remove = int3403_remove, | ||
| 466 | .driver = { | ||
| 467 | .name = "int3403 thermal", | ||
| 468 | .owner = THIS_MODULE, | ||
| 469 | .acpi_match_table = int3403_device_ids, | ||
| 470 | }, | ||
| 471 | }; | ||
| 472 | |||
| 473 | module_platform_driver(int3403_driver); | ||
| 474 | |||
| 475 | MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); | ||
| 476 | MODULE_LICENSE("GPL v2"); | ||
| 477 | MODULE_DESCRIPTION("ACPI INT3403 thermal driver"); | ||
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 4b2b999b7611..f8eb625b8400 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c | |||
| @@ -401,6 +401,10 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, | |||
| 401 | struct of_phandle_args sensor_specs; | 401 | struct of_phandle_args sensor_specs; |
| 402 | int ret, id; | 402 | int ret, id; |
| 403 | 403 | ||
| 404 | /* Check whether child is enabled or not */ | ||
| 405 | if (!of_device_is_available(child)) | ||
| 406 | continue; | ||
| 407 | |||
| 404 | /* For now, thermal framework supports only 1 sensor per zone */ | 408 | /* For now, thermal framework supports only 1 sensor per zone */ |
| 405 | ret = of_parse_phandle_with_args(child, "thermal-sensors", | 409 | ret = of_parse_phandle_with_args(child, "thermal-sensors", |
| 406 | "#thermal-sensor-cells", | 410 | "#thermal-sensor-cells", |
| @@ -771,6 +775,10 @@ int __init of_parse_thermal_zones(void) | |||
| 771 | struct thermal_zone_device *zone; | 775 | struct thermal_zone_device *zone; |
| 772 | struct thermal_zone_params *tzp; | 776 | struct thermal_zone_params *tzp; |
| 773 | 777 | ||
| 778 | /* Check whether child is enabled or not */ | ||
| 779 | if (!of_device_is_available(child)) | ||
| 780 | continue; | ||
| 781 | |||
| 774 | tz = thermal_of_build_thermal_zone(child); | 782 | tz = thermal_of_build_thermal_zone(child); |
| 775 | if (IS_ERR(tz)) { | 783 | if (IS_ERR(tz)) { |
| 776 | pr_err("failed to build thermal zone %s: %ld\n", | 784 | pr_err("failed to build thermal zone %s: %ld\n", |
| @@ -838,6 +846,10 @@ void of_thermal_destroy_zones(void) | |||
| 838 | for_each_child_of_node(np, child) { | 846 | for_each_child_of_node(np, child) { |
| 839 | struct thermal_zone_device *zone; | 847 | struct thermal_zone_device *zone; |
| 840 | 848 | ||
| 849 | /* Check whether child is enabled or not */ | ||
| 850 | if (!of_device_is_available(child)) | ||
| 851 | continue; | ||
| 852 | |||
| 841 | zone = thermal_zone_get_zone_by_name(child->name); | 853 | zone = thermal_zone_get_zone_by_name(child->name); |
| 842 | if (IS_ERR(zone)) | 854 | if (IS_ERR(zone)) |
| 843 | continue; | 855 | continue; |
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index f251521baaa2..fdd1f523a1ed 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <linux/thermal.h> | 25 | #include <linux/thermal.h> |
| 26 | #include <trace/events/thermal.h> | ||
| 26 | 27 | ||
| 27 | #include "thermal_core.h" | 28 | #include "thermal_core.h" |
| 28 | 29 | ||
| @@ -76,7 +77,7 @@ static unsigned long get_target_state(struct thermal_instance *instance, | |||
| 76 | next_target = instance->upper; | 77 | next_target = instance->upper; |
| 77 | break; | 78 | break; |
| 78 | case THERMAL_TREND_DROPPING: | 79 | case THERMAL_TREND_DROPPING: |
| 79 | if (cur_state == instance->lower) { | 80 | if (cur_state <= instance->lower) { |
| 80 | if (!throttle) | 81 | if (!throttle) |
| 81 | next_target = THERMAL_NO_TARGET; | 82 | next_target = THERMAL_NO_TARGET; |
| 82 | } else { | 83 | } else { |
| @@ -129,8 +130,10 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) | |||
| 129 | 130 | ||
| 130 | trend = get_tz_trend(tz, trip); | 131 | trend = get_tz_trend(tz, trip); |
| 131 | 132 | ||
| 132 | if (tz->temperature >= trip_temp) | 133 | if (tz->temperature >= trip_temp) { |
| 133 | throttle = true; | 134 | throttle = true; |
| 135 | trace_thermal_zone_trip(tz, trip, trip_type); | ||
| 136 | } | ||
| 134 | 137 | ||
| 135 | dev_dbg(&tz->device, "Trip%d[type=%d,temp=%ld]:trend=%d,throttle=%d\n", | 138 | dev_dbg(&tz->device, "Trip%d[type=%d,temp=%ld]:trend=%d,throttle=%d\n", |
| 136 | trip, trip_type, trip_temp, trend, throttle); | 139 | trip, trip_type, trip_temp, trend, throttle); |
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 1e23f4f8d2c2..9bf10aa6069b 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c | |||
| @@ -38,6 +38,9 @@ | |||
| 38 | #include <net/netlink.h> | 38 | #include <net/netlink.h> |
| 39 | #include <net/genetlink.h> | 39 | #include <net/genetlink.h> |
| 40 | 40 | ||
| 41 | #define CREATE_TRACE_POINTS | ||
| 42 | #include <trace/events/thermal.h> | ||
| 43 | |||
| 41 | #include "thermal_core.h" | 44 | #include "thermal_core.h" |
| 42 | #include "thermal_hwmon.h" | 45 | #include "thermal_hwmon.h" |
| 43 | 46 | ||
| @@ -368,6 +371,8 @@ static void handle_critical_trips(struct thermal_zone_device *tz, | |||
| 368 | if (tz->temperature < trip_temp) | 371 | if (tz->temperature < trip_temp) |
| 369 | return; | 372 | return; |
| 370 | 373 | ||
| 374 | trace_thermal_zone_trip(tz, trip, trip_type); | ||
| 375 | |||
| 371 | if (tz->ops->notify) | 376 | if (tz->ops->notify) |
| 372 | tz->ops->notify(tz, trip, trip_type); | 377 | tz->ops->notify(tz, trip, trip_type); |
| 373 | 378 | ||
| @@ -463,6 +468,7 @@ static void update_temperature(struct thermal_zone_device *tz) | |||
| 463 | tz->temperature = temp; | 468 | tz->temperature = temp; |
| 464 | mutex_unlock(&tz->lock); | 469 | mutex_unlock(&tz->lock); |
| 465 | 470 | ||
| 471 | trace_thermal_temperature(tz); | ||
| 466 | dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", | 472 | dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", |
| 467 | tz->last_temperature, tz->temperature); | 473 | tz->last_temperature, tz->temperature); |
| 468 | } | 474 | } |
| @@ -1287,6 +1293,7 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev) | |||
| 1287 | mutex_unlock(&cdev->lock); | 1293 | mutex_unlock(&cdev->lock); |
| 1288 | cdev->ops->set_cur_state(cdev, target); | 1294 | cdev->ops->set_cur_state(cdev, target); |
| 1289 | cdev->updated = true; | 1295 | cdev->updated = true; |
| 1296 | trace_cdev_update(cdev, target); | ||
| 1290 | dev_dbg(&cdev->device, "set to state %lu\n", target); | 1297 | dev_dbg(&cdev->device, "set to state %lu\n", target); |
| 1291 | } | 1298 | } |
| 1292 | EXPORT_SYMBOL(thermal_cdev_update); | 1299 | EXPORT_SYMBOL(thermal_cdev_update); |
| @@ -1790,6 +1797,10 @@ static int __init thermal_register_governors(void) | |||
| 1790 | if (result) | 1797 | if (result) |
| 1791 | return result; | 1798 | return result; |
| 1792 | 1799 | ||
| 1800 | result = thermal_gov_bang_bang_register(); | ||
| 1801 | if (result) | ||
| 1802 | return result; | ||
| 1803 | |||
| 1793 | return thermal_gov_user_space_register(); | 1804 | return thermal_gov_user_space_register(); |
| 1794 | } | 1805 | } |
| 1795 | 1806 | ||
| @@ -1797,6 +1808,7 @@ static void thermal_unregister_governors(void) | |||
| 1797 | { | 1808 | { |
| 1798 | thermal_gov_step_wise_unregister(); | 1809 | thermal_gov_step_wise_unregister(); |
| 1799 | thermal_gov_fair_share_unregister(); | 1810 | thermal_gov_fair_share_unregister(); |
| 1811 | thermal_gov_bang_bang_unregister(); | ||
| 1800 | thermal_gov_user_space_unregister(); | 1812 | thermal_gov_user_space_unregister(); |
| 1801 | } | 1813 | } |
| 1802 | 1814 | ||
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 3db339fb636f..d15d243de27a 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h | |||
| @@ -69,6 +69,14 @@ static inline int thermal_gov_fair_share_register(void) { return 0; } | |||
| 69 | static inline void thermal_gov_fair_share_unregister(void) {} | 69 | static inline void thermal_gov_fair_share_unregister(void) {} |
| 70 | #endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */ | 70 | #endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */ |
| 71 | 71 | ||
| 72 | #ifdef CONFIG_THERMAL_GOV_BANG_BANG | ||
| 73 | int thermal_gov_bang_bang_register(void); | ||
| 74 | void thermal_gov_bang_bang_unregister(void); | ||
| 75 | #else | ||
| 76 | static inline int thermal_gov_bang_bang_register(void) { return 0; } | ||
| 77 | static inline void thermal_gov_bang_bang_unregister(void) {} | ||
| 78 | #endif /* CONFIG_THERMAL_GOV_BANG_BANG */ | ||
| 79 | |||
| 72 | #ifdef CONFIG_THERMAL_GOV_USER_SPACE | 80 | #ifdef CONFIG_THERMAL_GOV_USER_SPACE |
| 73 | int thermal_gov_user_space_register(void); | 81 | int thermal_gov_user_space_register(void); |
| 74 | void thermal_gov_user_space_unregister(void); | 82 | void thermal_gov_user_space_unregister(void); |
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 1e0a317d3dcd..3860d02729dc 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c | |||
| @@ -167,6 +167,9 @@ static struct page *balloon_next_page(struct page *page) | |||
| 167 | 167 | ||
| 168 | static enum bp_state update_schedule(enum bp_state state) | 168 | static enum bp_state update_schedule(enum bp_state state) |
| 169 | { | 169 | { |
| 170 | if (state == BP_ECANCELED) | ||
| 171 | return BP_ECANCELED; | ||
| 172 | |||
| 170 | if (state == BP_DONE) { | 173 | if (state == BP_DONE) { |
| 171 | balloon_stats.schedule_delay = 1; | 174 | balloon_stats.schedule_delay = 1; |
| 172 | balloon_stats.retry_count = 1; | 175 | balloon_stats.retry_count = 1; |
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c index dd9c249ea311..95ee4302ffb8 100644 --- a/drivers/xen/pci.c +++ b/drivers/xen/pci.c | |||
| @@ -41,24 +41,29 @@ static int xen_add_device(struct device *dev) | |||
| 41 | #endif | 41 | #endif |
| 42 | 42 | ||
| 43 | if (pci_seg_supported) { | 43 | if (pci_seg_supported) { |
| 44 | struct physdev_pci_device_add add = { | 44 | struct { |
| 45 | .seg = pci_domain_nr(pci_dev->bus), | 45 | struct physdev_pci_device_add add; |
| 46 | .bus = pci_dev->bus->number, | 46 | uint32_t pxm; |
| 47 | .devfn = pci_dev->devfn | 47 | } add_ext = { |
| 48 | .add.seg = pci_domain_nr(pci_dev->bus), | ||
| 49 | .add.bus = pci_dev->bus->number, | ||
| 50 | .add.devfn = pci_dev->devfn | ||
| 48 | }; | 51 | }; |
| 52 | struct physdev_pci_device_add *add = &add_ext.add; | ||
| 53 | |||
| 49 | #ifdef CONFIG_ACPI | 54 | #ifdef CONFIG_ACPI |
| 50 | acpi_handle handle; | 55 | acpi_handle handle; |
| 51 | #endif | 56 | #endif |
| 52 | 57 | ||
| 53 | #ifdef CONFIG_PCI_IOV | 58 | #ifdef CONFIG_PCI_IOV |
| 54 | if (pci_dev->is_virtfn) { | 59 | if (pci_dev->is_virtfn) { |
| 55 | add.flags = XEN_PCI_DEV_VIRTFN; | 60 | add->flags = XEN_PCI_DEV_VIRTFN; |
| 56 | add.physfn.bus = physfn->bus->number; | 61 | add->physfn.bus = physfn->bus->number; |
| 57 | add.physfn.devfn = physfn->devfn; | 62 | add->physfn.devfn = physfn->devfn; |
| 58 | } else | 63 | } else |
| 59 | #endif | 64 | #endif |
| 60 | if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) | 65 | if (pci_ari_enabled(pci_dev->bus) && PCI_SLOT(pci_dev->devfn)) |
| 61 | add.flags = XEN_PCI_DEV_EXTFN; | 66 | add->flags = XEN_PCI_DEV_EXTFN; |
| 62 | 67 | ||
| 63 | #ifdef CONFIG_ACPI | 68 | #ifdef CONFIG_ACPI |
| 64 | handle = ACPI_HANDLE(&pci_dev->dev); | 69 | handle = ACPI_HANDLE(&pci_dev->dev); |
| @@ -77,8 +82,8 @@ static int xen_add_device(struct device *dev) | |||
| 77 | status = acpi_evaluate_integer(handle, "_PXM", | 82 | status = acpi_evaluate_integer(handle, "_PXM", |
| 78 | NULL, &pxm); | 83 | NULL, &pxm); |
| 79 | if (ACPI_SUCCESS(status)) { | 84 | if (ACPI_SUCCESS(status)) { |
| 80 | add.optarr[0] = pxm; | 85 | add->optarr[0] = pxm; |
| 81 | add.flags |= XEN_PCI_DEV_PXM; | 86 | add->flags |= XEN_PCI_DEV_PXM; |
| 82 | break; | 87 | break; |
| 83 | } | 88 | } |
| 84 | status = acpi_get_parent(handle, &handle); | 89 | status = acpi_get_parent(handle, &handle); |
| @@ -86,7 +91,7 @@ static int xen_add_device(struct device *dev) | |||
| 86 | } | 91 | } |
| 87 | #endif /* CONFIG_ACPI */ | 92 | #endif /* CONFIG_ACPI */ |
| 88 | 93 | ||
| 89 | r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, &add); | 94 | r = HYPERVISOR_physdev_op(PHYSDEVOP_pci_device_add, add); |
| 90 | if (r != -ENOSYS) | 95 | if (r != -ENOSYS) |
| 91 | return r; | 96 | return r; |
| 92 | pci_seg_supported = false; | 97 | pci_seg_supported = false; |
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index f97804bdf1ff..7461327e14e4 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | #define METHOD_NAME__CBA "_CBA" | 52 | #define METHOD_NAME__CBA "_CBA" |
| 53 | #define METHOD_NAME__CID "_CID" | 53 | #define METHOD_NAME__CID "_CID" |
| 54 | #define METHOD_NAME__CRS "_CRS" | 54 | #define METHOD_NAME__CRS "_CRS" |
| 55 | #define METHOD_NAME__DDN "_DDN" | ||
| 55 | #define METHOD_NAME__HID "_HID" | 56 | #define METHOD_NAME__HID "_HID" |
| 56 | #define METHOD_NAME__INI "_INI" | 57 | #define METHOD_NAME__INI "_INI" |
| 57 | #define METHOD_NAME__PLD "_PLD" | 58 | #define METHOD_NAME__PLD "_PLD" |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 57ee0528aacb..f34a0835aa4f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
| @@ -433,6 +433,7 @@ int acpi_device_set_power(struct acpi_device *device, int state); | |||
| 433 | int acpi_bus_init_power(struct acpi_device *device); | 433 | int acpi_bus_init_power(struct acpi_device *device); |
| 434 | int acpi_device_fix_up_power(struct acpi_device *device); | 434 | int acpi_device_fix_up_power(struct acpi_device *device); |
| 435 | int acpi_bus_update_power(acpi_handle handle, int *state_p); | 435 | int acpi_bus_update_power(acpi_handle handle, int *state_p); |
| 436 | int acpi_device_update_power(struct acpi_device *device, int *state_p); | ||
| 436 | bool acpi_bus_power_manageable(acpi_handle handle); | 437 | bool acpi_bus_power_manageable(acpi_handle handle); |
| 437 | 438 | ||
| 438 | #ifdef CONFIG_PM | 439 | #ifdef CONFIG_PM |
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 9fc1d71c82bc..ab2acf629a64 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h | |||
| @@ -46,7 +46,7 @@ | |||
| 46 | 46 | ||
| 47 | /* Current ACPICA subsystem version in YYYYMMDD format */ | 47 | /* Current ACPICA subsystem version in YYYYMMDD format */ |
| 48 | 48 | ||
| 49 | #define ACPI_CA_VERSION 0x20140828 | 49 | #define ACPI_CA_VERSION 0x20140926 |
| 50 | 50 | ||
| 51 | #include <acpi/acconfig.h> | 51 | #include <acpi/acconfig.h> |
| 52 | #include <acpi/actypes.h> | 52 | #include <acpi/actypes.h> |
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index ac03ec81d342..7000e66f768e 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h | |||
| @@ -721,7 +721,7 @@ typedef u32 acpi_event_type; | |||
| 721 | * | | | +--- Enabled for wake? | 721 | * | | | +--- Enabled for wake? |
| 722 | * | | +----- Set? | 722 | * | | +----- Set? |
| 723 | * | +------- Has a handler? | 723 | * | +------- Has a handler? |
| 724 | * +----------- <Reserved> | 724 | * +------------- <Reserved> |
| 725 | */ | 725 | */ |
| 726 | typedef u32 acpi_event_status; | 726 | typedef u32 acpi_event_status; |
| 727 | 727 | ||
| @@ -729,7 +729,7 @@ typedef u32 acpi_event_status; | |||
| 729 | #define ACPI_EVENT_FLAG_ENABLED (acpi_event_status) 0x01 | 729 | #define ACPI_EVENT_FLAG_ENABLED (acpi_event_status) 0x01 |
| 730 | #define ACPI_EVENT_FLAG_WAKE_ENABLED (acpi_event_status) 0x02 | 730 | #define ACPI_EVENT_FLAG_WAKE_ENABLED (acpi_event_status) 0x02 |
| 731 | #define ACPI_EVENT_FLAG_SET (acpi_event_status) 0x04 | 731 | #define ACPI_EVENT_FLAG_SET (acpi_event_status) 0x04 |
| 732 | #define ACPI_EVENT_FLAG_HANDLE (acpi_event_status) 0x08 | 732 | #define ACPI_EVENT_FLAG_HAS_HANDLER (acpi_event_status) 0x08 |
| 733 | 733 | ||
| 734 | /* Actions for acpi_set_gpe, acpi_gpe_wakeup, acpi_hw_low_set_gpe */ | 734 | /* Actions for acpi_set_gpe, acpi_gpe_wakeup, acpi_hw_low_set_gpe */ |
| 735 | 735 | ||
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index b7926bb9b444..407a12f663eb 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
| @@ -432,6 +432,7 @@ static inline bool acpi_driver_match_device(struct device *dev, | |||
| 432 | int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); | 432 | int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); |
| 433 | int acpi_device_modalias(struct device *, char *, int); | 433 | int acpi_device_modalias(struct device *, char *, int); |
| 434 | 434 | ||
| 435 | struct platform_device *acpi_create_platform_device(struct acpi_device *); | ||
| 435 | #define ACPI_PTR(_ptr) (_ptr) | 436 | #define ACPI_PTR(_ptr) (_ptr) |
| 436 | 437 | ||
| 437 | #else /* !CONFIG_ACPI */ | 438 | #else /* !CONFIG_ACPI */ |
diff --git a/include/linux/audit.h b/include/linux/audit.h index 36dffeccebdb..e58fe7df8b9c 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
| @@ -90,7 +90,7 @@ extern unsigned compat_dir_class[]; | |||
| 90 | extern unsigned compat_chattr_class[]; | 90 | extern unsigned compat_chattr_class[]; |
| 91 | extern unsigned compat_signal_class[]; | 91 | extern unsigned compat_signal_class[]; |
| 92 | 92 | ||
| 93 | extern int __weak audit_classify_compat_syscall(int abi, unsigned syscall); | 93 | extern int audit_classify_compat_syscall(int abi, unsigned syscall); |
| 94 | 94 | ||
| 95 | /* audit_names->type values */ | 95 | /* audit_names->type values */ |
| 96 | #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ | 96 | #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ |
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 653f0e2b6ca9..abcafaa20b86 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
| @@ -287,7 +287,7 @@ extern struct clocksource* clocksource_get_next(void); | |||
| 287 | extern void clocksource_change_rating(struct clocksource *cs, int rating); | 287 | extern void clocksource_change_rating(struct clocksource *cs, int rating); |
| 288 | extern void clocksource_suspend(void); | 288 | extern void clocksource_suspend(void); |
| 289 | extern void clocksource_resume(void); | 289 | extern void clocksource_resume(void); |
| 290 | extern struct clocksource * __init __weak clocksource_default_clock(void); | 290 | extern struct clocksource * __init clocksource_default_clock(void); |
| 291 | extern void clocksource_mark_unstable(struct clocksource *cs); | 291 | extern void clocksource_mark_unstable(struct clocksource *cs); |
| 292 | 292 | ||
| 293 | extern u64 | 293 | extern u64 |
diff --git a/include/linux/cpufreq-dt.h b/include/linux/cpufreq-dt.h new file mode 100644 index 000000000000..0414009e2c30 --- /dev/null +++ b/include/linux/cpufreq-dt.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2014 Marvell | ||
| 3 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __CPUFREQ_DT_H__ | ||
| 11 | #define __CPUFREQ_DT_H__ | ||
| 12 | |||
| 13 | struct cpufreq_dt_platform_data { | ||
| 14 | /* | ||
| 15 | * True when each CPU has its own clock to control its | ||
| 16 | * frequency, false when all CPUs are controlled by a single | ||
| 17 | * clock. | ||
| 18 | */ | ||
| 19 | bool independent_clocks; | ||
| 20 | }; | ||
| 21 | |||
| 22 | #endif /* __CPUFREQ_DT_H__ */ | ||
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 138336b6bb04..503b085b7832 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
| @@ -219,6 +219,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name) | |||
| 219 | struct cpufreq_driver { | 219 | struct cpufreq_driver { |
| 220 | char name[CPUFREQ_NAME_LEN]; | 220 | char name[CPUFREQ_NAME_LEN]; |
| 221 | u8 flags; | 221 | u8 flags; |
| 222 | void *driver_data; | ||
| 222 | 223 | ||
| 223 | /* needed by all drivers */ | 224 | /* needed by all drivers */ |
| 224 | int (*init) (struct cpufreq_policy *policy); | 225 | int (*init) (struct cpufreq_policy *policy); |
| @@ -312,6 +313,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data); | |||
| 312 | int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); | 313 | int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); |
| 313 | 314 | ||
| 314 | const char *cpufreq_get_current_driver(void); | 315 | const char *cpufreq_get_current_driver(void); |
| 316 | void *cpufreq_get_driver_data(void); | ||
| 315 | 317 | ||
| 316 | static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, | 318 | static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, |
| 317 | unsigned int min, unsigned int max) | 319 | unsigned int min, unsigned int max) |
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h index 72ab536ad3de..3849fce7ecfe 100644 --- a/include/linux/crash_dump.h +++ b/include/linux/crash_dump.h | |||
| @@ -14,14 +14,13 @@ | |||
| 14 | extern unsigned long long elfcorehdr_addr; | 14 | extern unsigned long long elfcorehdr_addr; |
| 15 | extern unsigned long long elfcorehdr_size; | 15 | extern unsigned long long elfcorehdr_size; |
| 16 | 16 | ||
| 17 | extern int __weak elfcorehdr_alloc(unsigned long long *addr, | 17 | extern int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size); |
| 18 | unsigned long long *size); | 18 | extern void elfcorehdr_free(unsigned long long addr); |
| 19 | extern void __weak elfcorehdr_free(unsigned long long addr); | 19 | extern ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos); |
| 20 | extern ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos); | 20 | extern ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos); |
| 21 | extern ssize_t __weak elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos); | 21 | extern int remap_oldmem_pfn_range(struct vm_area_struct *vma, |
| 22 | extern int __weak remap_oldmem_pfn_range(struct vm_area_struct *vma, | 22 | unsigned long from, unsigned long pfn, |
| 23 | unsigned long from, unsigned long pfn, | 23 | unsigned long size, pgprot_t prot); |
| 24 | unsigned long size, pgprot_t prot); | ||
| 25 | 24 | ||
| 26 | extern ssize_t copy_oldmem_page(unsigned long, char *, size_t, | 25 | extern ssize_t copy_oldmem_page(unsigned long, char *, size_t, |
| 27 | unsigned long, int); | 26 | unsigned long, int); |
diff --git a/include/linux/efi.h b/include/linux/efi.h index 45cb4ffdea62..0949f9c7e872 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
| @@ -92,6 +92,7 @@ typedef struct { | |||
| 92 | #define EFI_MEMORY_WC ((u64)0x0000000000000002ULL) /* write-coalescing */ | 92 | #define EFI_MEMORY_WC ((u64)0x0000000000000002ULL) /* write-coalescing */ |
| 93 | #define EFI_MEMORY_WT ((u64)0x0000000000000004ULL) /* write-through */ | 93 | #define EFI_MEMORY_WT ((u64)0x0000000000000004ULL) /* write-through */ |
| 94 | #define EFI_MEMORY_WB ((u64)0x0000000000000008ULL) /* write-back */ | 94 | #define EFI_MEMORY_WB ((u64)0x0000000000000008ULL) /* write-back */ |
| 95 | #define EFI_MEMORY_UCE ((u64)0x0000000000000010ULL) /* uncached, exported */ | ||
| 95 | #define EFI_MEMORY_WP ((u64)0x0000000000001000ULL) /* write-protect */ | 96 | #define EFI_MEMORY_WP ((u64)0x0000000000001000ULL) /* write-protect */ |
| 96 | #define EFI_MEMORY_RP ((u64)0x0000000000002000ULL) /* read-protect */ | 97 | #define EFI_MEMORY_RP ((u64)0x0000000000002000ULL) /* read-protect */ |
| 97 | #define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ | 98 | #define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ |
| @@ -502,6 +503,10 @@ typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char | |||
| 502 | typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, | 503 | typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, |
| 503 | u32 attr, unsigned long data_size, | 504 | u32 attr, unsigned long data_size, |
| 504 | void *data); | 505 | void *data); |
| 506 | typedef efi_status_t | ||
| 507 | efi_set_variable_nonblocking_t(efi_char16_t *name, efi_guid_t *vendor, | ||
| 508 | u32 attr, unsigned long data_size, void *data); | ||
| 509 | |||
| 505 | typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count); | 510 | typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count); |
| 506 | typedef void efi_reset_system_t (int reset_type, efi_status_t status, | 511 | typedef void efi_reset_system_t (int reset_type, efi_status_t status, |
| 507 | unsigned long data_size, efi_char16_t *data); | 512 | unsigned long data_size, efi_char16_t *data); |
| @@ -821,6 +826,7 @@ extern struct efi { | |||
| 821 | efi_get_variable_t *get_variable; | 826 | efi_get_variable_t *get_variable; |
| 822 | efi_get_next_variable_t *get_next_variable; | 827 | efi_get_next_variable_t *get_next_variable; |
| 823 | efi_set_variable_t *set_variable; | 828 | efi_set_variable_t *set_variable; |
| 829 | efi_set_variable_nonblocking_t *set_variable_nonblocking; | ||
| 824 | efi_query_variable_info_t *query_variable_info; | 830 | efi_query_variable_info_t *query_variable_info; |
| 825 | efi_update_capsule_t *update_capsule; | 831 | efi_update_capsule_t *update_capsule; |
| 826 | efi_query_capsule_caps_t *query_capsule_caps; | 832 | efi_query_capsule_caps_t *query_capsule_caps; |
| @@ -886,6 +892,13 @@ extern bool efi_poweroff_required(void); | |||
| 886 | (md) <= (efi_memory_desc_t *)((m)->map_end - (m)->desc_size); \ | 892 | (md) <= (efi_memory_desc_t *)((m)->map_end - (m)->desc_size); \ |
| 887 | (md) = (void *)(md) + (m)->desc_size) | 893 | (md) = (void *)(md) + (m)->desc_size) |
| 888 | 894 | ||
| 895 | /* | ||
| 896 | * Format an EFI memory descriptor's type and attributes to a user-provided | ||
| 897 | * character buffer, as per snprintf(), and return the buffer. | ||
| 898 | */ | ||
| 899 | char * __init efi_md_typeattr_format(char *buf, size_t size, | ||
| 900 | const efi_memory_desc_t *md); | ||
| 901 | |||
| 889 | /** | 902 | /** |
| 890 | * efi_range_is_wc - check the WC bit on an address range | 903 | * efi_range_is_wc - check the WC bit on an address range |
| 891 | * @start: starting kvirt address | 904 | * @start: starting kvirt address |
| @@ -1034,6 +1047,7 @@ struct efivar_operations { | |||
| 1034 | efi_get_variable_t *get_variable; | 1047 | efi_get_variable_t *get_variable; |
| 1035 | efi_get_next_variable_t *get_next_variable; | 1048 | efi_get_next_variable_t *get_next_variable; |
| 1036 | efi_set_variable_t *set_variable; | 1049 | efi_set_variable_t *set_variable; |
| 1050 | efi_set_variable_nonblocking_t *set_variable_nonblocking; | ||
| 1037 | efi_query_variable_store_t *query_variable_store; | 1051 | efi_query_variable_store_t *query_variable_store; |
| 1038 | }; | 1052 | }; |
| 1039 | 1053 | ||
| @@ -1227,4 +1241,7 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, | |||
| 1227 | unsigned long *load_addr, | 1241 | unsigned long *load_addr, |
| 1228 | unsigned long *load_size); | 1242 | unsigned long *load_size); |
| 1229 | 1243 | ||
| 1244 | efi_status_t efi_parse_options(char *cmdline); | ||
| 1245 | |||
| 1246 | bool efi_runtime_disabled(void); | ||
| 1230 | #endif /* _LINUX_EFI_H */ | 1247 | #endif /* _LINUX_EFI_H */ |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 40728cf1c452..3d770f5564b8 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
| @@ -403,6 +403,7 @@ int vsscanf(const char *, const char *, va_list); | |||
| 403 | extern int get_option(char **str, int *pint); | 403 | extern int get_option(char **str, int *pint); |
| 404 | extern char *get_options(const char *str, int nints, int *ints); | 404 | extern char *get_options(const char *str, int nints, int *ints); |
| 405 | extern unsigned long long memparse(const char *ptr, char **retptr); | 405 | extern unsigned long long memparse(const char *ptr, char **retptr); |
| 406 | extern bool parse_option_str(const char *str, const char *option); | ||
| 406 | 407 | ||
| 407 | extern int core_kernel_text(unsigned long addr); | 408 | extern int core_kernel_text(unsigned long addr); |
| 408 | extern int core_kernel_data(unsigned long addr); | 409 | extern int core_kernel_data(unsigned long addr); |
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index 6b06d378f3df..e465bb15912d 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h | |||
| @@ -283,7 +283,7 @@ struct kgdb_io { | |||
| 283 | 283 | ||
| 284 | extern struct kgdb_arch arch_kgdb_ops; | 284 | extern struct kgdb_arch arch_kgdb_ops; |
| 285 | 285 | ||
| 286 | extern unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs); | 286 | extern unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs); |
| 287 | 287 | ||
| 288 | #ifdef CONFIG_SERIAL_KGDB_NMI | 288 | #ifdef CONFIG_SERIAL_KGDB_NMI |
| 289 | extern int kgdb_register_nmi_console(void); | 289 | extern int kgdb_register_nmi_console(void); |
diff --git a/include/linux/memory.h b/include/linux/memory.h index bb7384e3c3d8..8b8d8d12348e 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h | |||
| @@ -35,7 +35,7 @@ struct memory_block { | |||
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | int arch_get_memory_phys_device(unsigned long start_pfn); | 37 | int arch_get_memory_phys_device(unsigned long start_pfn); |
| 38 | unsigned long __weak memory_block_size_bytes(void); | 38 | unsigned long memory_block_size_bytes(void); |
| 39 | 39 | ||
| 40 | /* These states are exposed to userspace as text strings in sysfs */ | 40 | /* These states are exposed to userspace as text strings in sysfs */ |
| 41 | #define MEM_ONLINE (1<<0) /* exposed to userspace */ | 41 | #define MEM_ONLINE (1<<0) /* exposed to userspace */ |
diff --git a/include/linux/oom.h b/include/linux/oom.h index 647395a1a550..e8d6e1058723 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h | |||
| @@ -50,6 +50,9 @@ static inline bool oom_task_origin(const struct task_struct *p) | |||
| 50 | extern unsigned long oom_badness(struct task_struct *p, | 50 | extern unsigned long oom_badness(struct task_struct *p, |
| 51 | struct mem_cgroup *memcg, const nodemask_t *nodemask, | 51 | struct mem_cgroup *memcg, const nodemask_t *nodemask, |
| 52 | unsigned long totalpages); | 52 | unsigned long totalpages); |
| 53 | |||
| 54 | extern int oom_kills_count(void); | ||
| 55 | extern void note_oom_kill(void); | ||
| 53 | extern void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | 56 | extern void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, |
| 54 | unsigned int points, unsigned long totalpages, | 57 | unsigned int points, unsigned long totalpages, |
| 55 | struct mem_cgroup *memcg, nodemask_t *nodemask, | 58 | struct mem_cgroup *memcg, nodemask_t *nodemask, |
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 9ab4bf7c4646..636e82834506 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h | |||
| @@ -15,6 +15,7 @@ enum { | |||
| 15 | PM_QOS_CPU_DMA_LATENCY, | 15 | PM_QOS_CPU_DMA_LATENCY, |
| 16 | PM_QOS_NETWORK_LATENCY, | 16 | PM_QOS_NETWORK_LATENCY, |
| 17 | PM_QOS_NETWORK_THROUGHPUT, | 17 | PM_QOS_NETWORK_THROUGHPUT, |
| 18 | PM_QOS_MEMORY_BANDWIDTH, | ||
| 18 | 19 | ||
| 19 | /* insert new class ID */ | 20 | /* insert new class ID */ |
| 20 | PM_QOS_NUM_CLASSES, | 21 | PM_QOS_NUM_CLASSES, |
| @@ -32,6 +33,7 @@ enum pm_qos_flags_status { | |||
| 32 | #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) | 33 | #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) |
| 33 | #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) | 34 | #define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) |
| 34 | #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 | 35 | #define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 |
| 36 | #define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE 0 | ||
| 35 | #define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE 0 | 37 | #define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE 0 |
| 36 | #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 | 38 | #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 |
| 37 | #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) | 39 | #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) |
| @@ -69,7 +71,8 @@ struct dev_pm_qos_request { | |||
| 69 | enum pm_qos_type { | 71 | enum pm_qos_type { |
| 70 | PM_QOS_UNITIALIZED, | 72 | PM_QOS_UNITIALIZED, |
| 71 | PM_QOS_MAX, /* return the largest value */ | 73 | PM_QOS_MAX, /* return the largest value */ |
| 72 | PM_QOS_MIN /* return the smallest value */ | 74 | PM_QOS_MIN, /* return the smallest value */ |
| 75 | PM_QOS_SUM /* return the sum */ | ||
| 73 | }; | 76 | }; |
| 74 | 77 | ||
| 75 | /* | 78 | /* |
diff --git a/include/linux/string.h b/include/linux/string.h index e6edfe51575a..2e22a2e58f3a 100644 --- a/include/linux/string.h +++ b/include/linux/string.h | |||
| @@ -132,7 +132,7 @@ int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4); | |||
| 132 | #endif | 132 | #endif |
| 133 | 133 | ||
| 134 | extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, | 134 | extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, |
| 135 | const void *from, size_t available); | 135 | const void *from, size_t available); |
| 136 | 136 | ||
| 137 | /** | 137 | /** |
| 138 | * strstarts - does @str start with @prefix? | 138 | * strstarts - does @str start with @prefix? |
| @@ -144,7 +144,8 @@ static inline bool strstarts(const char *str, const char *prefix) | |||
| 144 | return strncmp(str, prefix, strlen(prefix)) == 0; | 144 | return strncmp(str, prefix, strlen(prefix)) == 0; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | extern size_t memweight(const void *ptr, size_t bytes); | 147 | size_t memweight(const void *ptr, size_t bytes); |
| 148 | void memzero_explicit(void *s, size_t count); | ||
| 148 | 149 | ||
| 149 | /** | 150 | /** |
| 150 | * kbasename - return the last part of a pathname. | 151 | * kbasename - return the last part of a pathname. |
diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 0305cde21a74..ef90838b36a0 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h | |||
| @@ -44,6 +44,10 @@ | |||
| 44 | #define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ | 44 | #define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ |
| 45 | ((long)t-2732+5)/10 : ((long)t-2732-5)/10) | 45 | ((long)t-2732+5)/10 : ((long)t-2732-5)/10) |
| 46 | #define CELSIUS_TO_KELVIN(t) ((t)*10+2732) | 46 | #define CELSIUS_TO_KELVIN(t) ((t)*10+2732) |
| 47 | #define DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, off) (((t) - (off)) * 100) | ||
| 48 | #define DECI_KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, 2732) | ||
| 49 | #define MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, off) (((t) / 100) + (off)) | ||
| 50 | #define MILLICELSIUS_TO_DECI_KELVIN(t) MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, 2732) | ||
| 47 | 51 | ||
| 48 | /* Adding event notification support elements */ | 52 | /* Adding event notification support elements */ |
| 49 | #define THERMAL_GENL_FAMILY_NAME "thermal_event" | 53 | #define THERMAL_GENL_FAMILY_NAME "thermal_event" |
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 4f844c6b03ee..60beb5dc7977 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h | |||
| @@ -98,11 +98,11 @@ struct uprobes_state { | |||
| 98 | struct xol_area *xol_area; | 98 | struct xol_area *xol_area; |
| 99 | }; | 99 | }; |
| 100 | 100 | ||
| 101 | extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); | 101 | extern int set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); |
| 102 | extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); | 102 | extern int set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); |
| 103 | extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); | 103 | extern bool is_swbp_insn(uprobe_opcode_t *insn); |
| 104 | extern bool __weak is_trap_insn(uprobe_opcode_t *insn); | 104 | extern bool is_trap_insn(uprobe_opcode_t *insn); |
| 105 | extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); | 105 | extern unsigned long uprobe_get_swbp_addr(struct pt_regs *regs); |
| 106 | extern unsigned long uprobe_get_trap_addr(struct pt_regs *regs); | 106 | extern unsigned long uprobe_get_trap_addr(struct pt_regs *regs); |
| 107 | extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t); | 107 | extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t); |
| 108 | extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); | 108 | extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); |
| @@ -128,8 +128,8 @@ extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); | |||
| 128 | extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data); | 128 | extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data); |
| 129 | extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs); | 129 | extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs); |
| 130 | extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs); | 130 | extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs); |
| 131 | extern bool __weak arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs); | 131 | extern bool arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs); |
| 132 | extern void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, | 132 | extern void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, |
| 133 | void *src, unsigned long len); | 133 | void *src, unsigned long len); |
| 134 | #else /* !CONFIG_UPROBES */ | 134 | #else /* !CONFIG_UPROBES */ |
| 135 | struct uprobes_state { | 135 | struct uprobes_state { |
diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h new file mode 100644 index 000000000000..0f4f95d63c03 --- /dev/null +++ b/include/trace/events/thermal.h | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM thermal | ||
| 3 | |||
| 4 | #if !defined(_TRACE_THERMAL_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 5 | #define _TRACE_THERMAL_H | ||
| 6 | |||
| 7 | #include <linux/thermal.h> | ||
| 8 | #include <linux/tracepoint.h> | ||
| 9 | |||
| 10 | TRACE_EVENT(thermal_temperature, | ||
| 11 | |||
| 12 | TP_PROTO(struct thermal_zone_device *tz), | ||
| 13 | |||
| 14 | TP_ARGS(tz), | ||
| 15 | |||
| 16 | TP_STRUCT__entry( | ||
| 17 | __string(thermal_zone, tz->type) | ||
| 18 | __field(int, id) | ||
| 19 | __field(int, temp_prev) | ||
| 20 | __field(int, temp) | ||
| 21 | ), | ||
| 22 | |||
| 23 | TP_fast_assign( | ||
| 24 | __assign_str(thermal_zone, tz->type); | ||
| 25 | __entry->id = tz->id; | ||
| 26 | __entry->temp_prev = tz->last_temperature; | ||
| 27 | __entry->temp = tz->temperature; | ||
| 28 | ), | ||
| 29 | |||
| 30 | TP_printk("thermal_zone=%s id=%d temp_prev=%d temp=%d", | ||
| 31 | __get_str(thermal_zone), __entry->id, __entry->temp_prev, | ||
| 32 | __entry->temp) | ||
| 33 | ); | ||
| 34 | |||
| 35 | TRACE_EVENT(cdev_update, | ||
| 36 | |||
| 37 | TP_PROTO(struct thermal_cooling_device *cdev, unsigned long target), | ||
| 38 | |||
| 39 | TP_ARGS(cdev, target), | ||
| 40 | |||
| 41 | TP_STRUCT__entry( | ||
| 42 | __string(type, cdev->type) | ||
| 43 | __field(unsigned long, target) | ||
| 44 | ), | ||
| 45 | |||
| 46 | TP_fast_assign( | ||
| 47 | __assign_str(type, cdev->type); | ||
| 48 | __entry->target = target; | ||
| 49 | ), | ||
| 50 | |||
| 51 | TP_printk("type=%s target=%lu", __get_str(type), __entry->target) | ||
| 52 | ); | ||
| 53 | |||
| 54 | TRACE_EVENT(thermal_zone_trip, | ||
| 55 | |||
| 56 | TP_PROTO(struct thermal_zone_device *tz, int trip, | ||
| 57 | enum thermal_trip_type trip_type), | ||
| 58 | |||
| 59 | TP_ARGS(tz, trip, trip_type), | ||
| 60 | |||
| 61 | TP_STRUCT__entry( | ||
| 62 | __string(thermal_zone, tz->type) | ||
| 63 | __field(int, id) | ||
| 64 | __field(int, trip) | ||
| 65 | __field(enum thermal_trip_type, trip_type) | ||
| 66 | ), | ||
| 67 | |||
| 68 | TP_fast_assign( | ||
| 69 | __assign_str(thermal_zone, tz->type); | ||
| 70 | __entry->id = tz->id; | ||
| 71 | __entry->trip = trip; | ||
| 72 | __entry->trip_type = trip_type; | ||
| 73 | ), | ||
| 74 | |||
| 75 | TP_printk("thermal_zone=%s id=%d trip=%d trip_type=%d", | ||
| 76 | __get_str(thermal_zone), __entry->id, __entry->trip, | ||
| 77 | __entry->trip_type) | ||
| 78 | ); | ||
| 79 | |||
| 80 | #endif /* _TRACE_THERMAL_H */ | ||
| 81 | |||
| 82 | /* This part must be outside protection */ | ||
| 83 | #include <trace/define_trace.h> | ||
diff --git a/kernel/freezer.c b/kernel/freezer.c index aa6a8aadb911..a8900a3bc27a 100644 --- a/kernel/freezer.c +++ b/kernel/freezer.c | |||
| @@ -42,6 +42,9 @@ bool freezing_slow_path(struct task_struct *p) | |||
| 42 | if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK)) | 42 | if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK)) |
| 43 | return false; | 43 | return false; |
| 44 | 44 | ||
| 45 | if (test_thread_flag(TIF_MEMDIE)) | ||
| 46 | return false; | ||
| 47 | |||
| 45 | if (pm_nosig_freezing || cgroup_freezing(p)) | 48 | if (pm_nosig_freezing || cgroup_freezing(p)) |
| 46 | return true; | 49 | return true; |
| 47 | 50 | ||
| @@ -147,12 +150,6 @@ void __thaw_task(struct task_struct *p) | |||
| 147 | { | 150 | { |
| 148 | unsigned long flags; | 151 | unsigned long flags; |
| 149 | 152 | ||
| 150 | /* | ||
| 151 | * Clear freezing and kick @p if FROZEN. Clearing is guaranteed to | ||
| 152 | * be visible to @p as waking up implies wmb. Waking up inside | ||
| 153 | * freezer_lock also prevents wakeups from leaking outside | ||
| 154 | * refrigerator. | ||
| 155 | */ | ||
| 156 | spin_lock_irqsave(&freezer_lock, flags); | 153 | spin_lock_irqsave(&freezer_lock, flags); |
| 157 | if (frozen(p)) | 154 | if (frozen(p)) |
| 158 | wake_up_process(p); | 155 | wake_up_process(p); |
diff --git a/kernel/power/process.c b/kernel/power/process.c index 7b323221b9ee..5a6ec8678b9a 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
| @@ -46,13 +46,13 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 46 | while (true) { | 46 | while (true) { |
| 47 | todo = 0; | 47 | todo = 0; |
| 48 | read_lock(&tasklist_lock); | 48 | read_lock(&tasklist_lock); |
| 49 | do_each_thread(g, p) { | 49 | for_each_process_thread(g, p) { |
| 50 | if (p == current || !freeze_task(p)) | 50 | if (p == current || !freeze_task(p)) |
| 51 | continue; | 51 | continue; |
| 52 | 52 | ||
| 53 | if (!freezer_should_skip(p)) | 53 | if (!freezer_should_skip(p)) |
| 54 | todo++; | 54 | todo++; |
| 55 | } while_each_thread(g, p); | 55 | } |
| 56 | read_unlock(&tasklist_lock); | 56 | read_unlock(&tasklist_lock); |
| 57 | 57 | ||
| 58 | if (!user_only) { | 58 | if (!user_only) { |
| @@ -93,11 +93,11 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 93 | 93 | ||
| 94 | if (!wakeup) { | 94 | if (!wakeup) { |
| 95 | read_lock(&tasklist_lock); | 95 | read_lock(&tasklist_lock); |
| 96 | do_each_thread(g, p) { | 96 | for_each_process_thread(g, p) { |
| 97 | if (p != current && !freezer_should_skip(p) | 97 | if (p != current && !freezer_should_skip(p) |
| 98 | && freezing(p) && !frozen(p)) | 98 | && freezing(p) && !frozen(p)) |
| 99 | sched_show_task(p); | 99 | sched_show_task(p); |
| 100 | } while_each_thread(g, p); | 100 | } |
| 101 | read_unlock(&tasklist_lock); | 101 | read_unlock(&tasklist_lock); |
| 102 | } | 102 | } |
| 103 | } else { | 103 | } else { |
| @@ -108,6 +108,30 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 108 | return todo ? -EBUSY : 0; | 108 | return todo ? -EBUSY : 0; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static bool __check_frozen_processes(void) | ||
| 112 | { | ||
| 113 | struct task_struct *g, *p; | ||
| 114 | |||
| 115 | for_each_process_thread(g, p) | ||
| 116 | if (p != current && !freezer_should_skip(p) && !frozen(p)) | ||
| 117 | return false; | ||
| 118 | |||
| 119 | return true; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* | ||
| 123 | * Returns true if all freezable tasks (except for current) are frozen already | ||
| 124 | */ | ||
| 125 | static bool check_frozen_processes(void) | ||
| 126 | { | ||
| 127 | bool ret; | ||
| 128 | |||
| 129 | read_lock(&tasklist_lock); | ||
| 130 | ret = __check_frozen_processes(); | ||
| 131 | read_unlock(&tasklist_lock); | ||
| 132 | return ret; | ||
| 133 | } | ||
| 134 | |||
| 111 | /** | 135 | /** |
| 112 | * freeze_processes - Signal user space processes to enter the refrigerator. | 136 | * freeze_processes - Signal user space processes to enter the refrigerator. |
| 113 | * The current thread will not be frozen. The same process that calls | 137 | * The current thread will not be frozen. The same process that calls |
| @@ -118,6 +142,7 @@ static int try_to_freeze_tasks(bool user_only) | |||
| 118 | int freeze_processes(void) | 142 | int freeze_processes(void) |
| 119 | { | 143 | { |
| 120 | int error; | 144 | int error; |
| 145 | int oom_kills_saved; | ||
| 121 | 146 | ||
| 122 | error = __usermodehelper_disable(UMH_FREEZING); | 147 | error = __usermodehelper_disable(UMH_FREEZING); |
| 123 | if (error) | 148 | if (error) |
| @@ -132,11 +157,25 @@ int freeze_processes(void) | |||
| 132 | pm_wakeup_clear(); | 157 | pm_wakeup_clear(); |
| 133 | printk("Freezing user space processes ... "); | 158 | printk("Freezing user space processes ... "); |
| 134 | pm_freezing = true; | 159 | pm_freezing = true; |
| 160 | oom_kills_saved = oom_kills_count(); | ||
| 135 | error = try_to_freeze_tasks(true); | 161 | error = try_to_freeze_tasks(true); |
| 136 | if (!error) { | 162 | if (!error) { |
| 137 | printk("done."); | ||
| 138 | __usermodehelper_set_disable_depth(UMH_DISABLED); | 163 | __usermodehelper_set_disable_depth(UMH_DISABLED); |
| 139 | oom_killer_disable(); | 164 | oom_killer_disable(); |
| 165 | |||
| 166 | /* | ||
| 167 | * There might have been an OOM kill while we were | ||
| 168 | * freezing tasks and the killed task might be still | ||
| 169 | * on the way out so we have to double check for race. | ||
| 170 | */ | ||
| 171 | if (oom_kills_count() != oom_kills_saved && | ||
| 172 | !check_frozen_processes()) { | ||
| 173 | __usermodehelper_set_disable_depth(UMH_ENABLED); | ||
| 174 | printk("OOM in progress."); | ||
| 175 | error = -EBUSY; | ||
| 176 | } else { | ||
| 177 | printk("done."); | ||
| 178 | } | ||
| 140 | } | 179 | } |
| 141 | printk("\n"); | 180 | printk("\n"); |
| 142 | BUG_ON(in_atomic()); | 181 | BUG_ON(in_atomic()); |
| @@ -191,11 +230,11 @@ void thaw_processes(void) | |||
| 191 | thaw_workqueues(); | 230 | thaw_workqueues(); |
| 192 | 231 | ||
| 193 | read_lock(&tasklist_lock); | 232 | read_lock(&tasklist_lock); |
| 194 | do_each_thread(g, p) { | 233 | for_each_process_thread(g, p) { |
| 195 | /* No other threads should have PF_SUSPEND_TASK set */ | 234 | /* No other threads should have PF_SUSPEND_TASK set */ |
| 196 | WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK)); | 235 | WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK)); |
| 197 | __thaw_task(p); | 236 | __thaw_task(p); |
| 198 | } while_each_thread(g, p); | 237 | } |
| 199 | read_unlock(&tasklist_lock); | 238 | read_unlock(&tasklist_lock); |
| 200 | 239 | ||
| 201 | WARN_ON(!(curr->flags & PF_SUSPEND_TASK)); | 240 | WARN_ON(!(curr->flags & PF_SUSPEND_TASK)); |
| @@ -218,10 +257,10 @@ void thaw_kernel_threads(void) | |||
| 218 | thaw_workqueues(); | 257 | thaw_workqueues(); |
| 219 | 258 | ||
| 220 | read_lock(&tasklist_lock); | 259 | read_lock(&tasklist_lock); |
| 221 | do_each_thread(g, p) { | 260 | for_each_process_thread(g, p) { |
| 222 | if (p->flags & (PF_KTHREAD | PF_WQ_WORKER)) | 261 | if (p->flags & (PF_KTHREAD | PF_WQ_WORKER)) |
| 223 | __thaw_task(p); | 262 | __thaw_task(p); |
| 224 | } while_each_thread(g, p); | 263 | } |
| 225 | read_unlock(&tasklist_lock); | 264 | read_unlock(&tasklist_lock); |
| 226 | 265 | ||
| 227 | schedule(); | 266 | schedule(); |
diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 884b77058864..5f4c006c4b1e 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c | |||
| @@ -105,11 +105,27 @@ static struct pm_qos_object network_throughput_pm_qos = { | |||
| 105 | }; | 105 | }; |
| 106 | 106 | ||
| 107 | 107 | ||
| 108 | static BLOCKING_NOTIFIER_HEAD(memory_bandwidth_notifier); | ||
| 109 | static struct pm_qos_constraints memory_bw_constraints = { | ||
| 110 | .list = PLIST_HEAD_INIT(memory_bw_constraints.list), | ||
| 111 | .target_value = PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE, | ||
| 112 | .default_value = PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE, | ||
| 113 | .no_constraint_value = PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE, | ||
| 114 | .type = PM_QOS_SUM, | ||
| 115 | .notifiers = &memory_bandwidth_notifier, | ||
| 116 | }; | ||
| 117 | static struct pm_qos_object memory_bandwidth_pm_qos = { | ||
| 118 | .constraints = &memory_bw_constraints, | ||
| 119 | .name = "memory_bandwidth", | ||
| 120 | }; | ||
| 121 | |||
| 122 | |||
| 108 | static struct pm_qos_object *pm_qos_array[] = { | 123 | static struct pm_qos_object *pm_qos_array[] = { |
| 109 | &null_pm_qos, | 124 | &null_pm_qos, |
| 110 | &cpu_dma_pm_qos, | 125 | &cpu_dma_pm_qos, |
| 111 | &network_lat_pm_qos, | 126 | &network_lat_pm_qos, |
| 112 | &network_throughput_pm_qos | 127 | &network_throughput_pm_qos, |
| 128 | &memory_bandwidth_pm_qos, | ||
| 113 | }; | 129 | }; |
| 114 | 130 | ||
| 115 | static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, | 131 | static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, |
| @@ -130,6 +146,9 @@ static const struct file_operations pm_qos_power_fops = { | |||
| 130 | /* unlocked internal variant */ | 146 | /* unlocked internal variant */ |
| 131 | static inline int pm_qos_get_value(struct pm_qos_constraints *c) | 147 | static inline int pm_qos_get_value(struct pm_qos_constraints *c) |
| 132 | { | 148 | { |
| 149 | struct plist_node *node; | ||
| 150 | int total_value = 0; | ||
| 151 | |||
| 133 | if (plist_head_empty(&c->list)) | 152 | if (plist_head_empty(&c->list)) |
| 134 | return c->no_constraint_value; | 153 | return c->no_constraint_value; |
| 135 | 154 | ||
| @@ -140,6 +159,12 @@ static inline int pm_qos_get_value(struct pm_qos_constraints *c) | |||
| 140 | case PM_QOS_MAX: | 159 | case PM_QOS_MAX: |
| 141 | return plist_last(&c->list)->prio; | 160 | return plist_last(&c->list)->prio; |
| 142 | 161 | ||
| 162 | case PM_QOS_SUM: | ||
| 163 | plist_for_each(node, &c->list) | ||
| 164 | total_value += node->prio; | ||
| 165 | |||
| 166 | return total_value; | ||
| 167 | |||
| 143 | default: | 168 | default: |
| 144 | /* runtime check for not using enum */ | 169 | /* runtime check for not using enum */ |
| 145 | BUG(); | 170 | BUG(); |
diff --git a/lib/cmdline.c b/lib/cmdline.c index 76a712e6e20e..8f13cf73c2ec 100644 --- a/lib/cmdline.c +++ b/lib/cmdline.c | |||
| @@ -160,3 +160,32 @@ unsigned long long memparse(const char *ptr, char **retptr) | |||
| 160 | return ret; | 160 | return ret; |
| 161 | } | 161 | } |
| 162 | EXPORT_SYMBOL(memparse); | 162 | EXPORT_SYMBOL(memparse); |
| 163 | |||
| 164 | /** | ||
| 165 | * parse_option_str - Parse a string and check an option is set or not | ||
| 166 | * @str: String to be parsed | ||
| 167 | * @option: option name | ||
| 168 | * | ||
| 169 | * This function parses a string containing a comma-separated list of | ||
| 170 | * strings like a=b,c. | ||
| 171 | * | ||
| 172 | * Return true if there's such option in the string, or return false. | ||
| 173 | */ | ||
| 174 | bool parse_option_str(const char *str, const char *option) | ||
| 175 | { | ||
| 176 | while (*str) { | ||
| 177 | if (!strncmp(str, option, strlen(option))) { | ||
| 178 | str += strlen(option); | ||
| 179 | if (!*str || *str == ',') | ||
| 180 | return true; | ||
| 181 | } | ||
| 182 | |||
| 183 | while (*str && *str != ',') | ||
| 184 | str++; | ||
| 185 | |||
| 186 | if (*str == ',') | ||
| 187 | str++; | ||
| 188 | } | ||
| 189 | |||
| 190 | return false; | ||
| 191 | } | ||
diff --git a/lib/string.c b/lib/string.c index 2fc20aa06f84..10063300b830 100644 --- a/lib/string.c +++ b/lib/string.c | |||
| @@ -598,6 +598,22 @@ void *memset(void *s, int c, size_t count) | |||
| 598 | EXPORT_SYMBOL(memset); | 598 | EXPORT_SYMBOL(memset); |
| 599 | #endif | 599 | #endif |
| 600 | 600 | ||
| 601 | /** | ||
| 602 | * memzero_explicit - Fill a region of memory (e.g. sensitive | ||
| 603 | * keying data) with 0s. | ||
| 604 | * @s: Pointer to the start of the area. | ||
| 605 | * @count: The size of the area. | ||
| 606 | * | ||
| 607 | * memzero_explicit() doesn't need an arch-specific version as | ||
| 608 | * it just invokes the one of memset() implicitly. | ||
| 609 | */ | ||
| 610 | void memzero_explicit(void *s, size_t count) | ||
| 611 | { | ||
| 612 | memset(s, 0, count); | ||
| 613 | OPTIMIZER_HIDE_VAR(s); | ||
| 614 | } | ||
| 615 | EXPORT_SYMBOL(memzero_explicit); | ||
| 616 | |||
| 601 | #ifndef __HAVE_ARCH_MEMCPY | 617 | #ifndef __HAVE_ARCH_MEMCPY |
| 602 | /** | 618 | /** |
| 603 | * memcpy - Copy one area of memory to another | 619 | * memcpy - Copy one area of memory to another |
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index bbf405a3a18f..5340f6b91312 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
| @@ -404,6 +404,23 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, | |||
| 404 | dump_tasks(memcg, nodemask); | 404 | dump_tasks(memcg, nodemask); |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | /* | ||
| 408 | * Number of OOM killer invocations (including memcg OOM killer). | ||
| 409 | * Primarily used by PM freezer to check for potential races with | ||
| 410 | * OOM killed frozen task. | ||
| 411 | */ | ||
| 412 | static atomic_t oom_kills = ATOMIC_INIT(0); | ||
| 413 | |||
| 414 | int oom_kills_count(void) | ||
| 415 | { | ||
| 416 | return atomic_read(&oom_kills); | ||
| 417 | } | ||
| 418 | |||
| 419 | void note_oom_kill(void) | ||
| 420 | { | ||
| 421 | atomic_inc(&oom_kills); | ||
| 422 | } | ||
| 423 | |||
| 407 | #define K(x) ((x) << (PAGE_SHIFT-10)) | 424 | #define K(x) ((x) << (PAGE_SHIFT-10)) |
| 408 | /* | 425 | /* |
| 409 | * Must be called while holding a reference to p, which will be released upon | 426 | * Must be called while holding a reference to p, which will be released upon |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 736d8e1b6381..9cd36b822444 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
| @@ -2252,6 +2252,14 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, | |||
| 2252 | } | 2252 | } |
| 2253 | 2253 | ||
| 2254 | /* | 2254 | /* |
| 2255 | * PM-freezer should be notified that there might be an OOM killer on | ||
| 2256 | * its way to kill and wake somebody up. This is too early and we might | ||
| 2257 | * end up not killing anything but false positives are acceptable. | ||
| 2258 | * See freeze_processes. | ||
| 2259 | */ | ||
| 2260 | note_oom_kill(); | ||
| 2261 | |||
| 2262 | /* | ||
| 2255 | * Go through the zonelist yet one more time, keep very high watermark | 2263 | * Go through the zonelist yet one more time, keep very high watermark |
| 2256 | * here, this is only to catch a parallel oom killing, we must fail if | 2264 | * here, this is only to catch a parallel oom killing, we must fail if |
| 2257 | * we're still under heavy pressure. | 2265 | * we're still under heavy pressure. |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index bfe1cf6b492f..166d59cdc86b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
| @@ -781,16 +781,15 @@ static int snd_pcm_action_group(struct action_ops *ops, | |||
| 781 | { | 781 | { |
| 782 | struct snd_pcm_substream *s = NULL; | 782 | struct snd_pcm_substream *s = NULL; |
| 783 | struct snd_pcm_substream *s1; | 783 | struct snd_pcm_substream *s1; |
| 784 | int res = 0; | 784 | int res = 0, depth = 1; |
| 785 | 785 | ||
| 786 | snd_pcm_group_for_each_entry(s, substream) { | 786 | snd_pcm_group_for_each_entry(s, substream) { |
| 787 | if (do_lock && s != substream) { | 787 | if (do_lock && s != substream) { |
| 788 | if (s->pcm->nonatomic) | 788 | if (s->pcm->nonatomic) |
| 789 | mutex_lock_nested(&s->self_group.mutex, | 789 | mutex_lock_nested(&s->self_group.mutex, depth); |
| 790 | SINGLE_DEPTH_NESTING); | ||
| 791 | else | 790 | else |
| 792 | spin_lock_nested(&s->self_group.lock, | 791 | spin_lock_nested(&s->self_group.lock, depth); |
| 793 | SINGLE_DEPTH_NESTING); | 792 | depth++; |
| 794 | } | 793 | } |
| 795 | res = ops->pre_action(s, state); | 794 | res = ops->pre_action(s, state); |
| 796 | if (res < 0) | 795 | if (res < 0) |
| @@ -906,8 +905,7 @@ static int snd_pcm_action_lock_mutex(struct action_ops *ops, | |||
| 906 | down_read(&snd_pcm_link_rwsem); | 905 | down_read(&snd_pcm_link_rwsem); |
| 907 | if (snd_pcm_stream_linked(substream)) { | 906 | if (snd_pcm_stream_linked(substream)) { |
| 908 | mutex_lock(&substream->group->mutex); | 907 | mutex_lock(&substream->group->mutex); |
| 909 | mutex_lock_nested(&substream->self_group.mutex, | 908 | mutex_lock(&substream->self_group.mutex); |
| 910 | SINGLE_DEPTH_NESTING); | ||
| 911 | res = snd_pcm_action_group(ops, substream, state, 1); | 909 | res = snd_pcm_action_group(ops, substream, state, 1); |
| 912 | mutex_unlock(&substream->self_group.mutex); | 910 | mutex_unlock(&substream->self_group.mutex); |
| 913 | mutex_unlock(&substream->group->mutex); | 911 | mutex_unlock(&substream->group->mutex); |
| @@ -3311,7 +3309,7 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { | |||
| 3311 | 3309 | ||
| 3312 | #ifndef ARCH_HAS_DMA_MMAP_COHERENT | 3310 | #ifndef ARCH_HAS_DMA_MMAP_COHERENT |
| 3313 | /* This should be defined / handled globally! */ | 3311 | /* This should be defined / handled globally! */ |
| 3314 | #ifdef CONFIG_ARM | 3312 | #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) |
| 3315 | #define ARCH_HAS_DMA_MMAP_COHERENT | 3313 | #define ARCH_HAS_DMA_MMAP_COHERENT |
| 3316 | #endif | 3314 | #endif |
| 3317 | #endif | 3315 | #endif |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7eb44e78e141..62658f2f8c9f 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
| @@ -419,7 +419,7 @@ struct snd_hda_pin_quirk { | |||
| 419 | .subvendor = _subvendor,\ | 419 | .subvendor = _subvendor,\ |
| 420 | .name = _name,\ | 420 | .name = _name,\ |
| 421 | .value = _value,\ | 421 | .value = _value,\ |
| 422 | .pins = (const struct hda_pintbl[]) { _pins } \ | 422 | .pins = (const struct hda_pintbl[]) { _pins, {0, 0}} \ |
| 423 | } | 423 | } |
| 424 | #else | 424 | #else |
| 425 | 425 | ||
| @@ -427,7 +427,7 @@ struct snd_hda_pin_quirk { | |||
| 427 | { .codec = _codec,\ | 427 | { .codec = _codec,\ |
| 428 | .subvendor = _subvendor,\ | 428 | .subvendor = _subvendor,\ |
| 429 | .value = _value,\ | 429 | .value = _value,\ |
| 430 | .pins = (const struct hda_pintbl[]) { _pins } \ | 430 | .pins = (const struct hda_pintbl[]) { _pins, {0, 0}} \ |
| 431 | } | 431 | } |
| 432 | 432 | ||
| 433 | #endif | 433 | #endif |
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 39862e98551c..9dc9cf8c90e9 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
| @@ -1583,19 +1583,22 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) | |||
| 1583 | } | 1583 | } |
| 1584 | } | 1584 | } |
| 1585 | 1585 | ||
| 1586 | if (pin_eld->eld_valid && !eld->eld_valid) { | 1586 | if (pin_eld->eld_valid != eld->eld_valid) |
| 1587 | update_eld = true; | ||
| 1588 | eld_changed = true; | 1587 | eld_changed = true; |
| 1589 | } | 1588 | |
| 1589 | if (pin_eld->eld_valid && !eld->eld_valid) | ||
| 1590 | update_eld = true; | ||
| 1591 | |||
| 1590 | if (update_eld) { | 1592 | if (update_eld) { |
| 1591 | bool old_eld_valid = pin_eld->eld_valid; | 1593 | bool old_eld_valid = pin_eld->eld_valid; |
| 1592 | pin_eld->eld_valid = eld->eld_valid; | 1594 | pin_eld->eld_valid = eld->eld_valid; |
| 1593 | eld_changed = pin_eld->eld_size != eld->eld_size || | 1595 | if (pin_eld->eld_size != eld->eld_size || |
| 1594 | memcmp(pin_eld->eld_buffer, eld->eld_buffer, | 1596 | memcmp(pin_eld->eld_buffer, eld->eld_buffer, |
| 1595 | eld->eld_size) != 0; | 1597 | eld->eld_size) != 0) { |
| 1596 | if (eld_changed) | ||
| 1597 | memcpy(pin_eld->eld_buffer, eld->eld_buffer, | 1598 | memcpy(pin_eld->eld_buffer, eld->eld_buffer, |
| 1598 | eld->eld_size); | 1599 | eld->eld_size); |
| 1600 | eld_changed = true; | ||
| 1601 | } | ||
| 1599 | pin_eld->eld_size = eld->eld_size; | 1602 | pin_eld->eld_size = eld->eld_size; |
| 1600 | pin_eld->info = eld->info; | 1603 | pin_eld->info = eld->info; |
| 1601 | 1604 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bc86c36b4bfa..34b7bdb510c7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
| @@ -2884,6 +2884,9 @@ static void alc283_shutup(struct hda_codec *codec) | |||
| 2884 | 2884 | ||
| 2885 | alc_write_coef_idx(codec, 0x43, 0x9004); | 2885 | alc_write_coef_idx(codec, 0x43, 0x9004); |
| 2886 | 2886 | ||
| 2887 | /*depop hp during suspend*/ | ||
| 2888 | alc_write_coef_idx(codec, 0x06, 0x2100); | ||
| 2889 | |||
| 2887 | snd_hda_codec_write(codec, hp_pin, 0, | 2890 | snd_hda_codec_write(codec, hp_pin, 0, |
| 2888 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | 2891 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); |
| 2889 | 2892 | ||
| @@ -5610,9 +5613,9 @@ static void alc662_led_gpio1_mute_hook(void *private_data, int enabled) | |||
| 5610 | unsigned int oldval = spec->gpio_led; | 5613 | unsigned int oldval = spec->gpio_led; |
| 5611 | 5614 | ||
| 5612 | if (enabled) | 5615 | if (enabled) |
| 5613 | spec->gpio_led &= ~0x01; | ||
| 5614 | else | ||
| 5615 | spec->gpio_led |= 0x01; | 5616 | spec->gpio_led |= 0x01; |
| 5617 | else | ||
| 5618 | spec->gpio_led &= ~0x01; | ||
| 5616 | if (spec->gpio_led != oldval) | 5619 | if (spec->gpio_led != oldval) |
| 5617 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | 5620 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, |
| 5618 | spec->gpio_led); | 5621 | spec->gpio_led); |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 223c47b33ba3..c657752a420c 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
| @@ -385,6 +385,36 @@ YAMAHA_DEVICE(0x105d, NULL), | |||
| 385 | } | 385 | } |
| 386 | }, | 386 | }, |
| 387 | { | 387 | { |
| 388 | USB_DEVICE(0x0499, 0x1509), | ||
| 389 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
| 390 | /* .vendor_name = "Yamaha", */ | ||
| 391 | /* .product_name = "Steinberg UR22", */ | ||
| 392 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 393 | .type = QUIRK_COMPOSITE, | ||
| 394 | .data = (const struct snd_usb_audio_quirk[]) { | ||
| 395 | { | ||
| 396 | .ifnum = 1, | ||
| 397 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
| 398 | }, | ||
| 399 | { | ||
| 400 | .ifnum = 2, | ||
| 401 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
| 402 | }, | ||
| 403 | { | ||
| 404 | .ifnum = 3, | ||
| 405 | .type = QUIRK_MIDI_YAMAHA | ||
| 406 | }, | ||
| 407 | { | ||
| 408 | .ifnum = 4, | ||
| 409 | .type = QUIRK_IGNORE_INTERFACE | ||
| 410 | }, | ||
| 411 | { | ||
| 412 | .ifnum = -1 | ||
| 413 | } | ||
| 414 | } | ||
| 415 | } | ||
| 416 | }, | ||
| 417 | { | ||
| 388 | USB_DEVICE(0x0499, 0x150a), | 418 | USB_DEVICE(0x0499, 0x150a), |
| 389 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 419 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
| 390 | /* .vendor_name = "Yamaha", */ | 420 | /* .vendor_name = "Yamaha", */ |
diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c index 60b58cd18410..7ccb073f8316 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixxf.c +++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c | |||
| @@ -122,6 +122,14 @@ static void os_enter_line_edit_mode(void) | |||
| 122 | { | 122 | { |
| 123 | struct termios local_term_attributes; | 123 | struct termios local_term_attributes; |
| 124 | 124 | ||
| 125 | term_attributes_were_set = 0; | ||
| 126 | |||
| 127 | /* STDIN must be a terminal */ | ||
| 128 | |||
| 129 | if (!isatty(STDIN_FILENO)) { | ||
| 130 | return; | ||
| 131 | } | ||
| 132 | |||
| 125 | /* Get and keep the original attributes */ | 133 | /* Get and keep the original attributes */ |
| 126 | 134 | ||
| 127 | if (tcgetattr(STDIN_FILENO, &original_term_attributes)) { | 135 | if (tcgetattr(STDIN_FILENO, &original_term_attributes)) { |
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c index 53cee781e24e..24d32968802d 100644 --- a/tools/power/acpi/tools/acpidump/apdump.c +++ b/tools/power/acpi/tools/acpidump/apdump.c | |||
| @@ -146,7 +146,7 @@ u32 ap_get_table_length(struct acpi_table_header *table) | |||
| 146 | 146 | ||
| 147 | if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { | 147 | if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { |
| 148 | rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table); | 148 | rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table); |
| 149 | return (rsdp->length); | 149 | return (acpi_tb_get_rsdp_length(rsdp)); |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | /* Normal ACPI table */ | 152 | /* Normal ACPI table */ |
