1 /* 2 * IBM Real-Time Linux driver 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 * Copyright (C) IBM Corporation, 2010 19 * 20 * Author: Keith Mannthey <kmannth@us.ibm.com> 21 * Vernon Mauery <vernux@us.ibm.com> 22 * 23 */ 24 25 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 26 27 #include <linux/kernel.h> 28 #include <linux/delay.h> 29 #include <linux/module.h> 30 #include <linux/io.h> 31 #include <linux/dmi.h> 32 #include <linux/efi.h> 33 #include <linux/mutex.h> 34 #include <asm/bios_ebda.h> 35 36 #include <asm-generic/io-64-nonatomic-lo-hi.h> 37 38 static bool force; 39 module_param(force, bool, 0); 40 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); 41 42 static bool debug; 43 module_param(debug, bool, 0644); 44 MODULE_PARM_DESC(debug, "Show debug output"); 45 46 MODULE_LICENSE("GPL"); 47 MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>"); 48 MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>"); 49 50 #define RTL_ADDR_TYPE_IO 1 51 #define RTL_ADDR_TYPE_MMIO 2 52 53 #define RTL_CMD_ENTER_PRTM 1 54 #define RTL_CMD_EXIT_PRTM 2 55 56 /* The RTL table as presented by the EBDA: */ 57 struct ibm_rtl_table { 58 char signature[5]; /* signature should be "_RTL_" */ 59 u8 version; 60 u8 rt_status; 61 u8 command; 62 u8 command_status; 63 u8 cmd_address_type; 64 u8 cmd_granularity; 65 u8 cmd_offset; 66 u16 reserve1; 67 u32 cmd_port_address; /* platform dependent address */ 68 u32 cmd_port_value; /* platform dependent value */ 69 } __attribute__((packed)); 70 71 /* to locate "_RTL_" signature do a masked 5-byte integer compare */ 72 #define RTL_SIGNATURE 0x0000005f4c54525fULL 73 #define RTL_MASK 0x000000ffffffffffULL 74 75 #define RTL_DEBUG(fmt, ...) \ 76 do { \ 77 if (debug) \ 78 pr_info(fmt, ##__VA_ARGS__); \ 79 } while (0) 80 81 static DEFINE_MUTEX(rtl_lock); 82 static struct ibm_rtl_table __iomem *rtl_table; 83 static void __iomem *ebda_map; 84 static void __iomem *rtl_cmd_addr; 85 static u8 rtl_cmd_type; 86 static u8 rtl_cmd_width; 87 88 static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len) 89 { 90 if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO) 91 return ioremap(addr, len); 92 return ioport_map(addr, len); 93 } 94 95 static void rtl_port_unmap(void __iomem *addr) 96 { 97 if (addr && rtl_cmd_type == RTL_ADDR_TYPE_MMIO) 98 iounmap(addr); 99 else 100 ioport_unmap(addr); 101 } 102 103 static int ibm_rtl_write(u8 value) 104 { 105 int ret = 0, count = 0; 106 static u32 cmd_port_val; 107 108 RTL_DEBUG("%s(%d)\n", __func__, value); 109 110 value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM; 111 112 mutex_lock(&rtl_lock); 113 114 if (ioread8(&rtl_table->rt_status) != value) { 115 iowrite8(value, &rtl_table->command); 116 117 switch (rtl_cmd_width) { 118 case 8: 119 cmd_port_val = ioread8(&rtl_table->cmd_port_value); 120 RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val); 121 iowrite8((u8)cmd_port_val, rtl_cmd_addr); 122 break; 123 case 16: 124 cmd_port_val = ioread16(&rtl_table->cmd_port_value); 125 RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val); 126 iowrite16((u16)cmd_port_val, rtl_cmd_addr); 127 break; 128 case 32: 129 cmd_port_val = ioread32(&rtl_table->cmd_port_value); 130 RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val); 131 iowrite32(cmd_port_val, rtl_cmd_addr); 132 break; 133 } 134 135 while (ioread8(&rtl_table->command)) { 136 msleep(10); 137 if (count++ > 500) { 138 pr_err("Hardware not responding to " 139 "mode switch request\n"); 140 ret = -EIO; 141 break; 142 } 143 144 } 145 146 if (ioread8(&rtl_table->command_status)) { 147 RTL_DEBUG("command_status reports failed command\n"); 148 ret = -EIO; 149 } 150 } 151 152 mutex_unlock(&rtl_lock); 153 return ret; 154 } 155 156 static ssize_t rtl_show_version(struct device *dev, 157 struct device_attribute *attr, 158 char *buf) 159 { 160 return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version)); 161 } 162 163 static ssize_t rtl_show_state(struct device *dev, 164 struct device_attribute *attr, 165 char *buf) 166 { 167 return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status)); 168 } 169 170 static ssize_t rtl_set_state(struct device *dev, 171 struct device_attribute *attr, 172 const char *buf, 173 size_t count) 174 { 175 ssize_t ret; 176 177 if (count < 1 || count > 2) 178 return -EINVAL; 179 180 switch (buf[0]) { 181 case '0': 182 ret = ibm_rtl_write(0); 183 break; 184 case '1': 185 ret = ibm_rtl_write(1); 186 break; 187 default: 188 ret = -EINVAL; 189 } 190 if (ret >= 0) 191 ret = count; 192 193 return ret; 194 } 195 196 static struct bus_type rtl_subsys = { 197 .name = "ibm_rtl", 198 .dev_name = "ibm_rtl", 199 }; 200 201 static DEVICE_ATTR(version, S_IRUGO, rtl_show_version, NULL); 202 static DEVICE_ATTR(state, 0600, rtl_show_state, rtl_set_state); 203 204 static struct device_attribute *rtl_attributes[] = { 205 &dev_attr_version, 206 &dev_attr_state, 207 NULL 208 }; 209 210 211 static int rtl_setup_sysfs(void) { 212 int ret, i; 213 214 ret = subsys_system_register(&rtl_subsys, NULL); 215 if (!ret) { 216 for (i = 0; rtl_attributes[i]; i ++) 217 device_create_file(rtl_subsys.dev_root, rtl_attributes[i]); 218 } 219 return ret; 220 } 221 222 static void rtl_teardown_sysfs(void) { 223 int i; 224 for (i = 0; rtl_attributes[i]; i ++) 225 device_remove_file(rtl_subsys.dev_root, rtl_attributes[i]); 226 bus_unregister(&rtl_subsys); 227 } 228 229 230 static struct dmi_system_id __initdata ibm_rtl_dmi_table[] = { 231 { \ 232 .matches = { \ 233 DMI_MATCH(DMI_SYS_VENDOR, "IBM"), \ 234 }, \ 235 }, 236 { } 237 }; 238 239 static int __init ibm_rtl_init(void) { 240 unsigned long ebda_addr, ebda_size; 241 unsigned int ebda_kb; 242 int ret = -ENODEV, i; 243 244 if (force) 245 pr_warn("module loaded by force\n"); 246 /* first ensure that we are running on IBM HW */ 247 else if (efi_enabled(EFI_BOOT) || !dmi_check_system(ibm_rtl_dmi_table)) 248 return -ENODEV; 249 250 /* Get the address for the Extended BIOS Data Area */ 251 ebda_addr = get_bios_ebda(); 252 if (!ebda_addr) { 253 RTL_DEBUG("no BIOS EBDA found\n"); 254 return -ENODEV; 255 } 256 257 ebda_map = ioremap(ebda_addr, 4); 258 if (!ebda_map) 259 return -ENOMEM; 260 261 /* First word in the EDBA is the Size in KB */ 262 ebda_kb = ioread16(ebda_map); 263 RTL_DEBUG("EBDA is %d kB\n", ebda_kb); 264 265 if (ebda_kb == 0) 266 goto out; 267 268 iounmap(ebda_map); 269 ebda_size = ebda_kb*1024; 270 271 /* Remap the whole table */ 272 ebda_map = ioremap(ebda_addr, ebda_size); 273 if (!ebda_map) 274 return -ENOMEM; 275 276 /* search for the _RTL_ signature at the start of the table */ 277 for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) { 278 struct ibm_rtl_table __iomem * tmp; 279 tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i); 280 if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) { 281 phys_addr_t addr; 282 unsigned int plen; 283 RTL_DEBUG("found RTL_SIGNATURE at %p\n", tmp); 284 rtl_table = tmp; 285 /* The address, value, width and offset are platform 286 * dependent and found in the ibm_rtl_table */ 287 rtl_cmd_width = ioread8(&rtl_table->cmd_granularity); 288 rtl_cmd_type = ioread8(&rtl_table->cmd_address_type); 289 RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n", 290 rtl_cmd_width, rtl_cmd_type); 291 addr = ioread32(&rtl_table->cmd_port_address); 292 RTL_DEBUG("addr = %#llx\n", (unsigned long long)addr); 293 plen = rtl_cmd_width/sizeof(char); 294 rtl_cmd_addr = rtl_port_map(addr, plen); 295 RTL_DEBUG("rtl_cmd_addr = %p\n", rtl_cmd_addr); 296 if (!rtl_cmd_addr) { 297 ret = -ENOMEM; 298 break; 299 } 300 ret = rtl_setup_sysfs(); 301 break; 302 } 303 } 304 305 out: 306 if (ret) { 307 iounmap(ebda_map); 308 rtl_port_unmap(rtl_cmd_addr); 309 } 310 311 return ret; 312 } 313 314 static void __exit ibm_rtl_exit(void) 315 { 316 if (rtl_table) { 317 RTL_DEBUG("cleaning up"); 318 /* do not leave the machine in SMI-free mode */ 319 ibm_rtl_write(0); 320 /* unmap, unlink and remove all traces */ 321 rtl_teardown_sysfs(); 322 iounmap(ebda_map); 323 rtl_port_unmap(rtl_cmd_addr); 324 } 325 } 326 327 module_init(ibm_rtl_init); 328 module_exit(ibm_rtl_exit); 329