blob: 8fdcc2de8c6f089e58efa23d7e8293169981255e [file] [log] [blame]
Cyril Burc85e34d2016-11-15 11:50:41 +11001/* Copyright 2016 IBM
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 */
16
17#include <assert.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <getopt.h>
21#include <limits.h>
22#include <poll.h>
23#include <stdbool.h>
24#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <syslog.h>
Michael Neuling899ebac2017-01-14 11:20:26 -060029#include <signal.h>
Cyril Burc85e34d2016-11-15 11:50:41 +110030#include <sys/ioctl.h>
31#include <sys/mman.h>
32#include <sys/stat.h>
33#include <sys/timerfd.h>
34#include <sys/types.h>
35#include <time.h>
36#include <unistd.h>
Andrew Jeffery78210b92017-01-13 13:06:09 +103037#include <inttypes.h>
Cyril Burc85e34d2016-11-15 11:50:41 +110038
39#include <mtd/mtd-abi.h>
40
41#include <linux/aspeed-lpc-ctrl.h>
42
43#include "mbox.h"
44#include "common.h"
45
46#define LPC_CTRL_PATH "/dev/aspeed-lpc-ctrl"
47
Michael Neuling622992b2017-01-17 11:09:15 -060048
49/* Put pulled fds first */
Cyril Burc85e34d2016-11-15 11:50:41 +110050#define MBOX_FD 0
Michael Neuling622992b2017-01-17 11:09:15 -060051#define POLL_FDS 1
Cyril Burc85e34d2016-11-15 11:50:41 +110052#define LPC_CTRL_FD 1
53#define MTD_FD 2
54#define TOTAL_FDS 3
55
56#define ALIGN_UP(_v, _a) (((_v) + (_a) - 1) & ~((_a) - 1))
57
58#define MSG_OUT(f_, ...) do { if (verbosity != MBOX_LOG_NONE) { mbox_log(LOG_INFO, f_, ##__VA_ARGS__); } } while(0)
59#define MSG_ERR(f_, ...) do { if (verbosity != MBOX_LOG_NONE) { mbox_log(LOG_ERR, f_, ##__VA_ARGS__); } } while(0)
60
61#define BOOT_HICR7 0x30000e00U
62#define BOOT_HICR8 0xfe0001ffU
63
64struct mbox_context {
65 struct pollfd fds[TOTAL_FDS];
66 void *lpc_mem;
67 uint32_t base;
68 uint32_t size;
69 uint32_t pgsize;
70 bool dirty;
71 uint32_t dirtybase;
72 uint32_t dirtysize;
73 struct mtd_info_user mtd_info;
Cyril Bure8f2de12017-01-17 16:56:02 +110074 uint32_t flash_size;
Cyril Burc85e34d2016-11-15 11:50:41 +110075};
76
77static int running = 1;
Michael Neuling899ebac2017-01-14 11:20:26 -060078static int sighup = 0;
Cyril Burc85e34d2016-11-15 11:50:41 +110079
Cyril Bur46233672017-01-16 13:33:26 +110080static int point_to_flash(struct mbox_context *context)
Cyril Burc85e34d2016-11-15 11:50:41 +110081{
Cyril Buref315c12017-01-19 10:49:34 +110082 struct aspeed_lpc_ctrl_mapping map = { 0 };
Cyril Bur46233672017-01-16 13:33:26 +110083 int r = 0;
84
Cyril Burc85e34d2016-11-15 11:50:41 +110085 /*
Cyril Bur46233672017-01-16 13:33:26 +110086 * Point it to the real flash for sanity.
Cyril Burc85e34d2016-11-15 11:50:41 +110087 *
Cyril Bur46233672017-01-16 13:33:26 +110088 * This function assumes 32MB of flash which means that that
89 * hostboot expects flash to be at 0x0e000000 - 0x0fffffff on the
90 * LPC bus. If the machine actually has 64MB of flash then the
91 * map.addr should be 0x0c000000. TODO
Cyril Burc85e34d2016-11-15 11:50:41 +110092 *
93 * Until hostboot learns how to talk to this daemon this hardcode will
94 * get hostboot going. Furthermore, when hostboot does learn to talk
95 * then this mapping is unnecessary and this code should be removed.
96 */
97
Cyril Bure8f2de12017-01-17 16:56:02 +110098 /*
99 * The mask is because the top nibble is the host LPC FW space, we
Cyril Buref315c12017-01-19 10:49:34 +1100100 * want space 0. The struct has been zeroed, best to be explicit
101 * though.
Cyril Bure8f2de12017-01-17 16:56:02 +1100102 */
103 map.addr = (0UL - context->flash_size) & 0x0fffffff;
104 map.size = context->flash_size;
Cyril Bur46233672017-01-16 13:33:26 +1100105 map.offset = 0;
106 map.window_type = ASPEED_LPC_CTRL_WINDOW_FLASH;
107 map.window_id = 0; /* Theres only one */
Cyril Burc85e34d2016-11-15 11:50:41 +1100108
109 MSG_OUT("Pointing HOST LPC bus at the actual flash\n");
Cyril Bure8f2de12017-01-17 16:56:02 +1100110 MSG_OUT("Assuming %dMB of flash: HOST LPC 0x%08x\n", context->flash_size >> 20,
111 map.addr);
Cyril Burc85e34d2016-11-15 11:50:41 +1100112
Michael Neuling899ebac2017-01-14 11:20:26 -0600113 if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_MAP, &map) == -1) {
Cyril Bur46233672017-01-16 13:33:26 +1100114 r = -errno;
115 MSG_ERR("Couldn't MAP the host LPC bus to the platform flash\n");
116 }
117
Cyril Burc85e34d2016-11-15 11:50:41 +1100118 return r;
119}
120
121static int flash_write(struct mbox_context *context, uint32_t pos, uint32_t len)
122{
123 int rc;
124 struct erase_info_user erase_info = {
125 .start = pos,
126 };
127
128 assert(context);
129
130 erase_info.length = ALIGN_UP(len, context->mtd_info.erasesize);
131
132 MSG_OUT("Erasing 0x%08x for 0x%08x (aligned: 0x%08x)\n", pos, len, erase_info.length);
Michael Neuling622992b2017-01-17 11:09:15 -0600133 if (ioctl(context->fds[MTD_FD].fd, MEMERASE, &erase_info) == -1) {
Cyril Burc85e34d2016-11-15 11:50:41 +1100134 MSG_ERR("Couldn't MEMERASE ioctl, flash write lost: %s\n", strerror(errno));
135 return -1;
136 }
137
Michael Neuling622992b2017-01-17 11:09:15 -0600138 if (lseek(context->fds[MTD_FD].fd, pos, SEEK_SET) == (off_t) -1) {
Cyril Burc85e34d2016-11-15 11:50:41 +1100139 MSG_ERR("Couldn't seek to 0x%08x into MTD, flash write lost: %s\n", pos, strerror(errno));
140 return -1;
141 }
142
143 while (erase_info.length) {
Michael Neuling622992b2017-01-17 11:09:15 -0600144 rc = write(context->fds[MTD_FD].fd, context->lpc_mem + pos, erase_info.length);
Cyril Burc85e34d2016-11-15 11:50:41 +1100145 if (rc == -1) {
146 MSG_ERR("Couldn't write to flash! Flash write lost: %s\n", strerror(errno));
147 return -1;
148 }
149 erase_info.length -= rc;
150 pos += rc;
151 }
152
153 return 0;
154}
155
156/* TODO: Add come consistency around the daemon exiting and either
157 * way, ensuring it responds.
158 * I'm in favour of an approach where it does its best to stay alive
159 * and keep talking, the hacky prototype was written the other way.
160 * This function is now inconsistent
161 */
162static int dispatch_mbox(struct mbox_context *context)
163{
164 int r = 0;
165 int len;
166 off_t pos;
167 uint8_t byte;
168 union mbox_regs resp, req = { 0 };
169 uint16_t sizepg, basepg, dirtypg;
170 uint32_t dirtycount;
Cyril Buref315c12017-01-19 10:49:34 +1100171 struct aspeed_lpc_ctrl_mapping map = { 0 };
Cyril Burc85e34d2016-11-15 11:50:41 +1100172
173 assert(context);
174
175 map.addr = context->base;
176 map.size = context->size;
177 map.offset = 0;
178 map.window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY;
179 map.window_id = 0; /* Theres only one */
180
181 MSG_OUT("Dispatched to mbox\n");
182 r = read(context->fds[MBOX_FD].fd, &req, sizeof(req.raw));
183 if (r < 0) {
184 r = -errno;
185 MSG_ERR("Couldn't read: %s\n", strerror(errno));
186 goto out;
187 }
188 if (r < sizeof(req.msg)) {
189 MSG_ERR("Short read: %d expecting %zu\n", r, sizeof(req.msg));
190 r = -1;
191 goto out;
192 }
193
194 /* We are NOT going to update the last two 'status' bytes */
195 memcpy(&resp, &req, sizeof(req.msg));
196
197 sizepg = context->size >> context->pgsize;
198 basepg = context->base >> context->pgsize;
199 MSG_OUT("Got data in with command %d\n", req.msg.command);
200 switch (req.msg.command) {
201 case MBOX_C_RESET_STATE:
202 /* Called by early hostboot? TODO */
203 resp.msg.response = MBOX_R_SUCCESS;
Cyril Bur46233672017-01-16 13:33:26 +1100204 r = point_to_flash(context);
Cyril Burc85e34d2016-11-15 11:50:41 +1100205 if (r) {
206 resp.msg.response = MBOX_R_SYSTEM_ERROR;
207 MSG_ERR("Couldn't point the LPC BUS back to actual flash\n");
208 }
209 break;
210 case MBOX_C_GET_MBOX_INFO:
211 /* TODO Freak if data.data[0] isn't 1 */
212 resp.msg.data[0] = 1;
213 put_u16(&resp.msg.data[1], sizepg);
214 put_u16(&resp.msg.data[3], sizepg);
215 resp.msg.response = MBOX_R_SUCCESS;
216 /* Wow that can't stay negated thats horrible */
217 MSG_OUT("LPC_CTRL_IOCTL_MAP to 0x%08x for 0x%08x\n", map.addr, map.size);
Michael Neuling622992b2017-01-17 11:09:15 -0600218 r = ioctl(context->fds[LPC_CTRL_FD].fd,
Cyril Burc85e34d2016-11-15 11:50:41 +1100219 ASPEED_LPC_CTRL_IOCTL_MAP, &map);
220 if (r < 0) {
221 r = -errno;
222 resp.msg.response = MBOX_R_SYSTEM_ERROR;
223 MSG_ERR("Couldn't MAP ioctl(): %s\n", strerror(errno));
224 }
225 break;
226 case MBOX_C_GET_FLASH_INFO:
227 put_u32(&resp.msg.data[0], context->mtd_info.size);
228 put_u32(&resp.msg.data[4], context->mtd_info.erasesize);
229 resp.msg.response = MBOX_R_SUCCESS;
230 break;
231 case MBOX_C_READ_WINDOW:
232 /*
233 * We could probably play tricks with LPC mapping.
234 * That would require kernel involvement.
235 * We could also always copy the relevant flash part to
236 * context->base even if it turns out that offset is in
237 * the window...
238 * This approach is easiest.
239 */
Andrew Jeffery78210b92017-01-13 13:06:09 +1030240 if (context->dirty) {
Michael Neuling622992b2017-01-17 11:09:15 -0600241 r = read(context->fds[MTD_FD].fd, context->lpc_mem, context->size);
Andrew Jeffery78210b92017-01-13 13:06:09 +1030242 if (r != context->size) {
243 MSG_ERR("Short read: %d expecting %"PRIu32"\n", r, context->size);
244 goto out;
245 }
246 }
Cyril Burc85e34d2016-11-15 11:50:41 +1100247 basepg += get_u16(&req.msg.data[0]);
248 put_u16(&resp.msg.data[0], basepg);
249 resp.msg.response = MBOX_R_SUCCESS;
250 context->dirty = false;
251 break;
252 case MBOX_C_CLOSE_WINDOW:
253 context->dirty = true;
254 break;
255 case MBOX_C_WRITE_WINDOW:
256 basepg += get_u16(&req.msg.data[0]);
257 put_u16(&resp.msg.data[0], basepg);
258 resp.msg.response = MBOX_R_SUCCESS;
259 context->dirtybase = basepg << context->pgsize;
260 break;
261 /* Optimise these later */
262 case MBOX_C_WRITE_DIRTY:
263 case MBOX_C_WRITE_FENCE:
264 dirtypg = get_u16(&req.msg.data[0]);
265 dirtycount = get_u32(&req.msg.data[2]);
266 if (dirtycount == 0) {
267 resp.msg.response = MBOX_R_PARAM_ERROR;
268 break;
269 }
270 /*
271 * dirtypg is actually offset within window so we probs
272 * need to know if the window isn't at zero
273 */
274 if (flash_write(context, dirtypg << context->pgsize, dirtycount) != 0) {
275 resp.msg.response = MBOX_R_WRITE_ERROR;
276 break;
277 }
278 resp.msg.response = MBOX_R_SUCCESS;
279 break;
280 case MBOX_C_ACK:
281 resp.msg.response = MBOX_R_SUCCESS;
282 pos = lseek(context->fds[MBOX_FD].fd, MBOX_BMC_BYTE, SEEK_SET);
283 if (pos != MBOX_BMC_BYTE) {
284 r = -errno;
285 MSG_ERR("Couldn't lseek() to byte %d: %s\n", MBOX_BMC_BYTE,
286 strerror(errno));
287 }
288 /*
289 * NAND what is in the hardware and the request.
290 * This prevents the host being able to SET bits, it can
291 * only request set ones be cleared.
292 */
293 byte = ~(req.msg.data[0] & req.raw[MBOX_BMC_BYTE]);
294 len = write(context->fds[MBOX_FD].fd, &byte, 1);
295 if (len != 1) {
296 r = -errno;
297 MSG_ERR("Couldn't write to BMC status reg: %s\n",
298 strerror(errno));
299 }
300 pos = lseek(context->fds[MBOX_FD].fd, 0, SEEK_SET);
301 if (pos != 0) {
302 r = -errno;
303 MSG_ERR("Couldn't reset MBOX offset to zero\n");
304 }
305 break;
306 case MBOX_C_COMPLETED_COMMANDS:
307 /* This implementation always completes before responding */
308 resp.msg.data[0] = 0;
309 resp.msg.response = MBOX_R_SUCCESS;
310 break;
311 default:
312 MSG_ERR("UNKNOWN MBOX COMMAND\n");
313 resp.msg.response = MBOX_R_PARAM_ERROR;
314 r = -1;
315 }
316
317 MSG_OUT("Writing response to MBOX regs\n");
318 len = write(context->fds[MBOX_FD].fd, &resp, sizeof(resp.msg));
319 if (len < sizeof(resp.msg)) {
320 r = -errno;
321 MSG_ERR("Didn't write the full response\n");
322 }
323
324out:
325 return r;
326}
327
Cyril Burf0409b92017-01-25 11:02:20 +1100328
329#define CHUNKSIZE (64 * 1024)
330
Michael Neuling899ebac2017-01-14 11:20:26 -0600331int copy_flash(struct mbox_context *context)
332{
333 int r;
Cyril Burf0409b92017-01-25 11:02:20 +1100334 int readsize = CHUNKSIZE;
335 int offset = 0;
Michael Neuling899ebac2017-01-14 11:20:26 -0600336
337 /*
338 * Copy flash into RAM early, same time.
339 * The kernel has created the LPC->AHB mapping also, which means
340 * flash should work.
341 * Ideally we tell the kernel whats up and when to do stuff...
342 */
343 MSG_OUT("Loading flash into ram at %p for 0x%08x bytes\n",
344 context->lpc_mem, context->size);
345 if (lseek(context->fds[MTD_FD].fd, 0, SEEK_SET) != 0) {
346 r = -errno;
347 MSG_ERR("Couldn't reset MBOX pos to zero\n");
348 return r;
349 }
Cyril Burf0409b92017-01-25 11:02:20 +1100350 while (readsize) {
351 r = read(context->fds[MTD_FD].fd, context->lpc_mem + offset, readsize);
352 if (r != readsize) {
353 r = -errno;
354 MSG_ERR("Couldn't copy mtd into ram: %d\n", r);
355 return r;
356 }
357 offset += readsize;
358 readsize = context->size - offset;
359 if (readsize > CHUNKSIZE)
360 readsize = CHUNKSIZE;
Michael Neuling899ebac2017-01-14 11:20:26 -0600361 }
362 return 0;
363}
364
365void signal_hup(int signum, siginfo_t *info, void *uc)
366{
367 sighup = 1;
368}
369
Cyril Burc85e34d2016-11-15 11:50:41 +1100370static void usage(const char *name)
371{
Cyril Bure8f2de12017-01-17 16:56:02 +1100372 fprintf(stderr, "Usage %s [ -v[v] | --syslog ] --flash=size[K | M]\n", name);
373 fprintf(stderr, "\t--flash size[K | M]\t Map the flash for the according to 'size' in Kilobytes or Megabytes\n");
Cyril Burc85e34d2016-11-15 11:50:41 +1100374 fprintf(stderr, "\t--verbose\t Be [more] verbose\n");
375 fprintf(stderr, "\t--syslog\t Log output to syslog (pointless without -v)\n\n");
376}
377
378int main(int argc, char *argv[])
379{
380 struct mbox_context *context;
381 const char *name = argv[0];
382 char *pnor_filename = NULL;
383 int opt, polled, r, i;
Cyril Buref315c12017-01-19 10:49:34 +1100384 struct aspeed_lpc_ctrl_mapping map = { 0 };
Michael Neuling899ebac2017-01-14 11:20:26 -0600385 struct sigaction act;
Cyril Bure8f2de12017-01-17 16:56:02 +1100386 char *endptr;
Cyril Burc85e34d2016-11-15 11:50:41 +1100387
388 static const struct option long_options[] = {
Cyril Bure8f2de12017-01-17 16:56:02 +1100389 { "flash", required_argument, 0, 'f' },
390 { "verbose", no_argument, 0, 'v' },
391 { "syslog", no_argument, 0, 's' },
392 { 0, 0, 0, 0 }
Cyril Burc85e34d2016-11-15 11:50:41 +1100393 };
394
395 context = calloc(1, sizeof(*context));
396 for (i = 0; i < TOTAL_FDS; i++)
397 context->fds[i].fd = -1;
398
399 mbox_vlog = &mbox_log_console;
Cyril Bure8f2de12017-01-17 16:56:02 +1100400 while ((opt = getopt_long(argc, argv, "fv", long_options, NULL)) != -1) {
Cyril Burc85e34d2016-11-15 11:50:41 +1100401 switch (opt) {
402 case 0:
403 break;
Cyril Bure8f2de12017-01-17 16:56:02 +1100404 case 'f':
405 context->flash_size = strtol(optarg, &endptr, 0);
406 if (optarg == endptr) {
407 fprintf(stderr, "Unparseable flash size\n");
408 usage(name);
409 exit(EXIT_FAILURE);
410 }
411 if (*endptr == 'K') {
412 context->flash_size <<= 10;
413 } else if (*endptr == 'M') {
414 context->flash_size <<= 20;
415 } else if (*endptr != '\0') { /* Unknown units */
416 fprintf(stderr, "Unknown units '%c'\n", *endptr);
417 usage(name);
418 exit(EXIT_FAILURE);
419 }
420 break;
Cyril Burc85e34d2016-11-15 11:50:41 +1100421 case 'v':
422 verbosity++;
423 break;
424 case 's':
425 /* Avoid a double openlog() */
426 if (mbox_vlog != &vsyslog) {
427 openlog(PREFIX, LOG_ODELAY, LOG_DAEMON);
428 mbox_vlog = &vsyslog;
429 }
430 break;
431 default:
432 usage(name);
433 exit(EXIT_FAILURE);
434 }
435 }
436
Cyril Bure8f2de12017-01-17 16:56:02 +1100437 if (context->flash_size == 0) {
438 fprintf(stderr, "Must specify a non-zero flash size\n");
439 usage(name);
440 exit(EXIT_FAILURE);
441 }
442
Cyril Burc85e34d2016-11-15 11:50:41 +1100443 if (verbosity == MBOX_LOG_VERBOSE)
444 MSG_OUT("Verbose logging\n");
445
446 if (verbosity == MBOX_LOG_DEBUG)
447 MSG_OUT("Debug logging\n");
448
Michael Neuling899ebac2017-01-14 11:20:26 -0600449 MSG_OUT("Registering SigHUP hander\n");
450 act.sa_sigaction = signal_hup;
451 sigemptyset(&act.sa_mask);
452 act.sa_flags = SA_SIGINFO;
453 if (sigaction(SIGHUP, &act, NULL) < 0) {
454 perror("Registering SIGHUP");
455 exit(1);
456 }
457 sighup = 0;
458
Cyril Burc85e34d2016-11-15 11:50:41 +1100459 MSG_OUT("Starting\n");
460
461 MSG_OUT("Opening %s\n", MBOX_HOST_PATH);
462 context->fds[MBOX_FD].fd = open(MBOX_HOST_PATH, O_RDWR | O_NONBLOCK);
463 if (context->fds[MBOX_FD].fd < 0) {
464 r = -errno;
465 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
466 MBOX_HOST_PATH, strerror(errno));
467 goto finish;
468 }
469
470 MSG_OUT("Opening %s\n", LPC_CTRL_PATH);
471 context->fds[LPC_CTRL_FD].fd = open(LPC_CTRL_PATH, O_RDWR | O_SYNC);
472 if (context->fds[LPC_CTRL_FD].fd < 0) {
473 r = -errno;
474 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
475 LPC_CTRL_PATH, strerror(errno));
476 goto finish;
477 }
478
479 MSG_OUT("Getting buffer size...\n");
480 /* This may become more variable in the future */
481 context->pgsize = 12; /* 4K */
482 map.window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY;
483 map.window_id = 0; /* Theres only one */
484 if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_GET_SIZE,
485 &map) < 0) {
486 r = -errno;
487 MSG_OUT("fail\n");
488 MSG_ERR("Couldn't get lpc control buffer size: %s\n", strerror(-r));
489 goto finish;
490 }
491 /* And strip the first nibble, LPC access speciality */
492 context->size = map.size;
493 context->base = -context->size & 0x0FFFFFFF;
494
495 /* READ THE COMMENT AT THE START OF THIS FUNCTION! */
Cyril Bur46233672017-01-16 13:33:26 +1100496 r = point_to_flash(context);
Cyril Burc85e34d2016-11-15 11:50:41 +1100497 if (r) {
498 MSG_ERR("Failed to point the LPC BUS at the actual flash: %s\n",
499 strerror(-r));
500 goto finish;
501 }
502
503 MSG_OUT("Mapping %s for %u\n", LPC_CTRL_PATH, context->size);
504 context->lpc_mem = mmap(NULL, context->size, PROT_READ | PROT_WRITE, MAP_SHARED,
505 context->fds[LPC_CTRL_FD].fd, 0);
506 if (context->lpc_mem == MAP_FAILED) {
507 r = -errno;
508 MSG_ERR("Didn't manage to mmap %s: %s\n", LPC_CTRL_PATH, strerror(errno));
509 goto finish;
510 }
511
512 pnor_filename = get_dev_mtd();
513 if (!pnor_filename) {
514 MSG_ERR("Couldn't find the PNOR /dev/mtd partition\n");
515 r = -1;
516 goto finish;
517 }
518
519 MSG_OUT("Opening %s\n", pnor_filename);
520 context->fds[MTD_FD].fd = open(pnor_filename, O_RDWR);
521 if (context->fds[MTD_FD].fd < 0) {
522 r = -errno;
523 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
524 pnor_filename, strerror(errno));
525 goto finish;
526 }
527
528 if (ioctl(context->fds[MTD_FD].fd, MEMGETINFO, &context->mtd_info) == -1) {
529 MSG_ERR("Couldn't get information about MTD: %s\n", strerror(errno));
530 return -1;
531 }
532
Michael Neuling899ebac2017-01-14 11:20:26 -0600533 if (copy_flash(context))
Cyril Burc85e34d2016-11-15 11:50:41 +1100534 goto finish;
Cyril Burc85e34d2016-11-15 11:50:41 +1100535
536 context->fds[MBOX_FD].events = POLLIN;
Cyril Burc85e34d2016-11-15 11:50:41 +1100537
Cyril Burd8f6d7a2017-01-10 18:11:16 +1100538 /* Test the single write facility by setting all the regs to 0xFF */
539 MSG_OUT("Setting all MBOX regs to 0xff individually...\n");
540 for (i = 0; i < MBOX_REG_BYTES; i++) {
541 uint8_t byte = 0xff;
542 off_t pos;
543 int len;
544
545 pos = lseek(context->fds[MBOX_FD].fd, i, SEEK_SET);
546 if (pos != i) {
547 MSG_ERR("Couldn't lseek() to byte %d: %s\n", i,
548 strerror(errno));
549 break;
550 }
551 len = write(context->fds[MBOX_FD].fd, &byte, 1);
552 if (len != 1) {
553 MSG_ERR("Couldn't write MBOX reg %d: %s\n", i,
554 strerror(errno));
555 break;
556 }
557 }
558 if (lseek(context->fds[MBOX_FD].fd, 0, SEEK_SET) != 0) {
559 r = -errno;
560 MSG_ERR("Couldn't reset MBOX pos to zero\n");
561 goto finish;
562 }
563
Cyril Burc85e34d2016-11-15 11:50:41 +1100564 MSG_OUT("Entering polling loop\n");
565 while (running) {
Michael Neuling622992b2017-01-17 11:09:15 -0600566 polled = poll(context->fds, POLL_FDS, 1000);
Cyril Burc85e34d2016-11-15 11:50:41 +1100567 if (polled == 0)
568 continue;
Michael Neuling899ebac2017-01-14 11:20:26 -0600569 if ((polled == -1) && (errno != -EINTR) && (sighup == 1)) {
570 /* Got sighup. reset to point to flash and
571 * reread flash */
Michael Neuling899ebac2017-01-14 11:20:26 -0600572 r = point_to_flash(context);
573 if (r) {
574 goto finish;
575 }
Michael Neuling899ebac2017-01-14 11:20:26 -0600576 r = copy_flash(context);
577 if (r)
578 goto finish;
Michael Neuling899ebac2017-01-14 11:20:26 -0600579 sighup = 0;
580 continue;
581 }
Cyril Burc85e34d2016-11-15 11:50:41 +1100582 if (polled < 0) {
583 r = -errno;
584 MSG_ERR("Error from poll(): %s\n", strerror(errno));
585 break;
586 }
587 r = dispatch_mbox(context);
588 if (r < 0) {
589 MSG_ERR("Error handling MBOX event: %s\n", strerror(-r));
590 break;
591 }
592 }
593
594 MSG_OUT("Exiting\n");
595
Cyril Burc85e34d2016-11-15 11:50:41 +1100596finish:
597 if (context->lpc_mem)
598 munmap(context->lpc_mem, context->size);
599
600 free(pnor_filename);
601 close(context->fds[MTD_FD].fd);
602 close(context->fds[LPC_CTRL_FD].fd);
603 close(context->fds[MBOX_FD].fd);
604 free(context);
605
606 return r;
607}
608