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) 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", LPC_CTRL_PATH); 65 fd = open(LPC_CTRL_PATH, O_RDWR | O_SYNC); 66 if (fd < 0) { 67 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", 68 LPC_CTRL_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 %s for %u\n", LPC_CTRL_PATH, context->mem_size); 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("Didn't manage to mmap %s: %s\n", LPC_CTRL_PATH, 92 strerror(errno)); 93 return -errno; 94 } 95 96 return 0; 97 } 98 99 void free_lpc_dev(struct mbox_context *context) 100 { 101 if (context->mem) { 102 munmap(context->mem, context->mem_size); 103 } 104 close(context->fds[LPC_CTRL_FD].fd); 105 } 106 107 /* 108 * point_to_flash() - Point the lpc bus mapping to the actual flash device 109 * @context: The mbox context pointer 110 * 111 * Return: 0 on success otherwise negative error code 112 */ 113 int point_to_flash(struct mbox_context *context) 114 { 115 struct aspeed_lpc_ctrl_mapping map = { 116 .window_type = ASPEED_LPC_CTRL_WINDOW_FLASH, 117 .window_id = 0, /* Theres only one */ 118 .flags = 0, 119 /* 120 * The mask is because the top nibble is the host LPC FW space, 121 * we want space 0. 122 */ 123 .addr = 0x0FFFFFFF & -context->flash_size, 124 .offset = 0, 125 .size = context->flash_size 126 }; 127 128 if (context->state & MAPS_FLASH) { 129 return 0; /* LPC Bus already points to flash */ 130 } 131 /* Don't let the host access flash while we're suspended */ 132 if (context->state & STATE_SUSPENDED) { 133 MSG_ERR("Can't point lpc mapping to flash while suspended\n"); 134 return -MBOX_R_PARAM_ERROR; 135 } 136 137 MSG_OUT("Pointing HOST LPC bus at the actual flash\n"); 138 MSG_OUT("Assuming %dMB of flash: HOST LPC 0x%08x\n", 139 context->flash_size >> 20, map.addr); 140 141 if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_MAP, &map) 142 == -1) { 143 MSG_ERR("Failed to point the LPC BUS at the actual flash: %s\n", 144 strerror(errno)); 145 return -MBOX_R_SYSTEM_ERROR; 146 } 147 148 context->state = ACTIVE_MAPS_FLASH; 149 /* 150 * Since the host now has access to the flash it can change it out from 151 * under us 152 */ 153 return set_flash_bytemap(context, 0, context->flash_size, FLASH_DIRTY); 154 } 155 156 /* 157 * point_to_memory() - Point the lpc bus mapping to the reserved memory region 158 * @context: The mbox context pointer 159 * 160 * Return: 0 on success otherwise negative error code 161 */ 162 int point_to_memory(struct mbox_context *context) 163 { 164 struct aspeed_lpc_ctrl_mapping map = { 165 .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY, 166 .window_id = 0, /* There's only one */ 167 .flags = 0, 168 .addr = context->lpc_base, 169 .offset = 0, 170 .size = context->mem_size 171 }; 172 173 if (context->state & MAPS_MEM) { 174 return 0; /* LPC Bus already points to reserved memory area */ 175 } 176 177 MSG_OUT("Pointing HOST LPC bus at memory region %p of size 0x%.8x\n", 178 context->mem, context->mem_size); 179 MSG_OUT("LPC address 0x%.8x\n", map.addr); 180 181 if (ioctl(context->fds[LPC_CTRL_FD].fd, ASPEED_LPC_CTRL_IOCTL_MAP, 182 &map)) { 183 MSG_ERR("Failed to point the LPC BUS to memory: %s\n", 184 strerror(errno)); 185 return -MBOX_R_SYSTEM_ERROR; 186 } 187 188 /* LPC now maps memory (keep suspended state) */ 189 context->state = MAPS_MEM | (context->state & STATE_SUSPENDED); 190 191 return 0; 192 } 193