Tue Jul 18 10:04:50 2023 UTC ()
acpiec(4): Fix cv_timedwait abuse in acpiec_read/write.


(riastradh)
diff -r1.94 -r1.95 src/sys/dev/acpi/acpi_ec.c

cvs diff -r1.94 -r1.95 src/sys/dev/acpi/acpi_ec.c (expand / switch to unified diff)

--- src/sys/dev/acpi/acpi_ec.c 2023/07/18 10:04:40 1.94
+++ src/sys/dev/acpi/acpi_ec.c 2023/07/18 10:04:50 1.95
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: acpi_ec.c,v 1.94 2023/07/18 10:04:40 riastradh Exp $ */ 1/* $NetBSD: acpi_ec.c,v 1.95 2023/07/18 10:04:50 riastradh Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>. 4 * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 10 *
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in 14 * notice, this list of conditions and the following disclaimer in
@@ -47,27 +47,27 @@ @@ -47,27 +47,27 @@
47 * working and the handlers just busy loop. 47 * working and the handlers just busy loop.
48 * 48 *
49 * A callout is scheduled to compensate for missing interrupts on some 49 * A callout is scheduled to compensate for missing interrupts on some
50 * hardware. If the EC doesn't process a request for 5s, it is most likely 50 * hardware. If the EC doesn't process a request for 5s, it is most likely
51 * in a wedged state. No method to reset the EC is currently known. 51 * in a wedged state. No method to reset the EC is currently known.
52 * 52 *
53 * Special care has to be taken to not poll the EC in a busy loop without 53 * Special care has to be taken to not poll the EC in a busy loop without
54 * delay. This can prevent processing of Power Button events. At least some 54 * delay. This can prevent processing of Power Button events. At least some
55 * Lenovo Thinkpads seem to be implement the Power Button Override in the EC 55 * Lenovo Thinkpads seem to be implement the Power Button Override in the EC
56 * and the only option to recover on those models is to cut off all power. 56 * and the only option to recover on those models is to cut off all power.
57 */ 57 */
58 58
59#include <sys/cdefs.h> 59#include <sys/cdefs.h>
60__KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.94 2023/07/18 10:04:40 riastradh Exp $"); 60__KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.95 2023/07/18 10:04:50 riastradh Exp $");
61 61
62#ifdef _KERNEL_OPT 62#ifdef _KERNEL_OPT
63#include "opt_acpi_ec.h" 63#include "opt_acpi_ec.h"
64#endif 64#endif
65 65
66#include <sys/param.h> 66#include <sys/param.h>
67#include <sys/callout.h> 67#include <sys/callout.h>
68#include <sys/condvar.h> 68#include <sys/condvar.h>
69#include <sys/device.h> 69#include <sys/device.h>
70#include <sys/kernel.h> 70#include <sys/kernel.h>
71#include <sys/kthread.h> 71#include <sys/kthread.h>
72#include <sys/mutex.h> 72#include <sys/mutex.h>
73#include <sys/systm.h> 73#include <sys/systm.h>
@@ -685,37 +685,41 @@ acpiec_read(device_t dv, uint8_t addr, u @@ -685,37 +685,41 @@ acpiec_read(device_t dv, uint8_t addr, u
685 685
686 if (cold || acpiec_cold) { 686 if (cold || acpiec_cold) {
687 while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) { 687 while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) {
688 delay(1000); 688 delay(1000);
689 acpiec_gpe_state_machine(dv); 689 acpiec_gpe_state_machine(dv);
690 } 690 }
691 if (sc->sc_state != EC_STATE_FREE) { 691 if (sc->sc_state != EC_STATE_FREE) {
692 mutex_exit(&sc->sc_mtx); 692 mutex_exit(&sc->sc_mtx);
693 acpiec_unlock(dv); 693 acpiec_unlock(dv);
694 aprint_error_dev(dv, "command timed out, state %d\n", 694 aprint_error_dev(dv, "command timed out, state %d\n",
695 sc->sc_state); 695 sc->sc_state);
696 return AE_ERROR; 696 return AE_ERROR;
697 } 697 }
698 } else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) { 698 } else {
699 /* 699 const unsigned deadline = getticks() + EC_CMD_TIMEOUT*hz;
700 * XXX while (sc->sc_state != EC_STATE_FREE) 700 unsigned delta;
701 * cv_timedwait(...), 701
702 * plus deadline 702 while (sc->sc_state != EC_STATE_FREE &&
703 */ 703 (delta = deadline - getticks()) < INT_MAX)
704 mutex_exit(&sc->sc_mtx); 704 (void)cv_timedwait(&sc->sc_cv, &sc->sc_mtx, delta);
705 acpiec_unlock(dv); 705 if (sc->sc_state != EC_STATE_FREE) {
706 aprint_error_dev(dv, 706 mutex_exit(&sc->sc_mtx);
707 "command takes over %d sec...\n", EC_CMD_TIMEOUT); 707 acpiec_unlock(dv);
708 return AE_ERROR; 708 aprint_error_dev(dv,
 709 "command takes over %d sec...\n",
 710 EC_CMD_TIMEOUT);
 711 return AE_ERROR;
 712 }
