Brad Bishop | c9ed720 | 2019-06-14 12:33:18 -0400 | [diff] [blame^] | 1 | From b6b1cda6a526bad8c7f50aa4427bedbc6e539a4d Mon Sep 17 00:00:00 2001 |
| 2 | From: Artem Senichev <a.senichev@yadro.com> |
| 3 | Date: Fri, 23 Nov 2018 10:31:59 +0300 |
| 4 | Subject: [PATCH] Replace ColdFire FSI with plain FSI-over-GPIO |
| 5 | |
| 6 | Workaround to fix ColdFire FSI performance issue: |
| 7 | https://github.com/openbmc/openbmc/issues/3433 |
| 8 | Current implementation based on an old version of skeleton |
| 9 | (revision 517b35ed92ad2c0df5e048711c175bacb632f6d0), mostly it's |
| 10 | a copy-paste of op-hostctl module. |
| 11 | |
| 12 | Signed-off-by: Artem Senichev <a.senichev@yadro.com> |
| 13 | Signed-off-by: Alexander Filippov <a.filippov@yadro.com> |
| 14 | --- |
| 15 | control_host_obj.c | 259 ++++++++++++++++++++-------------- |
| 16 | 1 file changed, 152 insertions(+), 107 deletions(-) |
| 17 | |
| 18 | diff --git a/control_host_obj.c b/control_host_obj.c |
| 19 | index 27f7fc7..ca45182 100644 |
| 20 | --- a/control_host_obj.c |
| 21 | +++ b/control_host_obj.c |
| 22 | @@ -5,10 +5,10 @@ |
| 23 | #include <unistd.h> |
| 24 | #include <sys/stat.h> |
| 25 | #include <sys/mman.h> |
| 26 | -#include <errno.h> |
| 27 | - |
| 28 | #include <openbmc_intf.h> |
| 29 | #include <openbmc.h> |
| 30 | +#include <gpio.h> |
| 31 | +#include <gpio_configs.h> |
| 32 | |
| 33 | /* ------------------------------------------------------------------------- */ |
| 34 | static const gchar* dbus_object_path = "/org/openbmc/control"; |
| 35 | @@ -17,36 +17,31 @@ static const gchar* dbus_name = "org.openbmc.control.Host"; |
| 36 | |
| 37 | static GDBusObjectManagerServer *manager = NULL; |
| 38 | |
| 39 | -#define PPC_BIT32(bit) (0x80000000UL >> (bit)) |
| 40 | - |
| 41 | -#define FSI_EXTERNAL_MODE_PATH "/sys/devices/platform/gpio-fsi/external_mode" |
| 42 | -#define FSI_SCAN_PATH "/sys/devices/platform/gpio-fsi/fsi0/rescan" |
| 43 | - |
| 44 | -/* TODO: Change this over to the cfam path once the cfam chardev patches have landed */ |
| 45 | -#define FSI_RAW_PATH "/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/raw" |
| 46 | - |
| 47 | -#define FSI_SCAN_DELAY_US 10000 |
| 48 | +static GPIO* fsi_data; |
| 49 | +static GPIO* fsi_clk; |
| 50 | +static GPIO* fsi_enable; |
| 51 | +static GPIO* cronus_sel; |
| 52 | +static size_t num_optionals; |
| 53 | +static GPIO* optionals; |
| 54 | +static gboolean* optional_pols; |
| 55 | |
| 56 | -/* Attention registers */ |
| 57 | -#define FSI_A_SI1S 0x081c |
| 58 | -#define TRUE_MASK 0x100d |
| 59 | -#define INTERRUPT_STATUS_REG 0x100b |
| 60 | +/* Bit bang patterns */ |
| 61 | |
| 62 | -/* SBE boot register and values */ |
| 63 | -#define SBE_VITAL 0x281c |
| 64 | -#define SBE_WARMSTART PPC_BIT32(0) |
| 65 | -#define SBE_HW_TRIGGER PPC_BIT32(2) |
| 66 | -#define SBE_UPDATE_1ST_NIBBLE PPC_BIT32(3) |
| 67 | -#define SBE_IMAGE_SELECT PPC_BIT32(8) |
| 68 | -#define SBE_UPDATE_3RD_NIBBLE PPC_BIT32(11) |
| 69 | +//putcfam pu 281c 30000000 -p0 (Primary Side Select) |
| 70 | +static const char* primary = "000011111111110101111000111001100111111111111111111111111111101111111111"; |
| 71 | +//putcfam pu 281c B0000000 -p0 |
| 72 | +static const char* go = "000011111111110101111000111000100111111111111111111111111111101101111111"; |
| 73 | +//putcfam pu 0x281c 30900000 (Golden Side Select) |
| 74 | +static const char* golden = "000011111111110101111000111001100111101101111111111111111111101001111111"; |
| 75 | |
| 76 | -/* Once the side is selected and attention bits are set, this starts the SBE */ |
| 77 | -#define START_SBE (SBE_WARMSTART | SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE) |
| 78 | +/* Setup attentions */ |
| 79 | +//putcfam pu 0x081C 20000000 |
| 80 | +static const char* attnA = "000011111111111101111110001001101111111111111111111111111111110001111111"; |
| 81 | +//putcfam pu 0x100D 40000000 |
| 82 | +static const char* attnB = "000011111111111011111100101001011111111111111111111111111111110001111111"; |
| 83 | +//putcfam pu 0x100B FFFFFFFF |
| 84 | +static const char* attnC = "000011111111111011111101001000000000000000000000000000000000001011111111"; |
| 85 | |
| 86 | -/* Primary is first side. Golden is second side */ |
| 87 | -#define PRIMARY_SIDE (SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE) |
| 88 | -#define GOLDEN_SIDE (SBE_HW_TRIGGER | SBE_UPDATE_1ST_NIBBLE | \ |
| 89 | - SBE_IMAGE_SELECT | SBE_UPDATE_3RD_NIBBLE) |
| 90 | |
| 91 | static gboolean |
| 92 | on_init(Control *control, |
| 93 | @@ -57,126 +52,147 @@ on_init(Control *control, |
| 94 | return TRUE; |
| 95 | } |
| 96 | |
| 97 | -static gint |
| 98 | -fsi_putcfam(int fd, uint64_t addr64, uint32_t val_host) |
| 99 | +int gpio_clock_cycle(GPIO* gpio, int num_clks) |
| 100 | { |
| 101 | - int rc; |
| 102 | - uint32_t val = htobe32(val_host); |
| 103 | - /* Map FSI to FSI_BYTE, as the 'raw' kernel interface expects this */ |
| 104 | - uint32_t addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2); |
| 105 | - |
| 106 | - rc = lseek(fd, addr, SEEK_SET); |
| 107 | - if (rc < 0) { |
| 108 | - g_print("ERROR HostControl: cfam seek failed (0x%08x): %s\n", addr, |
| 109 | - strerror(errno)); |
| 110 | - return errno; |
| 111 | - }; |
| 112 | - |
| 113 | - rc = write(fd, &val, sizeof(val)); |
| 114 | - if (rc < 0) { |
| 115 | - g_print("ERROR HostControl: cfam write failed: %s\n", |
| 116 | - strerror(errno)); |
| 117 | - return errno; |
| 118 | - } |
| 119 | - |
| 120 | - return 0; |
| 121 | + g_assert(gpio != NULL); |
| 122 | + int i = 0; |
| 123 | + int r = GPIO_OK; |
| 124 | + for (i = 0; i < num_clks; i++) |
| 125 | + { |
| 126 | + if (gpio_write(gpio, 0) == -1) |
| 127 | + { |
| 128 | + r = GPIO_WRITE_ERROR; |
| 129 | + break; |
| 130 | + } |
| 131 | + if (gpio_write(gpio, 1) == -1) |
| 132 | + { |
| 133 | + r = GPIO_WRITE_ERROR; |
| 134 | + break; |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + return r; |
| 139 | } |
| 140 | |
| 141 | -static int fsi_rescan(void) |
| 142 | +int |
| 143 | +fsi_bitbang(const char* pattern) |
| 144 | { |
| 145 | - char *one = "1"; |
| 146 | - int fd, rc; |
| 147 | - |
| 148 | - fd = open(FSI_SCAN_PATH, O_WRONLY); |
| 149 | - if (fd < 0) { |
| 150 | - g_print("ERROR HostControl: Failed to open path '%s': %s\n", |
| 151 | - FSI_SCAN_PATH, strerror(errno)); |
| 152 | - return errno; |
| 153 | - } |
| 154 | - rc = write(fd, one, sizeof(one)); |
| 155 | - close(fd); |
| 156 | - if (rc < 0) { |
| 157 | - g_print("ERROR HostControl: Failed to perform FSI scan: %s\n", |
| 158 | - strerror(errno)); |
| 159 | - return errno; |
| 160 | + int rc=GPIO_OK; |
| 161 | + int i; |
| 162 | + for(i=0;i<strlen(pattern);i++) { |
| 163 | + rc = gpio_write(fsi_data,pattern[i] - '0'); |
| 164 | + if(rc!=GPIO_OK) { break; } |
| 165 | + rc = gpio_clock_cycle(fsi_clk,1); |
| 166 | + if(rc!=GPIO_OK) { break; } |
| 167 | } |
| 168 | - g_print("HostControl: Performing FSI scan (delay %d us)\n", |
| 169 | - FSI_SCAN_DELAY_US); |
| 170 | - usleep(FSI_SCAN_DELAY_US); |
| 171 | + return rc; |
| 172 | +} |
| 173 | |
| 174 | - return 0; |
| 175 | +int |
| 176 | +fsi_standby() |
| 177 | +{ |
| 178 | + int rc=GPIO_OK; |
| 179 | + rc = gpio_write(fsi_data,1); |
| 180 | + if(rc!=GPIO_OK) { return rc; } |
| 181 | + rc = gpio_clock_cycle(fsi_clk,5000); |
| 182 | + if(rc!=GPIO_OK) { return rc; } |
| 183 | + return rc; |
| 184 | } |
| 185 | |
| 186 | + |
| 187 | static gboolean |
| 188 | on_boot(ControlHost *host, |
| 189 | GDBusMethodInvocation *invocation, |
| 190 | gpointer user_data) |
| 191 | { |
| 192 | - int rc, cfam_fd; |
| 193 | + int rc = GPIO_OK; |
| 194 | GDBusProxy *proxy; |
| 195 | GError *error = NULL; |
| 196 | GDBusConnection *connection = |
| 197 | g_dbus_object_manager_server_get_connection(manager); |
| 198 | |
| 199 | + if (!(fsi_data && fsi_clk && fsi_enable && cronus_sel)) { |
| 200 | + g_print("ERROR invalid GPIO configuration, will not boot\n"); |
| 201 | + return FALSE; |
| 202 | + } |
| 203 | if(control_host_get_debug_mode(host)==1) { |
| 204 | - int fd; |
| 205 | - char *one = "1"; |
| 206 | g_print("Enabling debug mode; not booting host\n"); |
| 207 | - fd = open(FSI_EXTERNAL_MODE_PATH, O_RDWR); |
| 208 | - if (fd < 0) { |
| 209 | - g_print("ERROR HostControl: Failed to open path '%s'\n", |
| 210 | - FSI_EXTERNAL_MODE_PATH); |
| 211 | - return TRUE; |
| 212 | + rc |= gpio_open(fsi_enable, 1); |
| 213 | + rc |= gpio_open(cronus_sel, 0); |
| 214 | + if(rc!=GPIO_OK) { |
| 215 | + g_print("ERROR enabling debug mode: %d\n",rc); |
| 216 | } |
| 217 | - rc = write(fd, one, sizeof(one)); |
| 218 | - if (rc < 0) { |
| 219 | - g_print("ERROR HostControl: Failed to enable debug mode '%s'\n", |
| 220 | - FSI_EXTERNAL_MODE_PATH); |
| 221 | - } |
| 222 | - close(fd); |
| 223 | return TRUE; |
| 224 | } |
| 225 | g_print("Booting host\n"); |
| 226 | - |
| 227 | - rc = fsi_rescan(); |
| 228 | - if (rc < 0) |
| 229 | - return FALSE; |
| 230 | - |
| 231 | - cfam_fd = open(FSI_RAW_PATH, O_RDWR); |
| 232 | - if (cfam_fd < 0) { |
| 233 | - g_print("ERROR HostControl: Failed to open '%s'\n", FSI_RAW_PATH); |
| 234 | - return FALSE; |
| 235 | - } |
| 236 | - |
| 237 | Control* control = object_get_control((Object*)user_data); |
| 238 | control_host_complete_boot(host,invocation); |
| 239 | do { |
| 240 | - rc = fsi_putcfam(cfam_fd, FSI_A_SI1S, 0x20000000); |
| 241 | - rc |= fsi_putcfam(cfam_fd, TRUE_MASK, 0x40000000); |
| 242 | - rc |= fsi_putcfam(cfam_fd, INTERRUPT_STATUS_REG, 0xFFFFFFFF); |
| 243 | - if(rc) { break; } |
| 244 | + rc = gpio_open(fsi_clk, 1); |
| 245 | + rc |= gpio_open(fsi_data, 0); |
| 246 | + rc |= gpio_open(fsi_enable, 1); |
| 247 | + rc |= gpio_open(cronus_sel, 1); |
| 248 | + for (size_t i = 0; i < num_optionals; ++i) { |
| 249 | + rc |= gpio_open(&optionals[i], optional_pols[i]); |
| 250 | + } |
| 251 | + if(rc!=GPIO_OK) { break; } |
| 252 | + |
| 253 | + //data standy state |
| 254 | + rc = fsi_standby(); |
| 255 | + |
| 256 | + //clear out pipes |
| 257 | + rc |= gpio_write(fsi_data,0); |
| 258 | + rc |= gpio_clock_cycle(fsi_clk,256); |
| 259 | + rc |= gpio_write(fsi_data,1); |
| 260 | + rc |= gpio_clock_cycle(fsi_clk,50); |
| 261 | + if(rc!=GPIO_OK) { break; } |
| 262 | + |
| 263 | + rc = fsi_bitbang(attnA); |
| 264 | + rc |= fsi_standby(); |
| 265 | + |
| 266 | + rc |= fsi_bitbang(attnB); |
| 267 | + rc |= fsi_standby(); |
| 268 | + |
| 269 | + rc |= fsi_bitbang(attnC); |
| 270 | + rc |= fsi_standby(); |
| 271 | + if(rc!=GPIO_OK) { break; } |
| 272 | |
| 273 | const gchar* flash_side = control_host_get_flash_side(host); |
| 274 | g_print("Using %s side of the bios flash\n",flash_side); |
| 275 | if(strcmp(flash_side,"primary")==0) { |
| 276 | - rc |= fsi_putcfam(cfam_fd, SBE_VITAL, PRIMARY_SIDE); |
| 277 | + rc |= fsi_bitbang(primary); |
| 278 | } else if(strcmp(flash_side,"golden") == 0) { |
| 279 | - rc |= fsi_putcfam(cfam_fd, SBE_VITAL, GOLDEN_SIDE); |
| 280 | + rc |= fsi_bitbang(golden); |
| 281 | } else { |
| 282 | g_print("ERROR: Invalid flash side: %s\n",flash_side); |
| 283 | rc = 0xff; |
| 284 | |
| 285 | } |
| 286 | - if(rc) { break; } |
| 287 | + rc |= fsi_standby(); |
| 288 | + if(rc!=GPIO_OK) { break; } |
| 289 | + |
| 290 | + rc = fsi_bitbang(go); |
| 291 | + |
| 292 | + rc |= gpio_write(fsi_data,1); /* Data standby state */ |
| 293 | + rc |= gpio_clock_cycle(fsi_clk,2); |
| 294 | + |
| 295 | + rc |= gpio_write(fsi_clk,0); /* hold clk low for clock mux */ |
| 296 | + rc |= gpio_write(fsi_enable,0); |
| 297 | + rc |= gpio_clock_cycle(fsi_clk,16); |
| 298 | + rc |= gpio_write(fsi_clk,0); /* Data standby state */ |
| 299 | |
| 300 | - rc = fsi_putcfam(cfam_fd, SBE_VITAL, START_SBE); |
| 301 | } while(0); |
| 302 | - if(rc) |
| 303 | + if(rc != GPIO_OK) |
| 304 | { |
| 305 | - g_print("ERROR HostControl: SBE sequence failed (rc=%d)\n",rc); |
| 306 | + g_print("ERROR HostControl: GPIO sequence failed (rc=%d)\n",rc); |
| 307 | + } |
| 308 | + gpio_close(fsi_clk); |
| 309 | + gpio_close(fsi_data); |
| 310 | + gpio_close(fsi_enable); |
| 311 | + gpio_close(cronus_sel); |
| 312 | + for (size_t i = 0; i < num_optionals; ++i) { |
| 313 | + gpio_close(&optionals[i]); |
| 314 | } |
| 315 | - /* Close file descriptor */ |
| 316 | - close(cfam_fd); |
| 317 | |
| 318 | control_host_emit_booted(host); |
| 319 | |
| 320 | @@ -222,6 +238,35 @@ on_bus_acquired(GDBusConnection *connection, |
| 321 | g_dbus_object_manager_server_set_connection(manager, connection); |
| 322 | g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); |
| 323 | g_object_unref(object); |
| 324 | + |
| 325 | + // We don't free allocated memory as the service is a singleton, |
| 326 | + // this function can be called only once and these GPIO objects |
| 327 | + // have a process lifetime. |
| 328 | + fsi_data = malloc(sizeof(GPIO)); |
| 329 | + fsi_data->name = g_strdup("FSI_DATA"); // GPIO struct has non-const char pointer |
| 330 | + fsi_clk = malloc(sizeof(GPIO)); |
| 331 | + fsi_clk->name = g_strdup("FSI_CLK"); |
| 332 | + fsi_enable = malloc(sizeof(GPIO)); |
| 333 | + fsi_enable->name = g_strdup("FSI_ENABLE"); |
| 334 | + cronus_sel = malloc(sizeof(GPIO)); |
| 335 | + cronus_sel->name = g_strdup("CRONUS_SEL"); |
| 336 | + |
| 337 | + // WARNING: This portion of the hardcode is usable only with VESNIN. |
| 338 | + // For the upstream, it should be rewritten for reading this data from the |
| 339 | + // JSON file. |
| 340 | + num_optionals = 1; |
| 341 | + optionals = malloc(sizeof(GPIO)); |
| 342 | + optionals->name = g_strdup("CP0_FSI0_DATA_EN"); |
| 343 | + optional_pols = malloc(sizeof(gboolean)); |
| 344 | + optional_pols[0] = TRUE; |
| 345 | + |
| 346 | + gpio_get_params(fsi_data); |
| 347 | + gpio_get_params(fsi_clk); |
| 348 | + gpio_get_params(fsi_enable); |
| 349 | + gpio_get_params(cronus_sel); |
| 350 | + for (int i = 0; i < num_optionals; ++i) { |
| 351 | + gpio_get_params(&optionals[i]); |
| 352 | + } |
| 353 | } |
| 354 | |
| 355 | static void |
| 356 | -- |
| 357 | 2.20.1 |
| 358 | |