diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-core.c | 9 | ||||
-rw-r--r-- | block/blk-mq.c | 14 | ||||
-rw-r--r-- | block/partitions/Kconfig | 10 | ||||
-rw-r--r-- | block/partitions/Makefile | 1 | ||||
-rw-r--r-- | block/partitions/check.c | 4 | ||||
-rwxr-xr-x | block/partitions/rk.c | 344 | ||||
-rwxr-xr-x | block/partitions/rk.h | 40 |
7 files changed, 419 insertions, 3 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 323cc15b155a..0aa722c93d9f 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1796,11 +1796,16 @@ get_rq: /* * If this is the first request added after a plug, fire * of a plug trace. + * + * @request_count may become stale because of schedule + * out, so check plug list again. */ - if (!request_count) + if (!request_count || list_empty(&plug->list)) trace_block_plug(q); else { - if (request_count >= BLK_MAX_REQUEST_COUNT) { + struct request *last = list_entry_rq(plug->list.prev); + if (request_count >= BLK_MAX_REQUEST_COUNT || + blk_rq_bytes(last) >= BLK_PLUG_FLUSH_SIZE) { blk_flush_plug_list(plug, false); trace_block_plug(q); } diff --git a/block/blk-mq.c b/block/blk-mq.c index 0d1af3e44efb..434cb5f7d9ae 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1377,13 +1377,25 @@ static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio) */ plug = current->plug; if (plug) { + struct request *last = NULL; + blk_mq_bio_to_request(rq, bio); + + /* + * @request_count may become stale because of schedule + * out, so check the list again. + */ + if (list_empty(&plug->mq_list)) + request_count = 0; if (!request_count) trace_block_plug(q); + else + last = list_entry_rq(plug->mq_list.prev); blk_mq_put_ctx(data.ctx); - if (request_count >= BLK_MAX_REQUEST_COUNT) { + if (request_count >= BLK_MAX_REQUEST_COUNT || (last && + blk_rq_bytes(last) >= BLK_PLUG_FLUSH_SIZE)) { blk_flush_plug_list(plug, false); trace_block_plug(q); } diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig index 9b29a996c311..66a5a35bfe2d 100644 --- a/block/partitions/Kconfig +++ b/block/partitions/Kconfig @@ -261,6 +261,16 @@ config SYSV68_PARTITION sysv68). Otherwise, say N. +config RK_PARTITION + bool "Rockchip partition table support" if PARTITION_ADVANCED + default y if ARCH_ROCKCHIP + ---help--- + Like most systems, Rockchip use its own hard disk partition table + format, incompatible with all others. Say Y here if you would like + to be able to read the hard disk partition table format used by + Rockchip SoCs inside machines with eMMC as main storage disk. + Otherwise, say N. + config CMDLINE_PARTITION bool "Command line partition support" if PARTITION_ADVANCED select BLK_CMDLINE_PARSER diff --git a/block/partitions/Makefile b/block/partitions/Makefile index 37a95270503c..8cddc48e5d89 100644 --- a/block/partitions/Makefile +++ b/block/partitions/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ACORN_PARTITION) += acorn.o obj-$(CONFIG_AMIGA_PARTITION) += amiga.o obj-$(CONFIG_ATARI_PARTITION) += atari.o obj-$(CONFIG_AIX_PARTITION) += aix.o +obj-$(CONFIG_RK_PARTITION) += rk.o obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o obj-$(CONFIG_MAC_PARTITION) += mac.o obj-$(CONFIG_LDM_PARTITION) += ldm.o diff --git a/block/partitions/check.c b/block/partitions/check.c index 16118d11dbfc..073ed042854a 100644 --- a/block/partitions/check.c +++ b/block/partitions/check.c @@ -20,6 +20,7 @@ #include "check.h" +#include "rk.h" #include "acorn.h" #include "amiga.h" #include "atari.h" @@ -66,6 +67,9 @@ static int (*check_part[])(struct parsed_partitions *) = { adfspart_check_ADFS, #endif +#ifdef CONFIG_RK_PARTITION + rkpart_partition, +#endif #ifdef CONFIG_CMDLINE_PARTITION cmdline_partition, #endif diff --git a/block/partitions/rk.c b/block/partitions/rk.c new file mode 100755 index 000000000000..73a8f8db3be4 --- /dev/null +++ b/block/partitions/rk.c @@ -0,0 +1,344 @@ +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/bootmem.h> +#include "check.h" +#include "rk.h" + +/* rkpart_setup() parses into here */ +static struct cmdline_rk_partition *partitions; +/* the command line passed to mtdpart_setupd() */ +static char *cmdline; +static int cmdline_parsed; + +/* + * Parse one partition definition for an rkpart. Since there can be many + * comma separated partition definitions, this function calls itself + * recursively until no more partition definitions are found. Nice side + * effect: the memory to keep the rk_partition structs and the names + * is allocated upon the last definition being found. At that point the + * syntax has been verified ok. + */ +static struct rk_partition *newpart(char *s, + char **retptr, + int *num_parts, + int this_part, + unsigned char **extra_mem_ptr, + int extra_mem_size) +{ + struct rk_partition *parts; + sector_t size; + sector_t from = OFFSET_CONTINUOUS; + char *name; + int name_len; + unsigned char *extra_mem; + char delim; + + /* fetch the partition size */ + if (*s == '-') + { /* assign all remaining space to this partition */ + size = SIZE_REMAINING; + s++; + } + else + { + size = memparse(s, &s); + /* No sense support partition less than 8B */ + if (size < ((PAGE_SIZE) >> 9)) + { + printk(KERN_ERR ERRP "partition size too small (%llx)\n", (u64)size); + return NULL; + } + } + + /* fetch partition name */ + delim = 0; + /* check for from */ + if (*s == '@') + { + s++; + from = memparse(s, &s); + } + /* now look for name */ + if (*s == '(') + { + delim = ')'; + } + + if (delim) + { + char *p; + + name = ++s; + p = strchr(name, delim); + if (!p) + { + printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim); + return NULL; + } + name_len = p - name; + s = p + 1; + } + else + { + name = NULL; + name_len = 13; /* Partition_000 */ + } + + /* record name length for memory allocation later */ + extra_mem_size += name_len + 1; + + /* test if more partitions are following */ + if (*s == ',') + { + if (size == SIZE_REMAINING) + { + printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n"); + return NULL; + } + /* more partitions follow, parse them */ + parts = newpart(s + 1, &s, num_parts, this_part + 1, + &extra_mem, extra_mem_size); + if (!parts) + return NULL; + } + else + { /* this is the last partition: allocate space for all */ + int alloc_size; + + *num_parts = this_part + 1; + alloc_size = *num_parts * sizeof(struct rk_partition) + + extra_mem_size; + parts = kzalloc(alloc_size, GFP_KERNEL); + if (!parts) + { + printk(KERN_ERR ERRP "out of memory\n"); + return NULL; + } + extra_mem = (unsigned char *)(parts + *num_parts); + } + /* enter this partition (from will be calculated later if it is zero at this point) */ + parts[this_part].size = size; + parts[this_part].from = from; + if (name) + { + strlcpy(extra_mem, name, name_len + 1); + } + else + { + sprintf(extra_mem, "Partition_%03d", this_part); + } + parts[this_part].name = extra_mem; + extra_mem += name_len + 1; + + dbg(("partition %d: name <%s>, from %llx, size %llx\n", + this_part, + parts[this_part].name, + parts[this_part].from, + parts[this_part].size)); + + /* return (updated) pointer to extra_mem memory */ + if (extra_mem_ptr) + *extra_mem_ptr = extra_mem; + + /* return (updated) pointer command line string */ + *retptr = s; + + /* return partition table */ + return parts; +} + +/* + * Parse the command line. + */ +static int rkpart_setup_real(char *s) +{ + cmdline_parsed = 1; + + for( ; s != NULL; ) + { + struct cmdline_rk_partition *this_rk; + struct rk_partition *parts; + int rk_id_len; + int num_parts; + char *p, *rk_id; + + rk_id = s; + /* fetch <rk-id> */ + if (!(p = strchr(s, ':'))) + { + dbg(( "no rk-id\n")); + return 0; + } + rk_id_len = p - rk_id; + + dbg(("parsing <%s>\n", p + 1)); + + /* + * parse one mtd. have it reserve memory for the + * struct cmdline_mtd_partition and the mtd-id string. + */ + parts = newpart(p + 1, /* cmdline */ + &s, /* out: updated cmdline ptr */ + &num_parts, /* out: number of parts */ + 0, /* first partition */ + (unsigned char**)&this_rk, /* out: extra mem */ + rk_id_len + 1 + sizeof(*this_rk) + + sizeof(void*)-1 /*alignment*/); + if(!parts) + { + /* + * An error occurred. We're either: + * a) out of memory, or + * b) in the middle of the partition spec + * Either way, this mtd is hosed and we're + * unlikely to succeed in parsing any more + */ + return 0; + } + + /* align this_rk */ + this_rk = (struct cmdline_rk_partition *) + ALIGN((unsigned long)this_rk, sizeof(void*)); + /* enter results */ + this_rk->parts = parts; + this_rk->num_parts = num_parts; + this_rk->rk_id = (char*)(this_rk + 1); + strlcpy(this_rk->rk_id, rk_id, rk_id_len + 1); + + /* link into chain */ + this_rk->next = partitions; + partitions = this_rk; + + dbg(("rkid=<%s> num_parts=<%d>\n", + this_rk->mtd_id, this_rk->num_parts)); + + /* EOS - we're done */ + if (*s == 0) + break; + s++; + } + return 1; +} + +/* + * Main function to be called from the MTD mapping driver/device to + * obtain the partitioning information. At this point the command line + * arguments will actually be parsed and turned to struct mtd_partition + * information. It returns partitions for the requested mtd device, or + * the first one in the chain if a NULL mtd_id is passed in. + */ +static int parse_cmdline_partitions(sector_t n, + struct rk_partition **pparts, + unsigned long origin) +{ + unsigned long from; + int i; + struct cmdline_rk_partition *part; + /* Fixme: parameter should be coherence with part table id */ + const char *rk_id = "rk29xxnand"; + + /* parse command line */ + if (!cmdline_parsed) + rkpart_setup_real(cmdline); + + for(part = partitions; part; part = part->next) + { + if ((!rk_id) || (!strcmp(part->rk_id, rk_id))) + { + for(i = 0, from = 0; i < part->num_parts; i++) + { + if (part->parts[i].from == OFFSET_CONTINUOUS) + part->parts[i].from = from; + else + from = part->parts[i].from; + if (part->parts[i].size == SIZE_REMAINING) + part->parts[i].size = n - from - FROM_OFFSET; + if (from + part->parts[i].size > n) + { + printk(KERN_WARNING ERRP + "%s: partitioning exceeds flash size, truncating\n", + part->rk_id); + part->parts[i].size = n - from; + part->num_parts = i; + } + from += part->parts[i].size; + } + *pparts = kmemdup(part->parts, + sizeof(*part->parts) * part->num_parts, + GFP_KERNEL); + if (!*pparts) + return -ENOMEM; + return part->num_parts; + } + } + return 0; +} + +static void rkpart_bootmode_fixup(void) +{ + const char mode_emmc[] = " androidboot.mode=emmc"; + const char mode_nvme[] = " androidboot.mode=nvme"; + const char charger[] = " androidboot.charger.emmc=1"; + char *new_command_line; + size_t saved_command_line_len = strlen(saved_command_line); + + if (strstr(saved_command_line, "androidboot.mode=charger")) { + new_command_line = kzalloc(saved_command_line_len + + strlen(charger) + 1, GFP_KERNEL); + sprintf(new_command_line, "%s%s", + saved_command_line, charger); + } else { + new_command_line = kzalloc(saved_command_line_len + + strlen(mode_emmc) + 1, GFP_KERNEL); + if (strstr(saved_command_line, "storagemedia=nvme")) + sprintf(new_command_line, "%s%s", + saved_command_line, mode_nvme); + else + sprintf(new_command_line, "%s%s", + saved_command_line, mode_emmc); + } + saved_command_line = new_command_line; +} + +int rkpart_partition(struct parsed_partitions *state) +{ + int num_parts = 0, i; + sector_t n = get_capacity(state->bdev->bd_disk); + struct rk_partition *parts = NULL; + + if (n < SECTOR_1G) + return 0; + + if (!state->bdev->bd_disk->is_rk_disk) + return 0; + + /* Fixme: parameter should be coherence with part table */ + cmdline = strstr(saved_command_line, "mtdparts="); + if (!cmdline) + return 0; + cmdline += 9; + cmdline_parsed = 0; + + num_parts = parse_cmdline_partitions(n, &parts, 0); + if (num_parts < 0) + return num_parts; + + for (i = 0; i < num_parts; i++) { + put_partition( state, + i+1, + parts[i].from + FROM_OFFSET, + parts[i].size); + strcpy(state->parts[i+1].info.volname, parts[i].name); + printk(KERN_INFO "%10s: 0x%09llx -- 0x%09llx (%llu MB)\n", + parts[i].name, + (u64)parts[i].from * 512, + (u64)(parts[i].from + parts[i].size) * 512, + (u64)parts[i].size / 2048); + } + + rkpart_bootmode_fixup(); + + return 1; +} + + diff --git a/block/partitions/rk.h b/block/partitions/rk.h new file mode 100755 index 000000000000..25085e716df5 --- /dev/null +++ b/block/partitions/rk.h @@ -0,0 +1,40 @@ +/* + * block/partitions/rk.h + */ + +/* error message prefix */ +#define ERRP "rkpart: " + +/* debug macro */ +#define RKPART_DEBUG 0 +#if RKPART_DEBUG +#define dbg(x) do { \ +printk("DEBUG-CMDLINE-PART: "); \ +printk x; \ +} while (0) +#else +#define dbg(x) +#endif + +/* At least 1GB disk support*/ +#define SECTOR_1G 0x200000 + +/* Default partition table offet got from loader: 4MB*/ +#define FROM_OFFSET 0x2000 + +/* special size referring to all the remaining space in a partition */ +#define SIZE_REMAINING UINT_MAX +#define OFFSET_CONTINUOUS UINT_MAX + +struct rk_partition { + char *name; + sector_t from; + sector_t size; +}; +struct cmdline_rk_partition { + struct cmdline_rk_partition *next; + char *rk_id; + int num_parts; + struct rk_partition *parts; +}; +int rkpart_partition(struct parsed_partitions *state); |