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