Advertisement
Guest User

Untitled

a guest
Oct 19th, 2015
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 12.30 KB | None | 0 0
  1. commit 91b5c51494989ac111eed2ca0c2d2fcd0cb88423
  2. Author: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
  3. Date:   Wed Dec 4 19:32:00 2013 +0200
  4.  
  5.     OF: DT-Overlay configfs interface (v5)
  6.  
  7.     Add a runtime interface to using configfs for generic device tree overlay
  8.     usage. With it its possible to use device tree overlays without having
  9.     to use a per-platform overlay manager.
  10.  
  11.     Please see Documentation/devicetree/configfs-overlays.txt for more info.
  12.  
  13.     Changes since v4:
  14.     - Loading fix for multiple overlays as found out by
  15.       Geert Uytterhoeven <geert@linux-m68k.org>
  16.  
  17.     Changes since v3:
  18.     - Fixed compilation on SPARC & Xtensa
  19.  
  20.     Changes since v2:
  21.     - Removed ifdef CONFIG_OF_OVERLAY (since for now it's required)
  22.     - Created a documentation entry
  23.     - Slight rewording in Kconfig
  24.  
  25.     Changes since v1:
  26.     - of_resolve() -> of_resolve_phandles().
  27.  
  28.     Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
  29.  
  30. diff --git a/Documentation/devicetree/configfs-overlays.txt b/Documentation/devicetree/configfs-overlays.txt
  31. new file mode 100644
  32. index 0000000..5fa43e0
  33. --- /dev/null
  34. +++ b/Documentation/devicetree/configfs-overlays.txt
  35. @@ -0,0 +1,31 @@
  36. +Howto use the configfs overlay interface.
  37. +
  38. +A device-tree configfs entry is created in /config/device-tree/overlays
  39. +and and it is manipulated using standard file system I/O.
  40. +Note that this is a debug level interface, for use by developers and
  41. +not necessarily something accessed by normal users due to the
  42. +security implications of having direct access to the kernel's device tree.
  43. +
  44. +* To create an overlay you mkdir the directory:
  45. +
  46. +   # mkdir /config/device-tree/overlays/foo
  47. +
  48. +* Either you echo the overlay firmware file to the path property file.
  49. +
  50. +   # echo foo.dtbo >/config/device-tree/overlays/foo/path
  51. +
  52. +* Or you cat the contents of the overlay to the dtbo file
  53. +
  54. +   # cat foo.dtbo >/config/device-tree/overlays/foo/dtbo
  55. +
  56. +The overlay file will be applied, and devices will be created/destroyed
  57. +as required.
  58. +
  59. +To remove it simply rmdir the directory.
  60. +
  61. +   # rmdir /config/device-tree/overlays/foo
  62. +
  63. +The rationalle of the dual interface (firmware & direct copy) is that each is
  64. +better suited to different use patterns. The firmware interface is what's
  65. +intended to be used by hardware managers in the kernel, while the copy interface
  66. +make sense for developers (since it avoids problems with namespaces).
  67. diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
  68. index 59bb855..bbfe85f 100644
  69. --- a/drivers/of/Kconfig
  70. +++ b/drivers/of/Kconfig
  71. @@ -102,4 +102,11 @@ config OF_OVERLAY
  72.       While this option is selected automatically when needed, you can
  73.       enable it manually to improve device tree unit test coverage.
  74.  
  75. +config OF_CONFIGFS
  76. +   bool "Device Tree Overlay ConfigFS interface"
  77. +   select CONFIGFS_FS
  78. +   depends on OF_OVERLAY
  79. +   help
  80. +     Enable a simple user-space driven DT overlay interface.
  81. +
  82.  endif # OF
  83. diff --git a/drivers/of/Makefile b/drivers/of/Makefile
  84. index 156c072..46c8f57 100644
  85. --- a/drivers/of/Makefile
  86. +++ b/drivers/of/Makefile
  87. @@ -1,4 +1,5 @@
  88.  obj-y = base.o device.o platform.o
  89. +obj-$(CONFIG_OF_CONFIGFS) += configfs.o
  90.  obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
  91.  obj-$(CONFIG_OF_FLATTREE) += fdt.o
  92.  obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
  93. diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c
  94. new file mode 100644
  95. index 0000000..9fb1b35
  96. --- /dev/null
  97. +++ b/drivers/of/configfs.c
  98. @@ -0,0 +1,333 @@
  99. +/*
  100. + * Configfs entries for device-tree
  101. + *
  102. + * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
  103. + *
  104. + * This program is free software; you can redistribute it and/or
  105. + * modify it under the terms of the GNU General Public License
  106. + * as published by the Free Software Foundation; either version
  107. + * 2 of the License, or (at your option) any later version.
  108. + */
  109. +#include <linux/ctype.h>
  110. +#include <linux/cpu.h>
  111. +#include <linux/module.h>
  112. +#include <linux/of.h>
  113. +#include <linux/of_fdt.h>
  114. +#include <linux/spinlock.h>
  115. +#include <linux/sizes.h>
  116. +#include <linux/slab.h>
  117. +#include <linux/proc_fs.h>
  118. +#include <linux/configfs.h>
  119. +#include <linux/types.h>
  120. +#include <linux/stat.h>
  121. +#include <linux/limits.h>
  122. +#include <linux/file.h>
  123. +#include <linux/vmalloc.h>
  124. +#include <linux/firmware.h>
  125. +
  126. +#include "of_private.h"
  127. +
  128. +struct cfs_overlay_item {
  129. +   struct config_item  item;
  130. +
  131. +   char            path[PATH_MAX];
  132. +
  133. +   const struct firmware   *fw;
  134. +   struct device_node  *overlay;
  135. +   int         ov_id;
  136. +
  137. +   void            *dtbo;
  138. +   int         dtbo_size;
  139. +};
  140. +
  141. +static int create_overlay(struct cfs_overlay_item *overlay, void *blob)
  142. +{
  143. +   int err;
  144. +
  145. +   /* unflatten the tree */
  146. +   of_fdt_unflatten_tree(blob, &overlay->overlay);
  147. +   if (overlay->overlay == NULL) {
  148. +       pr_err("%s: failed to unflatten tree\n", __func__);
  149. +       err = -EINVAL;
  150. +       goto out_err;
  151. +   }
  152. +   pr_debug("%s: unflattened OK\n", __func__);
  153. +
  154. +   /* mark it as detached */
  155. +   of_node_set_flag(overlay->overlay, OF_DETACHED);
  156. +
  157. +   /* perform resolution */
  158. +   err = of_resolve_phandles(overlay->overlay);
  159. +   if (err != 0) {
  160. +       pr_err("%s: Failed to resolve tree\n", __func__);
  161. +       goto out_err;
  162. +   }
  163. +   pr_debug("%s: resolved OK\n", __func__);
  164. +
  165. +   err = of_overlay_create(overlay->overlay);
  166. +   if (err < 0) {
  167. +       pr_err("%s: Failed to create overlay (err=%d)\n",
  168. +               __func__, err);
  169. +       goto out_err;
  170. +   }
  171. +   overlay->ov_id = err;
  172. +
  173. +out_err:
  174. +   return err;
  175. +}
  176. +
  177. +static inline struct cfs_overlay_item *to_cfs_overlay_item(
  178. +       struct config_item *item)
  179. +{
  180. +   return item ? container_of(item, struct cfs_overlay_item, item) : NULL;
  181. +}
  182. +
  183. +CONFIGFS_ATTR_STRUCT(cfs_overlay_item);
  184. +#define CFS_OVERLAY_ITEM_ATTR(_name, _mode, _show, _store) \
  185. +struct cfs_overlay_item_attribute cfs_overlay_item_attr_##_name = \
  186. +   __CONFIGFS_ATTR(_name, _mode, _show, _store)
  187. +#define CFS_OVERLAY_ITEM_ATTR_RO(_name, _show) \
  188. +struct cfs_overlay_item_attribute cfs_overlay_item_attr_##_name = \
  189. +   __CONFIGFS_ATTR_RO(_name, _show)
  190. +
  191. +CONFIGFS_BIN_ATTR_STRUCT(cfs_overlay_item);
  192. +#define CFS_OVERLAY_ITEM_BIN_ATTR(_name, _mode, _read, _write, _priv, _max) \
  193. +struct cfs_overlay_item_bin_attribute cfs_overlay_item_bin_attr_##_name = \
  194. +   __CONFIGFS_BIN_ATTR(_name, _mode, _read, _write, _priv, _max)
  195. +#define CFS_OVERLAY_ITEM_BIN_ATTR_RO(_name, _read, _priv, _max)    \
  196. +struct cfs_overlay_item_bin_attribute cfs_overlay_item_bin_attr_##_name = \
  197. +   __CONFIGFS_BIN_ATTR_RO(_name, _read, _priv, _max)
  198. +
  199. +static ssize_t cfs_overlay_item_path_show(struct cfs_overlay_item *overlay,
  200. +       char *page)
  201. +{
  202. +   return sprintf(page, "%s\n", overlay->path);
  203. +}
  204. +
  205. +static ssize_t cfs_overlay_item_path_store(struct cfs_overlay_item *overlay,
  206. +       const char *page, size_t count)
  207. +{
  208. +   const char *p = page;
  209. +   char *s;
  210. +   int err;
  211. +
  212. +   /* if it's set do not allow changes */
  213. +   if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
  214. +       return -EPERM;
  215. +
  216. +   /* copy to path buffer (and make sure it's always zero terminated */
  217. +   count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p);
  218. +   overlay->path[sizeof(overlay->path) - 1] = '\0';
  219. +
  220. +   /* strip trailing newlines */
  221. +   s = overlay->path + strlen(overlay->path);
  222. +   while (s > overlay->path && *--s == '\n')
  223. +       *s = '\0';
  224. +
  225. +   pr_debug("%s: path is '%s'\n", __func__, overlay->path);
  226. +
  227. +   err = request_firmware(&overlay->fw, overlay->path, NULL);
  228. +   if (err != 0)
  229. +       goto out_err;
  230. +
  231. +   err = create_overlay(overlay, (void *)overlay->fw->data);
  232. +   if (err < 0)
  233. +       goto out_err;
  234. +
  235. +   return count;
  236. +
  237. +out_err:
  238. +
  239. +   release_firmware(overlay->fw);
  240. +   overlay->fw = NULL;
  241. +
  242. +   overlay->path[0] = '\0';
  243. +   return err;
  244. +}
  245. +
  246. +static ssize_t cfs_overlay_item_status_show(struct cfs_overlay_item *overlay,
  247. +       char *page)
  248. +{
  249. +   return sprintf(page, "%s\n",
  250. +           overlay->ov_id >= 0 ? "applied" : "unapplied");
  251. +}
  252. +
  253. +CFS_OVERLAY_ITEM_ATTR(path, S_IRUGO | S_IWUSR,
  254. +       cfs_overlay_item_path_show, cfs_overlay_item_path_store);
  255. +CFS_OVERLAY_ITEM_ATTR_RO(status, cfs_overlay_item_status_show);
  256. +
  257. +static struct configfs_attribute *cfs_overlay_attrs[] = {
  258. +   &cfs_overlay_item_attr_path.attr,
  259. +   &cfs_overlay_item_attr_status.attr,
  260. +   NULL,
  261. +};
  262. +
  263. +ssize_t cfs_overlay_item_dtbo_read(struct cfs_overlay_item *overlay,
  264. +       void *buf, size_t max_count)
  265. +{
  266. +   pr_debug("%s: buf=%p max_count=%u\n", __func__,
  267. +           buf, max_count);
  268. +
  269. +   if (overlay->dtbo == NULL)
  270. +       return 0;
  271. +
  272. +   /* copy if buffer provided */
  273. +   if (buf != NULL) {
  274. +       /* the buffer must be large enough */
  275. +       if (overlay->dtbo_size > max_count)
  276. +           return -ENOSPC;
  277. +
  278. +       memcpy(buf, overlay->dtbo, overlay->dtbo_size);
  279. +   }
  280. +
  281. +   return overlay->dtbo_size;
  282. +}
  283. +
  284. +ssize_t cfs_overlay_item_dtbo_write(struct cfs_overlay_item *overlay,
  285. +       const void *buf, size_t count)
  286. +{
  287. +   int err;
  288. +
  289. +   /* if it's set do not allow changes */
  290. +   if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
  291. +       return -EPERM;
  292. +
  293. +   /* copy the contents */
  294. +   overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
  295. +   if (overlay->dtbo == NULL)
  296. +       return -ENOMEM;
  297. +
  298. +   overlay->dtbo_size = count;
  299. +
  300. +   err = create_overlay(overlay, overlay->dtbo);
  301. +   if (err < 0)
  302. +       goto out_err;
  303. +
  304. +   return count;
  305. +
  306. +out_err:
  307. +   kfree(overlay->dtbo);
  308. +   overlay->dtbo = NULL;
  309. +   overlay->dtbo_size = 0;
  310. +
  311. +   return err;
  312. +}
  313. +
  314. +CFS_OVERLAY_ITEM_BIN_ATTR(dtbo, S_IRUGO | S_IWUSR,
  315. +       cfs_overlay_item_dtbo_read, cfs_overlay_item_dtbo_write,
  316. +       NULL, SZ_1M);
  317. +
  318. +static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = {
  319. +   &cfs_overlay_item_bin_attr_dtbo.bin_attr,
  320. +   NULL,
  321. +};
  322. +
  323. +static void cfs_overlay_release(struct config_item *item)
  324. +{
  325. +   struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
  326. +
  327. +   if (overlay->ov_id >= 0)
  328. +       of_overlay_destroy(overlay->ov_id);
  329. +   if (overlay->fw)
  330. +       release_firmware(overlay->fw);
  331. +   /* kfree with NULL is safe */
  332. +   kfree(overlay->dtbo);
  333. +   kfree(overlay);
  334. +}
  335. +
  336. +CONFIGFS_ATTR_OPS(cfs_overlay_item);
  337. +CONFIGFS_BIN_ATTR_OPS(cfs_overlay_item);
  338. +static struct configfs_item_operations cfs_overlay_item_ops = {
  339. +   .release        = cfs_overlay_release,
  340. +   .show_attribute     = cfs_overlay_item_attr_show,
  341. +   .store_attribute    = cfs_overlay_item_attr_store,
  342. +   .read_bin_attribute = cfs_overlay_item_bin_attr_read,
  343. +   .write_bin_attribute    = cfs_overlay_item_bin_attr_write,
  344. +};
  345. +
  346. +static struct config_item_type cfs_overlay_type = {
  347. +   .ct_item_ops    = &cfs_overlay_item_ops,
  348. +   .ct_attrs   = cfs_overlay_attrs,
  349. +   .ct_bin_attrs   = cfs_overlay_bin_attrs,
  350. +   .ct_owner   = THIS_MODULE,
  351. +};
  352. +
  353. +static struct config_item *cfs_overlay_group_make_item(
  354. +       struct config_group *group, const char *name)
  355. +{
  356. +   struct cfs_overlay_item *overlay;
  357. +
  358. +   overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
  359. +   if (!overlay)
  360. +       return ERR_PTR(-ENOMEM);
  361. +   overlay->ov_id = -1;
  362. +
  363. +   config_item_init_type_name(&overlay->item, name, &cfs_overlay_type);
  364. +   return &overlay->item;
  365. +}
  366. +
  367. +static void cfs_overlay_group_drop_item(struct config_group *group,
  368. +       struct config_item *item)
  369. +{
  370. +   struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
  371. +
  372. +   config_item_put(&overlay->item);
  373. +}
  374. +
  375. +static struct configfs_group_operations overlays_ops = {
  376. +   .make_item  = cfs_overlay_group_make_item,
  377. +   .drop_item  = cfs_overlay_group_drop_item,
  378. +};
  379. +
  380. +static struct config_item_type overlays_type = {
  381. +   .ct_group_ops   = &overlays_ops,
  382. +   .ct_owner       = THIS_MODULE,
  383. +};
  384. +
  385. +static struct configfs_group_operations of_cfs_ops = {
  386. +   /* empty - we don't allow anything to be created */
  387. +};
  388. +
  389. +static struct config_item_type of_cfs_type = {
  390. +   .ct_group_ops   = &of_cfs_ops,
  391. +   .ct_owner       = THIS_MODULE,
  392. +};
  393. +
  394. +struct config_group of_cfs_overlay_group;
  395. +
  396. +struct config_group *of_cfs_def_groups[] = {
  397. +   &of_cfs_overlay_group,
  398. +   NULL
  399. +};
  400. +
  401. +static struct configfs_subsystem of_cfs_subsys = {
  402. +   .su_group = {
  403. +       .cg_item = {
  404. +           .ci_namebuf = "device-tree",
  405. +           .ci_type = &of_cfs_type,
  406. +       },
  407. +       .default_groups = of_cfs_def_groups,
  408. +   },
  409. +   .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex),
  410. +};
  411. +
  412. +static int __init of_cfs_init(void)
  413. +{
  414. +   int ret;
  415. +
  416. +   pr_info("%s\n", __func__);
  417. +
  418. +   config_group_init(&of_cfs_subsys.su_group);
  419. +   config_group_init_type_name(&of_cfs_overlay_group, "overlays",
  420. +           &overlays_type);
  421. +
  422. +   ret = configfs_register_subsystem(&of_cfs_subsys);
  423. +   if (ret != 0) {
  424. +       pr_err("%s: failed to register subsys\n", __func__);
  425. +       goto out;
  426. +   }
  427. +   pr_info("%s: OK\n", __func__);
  428. +out:
  429. +   return ret;
  430. +}
  431. +late_initcall(of_cfs_init);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement