zephyr.c 6.92 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// © 2021 Raptor Engineering, LLC
//
// Released under the terms of the GPL v3
// See the LICENSE file for full details

#include <logging/log.h>
LOG_MODULE_REGISTER(kestrel_init, LOG_LEVEL_DBG);

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <zephyr.h>
13 14
#include <device.h>
#include <drivers/gpio.h>
15 16 17 18

#define WITH_ZEPHYR 1

#include "webservice.h"
19
#include "flash_filesystem.h"
20
#include "sbe_fsi.h"
21 22
#include "kestrel.h"

23 24 25
static struct gpio_callback host_power_button_callback_data;
static struct gpio_callback host_reset_button_callback_data;

26 27 28 29 30 31 32 33
#define KESTREL_INIT_THREAD_PRIORITY		K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1)
static K_THREAD_STACK_DEFINE(kestrel_init_thread_stack, 16384);
static struct k_thread kestrel_init_thread_data;
static struct k_sem kestrel_init_thread_lock;

static K_THREAD_STACK_DEFINE(kestrel_service_thread_stack, 16384);
static struct k_thread kestrel_service_thread_data;

34 35 36
static K_THREAD_STACK_DEFINE(thermal_service_thread_stack, 16384);
static struct k_thread thermal_service_thread_data;

37 38
#define KESTREL_IDLE_THREAD_PRIORITY		K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1)

39 40
#define BUTTON_PRESS_DEBOUNCE_DELAY_MS	200

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
static void kestrel_init_thread(void)
{
	kestrel_init();
	k_sem_give(&kestrel_init_thread_lock);
}

static void kestrel_service_thread(void)
{
	while (1) {
		if (host_background_service_task_active || host_console_service_task_requested) {
			k_thread_priority_set(k_current_get(), KESTREL_IDLE_THREAD_PRIORITY);
			if (primary_service_event_loop() == -EAGAIN) {
			    k_thread_priority_set(k_current_get(), KESTREL_SERVICE_THREAD_PRIORITY);
			}
			else {
			    k_thread_priority_set(k_current_get(), KESTREL_IDLE_THREAD_PRIORITY);
			    k_yield();
			}
		}
		else {
			k_thread_priority_set(k_current_get(), KESTREL_IDLE_THREAD_PRIORITY);
			k_yield();
		}
	}
}

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
static void thermal_service_thread(void)
{
	uint8_t response_data[IBM_POWER9_SBE_OCC_RESPONSE_SIZE];
	size_t response_length = 0;

	while (1) {
		if (host_power_status == HOST_POWER_STATUS_RUNNING)
		{
			if (k_mutex_lock(&occ_access_mutex, K_MSEC(1000)) != 0) {
				printk("Unable to acquire OCC mutex in a timely manner! %s:%d\n", __FILE__, __LINE__);
				continue;
			}

			if (occ_poll(0, 0x2400, IBM_POWER9_SBE_OCC_RESPONSE_SIZE, response_data, &response_length))
			{
				// Unable to read sensors
				host_cpu_temperature_sensor_count = 0;
			}

			k_mutex_unlock(&occ_access_mutex);

			k_usleep(100000);
		}
		else
		{
			host_cpu_temperature_sensor_count = 0;
			k_usleep(100000);
		}
	}
}

98 99
void host_power_button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
100 101
	static uint64_t last_press = 0;

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
	int want_power_on = 0;
	int want_power_off = 0;

	LOG_INF("Host power button pressed");

	// Deactivate interrupts on entering critical section
	int key = irq_lock();

	if (host_power_status == HOST_POWER_STATUS_OFFLINE) {
		want_power_on = 1;
	}
	else {
		want_power_off = 1;
	}

	// Re-activate interupts on exiting critical section
	irq_unlock(key);

120 121 122 123 124 125 126 127
	if ((k_uptime_get() - last_press) > BUTTON_PRESS_DEBOUNCE_DELAY_MS) {
		// The debounce delay has passed since last press, handle request
		if (want_power_on) {
			power_on_host();
		}
		else if (want_power_off) {
			power_off_chassis();
		}
128
	}
129 130

	last_press = k_uptime_get();
131 132 133 134
}

void host_reset_button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
135 136
	static uint64_t last_press = 0;

137 138 139 140 141 142 143 144 145
	// Deactivate interrupts on entering critical section
	int key = irq_lock();

	// FIXME
	// Implement host reset functionality

	// Re-activate interupts on exiting critical section
	irq_unlock(key);

