Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <string.h> |
| 4 | #include <fcntl.h> |
| 5 | #include <unistd.h> |
| 6 | #include <sys/stat.h> |
| 7 | #include <sys/mman.h> |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 8 | #include <errno.h> |
| 9 | |
Brad Bishop | f6c8568 | 2016-06-27 11:56:39 -0400 | [diff] [blame] | 10 | #include <openbmc_intf.h> |
| 11 | #include <openbmc.h> |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 12 | |
| 13 | /* ------------------------------------------------------------------------- */ |
| 14 | static const gchar* dbus_object_path = "/org/openbmc/control"; |
| 15 | static const gchar* instance_name = "host0"; |
| 16 | static const gchar* dbus_name = "org.openbmc.control.Host"; |
| 17 | |
| 18 | static GDBusObjectManagerServer *manager = NULL; |
| 19 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 20 | #define PPC_BIT32(bit) (0x80000000UL >> (bit)) |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 21 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 22 | #define FSI_EXTERNAL_MODE_PATH "/sys/devices/platform/gpio-fsi/external_mode" |
| 23 | #define FSI_SCAN_PATH "/sys/devices/platform/gpio-fsi/fsi0/rescan" |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 24 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 25 | /* TODO: Change this over to the cfam path once the cfam chardev patches have landed */ |
| 26 | #define FSI_RAW_PATH "/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/raw" |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 27 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 28 | #define FSI_SCAN_DELAY_US 10000 |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 29 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 30 | /* Attention registers */ |
| 31 | #define FSI_A_SI1S 0x081c |
| 32 | #define TRUE_MASK 0x100d |
| 33 | #define INTERRUPT_STATUS_REG 0x100b |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 34 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 35 | /* SBE boot register and values */ |
| 36 | #define SBE_VITAL 0x281c |
| 37 | #define SBE_WARMSTART PPC_BIT32(0) |
| 38 | #define SBE_HW_TRIGGER PPC_BIT32(2) |
| 39 | #define SBE_UPDATE_1ST_NIBBLE PPC_BIT32(3) |
| 40 | #define SBE_IMAGE_SELECT PPC_BIT32(8) |
| 41 | #define SBE_UPDATE_3RD_NIBBLE PPC_BIT32(11) |
| 42 | |
| 43 | /* Once the side is selected and attention bits are set, this starts the SBE */ |
| 44 | #define START_SBE (SBE_WARMSTART | SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE) |
| 45 | |
| 46 | /* Primary is first side. Golden is second side */ |
| 47 | #define PRIMARY_SIDE (SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE) |
| 48 | #define GOLDEN_SIDE (SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE | \ |
| 49 | SBE_IMAGE_SELECT | SBE_UPDATE_3RD_NIBBLE) |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 50 | |
| 51 | static gboolean |
| 52 | on_init(Control *control, |
| 53 | GDBusMethodInvocation *invocation, |
| 54 | gpointer user_data) |
| 55 | { |
| 56 | control_complete_init(control,invocation); |
| 57 | return TRUE; |
| 58 | } |
| 59 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 60 | static gint |
| 61 | fsi_putcfam(int fd, uint64_t addr64, uint32_t val_host) |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 62 | { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 63 | int rc; |
| 64 | uint32_t val = htobe32(val_host); |
| 65 | /* Map FSI to FSI_BYTE, as the 'raw' kernel interface expects this */ |
| 66 | uint32_t addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2); |
| 67 | |
| 68 | rc = lseek(fd, addr, SEEK_SET); |
| 69 | if (rc < 0) { |
| 70 | g_print("ERROR HostControl: cfam seek failed (0x%08x): %s\n", addr, |
| 71 | strerror(errno)); |
| 72 | return errno; |
| 73 | }; |
| 74 | |
| 75 | rc = write(fd, &val, sizeof(val)); |
| 76 | if (rc < 0) { |
| 77 | g_print("ERROR HostControl: cfam write failed: %s\n", |
| 78 | strerror(errno)); |
| 79 | return errno; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 80 | } |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 81 | |
| 82 | return 0; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 83 | } |
| 84 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 85 | static int fsi_rescan(void) |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 86 | { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 87 | char *one = "1"; |
| 88 | int fd, rc; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 89 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 90 | fd = open(FSI_SCAN_PATH, O_WRONLY); |
| 91 | if (fd < 0) { |
| 92 | g_print("ERROR HostControl: Failed to open path '%s': %s\n", |
| 93 | FSI_SCAN_PATH, strerror(errno)); |
| 94 | return errno; |
| 95 | } |
| 96 | rc = write(fd, one, sizeof(one)); |
| 97 | close(fd); |
| 98 | if (rc < 0) { |
| 99 | g_print("ERROR HostControl: Failed to perform FSI scan: %s\n", |
| 100 | strerror(errno)); |
| 101 | return errno; |
| 102 | } |
| 103 | g_print("HostControl: Performing FSI scan (delay %d us)\n", |
| 104 | FSI_SCAN_DELAY_US); |
| 105 | usleep(FSI_SCAN_DELAY_US); |
| 106 | |
| 107 | return 0; |
| 108 | } |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 109 | |
| 110 | static gboolean |
| 111 | on_boot(ControlHost *host, |
| 112 | GDBusMethodInvocation *invocation, |
| 113 | gpointer user_data) |
| 114 | { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 115 | int rc, cfam_fd; |
Adriana Kobylak | 37846da | 2016-08-19 10:57:18 -0500 | [diff] [blame] | 116 | GDBusProxy *proxy; |
| 117 | GError *error = NULL; |
Adriana Kobylak | 37846da | 2016-08-19 10:57:18 -0500 | [diff] [blame] | 118 | GDBusConnection *connection = |
| 119 | g_dbus_object_manager_server_get_connection(manager); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 120 | |
Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 121 | if(control_host_get_debug_mode(host)==1) { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 122 | int fd; |
| 123 | char *one = "1"; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 124 | g_print("Enabling debug mode; not booting host\n"); |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 125 | fd = open(FSI_EXTERNAL_MODE_PATH, O_RDWR); |
| 126 | if (fd < 0) { |
| 127 | g_print("ERROR HostControl: Failed to open path '%s'\n", |
| 128 | FSI_EXTERNAL_MODE_PATH); |
| 129 | return TRUE; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 130 | } |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 131 | rc = write(fd, one, sizeof(one)); |
| 132 | if (rc < 0) { |
| 133 | g_print("ERROR HostControl: Failed to enable debug mode '%s'\n", |
| 134 | FSI_EXTERNAL_MODE_PATH); |
| 135 | } |
| 136 | close(fd); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 137 | return TRUE; |
| 138 | } |
| 139 | g_print("Booting host\n"); |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 140 | |
| 141 | rc = fsi_rescan(); |
| 142 | if (rc < 0) |
| 143 | return FALSE; |
| 144 | |
| 145 | cfam_fd = open(FSI_RAW_PATH, O_RDWR); |
| 146 | if (cfam_fd < 0) { |
| 147 | g_print("ERROR HostControl: Failed to open '%s'\n", FSI_RAW_PATH); |
| 148 | return FALSE; |
| 149 | } |
| 150 | |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 151 | Control* control = object_get_control((Object*)user_data); |
| 152 | control_host_complete_boot(host,invocation); |
| 153 | do { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 154 | rc = fsi_putcfam(cfam_fd, FSI_A_SI1S, 0x20000000); |
| 155 | rc |= fsi_putcfam(cfam_fd, TRUE_MASK, 0x40000000); |
| 156 | rc |= fsi_putcfam(cfam_fd, INTERRUPT_STATUS_REG, 0xFFFFFFFF); |
| 157 | if(rc) { break; } |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 158 | |
| 159 | const gchar* flash_side = control_host_get_flash_side(host); |
| 160 | g_print("Using %s side of the bios flash\n",flash_side); |
| 161 | if(strcmp(flash_side,"primary")==0) { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 162 | rc |= fsi_putcfam(cfam_fd, SBE_VITAL, PRIMARY_SIDE); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 163 | } else if(strcmp(flash_side,"golden") == 0) { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 164 | rc |= fsi_putcfam(cfam_fd, SBE_VITAL, GOLDEN_SIDE); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 165 | } else { |
| 166 | g_print("ERROR: Invalid flash side: %s\n",flash_side); |
| 167 | rc = 0xff; |
| 168 | |
| 169 | } |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 170 | if(rc) { break; } |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 171 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 172 | rc = fsi_putcfam(cfam_fd, SBE_VITAL, START_SBE); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 173 | } while(0); |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 174 | if(rc) |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 175 | { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 176 | g_print("ERROR HostControl: SBE sequence failed (rc=%d)\n",rc); |
Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 177 | } |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 178 | /* Close file descriptor */ |
| 179 | close(cfam_fd); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 180 | |
| 181 | control_host_emit_booted(host); |
Adriana Kobylak | 37846da | 2016-08-19 10:57:18 -0500 | [diff] [blame] | 182 | |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 183 | return TRUE; |
| 184 | } |
| 185 | |
| 186 | static void |
| 187 | on_bus_acquired(GDBusConnection *connection, |
| 188 | const gchar *name, |
| 189 | gpointer user_data) |
| 190 | { |
| 191 | ObjectSkeleton *object; |
| 192 | //g_print ("Acquired a message bus connection: %s\n",name); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 193 | manager = g_dbus_object_manager_server_new(dbus_object_path); |
| 194 | |
| 195 | gchar *s; |
| 196 | s = g_strdup_printf("%s/%s",dbus_object_path,instance_name); |
| 197 | object = object_skeleton_new(s); |
| 198 | g_free(s); |
| 199 | |
| 200 | ControlHost* control_host = control_host_skeleton_new(); |
| 201 | object_skeleton_set_control_host(object, control_host); |
| 202 | g_object_unref(control_host); |
| 203 | |
| 204 | Control* control = control_skeleton_new(); |
| 205 | object_skeleton_set_control(object, control); |
| 206 | g_object_unref(control); |
| 207 | |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 208 | //define method callbacks here |
| 209 | g_signal_connect(control_host, |
| 210 | "handle-boot", |
| 211 | G_CALLBACK(on_boot), |
| 212 | object); /* user_data */ |
| 213 | g_signal_connect(control, |
| 214 | "handle-init", |
| 215 | G_CALLBACK(on_init), |
| 216 | NULL); /* user_data */ |
| 217 | |
| 218 | control_host_set_debug_mode(control_host,0); |
| 219 | control_host_set_flash_side(control_host,"primary"); |
| 220 | |
| 221 | /* Export the object (@manager takes its own reference to @object) */ |
Brad Bishop | 58e694d | 2016-04-13 16:04:32 -0400 | [diff] [blame] | 222 | g_dbus_object_manager_server_set_connection(manager, connection); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 223 | g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); |
| 224 | g_object_unref(object); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 225 | } |
| 226 | |
| 227 | static void |
| 228 | on_name_acquired(GDBusConnection *connection, |
| 229 | const gchar *name, |
| 230 | gpointer user_data) |
| 231 | { |
Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 232 | // g_print ("Acquired the name %s\n", name); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 233 | } |
| 234 | |
| 235 | static void |
| 236 | on_name_lost(GDBusConnection *connection, |
| 237 | const gchar *name, |
| 238 | gpointer user_data) |
| 239 | { |
Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 240 | // g_print ("Lost the name %s\n", name); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 241 | } |
| 242 | |
| 243 | gint |
| 244 | main(gint argc, gchar *argv[]) |
| 245 | { |
| 246 | GMainLoop *loop; |
| 247 | cmdline cmd; |
| 248 | cmd.argc = argc; |
| 249 | cmd.argv = argv; |
| 250 | |
| 251 | guint id; |
| 252 | loop = g_main_loop_new(NULL, FALSE); |
| 253 | |
| 254 | id = g_bus_own_name(DBUS_TYPE, |
| 255 | dbus_name, |
| 256 | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | |
| 257 | G_BUS_NAME_OWNER_FLAGS_REPLACE, |
| 258 | on_bus_acquired, |
| 259 | on_name_acquired, |
| 260 | on_name_lost, |
| 261 | &cmd, |
| 262 | NULL); |
| 263 | |
| 264 | g_main_loop_run(loop); |
| 265 | |
| 266 | g_bus_unown_name(id); |
| 267 | g_main_loop_unref(loop); |
| 268 | return 0; |
| 269 | } |