1 /* 2 * Mailbox Daemon LPC Helpers 3 * 4 * Copyright 2016 IBM 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 */ 19 20 #define _GNU_SOURCE 21 #include <assert.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <getopt.h> 25 #include <limits.h> 26 #include <poll.h> 27 #include <stdbool.h> 28 #include <stdint.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <syslog.h> 33 #include <signal.h> 34 #include <sys/ioctl.h> 35 #include <sys/mman.h> 36 #include <sys/stat.h> 37 #include <sys/timerfd.h> 38 #include <sys/types.h> 39 #include <time.h> 40 #include <unistd.h> 41 #include <inttypes.h> 42 43 #include "mbox.h" 44 #include "common.h" 45 #include "mboxd_lpc.h" 46 #include "mboxd_flash.h" 47 #include <linux/aspeed-lpc-ctrl.h> 48 49 #define LPC_CTRL_PATH "/dev/aspeed-lpc-ctrl" 50 51 int __init_lpc_dev(struct mbox_context *context, const char *path) 52 { 53 struct aspeed_lpc_ctrl_mapping map = { 54 .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY, 55 .window_id = 0, /* There's only one */ 56 .flags = 0, 57 .addr = 0, 58 .offset = 0, 59 .size = 0 60 }; 61 int fd; 62 63 /* Open LPC Device */ 64 MSG_OUT("Opening %s\n", path); 65 fd = open(path, O_RDWR | O_SYNC); 66 if (fd < 0) { 67 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", 68 path, strerror(errno)); 69 return -errno; 70 } 71 72 context->fds[LPC_CTRL_FD].fd = fd; 73 74 /* Find Size of Reserved Memory Region */ 75 MSG_OUT("Getting buffer size...\n"); 76 if (ioctl(fd, ASPEED_LPC_CTRL_IOCTL_GET_SIZE, &map) < 0) { 77 MSG_ERR("Couldn't get lpc control buffer size: %s\n", 78 strerror(errno)); 79 return -errno; 80 } 81 82 context->mem_size = map.size; 83 /* Map at the top of the 28-bit LPC firmware address space-0 */ 84 context->lpc_base = 0x0FFFFFFF & -context->mem_size; 85 86 /* mmap the Reserved Memory Region */ 87 MSG_OUT("Mapping in %u bytes of %s\n", context->mem_size, path); 88 context->mem = mmap(NULL, context->mem_size, PROT_READ | PROT_WRITE, 89 MAP_SHARED, fd, 0); 90 if (context->mem == MAP_FAILED) { 91 MSG_ERR("Failed to map %s: %s\n", path, strerror(errno)); 92 return -errno; 93 } 94 95 return 0; 96 } 97 98 int init_lpc_dev(struct mbox_context *context) 99 { 100 return __init_lpc_dev(context, LPC_CTRL_PATH); 101 } 102 103 void free_lpc_dev(struct mbox_context *context) 104 { 105 if (context->mem) { 106 munmap(context->mem, context->mem_size); 107 } 108 close(context->fds[LPC_CTRL_FD].fd); 109 } 110 111 /* 112 * point_to_flash() - Point the lpc bus mapping to the actual flash device 113 * @context: The mbox context pointer 114 * 115 * Return: 0 on success otherwise negative error code 116 */ 117 int point_to_flash(struct mbox_context *context) 118 { 119 struct aspeed_lpc_ctrl_mapping map = { 120 .window_type = ASPEED_LPC_CTRL_WINDOW_FLASH, 121 .window_id = 0, /* Theres only one */ 122 .flags = 0, 123 /* 124 * The mask is because the top nibble is the host LPC FW space, 125 * we want space 0. 126 */ 127 .addr = 0x0FFFFFFF & -context->flash_size, 128 .offset = 0, 129 .size = context->flash_size 130 }; 131 132 if (context->state & MAPS_FLASH) { 133 return 0; /* LPC Bus already points to flash */ 134 } 135 /* Don't let the host access flash while we're suspended */ 136 if (context->state & STATE_SUSPENDED) { 137 MSG_ERR("Can't point lpc mapping to flash while suspended\n"); 138 return -MBOX_R_PARAM_ERROR; 139 } 140 141 MSG_OUT("Pointing HOST LPC bus at the actual flash\n"); 142 MSG_OUT("Assuming %dMB of flash: HOST LPC 0x%08x\n", 143 context->flash_size >> 20, map.addr); 144 145 if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_MAP, &map) 146 == -1) { 147 MSG_ERR("Failed to point the LPC BUS at the actual flash: %s\n", 148 strerror(errno)); 149 return -MBOX_R_SYSTEM_ERROR; 150 } 151 152 context->state = ACTIVE_MAPS_FLASH; 153 /* 154 * Since the host now has access to the flash it can change it out from 155 * under us 156 */ 157 return set_flash_bytemap(context, 0, context->flash_size, FLASH_DIRTY); 158 } 159 160 /* 161 * point_to_memory() - Point the lpc bus mapping to the reserved memory region 162 * @context: The mbox context pointer 163 * 164 * Return: 0 on success otherwise negative error code 165 */ 166 int point_to_memory(struct mbox_context *context) 167 { 168 struct aspeed_lpc_ctrl_mapping map = { 169 .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY, 170 .window_id = 0, /* There's only one */ 171 .flags = 0, 172 .addr = context->lpc_base, 173 .offset = 0, 174 .size = context->mem_size 175 }; 176 177 if (context->state & MAPS_MEM) { 178 return 0; /* LPC Bus already points to reserved memory area */ 179 } 180 181 MSG_OUT("Pointing HOST LPC bus at memory region %p of size 0x%.8x\n", 182 context->mem, context->mem_size); 183 MSG_OUT("LPC address 0x%.8x\n", map.addr); 184 185 if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_MAP, 186 &map)) { 187 MSG_ERR("Failed to point the LPC BUS to memory: %s\n", 188 strerror(errno)); 189 return -MBOX_R_SYSTEM_ERROR; 190 } 191 192 /* LPC now maps memory (keep suspended state) */ 193 context->state = MAPS_MEM | (context->state & STATE_SUSPENDED); 194 195 return 0; 196 } 197