summaryrefslogtreecommitdiff
path: root/sys/dev/ic/pckbc.c
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2010-08-05 13:50:01 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2010-08-05 13:50:01 +0000
commit6515c10928cfbae6717c63eb18acb6f25211f018 (patch)
tree6638f98f4ebc27a0a7630c817b2e60a4ca2dc73b /sys/dev/ic/pckbc.c
parent86df2b0fcdc2ab7d6dba8b49aa56e3a0d6ef3ae4 (diff)
Change the management of commands in the active commands TAILQ to let issuers
of synchronous commands perform the TAILQ_REMOVE of the command themselves, instead of relying upon this being done for us if tsleep() returns zero. Since we momentarily set `cold' again around suspend, tsleep() becomes a no-op, which broke this assumption, and in turn caused TAILQ corruption, with items being put on the freelist while still on the active list. Found the hard way by ray@ playing with wsmoused after resume.
Diffstat (limited to 'sys/dev/ic/pckbc.c')
-rw-r--r--sys/dev/ic/pckbc.c27
1 files changed, 16 insertions, 11 deletions
diff --git a/sys/dev/ic/pckbc.c b/sys/dev/ic/pckbc.c
index 710ff9138e0..e83c3fc8158 100644
--- a/sys/dev/ic/pckbc.c
+++ b/sys/dev/ic/pckbc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pckbc.c,v 1.23 2010/07/22 14:27:44 deraadt Exp $ */
+/* $OpenBSD: pckbc.c,v 1.24 2010/08/05 13:50:00 miod Exp $ */
/* $NetBSD: pckbc.c,v 1.5 2000/06/09 04:58:35 soda Exp $ */
/*
@@ -69,7 +69,7 @@ struct pckbc_slotdata {
struct pckbc_devcmd cmds[NCMD];
};
-#define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL)
+#define CMD_IN_QUEUE(q) (!TAILQ_EMPTY(&(q)->cmdqueue))
void pckbc_init_slotdata(struct pckbc_slotdata *);
int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t);
@@ -796,14 +796,15 @@ pckbc_start(t, slot)
if (cmd->status)
printf("pckbc_start: command error\n");
- TAILQ_REMOVE(&q->cmdqueue, cmd, next);
- if (cmd->flags & KBC_CMDFLAG_SYNC)
+ if (cmd->flags & KBC_CMDFLAG_SYNC) {
wakeup(cmd);
- else {
+ cmd = TAILQ_NEXT(cmd, next);
+ } else {
+ TAILQ_REMOVE(&q->cmdqueue, cmd, next);
timeout_del(&t->t_cleanup);
TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
+ cmd = TAILQ_FIRST(&q->cmdqueue);
}
- cmd = TAILQ_FIRST(&q->cmdqueue);
} while (cmd);
return;
}
@@ -863,14 +864,16 @@ pckbc_cmdresponse(t, slot, data)
return (0);
/* dequeue: */
- TAILQ_REMOVE(&q->cmdqueue, cmd, next);
- if (cmd->flags & KBC_CMDFLAG_SYNC)
+ if (cmd->flags & KBC_CMDFLAG_SYNC) {
wakeup(cmd);
- else {
+ cmd = TAILQ_NEXT(cmd, next);
+ } else {
+ TAILQ_REMOVE(&q->cmdqueue, cmd, next);
timeout_del(&t->t_cleanup);
TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
+ cmd = TAILQ_FIRST(&q->cmdqueue);
}
- if (!CMD_IN_QUEUE(q))
+ if (cmd == NULL)
return (1);
restart:
pckbc_start(t, slot);
@@ -932,8 +935,10 @@ pckbc_enqueue_cmd(self, slot, cmd, len, responselen, sync, respbuf)
if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) {
TAILQ_REMOVE(&q->cmdqueue, nc, next);
pckbc_cleanup(t);
- } else
+ } else {
+ TAILQ_REMOVE(&q->cmdqueue, nc, next);
res = nc->status;
+ }
} else
timeout_add_sec(&t->t_cleanup, 1);