From ed57c34be5a5a75c318bc8729ebb6d1ed6a38e1b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 14 Jul 2014 10:41:38 -0700 Subject: [PATCH] 3.15-stable patches added patches: acpi-ec-add-asynchronous-command-byte-write-support.patch acpi-ec-avoid-race-condition-related-to-advance_transaction.patch acpi-ec-fix-race-condition-in-ec_transaction_completed.patch acpi-ec-remove-duplicated-ec_wait_ibf0-waiter.patch acpi-resources-only-reject-zero-length-resources-based-at-address-zero.patch hwmon-adc128d818-drop-write-support-on-inx_input-attributes.patch hwmon-adm1021-fix-cache-problem-when-writing-temperature-limits.patch hwmon-adm1029-ensure-the-fan_div-cache-is-updated-in-set_fan_div.patch hwmon-adm1031-fix-writes-to-limit-registers.patch hwmon-amc6821-fix-permissions-for-temp2_input.patch hwmon-emc2103-clamp-limits-instead-of-bailing-out.patch powerpc-kvm-remove-redundant-save-of-sier-and-mmcr2.patch powerpc-perf-add-ppmu_arch_207s-define.patch powerpc-perf-clear-mmcr2-when-enabling-pmu.patch powerpc-perf-never-program-book3s-pmcs-with-values-0x80000000.patch revert-acpi-ac-remove-ac-s-proc-directory.patch thermal-hwmon-make-the-check-for-critical-temp-valid-consistent.patch --- ...nchronous-command-byte-write-support.patch | 217 +++++++++++++++++ ...ition-related-to-advance_transaction.patch | 92 +++++++ ...ondition-in-ec_transaction_completed.patch | 135 +++++++++++ ...emove-duplicated-ec_wait_ibf0-waiter.patch | 93 +++++++ ...ngth-resources-based-at-address-zero.patch | 83 +++++++ ...rite-support-on-inx_input-attributes.patch | 88 +++++++ ...blem-when-writing-temperature-limits.patch | 70 ++++++ ..._div-cache-is-updated-in-set_fan_div.patch | 36 +++ ...dm1031-fix-writes-to-limit-registers.patch | 75 ++++++ ...6821-fix-permissions-for-temp2_input.patch | 31 +++ ...-clamp-limits-instead-of-bailing-out.patch | 65 +++++ ...ove-redundant-save-of-sier-and-mmcr2.patch | 44 ++++ ...werpc-perf-add-ppmu_arch_207s-define.patch | 77 ++++++ ...c-perf-clear-mmcr2-when-enabling-pmu.patch | 74 ++++++ ...m-book3s-pmcs-with-values-0x80000000.patch | 57 +++++ ...t-acpi-ac-remove-ac-s-proc-directory.patch | 228 ++++++++++++++++++ queue-3.15/series | 17 ++ ...k-for-critical-temp-valid-consistent.patch | 97 ++++++++ 18 files changed, 1579 insertions(+) create mode 100644 queue-3.15/acpi-ec-add-asynchronous-command-byte-write-support.patch create mode 100644 queue-3.15/acpi-ec-avoid-race-condition-related-to-advance_transaction.patch create mode 100644 queue-3.15/acpi-ec-fix-race-condition-in-ec_transaction_completed.patch create mode 100644 queue-3.15/acpi-ec-remove-duplicated-ec_wait_ibf0-waiter.patch create mode 100644 queue-3.15/acpi-resources-only-reject-zero-length-resources-based-at-address-zero.patch create mode 100644 queue-3.15/hwmon-adc128d818-drop-write-support-on-inx_input-attributes.patch create mode 100644 queue-3.15/hwmon-adm1021-fix-cache-problem-when-writing-temperature-limits.patch create mode 100644 queue-3.15/hwmon-adm1029-ensure-the-fan_div-cache-is-updated-in-set_fan_div.patch create mode 100644 queue-3.15/hwmon-adm1031-fix-writes-to-limit-registers.patch create mode 100644 queue-3.15/hwmon-amc6821-fix-permissions-for-temp2_input.patch create mode 100644 queue-3.15/hwmon-emc2103-clamp-limits-instead-of-bailing-out.patch create mode 100644 queue-3.15/powerpc-kvm-remove-redundant-save-of-sier-and-mmcr2.patch create mode 100644 queue-3.15/powerpc-perf-add-ppmu_arch_207s-define.patch create mode 100644 queue-3.15/powerpc-perf-clear-mmcr2-when-enabling-pmu.patch create mode 100644 queue-3.15/powerpc-perf-never-program-book3s-pmcs-with-values-0x80000000.patch create mode 100644 queue-3.15/revert-acpi-ac-remove-ac-s-proc-directory.patch create mode 100644 queue-3.15/thermal-hwmon-make-the-check-for-critical-temp-valid-consistent.patch diff --git a/queue-3.15/acpi-ec-add-asynchronous-command-byte-write-support.patch b/queue-3.15/acpi-ec-add-asynchronous-command-byte-write-support.patch new file mode 100644 index 00000000000..b6fca81efa4 --- /dev/null +++ b/queue-3.15/acpi-ec-add-asynchronous-command-byte-write-support.patch @@ -0,0 +1,217 @@ +From f92fca0060fc4dc9227342d0072d75df98c1e5a5 Mon Sep 17 00:00:00 2001 +From: Lv Zheng +Date: Sun, 15 Jun 2014 08:41:35 +0800 +Subject: ACPI / EC: Add asynchronous command byte write support + +From: Lv Zheng + +commit f92fca0060fc4dc9227342d0072d75df98c1e5a5 upstream. + +Move the first command byte write into advance_transaction() so that all +EC register accesses that can affect the command processing state machine +can happen in this asynchronous state machine advancement function. + +The advance_transaction() function then can be a complete implementation +of an asyncrhonous transaction for a single command so that: + 1. The first command byte can be written in the interrupt context; + 2. The command completion waiter can also be used to wait the first command + byte's timeout; + 3. In BURST mode, the follow-up command bytes can be written in the + interrupt context directly, so that it doesn't need to return to the + task context. Returning to the task context reduces the throughput of + the BURST mode and in the worst cases where the system workload is very + high, this leads to the hardware driven automatic BURST mode exit. + +In order not to increase memory consumption, convert 'done' into 'flags' +to contain multiple indications: + 1. ACPI_EC_COMMAND_COMPLETE: converting from original 'done' condition, + indicating the completion of the command transaction. + 2. ACPI_EC_COMMAND_POLL: indicating the availability of writing the first + command byte. A new command can utilize this flag to compete for the + right of accessing the underlying hardware. There is a follow-up bug + fix that has utilized this new flag. + +The 2 flags are important because it also reflects a key concept of IO +programs' design used in the system softwares. Normally an IO program +running in the kernel should first be implemented in the asynchronous way. +And the 2 flags are the most common way to implement its synchronous +operations on top of the asynchronous operations: +1. POLL: This flag can be used to block until the asynchronous operations + can happen. +2. COMPLETE: This flag can be used to block until the asynchronous + operations have completed. +By constructing code cleanly in this way, many difficult problems can be +solved smoothly. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=70891 +Link: https://bugzilla.kernel.org/show_bug.cgi?id=63931 +Link: https://bugzilla.kernel.org/show_bug.cgi?id=59911 +Reported-and-tested-by: Gareth Williams +Reported-and-tested-by: Hans de Goede +Reported-by: Barton Xu +Tested-by: Steffen Weber +Tested-by: Arthur Chen +Signed-off-by: Lv Zheng +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/ec.c | 83 +++++++++++++++++++++++++++++++----------------------- + 1 file changed, 48 insertions(+), 35 deletions(-) + +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -78,6 +78,9 @@ enum { + EC_FLAGS_BLOCKED, /* Transactions are blocked */ + }; + ++#define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ ++#define ACPI_EC_COMMAND_COMPLETE 0x02 /* Completed last byte */ ++ + /* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */ + static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY; + module_param(ec_delay, uint, 0644); +@@ -109,7 +112,7 @@ struct transaction { + u8 ri; + u8 wlen; + u8 rlen; +- bool done; ++ u8 flags; + }; + + struct acpi_ec *boot_ec, *first_ec; +@@ -150,63 +153,68 @@ static inline void acpi_ec_write_data(st + outb(data, ec->data_addr); + } + +-static int ec_transaction_done(struct acpi_ec *ec) ++static int ec_transaction_completed(struct acpi_ec *ec) + { + unsigned long flags; + int ret = 0; + spin_lock_irqsave(&ec->lock, flags); +- if (!ec->curr || ec->curr->done) ++ if (!ec->curr || (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE)) + ret = 1; + spin_unlock_irqrestore(&ec->lock, flags); + return ret; + } + +-static void start_transaction(struct acpi_ec *ec) +-{ +- ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0; +- ec->curr->done = false; +- acpi_ec_write_cmd(ec, ec->curr->command); +-} +- + static void advance_transaction(struct acpi_ec *ec) + { +- unsigned long flags; + struct transaction *t; + u8 status; + +- spin_lock_irqsave(&ec->lock, flags); + pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK"); + status = acpi_ec_read_status(ec); + t = ec->curr; + if (!t) +- goto unlock; +- if (t->wlen > t->wi) { +- if ((status & ACPI_EC_FLAG_IBF) == 0) +- acpi_ec_write_data(ec, +- t->wdata[t->wi++]); +- else +- goto err; +- } else if (t->rlen > t->ri) { +- if ((status & ACPI_EC_FLAG_OBF) == 1) { +- t->rdata[t->ri++] = acpi_ec_read_data(ec); +- if (t->rlen == t->ri) +- t->done = true; ++ goto err; ++ if (t->flags & ACPI_EC_COMMAND_POLL) { ++ if (t->wlen > t->wi) { ++ if ((status & ACPI_EC_FLAG_IBF) == 0) ++ acpi_ec_write_data(ec, t->wdata[t->wi++]); ++ else ++ goto err; ++ } else if (t->rlen > t->ri) { ++ if ((status & ACPI_EC_FLAG_OBF) == 1) { ++ t->rdata[t->ri++] = acpi_ec_read_data(ec); ++ if (t->rlen == t->ri) ++ t->flags |= ACPI_EC_COMMAND_COMPLETE; ++ } else ++ goto err; ++ } else if (t->wlen == t->wi && ++ (status & ACPI_EC_FLAG_IBF) == 0) ++ t->flags |= ACPI_EC_COMMAND_COMPLETE; ++ return; ++ } else { ++ if ((status & ACPI_EC_FLAG_IBF) == 0) { ++ acpi_ec_write_cmd(ec, t->command); ++ t->flags |= ACPI_EC_COMMAND_POLL; + } else + goto err; +- } else if (t->wlen == t->wi && +- (status & ACPI_EC_FLAG_IBF) == 0) +- t->done = true; +- goto unlock; ++ return; ++ } + err: + /* + * If SCI bit is set, then don't think it's a false IRQ + * otherwise will take a not handled IRQ as a false one. + */ +- if (in_interrupt() && !(status & ACPI_EC_FLAG_SCI)) +- ++t->irq_count; ++ if (!(status & ACPI_EC_FLAG_SCI)) { ++ if (in_interrupt() && t) ++ ++t->irq_count; ++ } ++} + +-unlock: +- spin_unlock_irqrestore(&ec->lock, flags); ++static void start_transaction(struct acpi_ec *ec) ++{ ++ ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0; ++ ec->curr->flags = 0; ++ advance_transaction(ec); + } + + static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data); +@@ -231,15 +239,17 @@ static int ec_poll(struct acpi_ec *ec) + /* don't sleep with disabled interrupts */ + if (EC_FLAGS_MSI || irqs_disabled()) { + udelay(ACPI_EC_MSI_UDELAY); +- if (ec_transaction_done(ec)) ++ if (ec_transaction_completed(ec)) + return 0; + } else { + if (wait_event_timeout(ec->wait, +- ec_transaction_done(ec), ++ ec_transaction_completed(ec), + msecs_to_jiffies(1))) + return 0; + } ++ spin_lock_irqsave(&ec->lock, flags); + advance_transaction(ec); ++ spin_unlock_irqrestore(&ec->lock, flags); + } while (time_before(jiffies, delay)); + pr_debug("controller reset, restart transaction\n"); + spin_lock_irqsave(&ec->lock, flags); +@@ -637,10 +647,13 @@ static int ec_check_sci(struct acpi_ec * + static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, + u32 gpe_number, void *data) + { ++ unsigned long flags; + struct acpi_ec *ec = data; + ++ spin_lock_irqsave(&ec->lock, flags); + advance_transaction(ec); +- if (ec_transaction_done(ec) && ++ spin_unlock_irqrestore(&ec->lock, flags); ++ if (ec_transaction_completed(ec) && + (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { + wake_up(&ec->wait); + ec_check_sci(ec, acpi_ec_read_status(ec)); diff --git a/queue-3.15/acpi-ec-avoid-race-condition-related-to-advance_transaction.patch b/queue-3.15/acpi-ec-avoid-race-condition-related-to-advance_transaction.patch new file mode 100644 index 00000000000..680889731a3 --- /dev/null +++ b/queue-3.15/acpi-ec-avoid-race-condition-related-to-advance_transaction.patch @@ -0,0 +1,92 @@ +From 66b42b78bc1e816f92b662e8888c89195e4199e1 Mon Sep 17 00:00:00 2001 +From: Lv Zheng +Date: Sun, 15 Jun 2014 08:41:17 +0800 +Subject: ACPI / EC: Avoid race condition related to advance_transaction() + +From: Lv Zheng + +commit 66b42b78bc1e816f92b662e8888c89195e4199e1 upstream. + +The advance_transaction() will be invoked from the IRQ context GPE handler +and the task context ec_poll(). The handling of this function is locked so +that the EC state machine are ensured to be advanced sequentially. + +But there is a problem. Before invoking advance_transaction(), EC_SC(R) is +read. Then for advance_transaction(), there could be race condition around +the lock from both contexts. The first one reading the register could fail +this race and when it passes the stale register value to the state machine +advancement code, the hardware condition is totally different from when +the register is read. And the hardware accesses determined from the wrong +hardware status can break the EC state machine. And there could be cases +that the functionalities of the platform firmware are seriously affected. +For example: + 1. When 2 EC_DATA(W) writes compete the IBF=0, the 2nd EC_DATA(W) write may + be invalid due to IBF=1 after the 1st EC_DATA(W) write. Then the + hardware will either refuse to respond a next EC_SC(W) write of the next + command or discard the current WR_EC command when it receives a EC_SC(W) + write of the next command. + 2. When 1 EC_SC(W) write and 1 EC_DATA(W) write compete the IBF=0, the + EC_DATA(W) write may be invalid due to IBF=1 after the EC_SC(W) write. + The next EC_DATA(R) could never be responded by the hardware. This is + the root cause of the reported issue. + +Fix this issue by moving the EC_SC(R) access into the lock so that we can +ensure that the state machine is advanced consistently. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=70891 +Link: https://bugzilla.kernel.org/show_bug.cgi?id=63931 +Link: https://bugzilla.kernel.org/show_bug.cgi?id=59911 +Reported-and-tested-by: Gareth Williams +Reported-and-tested-by: Hans de Goede +Reported-by: Barton Xu +Tested-by: Steffen Weber +Tested-by: Arthur Chen +Signed-off-by: Lv Zheng +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/ec.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -168,12 +168,15 @@ static void start_transaction(struct acp + acpi_ec_write_cmd(ec, ec->curr->command); + } + +-static void advance_transaction(struct acpi_ec *ec, u8 status) ++static void advance_transaction(struct acpi_ec *ec) + { + unsigned long flags; + struct transaction *t; ++ u8 status; + + spin_lock_irqsave(&ec->lock, flags); ++ pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK"); ++ status = acpi_ec_read_status(ec); + t = ec->curr; + if (!t) + goto unlock; +@@ -236,7 +239,7 @@ static int ec_poll(struct acpi_ec *ec) + msecs_to_jiffies(1))) + return 0; + } +- advance_transaction(ec, acpi_ec_read_status(ec)); ++ advance_transaction(ec); + } while (time_before(jiffies, delay)); + pr_debug("controller reset, restart transaction\n"); + spin_lock_irqsave(&ec->lock, flags); +@@ -635,11 +638,8 @@ static u32 acpi_ec_gpe_handler(acpi_hand + u32 gpe_number, void *data) + { + struct acpi_ec *ec = data; +- u8 status = acpi_ec_read_status(ec); +- +- pr_debug("~~~> interrupt, status:0x%02x\n", status); + +- advance_transaction(ec, status); ++ advance_transaction(ec); + if (ec_transaction_done(ec) && + (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { + wake_up(&ec->wait); diff --git a/queue-3.15/acpi-ec-fix-race-condition-in-ec_transaction_completed.patch b/queue-3.15/acpi-ec-fix-race-condition-in-ec_transaction_completed.patch new file mode 100644 index 00000000000..24f50191963 --- /dev/null +++ b/queue-3.15/acpi-ec-fix-race-condition-in-ec_transaction_completed.patch @@ -0,0 +1,135 @@ +From c0d653412fc8450370167a3268b78fc772ff9c87 Mon Sep 17 00:00:00 2001 +From: Lv Zheng +Date: Sun, 15 Jun 2014 08:42:07 +0800 +Subject: ACPI / EC: Fix race condition in ec_transaction_completed() + +From: Lv Zheng + +commit c0d653412fc8450370167a3268b78fc772ff9c87 upstream. + +There is a race condition in ec_transaction_completed(). + +When ec_transaction_completed() is called in the GPE handler, it could +return true because of (ec->curr == NULL). Then the wake_up() invocation +could complete the next command unexpectedly since there is no lock between +the 2 invocations. With the previous cleanup, the IBF=0 waiter race need +not be handled any more. It's now safe to return a flag from +advance_condition() to indicate the requirement of wakeup, the flag is +returned from a locked context. + +The ec_transaction_completed() is now only invoked by the ec_poll() where +the ec->curr is ensured to be different from NULL. + +After cleaning up, the EVT_SCI=1 check should be moved out of the wakeup +condition so that an EVT_SCI raised with (ec->curr == NULL) can trigger a +QR_SC command. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=70891 +Link: https://bugzilla.kernel.org/show_bug.cgi?id=63931 +Link: https://bugzilla.kernel.org/show_bug.cgi?id=59911 +Reported-and-tested-by: Gareth Williams +Reported-and-tested-by: Hans de Goede +Reported-by: Barton Xu +Tested-by: Steffen Weber +Tested-by: Arthur Chen +Signed-off-by: Lv Zheng +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/ec.c | 30 +++++++++++++++++------------- + 1 file changed, 17 insertions(+), 13 deletions(-) + +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -158,16 +158,17 @@ static int ec_transaction_completed(stru + unsigned long flags; + int ret = 0; + spin_lock_irqsave(&ec->lock, flags); +- if (!ec->curr || (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE)) ++ if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE)) + ret = 1; + spin_unlock_irqrestore(&ec->lock, flags); + return ret; + } + +-static void advance_transaction(struct acpi_ec *ec) ++static bool advance_transaction(struct acpi_ec *ec) + { + struct transaction *t; + u8 status; ++ bool wakeup = false; + + pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK"); + status = acpi_ec_read_status(ec); +@@ -183,21 +184,25 @@ static void advance_transaction(struct a + } else if (t->rlen > t->ri) { + if ((status & ACPI_EC_FLAG_OBF) == 1) { + t->rdata[t->ri++] = acpi_ec_read_data(ec); +- if (t->rlen == t->ri) ++ if (t->rlen == t->ri) { + t->flags |= ACPI_EC_COMMAND_COMPLETE; ++ wakeup = true; ++ } + } else + goto err; + } else if (t->wlen == t->wi && +- (status & ACPI_EC_FLAG_IBF) == 0) ++ (status & ACPI_EC_FLAG_IBF) == 0) { + t->flags |= ACPI_EC_COMMAND_COMPLETE; +- return; ++ wakeup = true; ++ } ++ return wakeup; + } else { + if ((status & ACPI_EC_FLAG_IBF) == 0) { + acpi_ec_write_cmd(ec, t->command); + t->flags |= ACPI_EC_COMMAND_POLL; + } else + goto err; +- return; ++ return wakeup; + } + err: + /* +@@ -208,13 +213,14 @@ err: + if (in_interrupt() && t) + ++t->irq_count; + } ++ return wakeup; + } + + static void start_transaction(struct acpi_ec *ec) + { + ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0; + ec->curr->flags = 0; +- advance_transaction(ec); ++ (void)advance_transaction(ec); + } + + static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data); +@@ -248,7 +254,7 @@ static int ec_poll(struct acpi_ec *ec) + return 0; + } + spin_lock_irqsave(&ec->lock, flags); +- advance_transaction(ec); ++ (void)advance_transaction(ec); + spin_unlock_irqrestore(&ec->lock, flags); + } while (time_before(jiffies, delay)); + pr_debug("controller reset, restart transaction\n"); +@@ -627,12 +633,10 @@ static u32 acpi_ec_gpe_handler(acpi_hand + struct acpi_ec *ec = data; + + spin_lock_irqsave(&ec->lock, flags); +- advance_transaction(ec); +- spin_unlock_irqrestore(&ec->lock, flags); +- if (ec_transaction_completed(ec)) { ++ if (advance_transaction(ec)) + wake_up(&ec->wait); +- ec_check_sci(ec, acpi_ec_read_status(ec)); +- } ++ spin_unlock_irqrestore(&ec->lock, flags); ++ ec_check_sci(ec, acpi_ec_read_status(ec)); + return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; + } + diff --git a/queue-3.15/acpi-ec-remove-duplicated-ec_wait_ibf0-waiter.patch b/queue-3.15/acpi-ec-remove-duplicated-ec_wait_ibf0-waiter.patch new file mode 100644 index 00000000000..66db0da6b27 --- /dev/null +++ b/queue-3.15/acpi-ec-remove-duplicated-ec_wait_ibf0-waiter.patch @@ -0,0 +1,93 @@ +From 9b80f0f73ae1583c22325ede341c74195847618c Mon Sep 17 00:00:00 2001 +From: Lv Zheng +Date: Sun, 15 Jun 2014 08:41:48 +0800 +Subject: ACPI / EC: Remove duplicated ec_wait_ibf0() waiter + +From: Lv Zheng + +commit 9b80f0f73ae1583c22325ede341c74195847618c upstream. + +After we've added the first command byte write into advance_transaction(), +the IBF=0 waiter is duplicated with the command completion waiter +implemented in the ec_poll() because: + If IBF=1 blocked the first command byte write invoked in the task + context ec_poll(), it would be kicked off upon IBF=0 interrupt or timed + out and retried again in the task context. + +Remove this seperate and duplicate IBF=0 waiter. By doing so we can +reduce the overall number of times to access the EC_SC(R) status +register. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=70891 +Link: https://bugzilla.kernel.org/show_bug.cgi?id=63931 +Link: https://bugzilla.kernel.org/show_bug.cgi?id=59911 +Reported-and-tested-by: Gareth Williams +Reported-and-tested-by: Hans de Goede +Reported-by: Barton Xu +Tested-by: Steffen Weber +Tested-by: Arthur Chen +Signed-off-by: Lv Zheng +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/ec.c | 27 +-------------------------- + 1 file changed, 1 insertion(+), 26 deletions(-) + +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -281,23 +281,6 @@ static int acpi_ec_transaction_unlocked( + return ret; + } + +-static int ec_check_ibf0(struct acpi_ec *ec) +-{ +- u8 status = acpi_ec_read_status(ec); +- return (status & ACPI_EC_FLAG_IBF) == 0; +-} +- +-static int ec_wait_ibf0(struct acpi_ec *ec) +-{ +- unsigned long delay = jiffies + msecs_to_jiffies(ec_delay); +- /* interrupt wait manually if GPE mode is not active */ +- while (time_before(jiffies, delay)) +- if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), +- msecs_to_jiffies(1))) +- return 0; +- return -ETIME; +-} +- + static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) + { + int status; +@@ -318,12 +301,6 @@ static int acpi_ec_transaction(struct ac + goto unlock; + } + } +- if (ec_wait_ibf0(ec)) { +- pr_err("input buffer is not empty, " +- "aborting transaction\n"); +- status = -ETIME; +- goto end; +- } + pr_debug("transaction start (cmd=0x%02x, addr=0x%02x)\n", + t->command, t->wdata ? t->wdata[0] : 0); + /* disable GPE during transaction if storm is detected */ +@@ -347,7 +324,6 @@ static int acpi_ec_transaction(struct ac + set_bit(EC_FLAGS_GPE_STORM, &ec->flags); + } + pr_debug("transaction end\n"); +-end: + if (ec->global_lock) + acpi_release_global_lock(glk); + unlock: +@@ -653,8 +629,7 @@ static u32 acpi_ec_gpe_handler(acpi_hand + spin_lock_irqsave(&ec->lock, flags); + advance_transaction(ec); + spin_unlock_irqrestore(&ec->lock, flags); +- if (ec_transaction_completed(ec) && +- (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { ++ if (ec_transaction_completed(ec)) { + wake_up(&ec->wait); + ec_check_sci(ec, acpi_ec_read_status(ec)); + } diff --git a/queue-3.15/acpi-resources-only-reject-zero-length-resources-based-at-address-zero.patch b/queue-3.15/acpi-resources-only-reject-zero-length-resources-based-at-address-zero.patch new file mode 100644 index 00000000000..1536f4a0ea7 --- /dev/null +++ b/queue-3.15/acpi-resources-only-reject-zero-length-resources-based-at-address-zero.patch @@ -0,0 +1,83 @@ +From 867f9d463b82462793ea4610e748be0b04b37fc7 Mon Sep 17 00:00:00 2001 +From: Andy Whitcroft +Date: Thu, 19 Jun 2014 11:19:16 +0100 +Subject: ACPI / resources: only reject zero length resources based at address zero + +From: Andy Whitcroft + +commit 867f9d463b82462793ea4610e748be0b04b37fc7 upstream. + +The recently merged change (in v3.14-rc6) to ACPI resource detection +(below) causes all zero length ACPI resources to be elided from the +table: + + commit b355cee88e3b1a193f0e9a81db810f6f83ad728b + Author: Zhang Rui + Date: Thu Feb 27 11:37:15 2014 +0800 + + ACPI / resources: ignore invalid ACPI device resources + +This change has caused a regression in (at least) serial port detection +for a number of machines (see LP#1313981 [1]). These seem to represent +their IO regions (presumably incorrectly) as a zero length region. +Reverting the above commit restores these serial devices. + +Only elide zero length resources which lie at address 0. + +Fixes: b355cee88e3b (ACPI / resources: ignore invalid ACPI device resources) +Signed-off-by: Andy Whitcroft +Acked-by: Zhang Rui +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/resource.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/acpi/resource.c ++++ b/drivers/acpi/resource.c +@@ -77,7 +77,7 @@ bool acpi_dev_resource_memory(struct acp + switch (ares->type) { + case ACPI_RESOURCE_TYPE_MEMORY24: + memory24 = &ares->data.memory24; +- if (!memory24->address_length) ++ if (!memory24->minimum && !memory24->address_length) + return false; + acpi_dev_get_memresource(res, memory24->minimum, + memory24->address_length, +@@ -85,7 +85,7 @@ bool acpi_dev_resource_memory(struct acp + break; + case ACPI_RESOURCE_TYPE_MEMORY32: + memory32 = &ares->data.memory32; +- if (!memory32->address_length) ++ if (!memory32->minimum && !memory32->address_length) + return false; + acpi_dev_get_memresource(res, memory32->minimum, + memory32->address_length, +@@ -93,7 +93,7 @@ bool acpi_dev_resource_memory(struct acp + break; + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + fixed_memory32 = &ares->data.fixed_memory32; +- if (!fixed_memory32->address_length) ++ if (!fixed_memory32->address && !fixed_memory32->address_length) + return false; + acpi_dev_get_memresource(res, fixed_memory32->address, + fixed_memory32->address_length, +@@ -150,7 +150,7 @@ bool acpi_dev_resource_io(struct acpi_re + switch (ares->type) { + case ACPI_RESOURCE_TYPE_IO: + io = &ares->data.io; +- if (!io->address_length) ++ if (!io->minimum && !io->address_length) + return false; + acpi_dev_get_ioresource(res, io->minimum, + io->address_length, +@@ -158,7 +158,7 @@ bool acpi_dev_resource_io(struct acpi_re + break; + case ACPI_RESOURCE_TYPE_FIXED_IO: + fixed_io = &ares->data.fixed_io; +- if (!fixed_io->address_length) ++ if (!fixed_io->address && !fixed_io->address_length) + return false; + acpi_dev_get_ioresource(res, fixed_io->address, + fixed_io->address_length, diff --git a/queue-3.15/hwmon-adc128d818-drop-write-support-on-inx_input-attributes.patch b/queue-3.15/hwmon-adc128d818-drop-write-support-on-inx_input-attributes.patch new file mode 100644 index 00000000000..b2bf615b9e5 --- /dev/null +++ b/queue-3.15/hwmon-adc128d818-drop-write-support-on-inx_input-attributes.patch @@ -0,0 +1,88 @@ +From 7fe7381cbdadf16792e733789983690b3fa82880 Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Mon, 7 Jul 2014 07:10:10 -0700 +Subject: hwmon: (adc128d818) Drop write support on inX_input attributes + +From: Guenter Roeck + +commit 7fe7381cbdadf16792e733789983690b3fa82880 upstream. + +Writes into input registers doesn't make sense, even more so since +the writes actually ended up writing into the maximum limit registers. +Drop it. + +Reviewed-by: Jean Delvare +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hwmon/adc128d818.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +--- a/drivers/hwmon/adc128d818.c ++++ b/drivers/hwmon/adc128d818.c +@@ -239,50 +239,50 @@ static ssize_t adc128_show_alarm(struct + return sprintf(buf, "%u\n", !!(alarms & mask)); + } + +-static SENSOR_DEVICE_ATTR_2(in0_input, S_IWUSR | S_IRUGO, +- adc128_show_in, adc128_set_in, 0, 0); ++static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, ++ adc128_show_in, NULL, 0, 0); + static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 0, 1); + static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 0, 2); + +-static SENSOR_DEVICE_ATTR_2(in1_input, S_IWUSR | S_IRUGO, +- adc128_show_in, adc128_set_in, 1, 0); ++static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, ++ adc128_show_in, NULL, 1, 0); + static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 1, 1); + static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 1, 2); + +-static SENSOR_DEVICE_ATTR_2(in2_input, S_IWUSR | S_IRUGO, +- adc128_show_in, adc128_set_in, 2, 0); ++static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, ++ adc128_show_in, NULL, 2, 0); + static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 2, 1); + static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 2, 2); + +-static SENSOR_DEVICE_ATTR_2(in3_input, S_IWUSR | S_IRUGO, +- adc128_show_in, adc128_set_in, 3, 0); ++static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, ++ adc128_show_in, NULL, 3, 0); + static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 3, 1); + static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 3, 2); + +-static SENSOR_DEVICE_ATTR_2(in4_input, S_IWUSR | S_IRUGO, +- adc128_show_in, adc128_set_in, 4, 0); ++static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, ++ adc128_show_in, NULL, 4, 0); + static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 4, 1); + static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 4, 2); + +-static SENSOR_DEVICE_ATTR_2(in5_input, S_IWUSR | S_IRUGO, +- adc128_show_in, adc128_set_in, 5, 0); ++static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, ++ adc128_show_in, NULL, 5, 0); + static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 5, 1); + static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 5, 2); + +-static SENSOR_DEVICE_ATTR_2(in6_input, S_IWUSR | S_IRUGO, +- adc128_show_in, adc128_set_in, 6, 0); ++static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, ++ adc128_show_in, NULL, 6, 0); + static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 6, 1); + static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, diff --git a/queue-3.15/hwmon-adm1021-fix-cache-problem-when-writing-temperature-limits.patch b/queue-3.15/hwmon-adm1021-fix-cache-problem-when-writing-temperature-limits.patch new file mode 100644 index 00000000000..20be3d92c93 --- /dev/null +++ b/queue-3.15/hwmon-adm1021-fix-cache-problem-when-writing-temperature-limits.patch @@ -0,0 +1,70 @@ +From c024044d4da2c9c3b32933b4235df1e409293b84 Mon Sep 17 00:00:00 2001 +From: Axel Lin +Date: Thu, 3 Jul 2014 22:45:45 +0800 +Subject: hwmon: (adm1021) Fix cache problem when writing temperature limits + +From: Axel Lin + +commit c024044d4da2c9c3b32933b4235df1e409293b84 upstream. + +The module test script for the adm1021 driver exposes a cache problem +when writing temperature limits. temp_min and temp_max are expected +to be stored in milli-degrees C but are stored in degrees C. + +Reported-by: Guenter Roeck +Signed-off-by: Axel Lin +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hwmon/adm1021.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/hwmon/adm1021.c ++++ b/drivers/hwmon/adm1021.c +@@ -185,7 +185,7 @@ static ssize_t set_temp_max(struct devic + struct adm1021_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + long temp; +- int err; ++ int reg_val, err; + + err = kstrtol(buf, 10, &temp); + if (err) +@@ -193,10 +193,11 @@ static ssize_t set_temp_max(struct devic + temp /= 1000; + + mutex_lock(&data->update_lock); +- data->temp_max[index] = clamp_val(temp, -128, 127); ++ reg_val = clamp_val(temp, -128, 127); ++ data->temp_max[index] = reg_val * 1000; + if (!read_only) + i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index), +- data->temp_max[index]); ++ reg_val); + mutex_unlock(&data->update_lock); + + return count; +@@ -210,7 +211,7 @@ static ssize_t set_temp_min(struct devic + struct adm1021_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + long temp; +- int err; ++ int reg_val, err; + + err = kstrtol(buf, 10, &temp); + if (err) +@@ -218,10 +219,11 @@ static ssize_t set_temp_min(struct devic + temp /= 1000; + + mutex_lock(&data->update_lock); +- data->temp_min[index] = clamp_val(temp, -128, 127); ++ reg_val = clamp_val(temp, -128, 127); ++ data->temp_min[index] = reg_val * 1000; + if (!read_only) + i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index), +- data->temp_min[index]); ++ reg_val); + mutex_unlock(&data->update_lock); + + return count; diff --git a/queue-3.15/hwmon-adm1029-ensure-the-fan_div-cache-is-updated-in-set_fan_div.patch b/queue-3.15/hwmon-adm1029-ensure-the-fan_div-cache-is-updated-in-set_fan_div.patch new file mode 100644 index 00000000000..d4e19f6d98b --- /dev/null +++ b/queue-3.15/hwmon-adm1029-ensure-the-fan_div-cache-is-updated-in-set_fan_div.patch @@ -0,0 +1,36 @@ +From 1035a9e3e9c76b64a860a774f5b867d28d34acc2 Mon Sep 17 00:00:00 2001 +From: Axel Lin +Date: Wed, 2 Jul 2014 08:29:55 +0800 +Subject: hwmon: (adm1029) Ensure the fan_div cache is updated in set_fan_div + +From: Axel Lin + +commit 1035a9e3e9c76b64a860a774f5b867d28d34acc2 upstream. + +Writing to fanX_div does not clear the cache. As a result, reading +from fanX_div may return the old value for up to two seconds +after writing a new value. + +This patch ensures the fan_div cache is updated in set_fan_div(). + +Reported-by: Guenter Roeck +Signed-off-by: Axel Lin +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hwmon/adm1029.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/hwmon/adm1029.c ++++ b/drivers/hwmon/adm1029.c +@@ -232,6 +232,9 @@ static ssize_t set_fan_div(struct device + /* Update the value */ + reg = (reg & 0x3F) | (val << 6); + ++ /* Update the cache */ ++ data->fan_div[attr->index] = reg; ++ + /* Write value */ + i2c_smbus_write_byte_data(client, + ADM1029_REG_FAN_DIV[attr->index], reg); diff --git a/queue-3.15/hwmon-adm1031-fix-writes-to-limit-registers.patch b/queue-3.15/hwmon-adm1031-fix-writes-to-limit-registers.patch new file mode 100644 index 00000000000..116c0000d54 --- /dev/null +++ b/queue-3.15/hwmon-adm1031-fix-writes-to-limit-registers.patch @@ -0,0 +1,75 @@ +From 145e74a4e5022225adb84f4e5d4fff7938475c35 Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Thu, 3 Jul 2014 13:44:23 -0700 +Subject: hwmon: (adm1031) Fix writes to limit registers + +From: Guenter Roeck + +commit 145e74a4e5022225adb84f4e5d4fff7938475c35 upstream. + +Upper limit for write operations to temperature limit registers +was clamped to a fractional value. However, limit registers do +not support fractional values. As a result, upper limits of 127.5 +degrees C or higher resulted in a rounded limit of 128 degrees C. +Since limit registers are signed, this was stored as -128 degrees C. +Clamp limits to (-55, +127) degrees C to solve the problem. + +Value on writes to auto_temp[12]_min and auto_temp[12]_max were not +clamped at all, but masked. As a result, out-of-range writes resulted +in a more or less arbitrary limit. Clamp those attributes to (0, 127) +degrees C for more predictable results. + +Cc: Axel Lin +Reviewed-by: Jean Delvare +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hwmon/adm1031.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/hwmon/adm1031.c ++++ b/drivers/hwmon/adm1031.c +@@ -365,6 +365,7 @@ set_auto_temp_min(struct device *dev, st + if (ret) + return ret; + ++ val = clamp_val(val, 0, 127000); + mutex_lock(&data->update_lock); + data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); + adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), +@@ -394,6 +395,7 @@ set_auto_temp_max(struct device *dev, st + if (ret) + return ret; + ++ val = clamp_val(val, 0, 127000); + mutex_lock(&data->update_lock); + data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], + data->pwm[nr]); +@@ -696,7 +698,7 @@ static ssize_t set_temp_min(struct devic + if (ret) + return ret; + +- val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875); ++ val = clamp_val(val, -55000, 127000); + mutex_lock(&data->update_lock); + data->temp_min[nr] = TEMP_TO_REG(val); + adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr), +@@ -717,7 +719,7 @@ static ssize_t set_temp_max(struct devic + if (ret) + return ret; + +- val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875); ++ val = clamp_val(val, -55000, 127000); + mutex_lock(&data->update_lock); + data->temp_max[nr] = TEMP_TO_REG(val); + adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr), +@@ -738,7 +740,7 @@ static ssize_t set_temp_crit(struct devi + if (ret) + return ret; + +- val = clamp_val(val, -55000, nr == 0 ? 127750 : 127875); ++ val = clamp_val(val, -55000, 127000); + mutex_lock(&data->update_lock); + data->temp_crit[nr] = TEMP_TO_REG(val); + adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr), diff --git a/queue-3.15/hwmon-amc6821-fix-permissions-for-temp2_input.patch b/queue-3.15/hwmon-amc6821-fix-permissions-for-temp2_input.patch new file mode 100644 index 00000000000..0d0f83c09e7 --- /dev/null +++ b/queue-3.15/hwmon-amc6821-fix-permissions-for-temp2_input.patch @@ -0,0 +1,31 @@ +From df86754b746e9a0ff6f863f690b1c01d408e3cdc Mon Sep 17 00:00:00 2001 +From: Axel Lin +Date: Wed, 2 Jul 2014 07:44:44 +0800 +Subject: hwmon: (amc6821) Fix permissions for temp2_input + +From: Axel Lin + +commit df86754b746e9a0ff6f863f690b1c01d408e3cdc upstream. + +temp2_input should not be writable, fix it. + +Reported-by: Guenter Roeck +Signed-off-by: Axel Lin +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hwmon/amc6821.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/hwmon/amc6821.c ++++ b/drivers/hwmon/amc6821.c +@@ -704,7 +704,7 @@ static SENSOR_DEVICE_ATTR(temp1_max_alar + get_temp_alarm, NULL, IDX_TEMP1_MAX); + static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, + get_temp_alarm, NULL, IDX_TEMP1_CRIT); +-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO | S_IWUSR, ++static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, + get_temp, NULL, IDX_TEMP2_INPUT); + static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, get_temp, + set_temp, IDX_TEMP2_MIN); diff --git a/queue-3.15/hwmon-emc2103-clamp-limits-instead-of-bailing-out.patch b/queue-3.15/hwmon-emc2103-clamp-limits-instead-of-bailing-out.patch new file mode 100644 index 00000000000..6979786f5e3 --- /dev/null +++ b/queue-3.15/hwmon-emc2103-clamp-limits-instead-of-bailing-out.patch @@ -0,0 +1,65 @@ +From f6c2dd20108c35e30e2c1f3c6142d189451a626b Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Sun, 6 Jul 2014 11:39:24 -0700 +Subject: hwmon: (emc2103) Clamp limits instead of bailing out + +From: Guenter Roeck + +commit f6c2dd20108c35e30e2c1f3c6142d189451a626b upstream. + +It is customary to clamp limits instead of bailing out with an error +if a configured limit is out of the range supported by the driver. +This simplifies limit configuration, since the user will not typically +know chip and/or driver specific limits. + +Reviewed-by: Jean Delvare +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hwmon/emc2103.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +--- a/drivers/hwmon/emc2103.c ++++ b/drivers/hwmon/emc2103.c +@@ -250,9 +250,7 @@ static ssize_t set_temp_min(struct devic + if (result < 0) + return result; + +- val = DIV_ROUND_CLOSEST(val, 1000); +- if ((val < -63) || (val > 127)) +- return -EINVAL; ++ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127); + + mutex_lock(&data->update_lock); + data->temp_min[nr] = val; +@@ -274,9 +272,7 @@ static ssize_t set_temp_max(struct devic + if (result < 0) + return result; + +- val = DIV_ROUND_CLOSEST(val, 1000); +- if ((val < -63) || (val > 127)) +- return -EINVAL; ++ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127); + + mutex_lock(&data->update_lock); + data->temp_max[nr] = val; +@@ -390,15 +386,14 @@ static ssize_t set_fan_target(struct dev + { + struct emc2103_data *data = emc2103_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); +- long rpm_target; ++ unsigned long rpm_target; + +- int result = kstrtol(buf, 10, &rpm_target); ++ int result = kstrtoul(buf, 10, &rpm_target); + if (result < 0) + return result; + + /* Datasheet states 16384 as maximum RPM target (table 3.2) */ +- if ((rpm_target < 0) || (rpm_target > 16384)) +- return -EINVAL; ++ rpm_target = clamp_val(rpm_target, 0, 16384); + + mutex_lock(&data->update_lock); + diff --git a/queue-3.15/powerpc-kvm-remove-redundant-save-of-sier-and-mmcr2.patch b/queue-3.15/powerpc-kvm-remove-redundant-save-of-sier-and-mmcr2.patch new file mode 100644 index 00000000000..5fea752b5a2 --- /dev/null +++ b/queue-3.15/powerpc-kvm-remove-redundant-save-of-sier-and-mmcr2.patch @@ -0,0 +1,44 @@ +From f73128f4f680e8be68cda831f2710214559583cb Mon Sep 17 00:00:00 2001 +From: Joel Stanley +Date: Tue, 8 Jul 2014 16:08:20 +0930 +Subject: powerpc/kvm: Remove redundant save of SIER AND MMCR2 + +From: Joel Stanley + +commit f73128f4f680e8be68cda831f2710214559583cb upstream. + +These two registers are already saved in the block above. Aside from +being unnecessary, by the time we get down to the second save location +r8 no longer contains MMCR2, so we are clobbering the saved value with +PMC5. + +MMCR2 primarily consists of counter freeze bits. So restoring the value +of PMC5 into MMCR2 will most likely have the effect of freezing +counters. + +Fixes: 72cde5a88d37 ("KVM: PPC: Book3S HV: Save/restore host PMU registers that are new in POWER8") +Signed-off-by: Joel Stanley +Acked-by: Michael Ellerman +Acked-by: Paul Mackerras +Reviewed-by: Alexander Graf +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Greg Kroah-Hartman + +--- + arch/powerpc/kvm/book3s_hv_interrupts.S | 5 ----- + 1 file changed, 5 deletions(-) + +--- a/arch/powerpc/kvm/book3s_hv_interrupts.S ++++ b/arch/powerpc/kvm/book3s_hv_interrupts.S +@@ -127,11 +127,6 @@ BEGIN_FTR_SECTION + stw r10, HSTATE_PMC + 24(r13) + stw r11, HSTATE_PMC + 28(r13) + END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) +-BEGIN_FTR_SECTION +- mfspr r9, SPRN_SIER +- std r8, HSTATE_MMCR + 40(r13) +- std r9, HSTATE_MMCR + 48(r13) +-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) + 31: + + /* diff --git a/queue-3.15/powerpc-perf-add-ppmu_arch_207s-define.patch b/queue-3.15/powerpc-perf-add-ppmu_arch_207s-define.patch new file mode 100644 index 00000000000..01660d7e72d --- /dev/null +++ b/queue-3.15/powerpc-perf-add-ppmu_arch_207s-define.patch @@ -0,0 +1,77 @@ +From 4d9690dd56b0d18f2af8a9d4a279cb205aae3345 Mon Sep 17 00:00:00 2001 +From: Joel Stanley +Date: Tue, 8 Jul 2014 16:08:21 +0930 +Subject: powerpc/perf: Add PPMU_ARCH_207S define + +From: Joel Stanley + +commit 4d9690dd56b0d18f2af8a9d4a279cb205aae3345 upstream. + +Instead of separate bits for every POWER8 PMU feature, have a single one +for v2.07 of the architecture. + +This saves us adding a MMCR2 define for a future patch. + +Signed-off-by: Joel Stanley +Acked-by: Michael Ellerman +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Greg Kroah-Hartman + +--- + arch/powerpc/include/asm/perf_event_server.h | 3 +-- + arch/powerpc/perf/core-book3s.c | 6 +++--- + arch/powerpc/perf/power8-pmu.c | 2 +- + 3 files changed, 5 insertions(+), 6 deletions(-) + +--- a/arch/powerpc/include/asm/perf_event_server.h ++++ b/arch/powerpc/include/asm/perf_event_server.h +@@ -61,8 +61,7 @@ struct power_pmu { + #define PPMU_SIAR_VALID 0x00000010 /* Processor has SIAR Valid bit */ + #define PPMU_HAS_SSLOT 0x00000020 /* Has sampled slot in MMCRA */ + #define PPMU_HAS_SIER 0x00000040 /* Has SIER */ +-#define PPMU_BHRB 0x00000080 /* has BHRB feature enabled */ +-#define PPMU_EBB 0x00000100 /* supports event based branch */ ++#define PPMU_ARCH_207S 0x00000080 /* PMC is architecture v2.07S */ + + /* + * Values for flags to get_alternatives() +--- a/arch/powerpc/perf/core-book3s.c ++++ b/arch/powerpc/perf/core-book3s.c +@@ -485,7 +485,7 @@ static bool is_ebb_event(struct perf_eve + * check that the PMU supports EBB, meaning those that don't can still + * use bit 63 of the event code for something else if they wish. + */ +- return (ppmu->flags & PPMU_EBB) && ++ return (ppmu->flags & PPMU_ARCH_207S) && + ((event->attr.config >> PERF_EVENT_CONFIG_EBB_SHIFT) & 1); + } + +@@ -777,7 +777,7 @@ void perf_event_print_debug(void) + if (ppmu->flags & PPMU_HAS_SIER) + sier = mfspr(SPRN_SIER); + +- if (ppmu->flags & PPMU_EBB) { ++ if (ppmu->flags & PPMU_ARCH_207S) { + pr_info("MMCR2: %016lx EBBHR: %016lx\n", + mfspr(SPRN_MMCR2), mfspr(SPRN_EBBHR)); + pr_info("EBBRR: %016lx BESCR: %016lx\n", +@@ -1711,7 +1711,7 @@ static int power_pmu_event_init(struct p + + if (has_branch_stack(event)) { + /* PMU has BHRB enabled */ +- if (!(ppmu->flags & PPMU_BHRB)) ++ if (!(ppmu->flags & PPMU_ARCH_207S)) + return -EOPNOTSUPP; + } + +--- a/arch/powerpc/perf/power8-pmu.c ++++ b/arch/powerpc/perf/power8-pmu.c +@@ -792,7 +792,7 @@ static struct power_pmu power8_pmu = { + .get_constraint = power8_get_constraint, + .get_alternatives = power8_get_alternatives, + .disable_pmc = power8_disable_pmc, +- .flags = PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_BHRB | PPMU_EBB, ++ .flags = PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_ARCH_207S, + .n_generic = ARRAY_SIZE(power8_generic_events), + .generic_events = power8_generic_events, + .cache_events = &power8_cache_events, diff --git a/queue-3.15/powerpc-perf-clear-mmcr2-when-enabling-pmu.patch b/queue-3.15/powerpc-perf-clear-mmcr2-when-enabling-pmu.patch new file mode 100644 index 00000000000..8cff03152c1 --- /dev/null +++ b/queue-3.15/powerpc-perf-clear-mmcr2-when-enabling-pmu.patch @@ -0,0 +1,74 @@ +From b50a6c584bb47b370f84bfd746770c0bbe7129b7 Mon Sep 17 00:00:00 2001 +From: Joel Stanley +Date: Tue, 8 Jul 2014 16:08:22 +0930 +Subject: powerpc/perf: Clear MMCR2 when enabling PMU + +From: Joel Stanley + +commit b50a6c584bb47b370f84bfd746770c0bbe7129b7 upstream. + +On POWER8 when switching to a KVM guest we set bits in MMCR2 to freeze +the PMU counters. Aside from on boot they are then never reset, +resulting in stuck perf counters for any user in the guest or host. + +We now set MMCR2 to 0 whenever enabling the PMU, which provides a sane +state for perf to use the PMU counters under either the guest or the +host. + +This was manifesting as a bug with ppc64_cpu --frequency: + + $ sudo ppc64_cpu --frequency + WARNING: couldn't run on cpu 0 + WARNING: couldn't run on cpu 8 + ... + WARNING: couldn't run on cpu 144 + WARNING: couldn't run on cpu 152 + min: 18446744073.710 GHz (cpu -1) + max: 0.000 GHz (cpu -1) + avg: 0.000 GHz + +The command uses a perf counter to measure CPU cycles over a fixed +amount of time, in order to approximate the frequency of the machine. +The counters were returning zero once a guest was started, regardless of +weather it was still running or had been shut down. + +By dumping the value of MMCR2, it was observed that once a guest is +running MMCR2 is set to 1s - which stops counters from running: + + $ sudo sh -c 'echo p > /proc/sysrq-trigger' + CPU: 0 PMU registers, ppmu = POWER8 n_counters = 6 + PMC1: 5b635e38 PMC2: 00000000 PMC3: 00000000 PMC4: 00000000 + PMC5: 1bf5a646 PMC6: 5793d378 PMC7: deadbeef PMC8: deadbeef + MMCR0: 0000000080000000 MMCR1: 000000001e000000 MMCRA: 0000040000000000 + MMCR2: fffffffffffffc00 EBBHR: 0000000000000000 + EBBRR: 0000000000000000 BESCR: 0000000000000000 + SIAR: 00000000000a51cc SDAR: c00000000fc40000 SIER: 0000000001000000 + +This is done unconditionally in book3s_hv_interrupts.S upon entering the +guest, and the original value is only save/restored if the host has +indicated it was using the PMU. This is okay, however the user of the +PMU needs to ensure that it is in a defined state when it starts using +it. + +Fixes: e05b9b9e5c10 ("powerpc/perf: Power8 PMU support") +Signed-off-by: Joel Stanley +Acked-by: Michael Ellerman +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Greg Kroah-Hartman + +--- + arch/powerpc/perf/core-book3s.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/powerpc/perf/core-book3s.c ++++ b/arch/powerpc/perf/core-book3s.c +@@ -1315,6 +1315,9 @@ static void power_pmu_enable(struct pmu + + write_mmcr0(cpuhw, mmcr0); + ++ if (ppmu->flags & PPMU_ARCH_207S) ++ mtspr(SPRN_MMCR2, 0); ++ + /* + * Enable instruction sampling if necessary + */ diff --git a/queue-3.15/powerpc-perf-never-program-book3s-pmcs-with-values-0x80000000.patch b/queue-3.15/powerpc-perf-never-program-book3s-pmcs-with-values-0x80000000.patch new file mode 100644 index 00000000000..6408d48a526 --- /dev/null +++ b/queue-3.15/powerpc-perf-never-program-book3s-pmcs-with-values-0x80000000.patch @@ -0,0 +1,57 @@ +From f56029410a13cae3652d1f34788045c40a13ffc7 Mon Sep 17 00:00:00 2001 +From: Anton Blanchard +Date: Thu, 29 May 2014 08:15:38 +1000 +Subject: powerpc/perf: Never program book3s PMCs with values >= 0x80000000 + +From: Anton Blanchard + +commit f56029410a13cae3652d1f34788045c40a13ffc7 upstream. + +We are seeing a lot of PMU warnings on POWER8: + + Can't find PMC that caused IRQ + +Looking closer, the active PMC is 0 at this point and we took a PMU +exception on the transition from negative to 0. Some versions of POWER8 +have an issue where they edge detect and not level detect PMC overflows. + +A number of places program the PMC with (0x80000000 - period_left), +where period_left can be negative. We can either fix all of these or +just ensure that period_left is always >= 1. + +This patch takes the second option. + +Signed-off-by: Anton Blanchard +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Greg Kroah-Hartman + +--- + arch/powerpc/perf/core-book3s.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +--- a/arch/powerpc/perf/core-book3s.c ++++ b/arch/powerpc/perf/core-book3s.c +@@ -996,7 +996,22 @@ static void power_pmu_read(struct perf_e + } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev); + + local64_add(delta, &event->count); +- local64_sub(delta, &event->hw.period_left); ++ ++ /* ++ * A number of places program the PMC with (0x80000000 - period_left). ++ * We never want period_left to be less than 1 because we will program ++ * the PMC with a value >= 0x800000000 and an edge detected PMC will ++ * roll around to 0 before taking an exception. We have seen this ++ * on POWER8. ++ * ++ * To fix this, clamp the minimum value of period_left to 1. ++ */ ++ do { ++ prev = local64_read(&event->hw.period_left); ++ val = prev - delta; ++ if (val < 1) ++ val = 1; ++ } while (local64_cmpxchg(&event->hw.period_left, prev, val) != prev); + } + + /* diff --git a/queue-3.15/revert-acpi-ac-remove-ac-s-proc-directory.patch b/queue-3.15/revert-acpi-ac-remove-ac-s-proc-directory.patch new file mode 100644 index 00000000000..55f7960d06b --- /dev/null +++ b/queue-3.15/revert-acpi-ac-remove-ac-s-proc-directory.patch @@ -0,0 +1,228 @@ +From e63f6e28dda6de3de2392ddca321e211fd860925 Mon Sep 17 00:00:00 2001 +From: Lan Tianyu +Date: Mon, 7 Jul 2014 01:13:46 +0200 +Subject: Revert "ACPI / AC: Remove AC's proc directory." + +From: Lan Tianyu + +commit e63f6e28dda6de3de2392ddca321e211fd860925 upstream. + +Revert commit ab0fd674d6ce (ACPI / AC: Remove AC's proc directory.), +because some old tools (e.g. kpowersave from kde 3.5.10) are still +using /proc/acpi/ac_adapter. + +Fixes: ab0fd674d6ce (ACPI / AC: Remove AC's proc directory.) +Reported-and-tested-by: Sorin Manolache +Signed-off-by: Lan Tianyu +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/ac.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 128 insertions(+), 2 deletions(-) + +--- a/drivers/acpi/ac.c ++++ b/drivers/acpi/ac.c +@@ -30,6 +30,10 @@ + #include + #include + #include ++#ifdef CONFIG_ACPI_PROCFS_POWER ++#include ++#include ++#endif + #include + #include + #include +@@ -52,6 +56,7 @@ MODULE_AUTHOR("Paul Diefenbaugh"); + MODULE_DESCRIPTION("ACPI AC Adapter Driver"); + MODULE_LICENSE("GPL"); + ++ + static int acpi_ac_add(struct acpi_device *device); + static int acpi_ac_remove(struct acpi_device *device); + static void acpi_ac_notify(struct acpi_device *device, u32 event); +@@ -67,6 +72,13 @@ static int acpi_ac_resume(struct device + #endif + static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume); + ++#ifdef CONFIG_ACPI_PROCFS_POWER ++extern struct proc_dir_entry *acpi_lock_ac_dir(void); ++extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir); ++static int acpi_ac_open_fs(struct inode *inode, struct file *file); ++#endif ++ ++ + static int ac_sleep_before_get_state_ms; + + static struct acpi_driver acpi_ac_driver = { +@@ -91,6 +103,16 @@ struct acpi_ac { + + #define to_acpi_ac(x) container_of(x, struct acpi_ac, charger) + ++#ifdef CONFIG_ACPI_PROCFS_POWER ++static const struct file_operations acpi_ac_fops = { ++ .owner = THIS_MODULE, ++ .open = acpi_ac_open_fs, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++#endif ++ + /* -------------------------------------------------------------------------- + AC Adapter Management + -------------------------------------------------------------------------- */ +@@ -143,6 +165,83 @@ static enum power_supply_property ac_pro + POWER_SUPPLY_PROP_ONLINE, + }; + ++#ifdef CONFIG_ACPI_PROCFS_POWER ++/* -------------------------------------------------------------------------- ++ FS Interface (/proc) ++ -------------------------------------------------------------------------- */ ++ ++static struct proc_dir_entry *acpi_ac_dir; ++ ++static int acpi_ac_seq_show(struct seq_file *seq, void *offset) ++{ ++ struct acpi_ac *ac = seq->private; ++ ++ ++ if (!ac) ++ return 0; ++ ++ if (acpi_ac_get_state(ac)) { ++ seq_puts(seq, "ERROR: Unable to read AC Adapter state\n"); ++ return 0; ++ } ++ ++ seq_puts(seq, "state: "); ++ switch (ac->state) { ++ case ACPI_AC_STATUS_OFFLINE: ++ seq_puts(seq, "off-line\n"); ++ break; ++ case ACPI_AC_STATUS_ONLINE: ++ seq_puts(seq, "on-line\n"); ++ break; ++ default: ++ seq_puts(seq, "unknown\n"); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int acpi_ac_open_fs(struct inode *inode, struct file *file) ++{ ++ return single_open(file, acpi_ac_seq_show, PDE_DATA(inode)); ++} ++ ++static int acpi_ac_add_fs(struct acpi_ac *ac) ++{ ++ struct proc_dir_entry *entry = NULL; ++ ++ printk(KERN_WARNING PREFIX "Deprecated procfs I/F for AC is loaded," ++ " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n"); ++ if (!acpi_device_dir(ac->device)) { ++ acpi_device_dir(ac->device) = ++ proc_mkdir(acpi_device_bid(ac->device), acpi_ac_dir); ++ if (!acpi_device_dir(ac->device)) ++ return -ENODEV; ++ } ++ ++ /* 'state' [R] */ ++ entry = proc_create_data(ACPI_AC_FILE_STATE, ++ S_IRUGO, acpi_device_dir(ac->device), ++ &acpi_ac_fops, ac); ++ if (!entry) ++ return -ENODEV; ++ return 0; ++} ++ ++static int acpi_ac_remove_fs(struct acpi_ac *ac) ++{ ++ ++ if (acpi_device_dir(ac->device)) { ++ remove_proc_entry(ACPI_AC_FILE_STATE, ++ acpi_device_dir(ac->device)); ++ remove_proc_entry(acpi_device_bid(ac->device), acpi_ac_dir); ++ acpi_device_dir(ac->device) = NULL; ++ } ++ ++ return 0; ++} ++#endif ++ + /* -------------------------------------------------------------------------- + Driver Model + -------------------------------------------------------------------------- */ +@@ -243,6 +342,11 @@ static int acpi_ac_add(struct acpi_devic + goto end; + + ac->charger.name = acpi_device_bid(device); ++#ifdef CONFIG_ACPI_PROCFS_POWER ++ result = acpi_ac_add_fs(ac); ++ if (result) ++ goto end; ++#endif + ac->charger.type = POWER_SUPPLY_TYPE_MAINS; + ac->charger.properties = ac_props; + ac->charger.num_properties = ARRAY_SIZE(ac_props); +@@ -258,8 +362,12 @@ static int acpi_ac_add(struct acpi_devic + ac->battery_nb.notifier_call = acpi_ac_battery_notify; + register_acpi_notifier(&ac->battery_nb); + end: +- if (result) ++ if (result) { ++#ifdef CONFIG_ACPI_PROCFS_POWER ++ acpi_ac_remove_fs(ac); ++#endif + kfree(ac); ++ } + + dmi_check_system(ac_dmi_table); + return result; +@@ -303,6 +411,10 @@ static int acpi_ac_remove(struct acpi_de + power_supply_unregister(&ac->charger); + unregister_acpi_notifier(&ac->battery_nb); + ++#ifdef CONFIG_ACPI_PROCFS_POWER ++ acpi_ac_remove_fs(ac); ++#endif ++ + kfree(ac); + + return 0; +@@ -315,9 +427,20 @@ static int __init acpi_ac_init(void) + if (acpi_disabled) + return -ENODEV; + ++#ifdef CONFIG_ACPI_PROCFS_POWER ++ acpi_ac_dir = acpi_lock_ac_dir(); ++ if (!acpi_ac_dir) ++ return -ENODEV; ++#endif ++ ++ + result = acpi_bus_register_driver(&acpi_ac_driver); +- if (result < 0) ++ if (result < 0) { ++#ifdef CONFIG_ACPI_PROCFS_POWER ++ acpi_unlock_ac_dir(acpi_ac_dir); ++#endif + return -ENODEV; ++ } + + return 0; + } +@@ -325,6 +448,9 @@ static int __init acpi_ac_init(void) + static void __exit acpi_ac_exit(void) + { + acpi_bus_unregister_driver(&acpi_ac_driver); ++#ifdef CONFIG_ACPI_PROCFS_POWER ++ acpi_unlock_ac_dir(acpi_ac_dir); ++#endif + } + module_init(acpi_ac_init); + module_exit(acpi_ac_exit); diff --git a/queue-3.15/series b/queue-3.15/series index a1405459e7f..28775fc2b50 100644 --- a/queue-3.15/series +++ b/queue-3.15/series @@ -12,3 +12,20 @@ workqueue-zero-cpumask-of-wq_numa_possible_cpumask-on-init.patch ahci-imx-manage-only-sata_ref_clk-in-imx_sata_enable.patch i8k-fix-non-smp-operation.patch serial-imx-fix-build-breakage.patch +thermal-hwmon-make-the-check-for-critical-temp-valid-consistent.patch +hwmon-adc128d818-drop-write-support-on-inx_input-attributes.patch +hwmon-amc6821-fix-permissions-for-temp2_input.patch +hwmon-emc2103-clamp-limits-instead-of-bailing-out.patch +hwmon-adm1031-fix-writes-to-limit-registers.patch +hwmon-adm1029-ensure-the-fan_div-cache-is-updated-in-set_fan_div.patch +hwmon-adm1021-fix-cache-problem-when-writing-temperature-limits.patch +revert-acpi-ac-remove-ac-s-proc-directory.patch +acpi-resources-only-reject-zero-length-resources-based-at-address-zero.patch +acpi-ec-avoid-race-condition-related-to-advance_transaction.patch +acpi-ec-add-asynchronous-command-byte-write-support.patch +acpi-ec-remove-duplicated-ec_wait_ibf0-waiter.patch +acpi-ec-fix-race-condition-in-ec_transaction_completed.patch +powerpc-kvm-remove-redundant-save-of-sier-and-mmcr2.patch +powerpc-perf-never-program-book3s-pmcs-with-values-0x80000000.patch +powerpc-perf-add-ppmu_arch_207s-define.patch +powerpc-perf-clear-mmcr2-when-enabling-pmu.patch diff --git a/queue-3.15/thermal-hwmon-make-the-check-for-critical-temp-valid-consistent.patch b/queue-3.15/thermal-hwmon-make-the-check-for-critical-temp-valid-consistent.patch new file mode 100644 index 00000000000..219669d271b --- /dev/null +++ b/queue-3.15/thermal-hwmon-make-the-check-for-critical-temp-valid-consistent.patch @@ -0,0 +1,97 @@ +From e8db5d6736a712a3e2280c0e31f4b301d85172d8 Mon Sep 17 00:00:00 2001 +From: Aaron Lu +Date: Wed, 21 May 2014 16:33:27 +0800 +Subject: thermal: hwmon: Make the check for critical temp valid consistent + +From: Aaron Lu + +commit e8db5d6736a712a3e2280c0e31f4b301d85172d8 upstream. + +On 05/21/2014 04:22 PM, Aaron Lu wrote: +> On 05/21/2014 01:57 PM, Kui Zhang wrote: +>> Hello, +>> +>> I get following error when rmmod thermal. +>> +>> rmmod thermal +>> Killed + +While dealing with this problem, I found another problem that also +results in a kernel crash on thermal module removal: + +From: Aaron Lu +Date: Wed, 21 May 2014 16:05:38 +0800 +Subject: thermal: hwmon: Make the check for critical temp valid consistent + +We used the tz->ops->get_crit_temp && !tz->ops->get_crit_temp(tz, temp) +to decide if we need to create the temp_crit attribute file but we just +check if tz->ops->get_crit_temp exists to decide if we need to remove +that attribute file. Some ACPI thermal zone doesn't have a valid critical +trip point and that would result in removing a non-existent device file +on thermal module unload. + +Signed-off-by: Aaron Lu +Signed-off-by: Zhang Rui +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/thermal/thermal_hwmon.c | 33 ++++++++++++++++++--------------- + 1 file changed, 18 insertions(+), 15 deletions(-) + +--- a/drivers/thermal/thermal_hwmon.c ++++ b/drivers/thermal/thermal_hwmon.c +@@ -140,6 +140,12 @@ thermal_hwmon_lookup_temp(const struct t + return NULL; + } + ++static bool thermal_zone_crit_temp_valid(struct thermal_zone_device *tz) ++{ ++ unsigned long temp; ++ return tz->ops->get_crit_temp && !tz->ops->get_crit_temp(tz, &temp); ++} ++ + int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) + { + struct thermal_hwmon_device *hwmon; +@@ -189,21 +195,18 @@ int thermal_add_hwmon_sysfs(struct therm + if (result) + goto free_temp_mem; + +- if (tz->ops->get_crit_temp) { +- unsigned long temperature; +- if (!tz->ops->get_crit_temp(tz, &temperature)) { +- snprintf(temp->temp_crit.name, +- sizeof(temp->temp_crit.name), ++ if (thermal_zone_crit_temp_valid(tz)) { ++ snprintf(temp->temp_crit.name, ++ sizeof(temp->temp_crit.name), + "temp%d_crit", hwmon->count); +- temp->temp_crit.attr.attr.name = temp->temp_crit.name; +- temp->temp_crit.attr.attr.mode = 0444; +- temp->temp_crit.attr.show = temp_crit_show; +- sysfs_attr_init(&temp->temp_crit.attr.attr); +- result = device_create_file(hwmon->device, +- &temp->temp_crit.attr); +- if (result) +- goto unregister_input; +- } ++ temp->temp_crit.attr.attr.name = temp->temp_crit.name; ++ temp->temp_crit.attr.attr.mode = 0444; ++ temp->temp_crit.attr.show = temp_crit_show; ++ sysfs_attr_init(&temp->temp_crit.attr.attr); ++ result = device_create_file(hwmon->device, ++ &temp->temp_crit.attr); ++ if (result) ++ goto unregister_input; + } + + mutex_lock(&thermal_hwmon_list_lock); +@@ -250,7 +253,7 @@ void thermal_remove_hwmon_sysfs(struct t + } + + device_remove_file(hwmon->device, &temp->temp_input.attr); +- if (tz->ops->get_crit_temp) ++ if (thermal_zone_crit_temp_valid(tz)) + device_remove_file(hwmon->device, &temp->temp_crit.attr); + + mutex_lock(&thermal_hwmon_list_lock); -- 2.47.3