perf: Report maximum values for counter overflow
[akaros.git] / kern / arch / x86 / devarch.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 #include <ros/memops.h>
11 #include <vfs.h>
12 #include <kmalloc.h>
13 #include <kref.h>
14 #include <kthread.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <assert.h>
18 #include <err.h>
19 #include <pmap.h>
20 #include <umem.h>
21 #include <smp.h>
22 #include <ip.h>
23 #include <time.h>
24 #include <bitops.h>
25 #include <core_set.h>
26 #include <address_range.h>
27 #include <arch/ros/perfmon.h>
28 #include <arch/topology.h>
29 #include <arch/perfmon.h>
30 #include <arch/ros/msr-index.h>
31 #include <arch/msr.h>
32 #include <arch/devarch.h>
33
34 #define REAL_MEM_SIZE (1024 * 1024)
35
36 struct perf_context {
37         struct perfmon_session *ps;
38         qlock_t resp_lock;
39         size_t resp_size;
40         uint8_t *resp;
41 };
42
43 struct io_map {
44         struct io_map *next;
45         int reserved;
46         char tag[13];
47         uint32_t start;
48         uint32_t end;
49 };
50
51 static struct {
52         spinlock_t lock;
53         struct io_map *map;
54         struct io_map *free;
55         struct io_map maps[32];                         // some initial free maps
56         qlock_t ql;                                     // lock for reading map
57 } iomap;
58
59 enum {
60         Qdir = 0,
61         Qioalloc = 1,
62         Qiob,
63         Qiow,
64         Qiol,
65         Qgdb,
66         Qrealmem,
67         Qmsr,
68         Qperf,
69
70         Qmax,
71 };
72
73 enum {
74         Linelen = 31,
75 };
76
77 struct dev archdevtab;
78 static struct dirtab archdir[Qmax] = {
79         {".", {Qdir, 0, QTDIR}, 0, 0555},
80         {"ioalloc", {Qioalloc, 0}, 0, 0444},
81         {"iob", {Qiob, 0}, 0, 0666},
82         {"iow", {Qiow, 0}, 0, 0666},
83         {"iol", {Qiol, 0}, 0, 0666},
84         {"gdb", {Qgdb, 0}, 0, 0660},
85         {"realmem", {Qrealmem, 0}, 0, 0444},
86         {"msr", {Qmsr, 0}, 0, 0666},
87         {"perf", {Qperf, 0}, 0, 0666},
88 };
89 /* White list entries needs to be ordered by start address, and never overlap.
90  */
91 #define MSR_MAX_VAR_COUNTERS 16
92 #define MSR_MAX_FIX_COUNTERS 4
93
94 static struct address_range msr_rd_wlist[] = {
95         ADDRESS_RANGE(0x00000000, 0xffffffff),
96 };
97 static struct address_range msr_wr_wlist[] = {
98         ADDRESS_RANGE(MSR_IA32_PERFCTR0,
99                                   MSR_IA32_PERFCTR0 + MSR_MAX_VAR_COUNTERS - 1),
100         ADDRESS_RANGE(MSR_ARCH_PERFMON_EVENTSEL0,
101                                   MSR_ARCH_PERFMON_EVENTSEL0 + MSR_MAX_VAR_COUNTERS - 1),
102         ADDRESS_RANGE(MSR_IA32_PERF_CTL, MSR_IA32_PERF_CTL),
103         ADDRESS_RANGE(MSR_CORE_PERF_FIXED_CTR0,
104                                   MSR_CORE_PERF_FIXED_CTR0 + MSR_MAX_FIX_COUNTERS - 1),
105         ADDRESS_RANGE(MSR_CORE_PERF_FIXED_CTR_CTRL, MSR_CORE_PERF_GLOBAL_OVF_CTRL),
106 };
107 int gdbactive = 0;
108
109 //
110 //  alloc some io port space and remember who it was
111 //  alloced to.  if port < 0, find a free region.
112 //
113 int ioalloc(int port, int size, int align, char *tag)
114 {
115         struct io_map *map, **l;
116         int i;
117
118         spin_lock(&(&iomap)->lock);
119         if (port < 0) {
120                 // find a free port above 0x400 and below 0x1000
121                 port = 0x400;
122                 for (l = &iomap.map; *l; l = &(*l)->next) {
123                         map = *l;
124                         if (map->start < 0x400)
125                                 continue;
126                         i = map->start - port;
127                         if (i > size)
128                                 break;
129                         if (align > 0)
130                                 port = ((port + align - 1) / align) * align;
131                         else
132                                 port = map->end;
133                 }
134                 if (*l == NULL) {
135                         spin_unlock(&(&iomap)->lock);
136                         return -1;
137                 }
138         } else {
139                 // Only 64KB I/O space on the x86.
140                 if ((port + size) > 0x10000) {
141                         spin_unlock(&(&iomap)->lock);
142                         return -1;
143                 }
144                 // see if the space clashes with previously allocated ports
145                 for (l = &iomap.map; *l; l = &(*l)->next) {
146                         map = *l;
147                         if (map->end <= port)
148                                 continue;
149                         if (map->reserved && map->start == port && map->end == port + size) {
150                                 map->reserved = 0;
151                                 spin_unlock(&(&iomap)->lock);
152                                 return map->start;
153                         }
154                         if (map->start >= port + size)
155                                 break;
156                         spin_unlock(&(&iomap)->lock);
157                         return -1;
158                 }
159         }
160         map = iomap.free;
161         if (map == NULL) {
162                 printd("ioalloc: out of maps");
163                 spin_unlock(&(&iomap)->lock);
164                 return port;
165         }
166         iomap.free = map->next;
167         map->next = *l;
168         map->start = port;
169         map->end = port + size;
170         strlcpy(map->tag, tag, sizeof(map->tag));
171         *l = map;
172
173         archdir[0].qid.vers++;
174
175         spin_unlock(&(&iomap)->lock);
176         return map->start;
177 }
178
179 void iofree(int port)
180 {
181         struct io_map *map, **l;
182
183         spin_lock(&(&iomap)->lock);
184         for (l = &iomap.map; *l; l = &(*l)->next) {
185                 if ((*l)->start == port) {
186                         map = *l;
187                         *l = map->next;
188                         map->next = iomap.free;
189                         iomap.free = map;
190                         break;
191                 }
192                 if ((*l)->start > port)
193                         break;
194         }
195         archdir[0].qid.vers++;
196         spin_unlock(&(&iomap)->lock);
197 }
198
199 int iounused(int start, int end)
200 {
201         struct io_map *map;
202
203         for (map = iomap.map; map; map = map->next) {
204                 if (((start >= map->start) && (start < map->end)) ||
205                     ((start <= map->start) && (end > map->start)))
206                         return 0;
207         }
208         return 1;
209 }
210
211 void ioinit(void)
212 {
213         int i;
214         char *excluded = "";
215
216         panic("Akaros doesn't do IO port allocation yet.  Don't init.");
217         for (i = 0; i < ARRAY_SIZE(iomap.maps) - 1; i++)
218                 iomap.maps[i].next = &iomap.maps[i + 1];
219         iomap.maps[i].next = NULL;
220         iomap.free = iomap.maps;
221         char *s;
222
223         s = excluded;
224         while (s && *s != '\0' && *s != '\n') {
225                 char *ends;
226                 int io_s, io_e;
227
228                 io_s = (int)strtol(s, &ends, 0);
229                 if (ends == NULL || ends == s || *ends != '-') {
230                         printd("ioinit: cannot parse option string\n");
231                         break;
232                 }
233                 s = ++ends;
234
235                 io_e = (int)strtol(s, &ends, 0);
236                 if (ends && *ends == ',')
237                         *ends++ = '\0';
238                 s = ends;
239
240                 ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated");
241         }
242 }
243
244 // Reserve a range to be ioalloced later.
245 // This is in particular useful for exchangable cards, such
246 // as pcmcia and cardbus cards.
247 int ioreserve(int unused_int, int size, int align, char *tag)
248 {
249         struct io_map *map, **l;
250         int i, port;
251
252         spin_lock(&(&iomap)->lock);
253         // find a free port above 0x400 and below 0x1000
254         port = 0x400;
255         for (l = &iomap.map; *l; l = &(*l)->next) {
256                 map = *l;
257                 if (map->start < 0x400)
258                         continue;
259                 i = map->start - port;
260                 if (i > size)
261                         break;
262                 if (align > 0)
263                         port = ((port + align - 1) / align) * align;
264                 else
265                         port = map->end;
266         }
267         if (*l == NULL) {
268                 spin_unlock(&(&iomap)->lock);
269                 return -1;
270         }
271         map = iomap.free;
272         if (map == NULL) {
273                 printd("ioalloc: out of maps");
274                 spin_unlock(&(&iomap)->lock);
275                 return port;
276         }
277         iomap.free = map->next;
278         map->next = *l;
279         map->start = port;
280         map->end = port + size;
281         map->reserved = 1;
282         strlcpy(map->tag, tag, sizeof(map->tag));
283         *l = map;
284
285         archdir[0].qid.vers++;
286
287         spin_unlock(&(&iomap)->lock);
288         return map->start;
289 }
290
291 static void checkport(int start, int end)
292 {
293         /* standard vga regs are OK */
294         if (start >= 0x2b0 && end <= 0x2df + 1)
295                 return;
296         if (start >= 0x3c0 && end <= 0x3da + 1)
297                 return;
298
299         if (iounused(start, end))
300                 return;
301         error(EPERM, ERROR_FIXME);
302 }
303
304 static struct chan *archattach(char *spec)
305 {
306         return devattach(archdevtab.name, spec);
307 }
308
309 struct walkqid *archwalk(struct chan *c, struct chan *nc, char **name,
310                                                  int nname)
311 {
312         return devwalk(c, nc, name, nname, archdir, Qmax, devgen);
313 }
314
315 static int archstat(struct chan *c, uint8_t * dp, int n)
316 {
317         archdir[Qrealmem].length = REAL_MEM_SIZE;
318
319         return devstat(c, dp, n, archdir, Qmax, devgen);
320 }
321
322 static struct perf_context *arch_create_perf_context(void)
323 {
324         ERRSTACK(1);
325         struct perf_context *pc = kzmalloc(sizeof(struct perf_context),
326                                            MEM_WAIT);
327
328         if (waserror()) {
329                 kfree(pc);
330                 nexterror();
331         }
332         qlock_init(&pc->resp_lock);
333         pc->ps = perfmon_create_session();
334         poperror();
335
336         return pc;
337 }
338
339 /* Called after the last reference (FD / chan) to pc is closed. */
340 static void arch_free_perf_context(struct perf_context *pc)
341 {
342         perfmon_close_session(pc->ps);
343         kfree(pc->resp);
344         kfree(pc);
345 }
346
347 static const uint8_t *arch_read_core_set(struct core_set *cset,
348                                          const uint8_t *kptr,
349                                          const uint8_t *ktop)
350 {
351         int i, nb;
352         uint32_t n;
353
354         error_assert(EBADMSG, (kptr + sizeof(uint32_t)) <= ktop);
355         kptr = get_le_u32(kptr, &n);
356         error_assert(EBADMSG, (kptr + n) <= ktop);
357         core_set_init(cset);
358         nb = MIN((int) n * 8, num_cores);
359         for (i = 0; i < nb; i++) {
360                 if (test_bit(i, (const unsigned long *) kptr))
361                         core_set_setcpu(cset, i);
362         }
363
364         return kptr + n;
365 }
366
367 static long arch_perf_write(struct perf_context *pc, const void *udata,
368                             long usize)
369 {
370         ERRSTACK(1);
371         void *kdata;
372         const uint8_t *kptr, *ktop;
373
374         kdata = user_memdup_errno(current, udata, usize);
375         if (unlikely(!kdata))
376                 return -1;
377         qlock(&pc->resp_lock);
378         if (waserror()) {
379                 qunlock(&pc->resp_lock);
380                 kfree(kdata);
381                 nexterror();
382         }
383         /* Fresh command, reset the response buffer */
384         kfree(pc->resp);
385         pc->resp = NULL;
386         pc->resp_size = 0;
387
388         kptr = kdata;
389         ktop = kptr + usize;
390         error_assert(EBADMSG, (kptr + 1) <= ktop);
391         switch (*kptr++) {
392                 case PERFMON_CMD_COUNTER_OPEN: {
393                         int ped;
394                         struct perfmon_event pev;
395                         struct core_set cset;
396
397                         error_assert(EBADMSG, (kptr + 3 * sizeof(uint64_t)) <= ktop);
398                         perfmon_init_event(&pev);
399                         kptr = get_le_u64(kptr, &pev.event);
400                         kptr = get_le_u64(kptr, &pev.flags);
401                         kptr = get_le_u64(kptr, &pev.trigger_count);
402                         kptr = get_le_u64(kptr, &pev.user_data);
403                         kptr = arch_read_core_set(&cset, kptr, ktop);
404
405                         ped = perfmon_open_event(&cset, pc->ps, &pev);
406
407                         pc->resp_size = sizeof(uint32_t);
408                         pc->resp = kmalloc(pc->resp_size, MEM_WAIT);
409                         put_le_u32(pc->resp, (uint32_t) ped);
410                         break;
411                 }
412                 case PERFMON_CMD_COUNTER_STATUS: {
413                         uint32_t ped;
414                         uint8_t *rptr;
415                         struct perfmon_status *pef;
416
417                         error_assert(EBADMSG, (kptr + sizeof(uint32_t)) <= ktop);
418                         kptr = get_le_u32(kptr, &ped);
419
420                         pef = perfmon_get_event_status(pc->ps, (int) ped);
421
422                         pc->resp_size = sizeof(uint32_t) + num_cores * sizeof(uint64_t);
423                         pc->resp = kmalloc(pc->resp_size, MEM_WAIT);
424                         rptr = put_le_u32(pc->resp, num_cores);
425                         for (int i = 0; i < num_cores; i++)
426                                 rptr = put_le_u64(rptr, pef->cores_values[i]);
427
428                         perfmon_free_event_status(pef);
429                         break;
430                 }
431                 case PERFMON_CMD_COUNTER_CLOSE: {
432                         uint32_t ped;
433
434                         error_assert(EBADMSG, (kptr + sizeof(uint32_t)) <= ktop);
435                         kptr = get_le_u32(kptr, &ped);
436
437                         perfmon_close_event(pc->ps, (int) ped);
438                         break;
439                 }
440                 case PERFMON_CMD_CPU_CAPS: {
441                         uint8_t *rptr;
442                         struct perfmon_cpu_caps pcc;
443
444                         kptr++;
445                         perfmon_get_cpu_caps(&pcc);
446
447                         pc->resp_size = 6 * sizeof(uint32_t);
448                         pc->resp = kmalloc(pc->resp_size, MEM_WAIT);
449
450                         rptr = put_le_u32(pc->resp, pcc.perfmon_version);
451                         rptr = put_le_u32(rptr, pcc.proc_arch_events);
452                         rptr = put_le_u32(rptr, pcc.bits_x_counter);
453                         rptr = put_le_u32(rptr, pcc.counters_x_proc);
454                         rptr = put_le_u32(rptr, pcc.bits_x_fix_counter);
455                         rptr = put_le_u32(rptr, pcc.fix_counters_x_proc);
456                         break;
457                 }
458                 default:
459                         error(EINVAL, "Invalid perfmon command: 0x%x", kptr[-1]);
460         }
461         poperror();
462         qunlock(&pc->resp_lock);
463         kfree(kdata);
464
465         return (long) (kptr - (const uint8_t *) kdata);
466 }
467
468 static struct chan *archopen(struct chan *c, int omode)
469 {
470         c = devopen(c, omode, archdir, Qmax, devgen);
471         switch ((uint32_t) c->qid.path) {
472                 case Qperf:
473                         if (!perfmon_supported())
474                                 error(ENODEV, "perf is not supported");
475                         assert(!c->aux);
476                         c->aux = arch_create_perf_context();
477                         break;
478         }
479
480         return c;
481 }
482
483 static void archclose(struct chan *c)
484 {
485         switch ((uint32_t) c->qid.path) {
486                 case Qperf:
487                         if (c->aux) {
488                                 arch_free_perf_context((struct perf_context *) c->aux);
489                                 c->aux = NULL;
490                         }
491                         break;
492         }
493 }
494
495 static long archread(struct chan *c, void *a, long n, int64_t offset)
496 {
497         char *buf, *p;
498         int err, port;
499         uint64_t *values;
500         uint16_t *sp;
501         uint32_t *lp;
502         struct io_map *map;
503         struct core_set cset;
504         struct msr_address msra;
505         struct msr_value msrv;
506
507         switch ((uint32_t) c->qid.path) {
508                 case Qdir:
509                         return devdirread(c, a, n, archdir, Qmax, devgen);
510                 case Qgdb:
511                         p = gdbactive ? "1" : "0";
512                         return readstr(offset, a, n, p);
513                 case Qiob:
514                         port = offset;
515                         checkport(offset, offset + n);
516                         for (p = a; port < offset + n; port++)
517                                 *p++ = inb(port);
518                         return n;
519                 case Qiow:
520                         if (n & 1)
521                                 error(EINVAL, ERROR_FIXME);
522                         checkport(offset, offset + n);
523                         sp = a;
524                         for (port = offset; port < offset + n; port += 2)
525                                 *sp++ = inw(port);
526                         return n;
527                 case Qiol:
528                         if (n & 3)
529                                 error(EINVAL, ERROR_FIXME);
530                         checkport(offset, offset + n);
531                         lp = a;
532                         for (port = offset; port < offset + n; port += 4)
533                                 *lp++ = inl(port);
534                         return n;
535                 case Qioalloc:
536                         break;
537                 case Qrealmem:
538                         return readmem(offset, a, n, KADDR(0), REAL_MEM_SIZE);
539                 case Qmsr:
540                         if (!address_range_find(msr_rd_wlist, ARRAY_SIZE(msr_rd_wlist),
541                                                 (uintptr_t) offset))
542                                 error(EPERM, "MSR 0x%x not in read whitelist", offset);
543                         core_set_init(&cset);
544                         core_set_fill_available(&cset);
545                         msr_set_address(&msra, (uint32_t) offset);
546                         values = kzmalloc(num_cores * sizeof(uint64_t),
547                                           MEM_WAIT);
548                         if (!values)
549                                 error(ENOMEM, ERROR_FIXME);
550                         msr_set_values(&msrv, values, num_cores);
551
552                         err = msr_cores_read(&cset, &msra, &msrv);
553
554                         if (likely(!err)) {
555                                 if (n >= num_cores * sizeof(uint64_t)) {
556                                         if (!memcpy_to_user_errno(current, a, values,
557                                                                   num_cores * sizeof(uint64_t)))
558                                                 n = num_cores * sizeof(uint64_t);
559                                         else
560                                                 n = -1;
561                                 } else {
562                                         kfree(values);
563                                         error(ERANGE, "Not enough space for MSR read");
564                                 }
565                         } else {
566                                 switch (-err) {
567                                 case (EFAULT):
568                                         error(-err, "read_msr() faulted on MSR 0x%x", offset);
569                                 case (ERANGE):
570                                         error(-err, "Not enough space for MSR read");
571                                 };
572                                 error(-err, "MSR read failed");
573                         }
574                         kfree(values);
575                         return n;
576                 case Qperf: {
577                         struct perf_context *pc = (struct perf_context *) c->aux;
578
579                         assert(pc);
580                         qlock(&pc->resp_lock);
581                         if (pc->resp && ((size_t) offset < pc->resp_size)) {
582                                 n = MIN(n, (long) pc->resp_size - (long) offset);
583                                 if (memcpy_to_user_errno(current, a, pc->resp + offset, n))
584                                         n = -1;
585                         } else {
586                                 n = 0;
587                         }
588                         qunlock(&pc->resp_lock);
589
590                         return n;
591                 }
592                 default:
593                         error(EINVAL, ERROR_FIXME);
594         }
595
596         if ((buf = kzmalloc(n, 0)) == NULL)
597                 error(ENOMEM, ERROR_FIXME);
598         p = buf;
599         n = n / Linelen;
600         offset = offset / Linelen;
601
602         switch ((uint32_t) c->qid.path) {
603                 case Qioalloc:
604                         spin_lock(&(&iomap)->lock);
605                         for (map = iomap.map; n > 0 && map != NULL; map = map->next) {
606                                 if (offset-- > 0)
607                                         continue;
608                                 snprintf(p, n * Linelen, "%#8p %#8p %-12.12s\n", map->start,
609                                          map->end - 1, map->tag);
610                                 p += Linelen;
611                                 n--;
612                         }
613                         spin_unlock(&(&iomap)->lock);
614                         break;
615         }
616
617         n = p - buf;
618         memmove(a, buf, n);
619         kfree(buf);
620
621         return n;
622 }
623
624 static long archwrite(struct chan *c, void *a, long n, int64_t offset)
625 {
626         char *p;
627         int port, err;
628         uint64_t value;
629         uint16_t *sp;
630         uint32_t *lp;
631         struct core_set cset;
632         struct msr_address msra;
633         struct msr_value msrv;
634
635         switch ((uint32_t) c->qid.path) {
636                 case Qgdb:
637                         p = a;
638                         if (n != 1)
639                                 error(EINVAL, "Gdb: Write one byte, '1' or '0'");
640                         if (*p == '1')
641                                 gdbactive = 1;
642                         else if (*p == '0')
643                                 gdbactive = 0;
644                         else
645                                 error(EINVAL, "Gdb: must be 1 or 0");
646                         return 1;
647                 case Qiob:
648                         p = a;
649                         checkport(offset, offset + n);
650                         for (port = offset; port < offset + n; port++)
651                                 outb(port, *p++);
652                         return n;
653                 case Qiow:
654                         if (n & 1)
655                                 error(EINVAL, ERROR_FIXME);
656                         checkport(offset, offset + n);
657                         sp = a;
658                         for (port = offset; port < offset + n; port += 2)
659                                 outw(port, *sp++);
660                         return n;
661                 case Qiol:
662                         if (n & 3)
663                                 error(EINVAL, ERROR_FIXME);
664                         checkport(offset, offset + n);
665                         lp = a;
666                         for (port = offset; port < offset + n; port += 4)
667                                 outl(port, *lp++);
668                         return n;
669                 case Qmsr:
670                         if (!address_range_find(msr_wr_wlist, ARRAY_SIZE(msr_wr_wlist),
671                                                 (uintptr_t) offset))
672                                 error(EPERM, "MSR 0x%x not in write whitelist", offset);
673                         if (n != sizeof(uint64_t))
674                                 error(EINVAL, "Tried to write more than a u64 (%p)", n);
675                         if (memcpy_from_user_errno(current, &value, a, sizeof(value)))
676                                 return -1;
677
678                         core_set_init(&cset);
679                         core_set_fill_available(&cset);
680                         msr_set_address(&msra, (uint32_t) offset);
681                         msr_set_value(&msrv, value);
682
683                         err = msr_cores_write(&cset, &msra, &msrv);
684                         if (unlikely(err)) {
685                                 switch (-err) {
686                                 case (EFAULT):
687                                         error(-err, "write_msr() faulted on MSR 0x%x", offset);
688                                 case (ERANGE):
689                                         error(-err, "Not enough space for MSR write");
690                                 };
691                                 error(-err, "MSR write failed");
692                         }
693                         return sizeof(uint64_t);
694                 case Qperf: {
695                         struct perf_context *pc = (struct perf_context *) c->aux;
696
697                         assert(pc);
698
699                         return arch_perf_write(pc, a, n);
700                 }
701                 default:
702                         error(EINVAL, ERROR_FIXME);
703         }
704         return 0;
705 }
706
707 static void archinit(void)
708 {
709         int ret;
710
711         ret = address_range_init(msr_rd_wlist, ARRAY_SIZE(msr_rd_wlist));
712         assert(!ret);
713         ret = address_range_init(msr_wr_wlist, ARRAY_SIZE(msr_wr_wlist));
714         assert(!ret);
715 }
716
717 struct dev archdevtab __devtab = {
718         .name = "arch",
719
720         .reset = devreset,
721         .init = archinit,
722         .shutdown = devshutdown,
723         .attach = archattach,
724         .walk = archwalk,
725         .stat = archstat,
726         .open = archopen,
727         .create = devcreate,
728         .close = archclose,
729         .read = archread,
730         .bread = devbread,
731         .write = archwrite,
732         .bwrite = devbwrite,
733         .remove = devremove,
734         .wstat = devwstat,
735 };
736
737 void archreset(void)
738 {
739         int i;
740
741         /*
742          * And sometimes there is no keyboard...
743          *
744          * The reset register (0xcf9) is usually in one of the bridge
745          * chips. The actual location and sequence could be extracted from
746          * ACPI but why bother, this is the end of the line anyway.
747          print("Takes a licking and keeps on ticking...\n");
748          */
749         i = inb(0xcf9); /* ICHx reset control */
750         i &= 0x06;
751         outb(0xcf9, i | 0x02);  /* SYS_RST */
752         udelay(1000);
753         outb(0xcf9, i | 0x06);  /* RST_CPU transition */
754
755         udelay(100 * 1000);
756
757         /* some broken hardware -- as well as qemu -- might
758          * never reboot anyway with cf9. This is a standard
759          * keyboard reboot sequence known to work on really
760          * broken stuff -- like qemu. If there is no
761          * keyboard it will do no harm.
762          */
763         for (;;) {
764                 (void)inb(0x64);
765                 outb(0x64, 0xFE);
766                 udelay(100 * 1000);
767         }
768 }