709 } 713 }
710 714
711done: 715done:
712 DPRINTF(ACPIEC_DEBUG_RW, sc, 716 DPRINTF(ACPIEC_DEBUG_RW, sc,
713 "pid %ld %s, lid %ld%s%s: read addr 0x%"PRIx8": 0x%"PRIx8"\n", 717 "pid %ld %s, lid %ld%s%s: read addr 0x%"PRIx8": 0x%"PRIx8"\n",
714 (long)curproc->p_pid, curproc->p_comm, 718 (long)curproc->p_pid, curproc->p_comm,
715 (long)curlwp->l_lid, curlwp->l_name ? " " : "", 719 (long)curlwp->l_lid, curlwp->l_name ? " " : "",
716 curlwp->l_name ? curlwp->l_name : "", 720 curlwp->l_name ? curlwp->l_name : "",
717 addr, sc->sc_cur_val); 721 addr, sc->sc_cur_val);
718 722
719 *val = sc->sc_cur_val; 723 *val = sc->sc_cur_val;
720 724
721 mutex_exit(&sc->sc_mtx); 725 mutex_exit(&sc->sc_mtx);
@@ -754,37 +758,41 @@ acpiec_write(device_t dv, uint8_t addr,  @@ -754,37 +758,41 @@ acpiec_write(device_t dv, uint8_t addr,
754 758
755 if (cold || acpiec_cold) { 759 if (cold || acpiec_cold) {
756 while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) { 760 while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) {
757 delay(1000); 761 delay(1000);
758 acpiec_gpe_state_machine(dv); 762 acpiec_gpe_state_machine(dv);
759 } 763 }
760 if (sc->sc_state != EC_STATE_FREE) { 764 if (sc->sc_state != EC_STATE_FREE) {
761 mutex_exit(&sc->sc_mtx); 765 mutex_exit(&sc->sc_mtx);
762 acpiec_unlock(dv); 766 acpiec_unlock(dv);
763 aprint_error_dev(dv, "command timed out, state %d\n", 767 aprint_error_dev(dv, "command timed out, state %d\n",
764 sc->sc_state); 768 sc->sc_state);
765 return AE_ERROR; 769 return AE_ERROR;
766 } 770 }
767 } else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) { 771 } else {
768 /* 772 const unsigned deadline = getticks() + EC_CMD_TIMEOUT*hz;
769 * XXX while (sc->sc_state != EC_STATE_FREE) 773 unsigned delta;
770 * cv_timedwait(...), 774
771 * plus deadline 775 while (sc->sc_state != EC_STATE_FREE &&
772 */ 776 (delta = deadline - getticks()) < INT_MAX)
773 mutex_exit(&sc->sc_mtx); 777 (void)cv_timedwait(&sc->sc_cv, &sc->sc_mtx, delta);
774 acpiec_unlock(dv); 778 if (sc->sc_state != EC_STATE_FREE) {
775 aprint_error_dev(dv, 779 mutex_exit(&sc->sc_mtx);
776 "command takes over %d sec...\n", EC_CMD_TIMEOUT); 780 acpiec_unlock(dv);
777 return AE_ERROR; 781 aprint_error_dev(dv,
 782 "command takes over %d sec...\n",
 783 EC_CMD_TIMEOUT);
 784 return AE_ERROR;
 785 }
778 } 786 }
779 787
780done: 788done:
781 DPRINTF(ACPIEC_DEBUG_RW, sc, 789 DPRINTF(ACPIEC_DEBUG_RW, sc,
782 "pid %ld %s, lid %ld%s%s: write addr 0x%"PRIx8": 0x%"PRIx8 790 "pid %ld %s, lid %ld%s%s: write addr 0x%"PRIx8": 0x%"PRIx8
783 " done\n", 791 " done\n",
784 (long)curproc->p_pid, curproc->p_comm, 792 (long)curproc->p_pid, curproc->p_comm,
785 (long)curlwp->l_lid, curlwp->l_name ? " " : "", 793 (long)curlwp->l_lid, curlwp->l_name ? " " : "",
786 curlwp->l_name ? curlwp->l_name : "", 794 curlwp->l_name ? curlwp->l_name : "",
787 addr, val); 795 addr, val);
788 796
789 mutex_exit(&sc->sc_mtx); 797 mutex_exit(&sc->sc_mtx);
790 acpiec_unlock(dv); 798 acpiec_unlock(dv);