| 1 | |
| 2 |
|
| 3 | #include <linux/blkdev.h>
|
| 4 | #include <linux/major.h>
|
| 5 | #include <linux/of.h>
|
| 6 | #include <linux/string.h>
|
| 7 | #include "check.h"
|
| 8 |
|
| 9 | static int validate_of_partition(struct device_node *np, int slot)
|
| 10 | {
|
| 11 | u64 offset, size;
|
| 12 | int len;
|
| 13 |
|
| 14 | const __be32 *reg = of_get_property(np, "reg", &len);
|
| 15 | int a_cells = of_n_addr_cells(np);
|
| 16 | int s_cells = of_n_size_cells(np);
|
| 17 |
|
| 18 |
|
| 19 | if (len / sizeof(*reg) != a_cells + s_cells)
|
| 20 | return -EINVAL;
|
| 21 |
|
| 22 |
|
| 23 | offset = of_read_number(reg, a_cells);
|
| 24 | if (offset % SECTOR_SIZE)
|
| 25 | return -EINVAL;
|
| 26 |
|
| 27 |
|
| 28 | size = of_read_number(reg + a_cells, s_cells);
|
| 29 | if (!size || size % SECTOR_SIZE)
|
| 30 | return -EINVAL;
|
| 31 |
|
| 32 | return 0;
|
| 33 | }
|
| 34 |
|
| 35 | static void add_of_partition(struct parsed_partitions *state, int slot,
|
| 36 | struct device_node *np)
|
| 37 | {
|
| 38 | struct partition_meta_info *info;
|
| 39 | const char *partname;
|
| 40 | int len;
|
| 41 |
|
| 42 | const __be32 *reg = of_get_property(np, "reg", &len);
|
| 43 | int a_cells = of_n_addr_cells(np);
|
| 44 | int s_cells = of_n_size_cells(np);
|
| 45 |
|
| 46 |
|
| 47 | u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE;
|
| 48 | u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE;
|
| 49 |
|
| 50 | put_partition(state, slot, offset, size);
|
| 51 |
|
| 52 | if (of_property_read_bool(np, "read-only"))
|
| 53 | state->parts[slot].flags |= ADDPART_FLAG_READONLY;
|
| 54 |
|
| 55 | |
| 56 | * Follow MTD label logic, search for label property,
|
| 57 | * fallback to node name if not found.
|
| 58 |
|
| 59 | info = &state->parts[slot].info;
|
| 60 | partname = of_get_property(np, "label", &len);
|
| 61 | if (!partname)
|
| 62 | partname = of_get_property(np, "name", &len);
|
| 63 | strscpy(info->volname, partname, sizeof(info->volname));
|
| 64 |
|
| 65 | seq_buf_printf(&state->pp_buf, "(%s)", info->volname);
|
| 66 | }
|
| 67 |
|
| 68 | int of_partition(struct parsed_partitions *state)
|
| 69 | {
|
| 70 | struct device *ddev = disk_to_dev(state->disk);
|
| 71 | struct device_node *np;
|
| 72 | int slot;
|
| 73 |
|
| 74 | struct device_node *partitions_np = of_node_get(ddev->of_node);
|
| 75 |
|
| 76 | if (!partitions_np ||
|
| 77 | !of_device_is_compatible(partitions_np, "fixed-partitions")) {
|
| 78 | of_node_put(partitions_np);
|
| 79 | return 0;
|
| 80 | }
|
| 81 |
|
| 82 | slot = 1;
|
| 83 |
|
| 84 | for_each_child_of_node(partitions_np, np) {
|
| 85 | if (validate_of_partition(np, slot)) {
|
| 86 | of_node_put(np);
|
| 87 | of_node_put(partitions_np);
|
| 88 |
|
| 89 | return -1;
|
| 90 | }
|
| 91 |
|
| 92 | slot++;
|
| 93 | }
|
| 94 |
|
| 95 | slot = 1;
|
| 96 | for_each_child_of_node(partitions_np, np) {
|
| 97 | if (slot >= state->limit) {
|
| 98 | of_node_put(np);
|
| 99 | break;
|
| 100 | }
|
| 101 |
|
| 102 | add_of_partition(state, slot, np);
|
| 103 |
|
| 104 | slot++;
|
| 105 | }
|
| 106 |
|
| 107 | seq_buf_puts(&state->pp_buf, "\n");
|
| 108 |
|
| 109 | of_node_put(partitions_np);
|
| 110 | return 1;
|
| 111 | }
|