From 70680c754ee59eb1768f398325e60385790872e5 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Wed, 12 Oct 2022 22:49:32 +0800 Subject: [PATCH] drivers: rkflash: Using kmap_atomic to build page address mapping The virtual address of allocated __GFP_HIGHMEM pages is not mapped, Using kmap_atomic to build it, or it will failed like: Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = 50ec00c8 [00000000] *pgd=00000000 Internal error: Oops: 817 [#1] PREEMPT SMP ARM Modules linked in: CPU: 3 PID: 67 Comm: rkflash Not tainted 4.19.111 #67 Hardware name: Generic DT based system PC is at memcpy+0x50/0x330 LR is at 0x61640a68 Change-Id: I0cde9012d29e49d9ba751cb019ccfa784c01b7c7 Signed-off-by: Jon Lin --- drivers/rkflash/rkflash_blk.c | 67 ++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/drivers/rkflash/rkflash_blk.c b/drivers/rkflash/rkflash_blk.c index 5d09dbc63a62..14a6c0a512d8 100644 --- a/drivers/rkflash/rkflash_blk.c +++ b/drivers/rkflash/rkflash_blk.c @@ -223,20 +223,26 @@ static int rkflash_blk_xfer(struct flash_blk_dev *dev, static int rkflash_blk_check_buffer_align(struct request *req, char **pbuf) { int nr_vec = 0; - struct bio_vec bvec; + struct bio_vec bv; struct req_iterator iter; char *buffer; void *firstbuf = 0; char *nextbuffer = 0; - rq_for_each_segment(bvec, req, iter) { - buffer = page_address(bvec.bv_page) + bvec.bv_offset; + rq_for_each_segment(bv, req, iter) { + /* high mem return 0 and using kernel buffer */ + if (PageHighMem(bv.bv_page)) + return 0; + + buffer = page_address(bv.bv_page) + bv.bv_offset; + if (!buffer) + return 0; if (!firstbuf) firstbuf = buffer; nr_vec++; if (nextbuffer && nextbuffer != buffer) return 0; - nextbuffer = buffer + bvec.bv_len; + nextbuffer = buffer + bv.bv_len; } *pbuf = firstbuf; return 1; @@ -247,12 +253,11 @@ static blk_status_t do_blktrans_all_request(struct flash_blk_ops *tr, struct request *req) { unsigned long block, nsect; - char *buf = NULL; + char *buf = NULL, *page_buf; struct req_iterator rq_iter; struct bio_vec bvec; int ret; unsigned long totle_nsect; - unsigned long rq_len = 0; block = blk_rq_pos(req); nsect = blk_rq_cur_bytes(req) >> 9; @@ -281,11 +286,13 @@ static blk_status_t do_blktrans_all_request(struct flash_blk_ops *tr, char *p = buf; rq_for_each_segment(bvec, req, rq_iter) { - memcpy(page_address(bvec.bv_page) + - bvec.bv_offset, - p, - bvec.bv_len); + page_buf = kmap_atomic(bvec.bv_page); + memcpy(page_buf + + bvec.bv_offset, + p, + bvec.bv_len); p += bvec.bv_len; + kunmap_atomic(page_buf); } } @@ -296,30 +303,26 @@ static blk_status_t do_blktrans_all_request(struct flash_blk_ops *tr, case REQ_OP_WRITE: rkflash_print_bio("%s write block=%lx nsec=%lx\n", __func__, block, totle_nsect); - rq_for_each_segment(bvec, req, rq_iter) { - if ((page_address(bvec.bv_page) + bvec.bv_offset) == (buf + rq_len)) { - rq_len += bvec.bv_len; - } else { - if (rq_len) { - ret = rkflash_blk_xfer(dev, - block, - rq_len >> 9, - buf, - REQ_OP_WRITE); - } - block += rq_len >> 9; - buf = (page_address(bvec.bv_page) + bvec.bv_offset); - rq_len = bvec.bv_len; + buf = mtd_read_temp_buffer; + rkflash_blk_check_buffer_align(req, &buf); + if (buf == mtd_read_temp_buffer) { + char *p = buf; + + rq_for_each_segment(bvec, req, rq_iter) { + page_buf = kmap_atomic(bvec.bv_page); + memcpy(p, + page_buf + + bvec.bv_offset, + bvec.bv_len); + p += bvec.bv_len; + kunmap_atomic(page_buf); } } - - if (rq_len) { - ret = rkflash_blk_xfer(dev, - block, - rq_len >> 9, - buf, - REQ_OP_WRITE); - } + ret = rkflash_blk_xfer(dev, + block, + totle_nsect, + buf, + REQ_OP_WRITE); if (ret) return BLK_STS_IOERR;