156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli/* 256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * RAM Oops/Panic logger 356d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * 456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com> 556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * 656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * This program is free software; you can redistribute it and/or 756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * modify it under the terms of the GNU General Public License 856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * version 2 as published by the Free Software Foundation. 956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * 1056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * This program is distributed in the hope that it will be useful, but 1156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * WITHOUT ANY WARRANTY; without even the implied warranty of 1256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1356d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * General Public License for more details. 1456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * 1556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * You should have received a copy of the GNU General Public License 1656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * along with this program; if not, write to the Free Software 1756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 1856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * 02110-1301 USA 1956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli * 2056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli */ 2156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 220169256e4bbf29e507cdd1df5812c093d610f1d5Marco Stornelli#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 230169256e4bbf29e507cdd1df5812c093d610f1d5Marco Stornelli 2456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli#include <linux/kernel.h> 2583c1b31794a9e3cb30edabef7e57fbdbe129c5ceJames Bottomley#include <linux/err.h> 2656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli#include <linux/module.h> 2756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli#include <linux/kmsg_dump.h> 2856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli#include <linux/time.h> 2956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli#include <linux/io.h> 3056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli#include <linux/ioport.h> 31c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park#include <linux/platform_device.h> 3213aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli#include <linux/slab.h> 33c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park#include <linux/ramoops.h> 3456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 3556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli#define RAMOOPS_KERNMSG_HDR "====" 363e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache#define MIN_MEM_SIZE 4096UL 3756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 383e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordachestatic ulong record_size = MIN_MEM_SIZE; 393e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordachemodule_param(record_size, ulong, 0400); 403e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu IordacheMODULE_PARM_DESC(record_size, 413e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache "size of each dump done on oops/panic"); 4256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 4356d611a04fb2db77334e06274de4daed92e2c626Marco Stornellistatic ulong mem_address; 4456d611a04fb2db77334e06274de4daed92e2c626Marco Stornellimodule_param(mem_address, ulong, 0400); 4556d611a04fb2db77334e06274de4daed92e2c626Marco StornelliMODULE_PARM_DESC(mem_address, 4656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli "start of reserved RAM used to store oops/panic logs"); 4756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 4856d611a04fb2db77334e06274de4daed92e2c626Marco Stornellistatic ulong mem_size; 4956d611a04fb2db77334e06274de4daed92e2c626Marco Stornellimodule_param(mem_size, ulong, 0400); 5056d611a04fb2db77334e06274de4daed92e2c626Marco StornelliMODULE_PARM_DESC(mem_size, 5156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli "size of reserved RAM used to store oops/panic logs"); 5256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 5356d611a04fb2db77334e06274de4daed92e2c626Marco Stornellistatic int dump_oops = 1; 5456d611a04fb2db77334e06274de4daed92e2c626Marco Stornellimodule_param(dump_oops, int, 0600); 5556d611a04fb2db77334e06274de4daed92e2c626Marco StornelliMODULE_PARM_DESC(dump_oops, 5656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli "set to 1 to dump oopses, 0 to only dump panics (default 1)"); 5756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 5856d611a04fb2db77334e06274de4daed92e2c626Marco Stornellistatic struct ramoops_context { 5956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli struct kmsg_dumper dump; 6056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli void *virt_addr; 6156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli phys_addr_t phys_addr; 6256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli unsigned long size; 633e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache unsigned long record_size; 646b4d2a2733b9a17112f746d498c9f9a0427dcdd8Sergiu Iordache int dump_oops; 6556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli int count; 6656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli int max_count; 6756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli} oops_cxt; 6856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 6913aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornellistatic struct platform_device *dummy; 7013aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornellistatic struct ramoops_platform_data *dummy_data; 7113aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli 7256d611a04fb2db77334e06274de4daed92e2c626Marco Stornellistatic void ramoops_do_dump(struct kmsg_dumper *dumper, 7356d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli enum kmsg_dump_reason reason, const char *s1, unsigned long l1, 7456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli const char *s2, unsigned long l2) 7556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli{ 7656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli struct ramoops_context *cxt = container_of(dumper, 7756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli struct ramoops_context, dump); 7856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli unsigned long s1_start, s2_start; 7956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli unsigned long l1_cpy, l2_cpy; 801873bb8115e678ad9fd0aac9dbbc68383bc36e06Ahmed S. Darwish int res, hdr_size; 811873bb8115e678ad9fd0aac9dbbc68383bc36e06Ahmed S. Darwish char *buf, *buf_orig; 8256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli struct timeval timestamp; 8356d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 84fc2d557c74dc58294b9acc7231a2113ae59af97cSeiji Aguchi if (reason != KMSG_DUMP_OOPS && 85a3dd3323058d281abd584b15ad4c5b65064d7a61WANG Cong reason != KMSG_DUMP_PANIC) 86fc2d557c74dc58294b9acc7231a2113ae59af97cSeiji Aguchi return; 87fc2d557c74dc58294b9acc7231a2113ae59af97cSeiji Aguchi 8856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli /* Only dump oopses if dump_oops is set */ 896b4d2a2733b9a17112f746d498c9f9a0427dcdd8Sergiu Iordache if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops) 9056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli return; 9156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 923e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache buf = cxt->virt_addr + (cxt->count * cxt->record_size); 931873bb8115e678ad9fd0aac9dbbc68383bc36e06Ahmed S. Darwish buf_orig = buf; 941873bb8115e678ad9fd0aac9dbbc68383bc36e06Ahmed S. Darwish 953e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache memset(buf, '\0', cxt->record_size); 9656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR); 9756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli buf += res; 9856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli do_gettimeofday(×tamp); 9956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec); 10056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli buf += res; 10156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 1021873bb8115e678ad9fd0aac9dbbc68383bc36e06Ahmed S. Darwish hdr_size = buf - buf_orig; 1033e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache l2_cpy = min(l2, cxt->record_size - hdr_size); 1043e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache l1_cpy = min(l1, cxt->record_size - hdr_size - l2_cpy); 10556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 10656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli s2_start = l2 - l2_cpy; 10756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli s1_start = l1 - l1_cpy; 10856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 10956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli memcpy(buf, s1 + s1_start, l1_cpy); 11056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy); 11156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 11256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli cxt->count = (cxt->count + 1) % cxt->max_count; 11356d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli} 11456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 115c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Parkstatic int __init ramoops_probe(struct platform_device *pdev) 11656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli{ 117c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park struct ramoops_platform_data *pdata = pdev->dev.platform_data; 11856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli struct ramoops_context *cxt = &oops_cxt; 11956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli int err = -EINVAL; 12056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 1213e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache if (!pdata->mem_size || !pdata->record_size) { 1223e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache pr_err("The memory size and the record size must be " 1233e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache "non-zero\n"); 12456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli goto fail3; 12556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli } 12656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 127fdb5950754eb3dedb9fea7c8828d3e51d9dbc3f7Marco Stornelli pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); 128fdb5950754eb3dedb9fea7c8828d3e51d9dbc3f7Marco Stornelli pdata->record_size = rounddown_pow_of_two(pdata->record_size); 12956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 1303e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache /* Check for the minimum memory size */ 1313e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache if (pdata->mem_size < MIN_MEM_SIZE && 1323e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache pdata->record_size < MIN_MEM_SIZE) { 1333e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache pr_err("memory size too small, minium is %lu\n", MIN_MEM_SIZE); 13456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli goto fail3; 13556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli } 13656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 1373e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache if (pdata->mem_size < pdata->record_size) { 1383e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache pr_err("The memory size must be larger than the " 1393e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache "records size\n"); 1403e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache goto fail3; 1413e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache } 1423e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache 1433e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache cxt->max_count = pdata->mem_size / pdata->record_size; 14456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli cxt->count = 0; 14513aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli cxt->size = pdata->mem_size; 14613aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli cxt->phys_addr = pdata->mem_address; 1473e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache cxt->record_size = pdata->record_size; 1486b4d2a2733b9a17112f746d498c9f9a0427dcdd8Sergiu Iordache cxt->dump_oops = pdata->dump_oops; 14956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 15056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) { 1510169256e4bbf29e507cdd1df5812c093d610f1d5Marco Stornelli pr_err("request mem region failed\n"); 15256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli err = -EINVAL; 15356d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli goto fail3; 15456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli } 15556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 15656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli cxt->virt_addr = ioremap(cxt->phys_addr, cxt->size); 15756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli if (!cxt->virt_addr) { 1580169256e4bbf29e507cdd1df5812c093d610f1d5Marco Stornelli pr_err("ioremap failed\n"); 15956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli goto fail2; 16056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli } 16156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 16256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli cxt->dump.dump = ramoops_do_dump; 16356d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli err = kmsg_dump_register(&cxt->dump); 16456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli if (err) { 1650169256e4bbf29e507cdd1df5812c093d610f1d5Marco Stornelli pr_err("registering kmsg dumper failed\n"); 16656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli goto fail1; 16756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli } 16856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 169c755201eb5c1e09f3477d0e83ae1e3aadac0e8d1Kees Cook /* 170c755201eb5c1e09f3477d0e83ae1e3aadac0e8d1Kees Cook * Update the module parameter variables as well so they are visible 171c755201eb5c1e09f3477d0e83ae1e3aadac0e8d1Kees Cook * through /sys/module/ramoops/parameters/ 172c755201eb5c1e09f3477d0e83ae1e3aadac0e8d1Kees Cook */ 173c755201eb5c1e09f3477d0e83ae1e3aadac0e8d1Kees Cook mem_size = pdata->mem_size; 174c755201eb5c1e09f3477d0e83ae1e3aadac0e8d1Kees Cook mem_address = pdata->mem_address; 175c755201eb5c1e09f3477d0e83ae1e3aadac0e8d1Kees Cook record_size = pdata->record_size; 176c755201eb5c1e09f3477d0e83ae1e3aadac0e8d1Kees Cook dump_oops = pdata->dump_oops; 177c755201eb5c1e09f3477d0e83ae1e3aadac0e8d1Kees Cook 17856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli return 0; 17956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 18056d611a04fb2db77334e06274de4daed92e2c626Marco Stornellifail1: 18156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli iounmap(cxt->virt_addr); 18256d611a04fb2db77334e06274de4daed92e2c626Marco Stornellifail2: 18356d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli release_mem_region(cxt->phys_addr, cxt->size); 18456d611a04fb2db77334e06274de4daed92e2c626Marco Stornellifail3: 18556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli return err; 18656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli} 18756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 188c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Parkstatic int __exit ramoops_remove(struct platform_device *pdev) 18956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli{ 19056d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli struct ramoops_context *cxt = &oops_cxt; 19156d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 19256d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli if (kmsg_dump_unregister(&cxt->dump) < 0) 1930169256e4bbf29e507cdd1df5812c093d610f1d5Marco Stornelli pr_warn("could not unregister kmsg_dumper\n"); 19456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 19556d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli iounmap(cxt->virt_addr); 19656d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli release_mem_region(cxt->phys_addr, cxt->size); 197c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park return 0; 19856d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli} 19956d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 200c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Parkstatic struct platform_driver ramoops_driver = { 201c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park .remove = __exit_p(ramoops_remove), 202c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park .driver = { 203c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park .name = "ramoops", 204c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park .owner = THIS_MODULE, 205c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park }, 206c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park}; 207c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park 208c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Parkstatic int __init ramoops_init(void) 209c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park{ 21013aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli int ret; 21113aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli ret = platform_driver_probe(&ramoops_driver, ramoops_probe); 21213aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli if (ret == -ENODEV) { 21313aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli /* 21413aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli * If we didn't find a platform device, we use module parameters 21513aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli * building platform data on the fly. 21613aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli */ 2170169256e4bbf29e507cdd1df5812c093d610f1d5Marco Stornelli pr_info("platform device not found, using module parameters\n"); 21813aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli dummy_data = kzalloc(sizeof(struct ramoops_platform_data), 21913aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli GFP_KERNEL); 22013aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli if (!dummy_data) 22113aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli return -ENOMEM; 22213aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli dummy_data->mem_size = mem_size; 22313aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli dummy_data->mem_address = mem_address; 2243e5c4fadb9943c7539364d0c8425db071a2020e4Sergiu Iordache dummy_data->record_size = record_size; 2256b4d2a2733b9a17112f746d498c9f9a0427dcdd8Sergiu Iordache dummy_data->dump_oops = dump_oops; 22613aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli dummy = platform_create_bundle(&ramoops_driver, ramoops_probe, 22713aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli NULL, 0, dummy_data, 22813aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli sizeof(struct ramoops_platform_data)); 22913aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli 23013aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli if (IS_ERR(dummy)) 23113aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli ret = PTR_ERR(dummy); 23213aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli else 23313aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli ret = 0; 23413aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli } 23513aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli 23613aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli return ret; 237c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park} 238c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park 239c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Parkstatic void __exit ramoops_exit(void) 240c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park{ 241c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park platform_driver_unregister(&ramoops_driver); 24213aefd7293e7a697bbf452fca65e69cc1fa8a31cMarco Stornelli kfree(dummy_data); 243c3b92ce9e75f6353104fc7f8e32fb9fdb2550ad0Kyungmin Park} 24456d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 24556d611a04fb2db77334e06274de4daed92e2c626Marco Stornellimodule_init(ramoops_init); 24656d611a04fb2db77334e06274de4daed92e2c626Marco Stornellimodule_exit(ramoops_exit); 24756d611a04fb2db77334e06274de4daed92e2c626Marco Stornelli 24856d611a04fb2db77334e06274de4daed92e2c626Marco StornelliMODULE_LICENSE("GPL"); 24956d611a04fb2db77334e06274de4daed92e2c626Marco StornelliMODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>"); 25056d611a04fb2db77334e06274de4daed92e2c626Marco StornelliMODULE_DESCRIPTION("RAM Oops/Panic logger/driver"); 251