sec_pmsg.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * COPYRIGHT(C) 2016-2023 Samsung Electronics Co., Ltd. All Right Reserved.
  4. */
  5. #define pr_fmt(fmt) KBUILD_MODNAME ":%s() " fmt, __func__
  6. #include <linux/kernel.h>
  7. #include <linux/memblock.h>
  8. #include <linux/module.h>
  9. #include <linux/mutex.h>
  10. #include <linux/of.h>
  11. #include <linux/of_address.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/pstore.h>
  14. #include <linux/sched/clock.h>
  15. #include <linux/slab.h>
  16. #include <linux/time.h>
  17. #include <linux/uaccess.h>
  18. #include <linux/samsung/sec_kunit.h>
  19. #include <linux/samsung/sec_of.h>
  20. #include <linux/samsung/debug/sec_boot_stat.h>
  21. #include <linux/samsung/debug/sec_debug.h>
  22. #include "sec_pmsg.h"
  23. /* This defines are for PSTORE */
  24. #define SS_LOGGER_LEVEL_HEADER (1)
  25. #define SS_LOGGER_LEVEL_PREFIX (2)
  26. #define SS_LOGGER_LEVEL_TEXT (3)
  27. #define SS_LOGGER_LEVEL_MAX (4)
  28. #define SS_LOGGER_SKIP_COUNT (4)
  29. #define SS_LOGGER_STRING_PAD (1)
  30. #define SS_LOGGER_HEADER_SIZE (80)
  31. #define SS_LOG_ID_MAIN (0)
  32. #define SS_LOG_ID_RADIO (1)
  33. #define SS_LOG_ID_EVENTS (2)
  34. #define SS_LOG_ID_SYSTEM (3)
  35. #define SS_LOG_ID_CRASH (4)
  36. #define SS_LOG_ID_KERNEL (5)
  37. static struct pmsg_drvdata *sec_pmsg __read_mostly;
  38. static char *pmsg_buf __read_mostly;
  39. static size_t pmsg_size __read_mostly;
  40. static size_t pmsg_idx;
  41. static void (*__pmsg_memcpy_toio)(void *, const void *, size_t) __read_mostly;
  42. static void notrace ____pmsg_memcpy_toio(void *dst, const void *src, size_t cnt)
  43. {
  44. memcpy_toio(dst, src, cnt);
  45. }
  46. static void notrace ____pmsg_memcpy(void *dst, const void *src, size_t cnt)
  47. {
  48. memcpy(dst, src, cnt);
  49. }
  50. static void notrace ____pmsg_memcpy_dummy(void *dst, const void *src, size_t cnt)
  51. {
  52. }
  53. static inline void __pmsg_logger(const char *buf, size_t size)
  54. {
  55. size_t f_len, s_len, remain_space;
  56. size_t idx;
  57. idx = pmsg_idx % pmsg_size;
  58. remain_space = pmsg_size - idx;
  59. f_len = min(size, remain_space);
  60. __pmsg_memcpy_toio(&(pmsg_buf[idx]), buf, f_len);
  61. s_len = size - f_len;
  62. if (unlikely(s_len))
  63. __pmsg_memcpy_toio(pmsg_buf, &buf[f_len], s_len);
  64. pmsg_idx += size;
  65. }
  66. __ss_static __ss_always_inline
  67. int ____logger_level_header(struct pmsg_logger *logger,
  68. struct logger_level_header_ctx *llhc)
  69. {
  70. u64 tv_kernel = llhc->tv_kernel;
  71. u64 rem_nsec;
  72. struct tm tm_buf;
  73. rem_nsec = do_div(tv_kernel, 1000000000);
  74. time64_to_tm(logger->tv_sec, 0, &tm_buf);
  75. return scnprintf(llhc->buffer, SS_LOGGER_HEADER_SIZE,
  76. "\n[%5llu.%06llu][%d:%16s] %02d-%02d "
  77. "%02d:%02d:%02d.%03d %5d %5d ",
  78. (unsigned long long)tv_kernel,
  79. (unsigned long long)rem_nsec / 1000,
  80. llhc->cpu, llhc->comm,
  81. tm_buf.tm_mon + 1, tm_buf.tm_mday,
  82. tm_buf.tm_hour, tm_buf.tm_min,
  83. tm_buf.tm_sec, logger->tv_nsec / 1000000,
  84. logger->pid, logger->tid);
  85. }
  86. static inline void __logger_level_header(struct pmsg_logger *logger,
  87. char *buffer, size_t count)
  88. {
  89. struct logger_level_header_ctx _llhc;
  90. struct logger_level_header_ctx *llhc = &_llhc;
  91. int buffer_len;
  92. if (IS_ENABLED(CONFIG_SEC_PMSG_USE_EVENT_LOG)
  93. && logger->id == SS_LOG_ID_EVENTS)
  94. return;
  95. llhc->cpu = raw_smp_processor_id();
  96. llhc->comm = current->comm;
  97. llhc->tv_kernel = local_clock();
  98. llhc->buffer = buffer;
  99. llhc->count = count;
  100. buffer_len = ____logger_level_header(logger, llhc);
  101. __pmsg_logger(buffer, buffer_len - 1);
  102. }
  103. __ss_static __ss_inline char ____logger_level_prefix(struct pmsg_logger *logger)
  104. {
  105. const char *prio_magic = "!.VDIWEFS";
  106. const size_t prio_magic_len = sizeof("!.VDIWEFS") - 1;
  107. size_t prio = (size_t)logger->msg[0];
  108. return prio < prio_magic_len ? prio_magic[prio] : '?';
  109. }
  110. static inline void __logger_level_prefix(struct pmsg_logger *logger,
  111. char *buffer, size_t count)
  112. {
  113. if (IS_ENABLED(CONFIG_SEC_PMSG_USE_EVENT_LOG) &&
  114. logger->id == SS_LOG_ID_EVENTS)
  115. return;
  116. buffer[0] = ____logger_level_prefix(logger);
  117. if (IS_ENABLED(CONFIG_SEC_PMSG_USE_EVENT_LOG))
  118. logger->msg[0] = 0xff;
  119. __pmsg_logger(buffer, 1);
  120. }
  121. static inline void __ss_logger_level_text_event_log(struct pmsg_logger *logger,
  122. char *buffer, size_t count)
  123. {
  124. /* TODO: CONFIG_SEC_PMSG_USE_EVENT_LOG (CONFIG_SEC_EVENT_LOG in
  125. * a legacy implementation) is never used, yet.
  126. * It's maybe deprecated and I'll implement it if it is required.
  127. */
  128. }
  129. static inline void ____logger_level_text(struct pmsg_logger *logger,
  130. char *buffer, size_t count)
  131. {
  132. char *eatnl = &buffer[count - SS_LOGGER_STRING_PAD];
  133. if (count == SS_LOGGER_SKIP_COUNT && *eatnl != '\0')
  134. return;
  135. if (count > 1 && *(uint16_t*)buffer == *(uint16_t *)"!@") {
  136. /* To prevent potential buffer overrun
  137. * put a null at the end of the buffer.
  138. */
  139. buffer[count - 1] = '\0';
  140. /* FIXME: print without a module and a function name */
  141. printk(KERN_INFO "%s\n", buffer);
  142. sec_boot_stat_add(buffer);
  143. }
  144. __pmsg_logger(buffer, count - 1);
  145. }
  146. static inline void __logger_level_text(struct pmsg_logger *logger,
  147. char *buffer, size_t count)
  148. {
  149. if (unlikely(logger->id == SS_LOG_ID_EVENTS)) {
  150. __ss_logger_level_text_event_log(logger, buffer, count);
  151. return;
  152. }
  153. ____logger_level_text(logger, buffer, count);
  154. }
  155. static inline int __logger_combine_pmsg(struct pmsg_logger *logger,
  156. char *buffer, size_t count, unsigned int level)
  157. {
  158. switch (level) {
  159. case SS_LOGGER_LEVEL_HEADER:
  160. __logger_level_header(logger, buffer, count);
  161. break;
  162. case SS_LOGGER_LEVEL_PREFIX:
  163. __logger_level_prefix(logger, buffer, count);
  164. break;
  165. case SS_LOGGER_LEVEL_TEXT:
  166. __logger_level_text(logger, buffer, count);
  167. break;
  168. default:
  169. pr_warn("unknown logger level : %u\n", level);
  170. break;
  171. }
  172. __pmsg_logger(" ", 1);
  173. return 0;
  174. }
  175. static __always_inline void __logger_write_user_pmsg_log_header(
  176. struct pmsg_logger *logger, char *buffer, size_t count)
  177. {
  178. struct ss_pmsg_log_header_t *pmsg_header =
  179. (struct ss_pmsg_log_header_t *)buffer;
  180. if (pmsg_header->magic != 'l') {
  181. __logger_combine_pmsg(logger, buffer, count, SS_LOGGER_LEVEL_TEXT);
  182. } else {
  183. logger->pid = pmsg_header->pid;
  184. logger->uid = pmsg_header->uid;
  185. logger->len = pmsg_header->len;
  186. }
  187. }
  188. static __always_inline void __logger_write_user_android_log_header(
  189. struct pmsg_logger *logger, char *buffer, size_t count)
  190. {
  191. struct ss_android_log_header_t *header =
  192. (struct ss_android_log_header_t *)buffer;
  193. logger->id = header->id;
  194. logger->tid = header->tid;
  195. logger->tv_sec = header->tv_sec;
  196. logger->tv_nsec = header->tv_nsec;
  197. if (logger->id > 7)
  198. __logger_combine_pmsg(logger, buffer, count, SS_LOGGER_LEVEL_TEXT);
  199. else
  200. __logger_combine_pmsg(logger, buffer, count, SS_LOGGER_LEVEL_HEADER);
  201. }
  202. static __always_inline int __pmsg_write_user(struct pstore_record *record,
  203. const char __user *buf, size_t count)
  204. {
  205. struct pmsg_drvdata *drvdata = record->psi->data;
  206. struct pmsg_logger *logger = drvdata->logger;
  207. char *big_buffer = NULL;
  208. char *buffer;
  209. int err;
  210. if (unlikely(count > MAX_BUFFER_SIZE)) {
  211. big_buffer = kmalloc(count, GFP_KERNEL);
  212. if (unlikely(!big_buffer))
  213. return -ENOMEM;
  214. buffer = big_buffer;
  215. } else {
  216. struct pmsg_buffer *buf =
  217. per_cpu_ptr(drvdata->buf, raw_smp_processor_id());
  218. buffer = &buf->buffer[0];
  219. }
  220. err = __copy_from_user(buffer, buf, count);
  221. if (unlikely(err))
  222. return -EFAULT;
  223. switch (count) {
  224. case sizeof(struct ss_pmsg_log_header_t):
  225. __logger_write_user_pmsg_log_header(logger, buffer, count);
  226. break;
  227. case sizeof(struct ss_android_log_header_t):
  228. __logger_write_user_android_log_header(logger, buffer, count);
  229. break;
  230. case sizeof(unsigned char):
  231. logger->msg[0] = buffer[0];
  232. __logger_combine_pmsg(logger, buffer, count, SS_LOGGER_LEVEL_PREFIX);
  233. break;
  234. default:
  235. __logger_combine_pmsg(logger, buffer, count, SS_LOGGER_LEVEL_TEXT);
  236. break;
  237. }
  238. kfree(big_buffer);
  239. return 0;
  240. }
  241. static int notrace sec_pmsg_write_user(struct pstore_record *record,
  242. const char __user *buf)
  243. {
  244. if (unlikely(record->type != PSTORE_TYPE_PMSG))
  245. return -EINVAL;
  246. return __pmsg_write_user(record, buf, record->size);
  247. }
  248. static ssize_t notrace sec_pmsg_read(struct pstore_record *record)
  249. {
  250. /* FIXME: I don't do anything. */
  251. return 0;
  252. }
  253. static int notrace sec_pmsg_write(struct pstore_record *record)
  254. {
  255. /* FIXME: I don't do anything. */
  256. return 0;
  257. }
  258. static struct pstore_info sec_pmsg_pstore = {
  259. .owner = THIS_MODULE,
  260. .name = "sec,pstore_pmsg",
  261. .read = sec_pmsg_read,
  262. .write = sec_pmsg_write,
  263. .write_user = sec_pmsg_write_user,
  264. .flags = PSTORE_FLAGS_PMSG,
  265. };
  266. static noinline int __pmsg_parse_dt_memory_region(struct builder *bd,
  267. struct device_node *np)
  268. {
  269. struct pmsg_drvdata *drvdata =
  270. container_of(bd, struct pmsg_drvdata, bd);
  271. struct device *dev = bd->dev;
  272. struct device_node *mem_np;
  273. struct reserved_mem *rmem;
  274. mem_np = of_parse_phandle(np, "memory-region", 0);
  275. if (!mem_np)
  276. return -EINVAL;
  277. rmem = of_reserved_mem_lookup(mem_np);
  278. if (!rmem) {
  279. dev_warn(dev, "failed to get a reserved memory (%s)\n",
  280. mem_np->name);
  281. return -EFAULT;
  282. }
  283. drvdata->rmem = rmem;
  284. return 0;
  285. }
  286. static bool __pmsg_is_in_reserved_mem_bound(
  287. const struct reserved_mem *rmem,
  288. phys_addr_t base, phys_addr_t size)
  289. {
  290. phys_addr_t rmem_base = rmem->base;
  291. phys_addr_t rmem_end = rmem_base + rmem->size - 1;
  292. phys_addr_t end = base + size - 1;
  293. if ((base >= rmem_base) && (end <= rmem_end))
  294. return true;
  295. return false;
  296. }
  297. static int __pmsg_use_partial_reserved_mem(
  298. struct pmsg_drvdata *drvdata, struct device_node *np)
  299. {
  300. struct reserved_mem *rmem = drvdata->rmem;
  301. phys_addr_t base;
  302. phys_addr_t size;
  303. int err;
  304. err = sec_of_parse_reg_prop(np, &base, &size);
  305. if (err)
  306. return err;
  307. if (!__pmsg_is_in_reserved_mem_bound(rmem, base, size))
  308. return -ERANGE;
  309. drvdata->paddr = base;
  310. drvdata->size = size;
  311. return 0;
  312. }
  313. static int __pmsg_use_entire_reserved_mem(
  314. struct pmsg_drvdata *drvdata)
  315. {
  316. struct reserved_mem *rmem = drvdata->rmem;
  317. drvdata->paddr = rmem->base;
  318. drvdata->size = rmem->size;
  319. return 0;
  320. }
  321. static noinline int __pmsg_parse_dt_splitted_reserved_mem(struct builder *bd,
  322. struct device_node *np)
  323. {
  324. struct pmsg_drvdata *drvdata =
  325. container_of(bd, struct pmsg_drvdata, bd);
  326. int err;
  327. if (of_property_read_bool(np, "sec,use-partial_reserved_mem"))
  328. err = __pmsg_use_partial_reserved_mem(drvdata, np);
  329. else
  330. err = __pmsg_use_entire_reserved_mem(drvdata);
  331. if (err)
  332. return -EFAULT;
  333. return 0;
  334. }
  335. static noinline int __pmsg_parse_dt_test_no_map(struct builder *bd,
  336. struct device_node *np)
  337. {
  338. struct pmsg_drvdata *drvdata =
  339. container_of(bd, struct pmsg_drvdata, bd);
  340. struct device_node *mem_np;
  341. mem_np = of_parse_phandle(np, "memory-region", 0);
  342. if (!mem_np)
  343. return -EINVAL;
  344. if (!of_property_read_bool(mem_np, "no-map")) {
  345. pmsg_buf = phys_to_virt(drvdata->paddr);
  346. __pmsg_memcpy_toio = ____pmsg_memcpy;
  347. drvdata->nomap = false;
  348. } else {
  349. __pmsg_memcpy_toio = ____pmsg_memcpy_toio;
  350. drvdata->nomap = true;
  351. }
  352. return 0;
  353. }
  354. #if IS_BUILTIN(CONFIG_SEC_PMSG)
  355. static __always_inline unsigned long __free_reserved_area(void *start, void *end, int poison, const char *s)
  356. {
  357. return free_reserved_area(start, end, poison, s);
  358. }
  359. #else
  360. /* FIXME: this is a copy of 'free_reserved_area' of 'page_alloc.c' */
  361. static unsigned long __free_reserved_area(void *start, void *end, int poison, const char *s)
  362. {
  363. void *pos;
  364. unsigned long pages = 0;
  365. start = (void *)PAGE_ALIGN((unsigned long)start);
  366. end = (void *)((unsigned long)end & PAGE_MASK);
  367. for (pos = start; pos < end; pos += PAGE_SIZE, pages++) {
  368. struct page *page = virt_to_page(pos);
  369. void *direct_map_addr;
  370. direct_map_addr = page_address(page);
  371. direct_map_addr = kasan_reset_tag(direct_map_addr);
  372. if ((unsigned int)poison <= 0xFF)
  373. memset(direct_map_addr, poison, PAGE_SIZE);
  374. free_reserved_page(page);
  375. }
  376. if (pages && s)
  377. pr_info("Freeing %s memory: %ldK\n",
  378. s, pages << (PAGE_SHIFT - 10));
  379. return pages;
  380. }
  381. #endif
  382. static void __pmsg_free_reserved_area(struct pmsg_drvdata *drvdata)
  383. {
  384. struct device *dev = drvdata->bd.dev;
  385. uint8_t *start;
  386. if (drvdata->nomap) {
  387. dev_warn(dev, "reserved_mem has 'no-map' and can't be freed\n");
  388. return;
  389. }
  390. start = (uint8_t *)phys_to_virt(drvdata->paddr);
  391. __free_reserved_area(start, start + drvdata->size, -1, "sec_pmsg");
  392. }
  393. __ss_static int __pmsg_handle_dt_debug_level(struct pmsg_drvdata *drvdata,
  394. struct device_node *np, unsigned int sec_dbg_level)
  395. {
  396. int err;
  397. err = sec_of_test_debug_level(np, "sec,debug_level", sec_dbg_level);
  398. if (err == -EINVAL) {
  399. __pmsg_free_reserved_area(drvdata);
  400. __pmsg_memcpy_toio = ____pmsg_memcpy_dummy;
  401. return -EPERM;
  402. }
  403. return 0;
  404. }
  405. static noinline int __pmsg_parse_dt_check_debug_level(struct builder *bd,
  406. struct device_node *np)
  407. {
  408. struct pmsg_drvdata *drvdata =
  409. container_of(bd, struct pmsg_drvdata, bd);
  410. unsigned int sec_dbg_level = sec_debug_level();
  411. int err;
  412. err = __pmsg_handle_dt_debug_level(drvdata, np, sec_dbg_level);
  413. if (err)
  414. dev_warn(bd->dev, "pmsg will not be stored\n");
  415. return 0;
  416. }
  417. static const struct dt_builder __pmsg_dt_builder[] = {
  418. DT_BUILDER(__pmsg_parse_dt_memory_region),
  419. DT_BUILDER(__pmsg_parse_dt_splitted_reserved_mem),
  420. DT_BUILDER(__pmsg_parse_dt_test_no_map),
  421. DT_BUILDER(__pmsg_parse_dt_check_debug_level),
  422. };
  423. static noinline int __pmsg_parse_dt(struct builder *bd)
  424. {
  425. return sec_director_parse_dt(bd, __pmsg_dt_builder,
  426. ARRAY_SIZE(__pmsg_dt_builder));
  427. }
  428. static noinline int __pmsg_prepare_logger(struct builder *bd)
  429. {
  430. struct pmsg_drvdata *drvdata =
  431. container_of(bd, struct pmsg_drvdata, bd);
  432. struct device *dev = bd->dev;
  433. struct pmsg_logger *logger;
  434. logger = devm_kmalloc(dev, sizeof(*drvdata->logger), GFP_KERNEL);
  435. if (!logger)
  436. return -ENOMEM;
  437. drvdata->logger = logger;
  438. return 0;
  439. }
  440. static noinline int __pmsg_prepare_buffer(struct builder *bd)
  441. {
  442. struct pmsg_drvdata *drvdata =
  443. container_of(bd, struct pmsg_drvdata, bd);
  444. struct device *dev = bd->dev;
  445. struct pmsg_buffer *buf;
  446. buf = devm_alloc_percpu(dev, struct pmsg_buffer);
  447. if (!buf)
  448. return -ENOMEM;
  449. drvdata->buf = buf;
  450. return 0;
  451. }
  452. static void *__pmsg_ioremap(struct pmsg_drvdata *drvdata)
  453. {
  454. struct device *dev = drvdata->bd.dev;
  455. if (pmsg_buf)
  456. return pmsg_buf;
  457. #if IS_ENABLED(CONFIG_HAS_IOMEM)
  458. return devm_ioremap(dev, drvdata->paddr, drvdata->size);
  459. #else
  460. dev = dev;
  461. return ioremap(drvdata->paddr, drvdata->size);
  462. #endif
  463. }
  464. static noinline int __pmsg_prepare_carveout(struct builder *bd)
  465. {
  466. struct pmsg_drvdata *drvdata =
  467. container_of(bd, struct pmsg_drvdata, bd);
  468. pmsg_buf = __pmsg_ioremap(drvdata);
  469. if (!pmsg_buf)
  470. return -EFAULT;
  471. pmsg_size = drvdata->size;
  472. pmsg_idx = 0;
  473. return 0;
  474. }
  475. static noinline int __pmsg_pstore_register(struct builder *bd)
  476. {
  477. struct pmsg_drvdata *drvdata =
  478. container_of(bd, struct pmsg_drvdata, bd);
  479. sec_pmsg_pstore.data = drvdata;
  480. drvdata->pstore= &sec_pmsg_pstore;
  481. return pstore_register(drvdata->pstore);
  482. }
  483. static noinline void __pmsg_pstore_unregister(struct builder *bd)
  484. {
  485. struct pmsg_drvdata *drvdata =
  486. container_of(bd, struct pmsg_drvdata, bd);
  487. sec_pmsg_pstore.data = NULL;
  488. pstore_unregister(drvdata->pstore);
  489. }
  490. static noinline int __pmsg_probe_epilog(struct builder *bd)
  491. {
  492. struct pmsg_drvdata *drvdata =
  493. container_of(bd, struct pmsg_drvdata, bd);
  494. struct device *dev = bd->dev;
  495. dev_set_drvdata(dev, drvdata);
  496. sec_pmsg = drvdata;
  497. return 0;
  498. }
  499. static noinline void __pmsg_remove_prolog(struct builder *bd)
  500. {
  501. sec_pmsg = NULL;
  502. }
  503. static int __pmsg_probe(struct platform_device *pdev,
  504. const struct dev_builder *builder, ssize_t n)
  505. {
  506. struct device *dev = &pdev->dev;
  507. struct pmsg_drvdata *drvdata;
  508. drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
  509. if (!drvdata)
  510. return -ENOMEM;
  511. drvdata->bd.dev = dev;
  512. return sec_director_probe_dev(&drvdata->bd, builder, n);
  513. }
  514. static int __pmsg_remove(struct platform_device *pdev,
  515. const struct dev_builder *builder, ssize_t n)
  516. {
  517. struct pmsg_drvdata *drvdata = platform_get_drvdata(pdev);
  518. sec_director_destruct_dev(&drvdata->bd, builder, n, n);
  519. return 0;
  520. }
  521. static const struct dev_builder __pmsg_dev_builder[] = {
  522. DEVICE_BUILDER(__pmsg_parse_dt, NULL),
  523. DEVICE_BUILDER(__pmsg_prepare_logger, NULL),
  524. DEVICE_BUILDER(__pmsg_prepare_buffer, NULL),
  525. DEVICE_BUILDER(__pmsg_prepare_carveout, NULL),
  526. DEVICE_BUILDER(__pmsg_pstore_register, __pmsg_pstore_unregister),
  527. DEVICE_BUILDER(__pmsg_probe_epilog, __pmsg_remove_prolog),
  528. };
  529. static int sec_pmsg_probe(struct platform_device *pdev)
  530. {
  531. return __pmsg_probe(pdev, __pmsg_dev_builder,
  532. ARRAY_SIZE(__pmsg_dev_builder));
  533. }
  534. static int sec_pmsg_remove(struct platform_device *pdev)
  535. {
  536. return __pmsg_remove(pdev, __pmsg_dev_builder,
  537. ARRAY_SIZE(__pmsg_dev_builder));
  538. }
  539. static const struct of_device_id sec_pmsg_match_table[] = {
  540. { .compatible = "samsung,pstore_pmsg" },
  541. {},
  542. };
  543. MODULE_DEVICE_TABLE(of, sec_pmsg_match_table);
  544. static struct platform_driver sec_pmsg_driver = {
  545. .driver = {
  546. .name = "sec,pmsg",
  547. .of_match_table = of_match_ptr(sec_pmsg_match_table),
  548. },
  549. .probe = sec_pmsg_probe,
  550. .remove = sec_pmsg_remove,
  551. };
  552. static int __init sec_pmsg_init(void)
  553. {
  554. return platform_driver_register(&sec_pmsg_driver);
  555. }
  556. module_init(sec_pmsg_init);
  557. static void __exit sec_pmsg_exit(void)
  558. {
  559. platform_driver_unregister(&sec_pmsg_driver);
  560. }
  561. module_exit(sec_pmsg_exit);
  562. MODULE_AUTHOR("Samsung Electronics");
  563. MODULE_DESCRIPTION("PSTORE backend for saving android platform log");
  564. MODULE_LICENSE("GPL v2");