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" |
Joel Stanley | bed673e | 2020-01-06 15:54:40 +1100 | [diff] [blame] | 23 | #define FSI_SCAN_PATH "/sys/class/fsi-master/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 */ |
Joel Stanley | bed673e | 2020-01-06 15:54:40 +1100 | [diff] [blame] | 26 | #define FSI_RAW_PATH "/sys/class/fsi-master/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 | { |
Patrick Williams | 783fbb0 | 2024-10-04 09:35:13 -0400 | [diff] [blame^] | 56 | (void) user_data; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 57 | control_complete_init(control,invocation); |
| 58 | return TRUE; |
| 59 | } |
| 60 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 61 | static gint |
| 62 | fsi_putcfam(int fd, uint64_t addr64, uint32_t val_host) |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 63 | { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 64 | int rc; |
| 65 | uint32_t val = htobe32(val_host); |
| 66 | /* Map FSI to FSI_BYTE, as the 'raw' kernel interface expects this */ |
| 67 | uint32_t addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2); |
| 68 | |
| 69 | rc = lseek(fd, addr, SEEK_SET); |
| 70 | if (rc < 0) { |
| 71 | g_print("ERROR HostControl: cfam seek failed (0x%08x): %s\n", addr, |
| 72 | strerror(errno)); |
| 73 | return errno; |
| 74 | }; |
| 75 | |
| 76 | rc = write(fd, &val, sizeof(val)); |
| 77 | if (rc < 0) { |
| 78 | g_print("ERROR HostControl: cfam write failed: %s\n", |
| 79 | strerror(errno)); |
| 80 | return errno; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 81 | } |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 82 | |
| 83 | return 0; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 84 | } |
| 85 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 86 | static int fsi_rescan(void) |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 87 | { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 88 | char *one = "1"; |
| 89 | int fd, rc; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 90 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 91 | fd = open(FSI_SCAN_PATH, O_WRONLY); |
| 92 | if (fd < 0) { |
| 93 | g_print("ERROR HostControl: Failed to open path '%s': %s\n", |
| 94 | FSI_SCAN_PATH, strerror(errno)); |
| 95 | return errno; |
| 96 | } |
Andrew Geissler | 3fbb444 | 2020-09-01 12:34:18 -0500 | [diff] [blame] | 97 | rc = write(fd, one, sizeof(*one)); |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 98 | close(fd); |
| 99 | if (rc < 0) { |
| 100 | g_print("ERROR HostControl: Failed to perform FSI scan: %s\n", |
| 101 | strerror(errno)); |
| 102 | return errno; |
| 103 | } |
| 104 | g_print("HostControl: Performing FSI scan (delay %d us)\n", |
| 105 | FSI_SCAN_DELAY_US); |
| 106 | usleep(FSI_SCAN_DELAY_US); |
| 107 | |
| 108 | return 0; |
| 109 | } |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 110 | |
| 111 | static gboolean |
| 112 | on_boot(ControlHost *host, |
| 113 | GDBusMethodInvocation *invocation, |
| 114 | gpointer user_data) |
| 115 | { |
Patrick Williams | 783fbb0 | 2024-10-04 09:35:13 -0400 | [diff] [blame^] | 116 | (void) user_data; |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 117 | int rc, cfam_fd; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 118 | |
Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 119 | if(control_host_get_debug_mode(host)==1) { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 120 | int fd; |
| 121 | char *one = "1"; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 122 | g_print("Enabling debug mode; not booting host\n"); |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 123 | fd = open(FSI_EXTERNAL_MODE_PATH, O_RDWR); |
| 124 | if (fd < 0) { |
| 125 | g_print("ERROR HostControl: Failed to open path '%s'\n", |
| 126 | FSI_EXTERNAL_MODE_PATH); |
| 127 | return TRUE; |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 128 | } |
Andrew Geissler | 3fbb444 | 2020-09-01 12:34:18 -0500 | [diff] [blame] | 129 | rc = write(fd, one, sizeof(*one)); |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 130 | if (rc < 0) { |
| 131 | g_print("ERROR HostControl: Failed to enable debug mode '%s'\n", |
| 132 | FSI_EXTERNAL_MODE_PATH); |
| 133 | } |
| 134 | close(fd); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 135 | return TRUE; |
| 136 | } |
| 137 | g_print("Booting host\n"); |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 138 | |
| 139 | rc = fsi_rescan(); |
| 140 | if (rc < 0) |
| 141 | return FALSE; |
| 142 | |
| 143 | cfam_fd = open(FSI_RAW_PATH, O_RDWR); |
| 144 | if (cfam_fd < 0) { |
| 145 | g_print("ERROR HostControl: Failed to open '%s'\n", FSI_RAW_PATH); |
| 146 | return FALSE; |
| 147 | } |
| 148 | |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 149 | control_host_complete_boot(host,invocation); |
| 150 | do { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 151 | rc = fsi_putcfam(cfam_fd, FSI_A_SI1S, 0x20000000); |
| 152 | rc |= fsi_putcfam(cfam_fd, TRUE_MASK, 0x40000000); |
| 153 | rc |= fsi_putcfam(cfam_fd, INTERRUPT_STATUS_REG, 0xFFFFFFFF); |
| 154 | if(rc) { break; } |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 155 | |
| 156 | const gchar* flash_side = control_host_get_flash_side(host); |
| 157 | g_print("Using %s side of the bios flash\n",flash_side); |
| 158 | if(strcmp(flash_side,"primary")==0) { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 159 | rc |= fsi_putcfam(cfam_fd, SBE_VITAL, PRIMARY_SIDE); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 160 | } else if(strcmp(flash_side,"golden") == 0) { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 161 | rc |= fsi_putcfam(cfam_fd, SBE_VITAL, GOLDEN_SIDE); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 162 | } else { |
| 163 | g_print("ERROR: Invalid flash side: %s\n",flash_side); |
| 164 | rc = 0xff; |
| 165 | |
| 166 | } |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 167 | if(rc) { break; } |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 168 | |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 169 | rc = fsi_putcfam(cfam_fd, SBE_VITAL, START_SBE); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 170 | } while(0); |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 171 | if(rc) |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 172 | { |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 173 | g_print("ERROR HostControl: SBE sequence failed (rc=%d)\n",rc); |
Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 174 | } |
Joel Stanley | 5da4f4f | 2018-07-13 13:59:57 +0930 | [diff] [blame] | 175 | /* Close file descriptor */ |
| 176 | close(cfam_fd); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 177 | |
| 178 | control_host_emit_booted(host); |
Adriana Kobylak | 37846da | 2016-08-19 10:57:18 -0500 | [diff] [blame] | 179 | |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 180 | return TRUE; |
| 181 | } |
| 182 | |
| 183 | static void |
| 184 | on_bus_acquired(GDBusConnection *connection, |
| 185 | const gchar *name, |
| 186 | gpointer user_data) |
| 187 | { |
Patrick Williams | 783fbb0 | 2024-10-04 09:35:13 -0400 | [diff] [blame^] | 188 | (void) name; |
| 189 | (void) user_data; |
| 190 | |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 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 | { |
Patrick Williams | 783fbb0 | 2024-10-04 09:35:13 -0400 | [diff] [blame^] | 232 | (void) connection; |
| 233 | (void) name; |
| 234 | (void) user_data; |
Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 235 | // g_print ("Acquired the name %s\n", name); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | static void |
| 239 | on_name_lost(GDBusConnection *connection, |
| 240 | const gchar *name, |
| 241 | gpointer user_data) |
| 242 | { |
Patrick Williams | 783fbb0 | 2024-10-04 09:35:13 -0400 | [diff] [blame^] | 243 | (void) connection; |
| 244 | (void) name; |
| 245 | (void) user_data; |
Lei YU | 75a18a2 | 2016-11-22 01:47:47 +0800 | [diff] [blame] | 246 | // g_print ("Lost the name %s\n", name); |
Brad Bishop | 7739049 | 2016-04-13 10:47:19 -0400 | [diff] [blame] | 247 | } |
| 248 | |
| 249 | gint |
| 250 | main(gint argc, gchar *argv[]) |
| 251 | { |
| 252 | GMainLoop *loop; |
| 253 | cmdline cmd; |
| 254 | cmd.argc = argc; |
| 255 | cmd.argv = argv; |
| 256 | |
| 257 | guint id; |
| 258 | loop = g_main_loop_new(NULL, FALSE); |
| 259 | |
| 260 | id = g_bus_own_name(DBUS_TYPE, |
| 261 | dbus_name, |
| 262 | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | |
| 263 | G_BUS_NAME_OWNER_FLAGS_REPLACE, |
| 264 | on_bus_acquired, |
| 265 | on_name_acquired, |
| 266 | on_name_lost, |
| 267 | &cmd, |
| 268 | NULL); |
| 269 | |
| 270 | g_main_loop_run(loop); |
| 271 | |
| 272 | g_bus_unown_name(id); |
| 273 | g_main_loop_unref(loop); |
| 274 | return 0; |
| 275 | } |