1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2022 Oxide Computer Company
14 */
15
16 #include "payload_common.h"
17 #include "payload_utils.h"
18 #include "test_defs.h"
19
20 #define LAPIC_OFF_SVR 0xf0
21 #define LAPIC_OFF_TIMER_ICR 0x380
22 #define LAPIC_OFF_TIMER_CCR 0x390
23 #define LAPIC_OFF_TIMER_DCR 0x3e0
24
25
26 #define LAPIC_SVR_ENABLE 0x100
27
28 static void
write_vlapic(uint_t reg,uint32_t value)29 write_vlapic(uint_t reg, uint32_t value)
30 {
31 volatile uint32_t *ptr = (uint32_t *)(MMIO_LAPIC_BASE + reg);
32 *ptr = value;
33 }
34
35 static uint32_t
read_vlapic(uint_t reg)36 read_vlapic(uint_t reg)
37 {
38 volatile uint32_t *ptr = (uint32_t *)(MMIO_LAPIC_BASE + reg);
39 return (*ptr);
40 }
41
42 static uint32_t
divisor_to_dcr(uint32_t inp)43 divisor_to_dcr(uint32_t inp)
44 {
45 switch (inp) {
46 case 1:
47 return (0xb);
48 case 2:
49 return (0x0);
50 case 4:
51 return (0x1);
52 case 8:
53 return (0x2);
54 case 16:
55 return (0x3);
56 case 32:
57 return (0x8);
58 case 64:
59 return (0x9);
60 case 128:
61 return (0xa);
62 default:
63 /* fail immediate if divisor is out of range */
64 outl(IOP_TEST_VALUE, 1);
65 return (0xff);
66 }
67 }
68
69
70 void
start(void)71 start(void)
72 {
73 write_vlapic(LAPIC_OFF_SVR, LAPIC_SVR_ENABLE);
74
75 /* loop for as long as the host wants */
76 for (;;) {
77 uint32_t divisor;
78 uint32_t start, end;
79
80 divisor = inl(IOP_TEST_PARAM);
81 write_vlapic(LAPIC_OFF_TIMER_DCR, divisor_to_dcr(divisor));
82 write_vlapic(LAPIC_OFF_TIMER_ICR, 0xffffffff);
83
84 start = read_vlapic(LAPIC_OFF_TIMER_CCR);
85 outl(IOP_TEST_VALUE, start);
86
87 uint32_t target = start - LAPIC_TARGET_TICKS;
88 do {
89 end = read_vlapic(LAPIC_OFF_TIMER_CCR);
90 /* wait for enough ticks to pass */
91 } while (end > target);
92 outl(IOP_TEST_VALUE, end);
93 }
94 }
95