146 147 148 149 150 151
	if ((k_uptime_get() - last_press) > BUTTON_PRESS_DEBOUNCE_DELAY_MS) {
		// The debounce delay has passed since last press, handle request
		LOG_WRN("[FIXME] Reset button pressed, but not implemented!");
	}

	last_press = k_uptime_get();
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
}

static int configure_gpios(void)
{
	const struct device *button;
	int retcode;
	int ret;

	retcode = 0;

	// Set up power button
	button = device_get_binding(KESTREL_HOST_POWER_BUTTON_GPIO);
	if (button == NULL) {
		printk("[ERROR] Unable to locate host power button on node %s\n", KESTREL_HOST_POWER_BUTTON_GPIO);
		retcode = -1;
	}
	else {
		ret = gpio_pin_interrupt_configure(button, KESTREL_HOST_POWER_BUTTON_PIN, GPIO_INT_EDGE_TO_ACTIVE);
		if (ret != 0) {
			printk("[ERROR] failed to configure interrupt on %s pin %d (returned %d)\n", KESTREL_HOST_POWER_BUTTON_GPIO, KESTREL_HOST_POWER_BUTTON_PIN, ret);
			retcode = -1;
		}
		else {
			gpio_init_callback(&host_power_button_callback_data, host_power_button_pressed, BIT(KESTREL_HOST_POWER_BUTTON_PIN));
			gpio_add_callback(button, &host_power_button_callback_data);
		}
	}

	// Set up reset button
	button = device_get_binding(KESTREL_HOST_RESET_BUTTON_GPIO);
	if (button == NULL) {
		printk("[ERROR] Unable to locate host reset button on node %s\n", KESTREL_HOST_RESET_BUTTON_GPIO);
		retcode = -1;
	}
	else {
		ret = gpio_pin_interrupt_configure(button, KESTREL_HOST_RESET_BUTTON_PIN, GPIO_INT_EDGE_TO_ACTIVE);
		if (ret != 0) {
			printk("[ERROR] failed to configure interrupt on %s pin %d (returned %d)\n", KESTREL_HOST_RESET_BUTTON_GPIO, KESTREL_HOST_RESET_BUTTON_PIN, ret);
			retcode = -1;
		}
		else {
			gpio_init_callback(&host_reset_button_callback_data, host_reset_button_pressed, BIT(KESTREL_HOST_RESET_BUTTON_PIN));
			gpio_add_callback(button, &host_reset_button_callback_data);
		}
	}

	return retcode;
}

201 202 203 204 205 206 207 208 209 210 211 212
void main(void)
{
	// Set root command and prompt for all shells
	Z_STRUCT_SECTION_FOREACH(shell, sh) {
		shell_prompt_change(sh, "FSP0>");
	}
	shell_set_root_cmd("kestrel");

	k_tid_t kestrel_init_thread_id;

	k_sem_init(&kestrel_init_thread_lock, 0, UINT_MAX);

213 214 215
	// Run early setup
	initialize_flash_filesystem();

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	// Kick off Kestrel initialization thread
	kestrel_init_thread_id = k_thread_create(&kestrel_init_thread_data, kestrel_init_thread_stack,
			K_THREAD_STACK_SIZEOF(kestrel_init_thread_stack),
			(k_thread_entry_t)kestrel_init_thread,
			NULL, NULL, NULL, KESTREL_INIT_THREAD_PRIORITY, 0, K_NO_WAIT);
	k_thread_name_set(kestrel_init_thread_id, "sys_init");

	// Start background services
	start_webservice();

	// Wait for Kestrel initialization to finish
	k_sem_take(&kestrel_init_thread_lock, K_FOREVER);

	kestrel_service_thread_id = k_thread_create(&kestrel_service_thread_data, kestrel_service_thread_stack,
			K_THREAD_STACK_SIZEOF(kestrel_service_thread_stack),
			(k_thread_entry_t)kestrel_service_thread,
			NULL, NULL, NULL, KESTREL_SERVICE_THREAD_PRIORITY, 0, K_NO_WAIT);
	k_thread_name_set(kestrel_service_thread_id, "kestrel_service");

235 236 237 238 239 240
	thermal_service_thread_id = k_thread_create(&thermal_service_thread_data, thermal_service_thread_stack,
			K_THREAD_STACK_SIZEOF(thermal_service_thread_stack),
			(k_thread_entry_t)thermal_service_thread,
			NULL, NULL, NULL, KESTREL_SERVICE_THREAD_PRIORITY, 0, K_NO_WAIT);
	k_thread_name_set(thermal_service_thread_id, "thermal_service");

241 242 243
	// Run late setup
	configure_gpios();

244 245
	LOG_INF("Kestrel system initialization complete\n");
}