[PATCH] virtio-balloon: fix a typo in comment of virtballoon_migratepage()
Typo: compation --> compaction Signed-off-by: Liu Xiang --- drivers/virtio/virtio_balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 7da25b87f..c25665802 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -734,7 +734,7 @@ static void report_free_page_func(struct work_struct *work) #ifdef CONFIG_BALLOON_COMPACTION /* * virtballoon_migratepage - perform the balloon page migration on behalf of - * a compation thread. (called under page lock) + * a compaction thread. (called under page lock) * @vb_dev_info: the balloon device * @newpage: page that will replace the isolated page after migration finishes. * @page : the isolated (old) page that is about to be migrated to newpage. -- 2.17.1
[PATCH] virtio-balloon: move release_pages_balloon() outside of mutex_unlock(>balloon_lock)
Since pages have been deflated to a local list, there is no race between fill and leak. Signed-off-by: Liu Xiang --- drivers/virtio/virtio_balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 8985fc2ce..7da25b87f 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -303,8 +303,8 @@ static unsigned leak_balloon(struct virtio_balloon *vb, size_t num) */ if (vb->num_pfns != 0) tell_host(vb, vb->deflate_vq); - release_pages_balloon(vb, ); mutex_unlock(>balloon_lock); + release_pages_balloon(vb, ); return num_freed_pages; } -- 2.17.1
Re: [PATCH] ARM: fix smp_processor_id() in preemptible warning in harden_branch_predictor()
Russell King - ARM Linux admin 于2021年3月25日周四 下午6:06写道: > > On Thu, Mar 25, 2021 at 05:50:49PM +0800, Liu Xiang wrote: > > When CONFIG_HARDEN_BRANCH_PREDICTOR is selected and user aborts occur, > > there is a warning: > > > > BUG: using smp_processor_id() in preemptible [] code: errnotest/577 > > caller is __do_user_fault.constprop.4+0x24/0x88 > > CPU: 1 PID: 577 Comm: errnotest Not tainted > > 4.14.188-rt87-fmsh-4-g58055877a #1 > > Hardware name: FMSH PSOC Platform > > [<8010d6d4>] (unwind_backtrace) from [<8010a228>] (show_stack+0x10/0x14) > > [<8010a228>] (show_stack) from [<80698f44>] (dump_stack+0x7c/0x98) > > [<80698f44>] (dump_stack) from [<803d17d0>] > > (check_preemption_disabled+0xc4/0xfc) > > [<803d17d0>] (check_preemption_disabled) from [<80110eb8>] > > (__do_user_fault.constprop.4+0x24/0x88) > > [<80110eb8>] (__do_user_fault.constprop.4) from [<801112e4>] > > (do_page_fault+0x2dc/0x310) > > [<801112e4>] (do_page_fault) from [<801012a8>] (do_DataAbort+0x38/0xb8) > > [<801012a8>] (do_DataAbort) from [<8010b03c>] (__dabt_usr+0x3c/0x40) > > Exception stack(0xb21d1fb0 to 0xb21d1ff8) > > 1fa0: fff4 0054 > > fff4 > > 1fc0: 7ed81cc8 7ed81ca0 0007a440 > > > > 1fe0: 7ed81ca0 00010493 0001f330 20030010 > > This is not the right fix - preemption is supposed to be disabled before > this function is called. I'm not sure at the present time what the right > fix is supposed to be because I've forgotten most of the background > behind why this was placed where it is. > > -- > RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ > FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last! I have tested with the current mainline kernel, the warning still exists. [ 14.404322] BUG: using smp_processor_id() in preemptible [] code: errnotest/81 [ 14.404795] caller is __do_user_fault.constprop.5+0x54/0x7c [ 14.405163] CPU: 1 PID: 81 Comm: errnotest Not tainted 5.12.0-rc4-ge97a94a30e55-dirty #6 [ 14.405616] Hardware name: ARM-Versatile Express [ 14.406475] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 14.407018] [] (show_stack) from [] (dump_stack+0x8c/0xa0) [ 14.407398] [] (dump_stack) from [] (check_preemption_disabled+0x114/0x118) [ 14.407906] [] (check_preemption_disabled) from [] (__do_user_fault.constprop.5+0x54/0x7c) [ 14.408367] [] (__do_user_fault.constprop.5) from [] (do_page_fault+0x208/0x3bc) [ 14.408907] [] (do_page_fault) from [] (do_DataAbort+0x3c/0xbc) [ 14.409266] [] (do_DataAbort) from [] (__dabt_usr+0x3c/0x40) [ 14.409721] Exception stack(0xc285ffb0 to 0xc285fff8) [ 14.410099] ffa0: fff4 0054 fff4 [ 14.411000] ffc0: bed90d28 bed90d00 0007a440 [ 14.411386] ffe0: bed90d00 00010493 0001f330 20030010 Segmentation fault
[PATCH] ARM: fix smp_processor_id() in preemptible warning in harden_branch_predictor()
When CONFIG_HARDEN_BRANCH_PREDICTOR is selected and user aborts occur, there is a warning: BUG: using smp_processor_id() in preemptible [] code: errnotest/577 caller is __do_user_fault.constprop.4+0x24/0x88 CPU: 1 PID: 577 Comm: errnotest Not tainted 4.14.188-rt87-fmsh-4-g58055877a #1 Hardware name: FMSH PSOC Platform [<8010d6d4>] (unwind_backtrace) from [<8010a228>] (show_stack+0x10/0x14) [<8010a228>] (show_stack) from [<80698f44>] (dump_stack+0x7c/0x98) [<80698f44>] (dump_stack) from [<803d17d0>] (check_preemption_disabled+0xc4/0xfc) [<803d17d0>] (check_preemption_disabled) from [<80110eb8>] (__do_user_fault.constprop.4+0x24/0x88) [<80110eb8>] (__do_user_fault.constprop.4) from [<801112e4>] (do_page_fault+0x2dc/0x310) [<801112e4>] (do_page_fault) from [<801012a8>] (do_DataAbort+0x38/0xb8) [<801012a8>] (do_DataAbort) from [<8010b03c>] (__dabt_usr+0x3c/0x40) Exception stack(0xb21d1fb0 to 0xb21d1ff8) 1fa0: fff4 0054 fff4 1fc0: 7ed81cc8 7ed81ca0 0007a440 00000000 1fe0: 7ed81ca0 00010493 0001f330 20030010 Signed-off-by: Liu Xiang --- arch/arm/include/asm/system_misc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h index 66f6a3ae6..4a55cfbdf 100644 --- a/arch/arm/include/asm/system_misc.h +++ b/arch/arm/include/asm/system_misc.h @@ -22,9 +22,10 @@ DECLARE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn); static inline void harden_branch_predictor(void) { harden_branch_predictor_fn_t fn = per_cpu(harden_branch_predictor_fn, - smp_processor_id()); + get_cpu()); if (fn) fn(); + put_cpu(); } #else #define harden_branch_predictor() do { } while (0) -- 2.17.1
[PATCH] drm/virtio: check the return value of virtio_gpu_alloc_cmd_resp()
Now there is no check with the return value of virtio_gpu_alloc_cmd_resp(). If it fails, the following operation will cause a fault. Signed-off-by: Liu Xiang --- drivers/gpu/drm/virtio/virtgpu_vq.c | 89 + 1 file changed, 89 insertions(+) diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index cf84d382d..2e59ad55f 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -507,6 +507,9 @@ void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf; cmd_p = virtio_gpu_alloc_cmd(vgdev, , sizeof(*cmd_p)); + if (IS_ERR(cmd_p)) + return; + memset(cmd_p, 0, sizeof(*cmd_p)); vbuf->objs = objs; @@ -540,6 +543,9 @@ void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev, cmd_p = virtio_gpu_alloc_cmd_cb(vgdev, , sizeof(*cmd_p), virtio_gpu_cmd_unref_cb); + if (IS_ERR(cmd_p)) + return; + memset(cmd_p, 0, sizeof(*cmd_p)); cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_UNREF); @@ -560,6 +566,9 @@ void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf; cmd_p = virtio_gpu_alloc_cmd(vgdev, , sizeof(*cmd_p)); + if (IS_ERR(cmd_p)) + return; + memset(cmd_p, 0, sizeof(*cmd_p)); cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_SET_SCANOUT); @@ -582,6 +591,9 @@ void virtio_gpu_cmd_resource_flush(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf; cmd_p = virtio_gpu_alloc_cmd(vgdev, , sizeof(*cmd_p)); + if (IS_ERR(cmd_p)) + return; + memset(cmd_p, 0, sizeof(*cmd_p)); cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_FLUSH); @@ -612,6 +624,9 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev, shmem->pages, DMA_TO_DEVICE); cmd_p = virtio_gpu_alloc_cmd(vgdev, , sizeof(*cmd_p)); + if (IS_ERR(cmd_p)) + return; + memset(cmd_p, 0, sizeof(*cmd_p)); vbuf->objs = objs; @@ -637,6 +652,9 @@ virtio_gpu_cmd_resource_attach_backing(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf; cmd_p = virtio_gpu_alloc_cmd(vgdev, , sizeof(*cmd_p)); + if (IS_ERR(cmd_p)) + return; + memset(cmd_p, 0, sizeof(*cmd_p)); cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING); @@ -778,6 +796,11 @@ int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev) (vgdev, _gpu_cmd_get_display_info_cb, , sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_display_info), resp_buf); + if (IS_ERR(cmd_p)) { + kfree(resp_buf); + return PTR_ERR(cmd_p); + } + memset(cmd_p, 0, sizeof(*cmd_p)); vgdev->display_info_pending = true; @@ -801,6 +824,11 @@ int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx) (vgdev, _gpu_cmd_get_capset_info_cb, , sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_capset_info), resp_buf); + if (IS_ERR(cmd_p)) { + kfree(resp_buf); + return PTR_ERR(cmd_p); + } + memset(cmd_p, 0, sizeof(*cmd_p)); cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_GET_CAPSET_INFO); @@ -876,6 +904,13 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, (vgdev, _gpu_cmd_capset_cb, , sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_capset) + max_size, resp_buf); + if (IS_ERR(cmd_p)) { + kfree(resp_buf); + kfree(cache_ent->caps_cache); + kfree(cache_ent); + return PTR_ERR(cmd_p); + } + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_GET_CAPSET); cmd_p->capset_id = cpu_to_le32(vgdev->capsets[idx].id); cmd_p->capset_version = cpu_to_le32(version); @@ -905,6 +940,11 @@ int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev) (vgdev, _gpu_cmd_get_edid_cb, , sizeof(*cmd_p), sizeof(struct virtio_gpu_resp_edid), resp_buf); + if (IS_ERR(cmd_p)) { + kfree(resp_buf); + return PTR_ERR(cmd_p); + } + cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_GET_EDID); cmd_p->scanout = cpu_to_le32(scanout); virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); @@ -920,6 +960,9 @@ void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id, struct virtio_gpu_vbuffer *vbuf; cmd
Re: [PATCH] pinctrl: sunxi: fix use-after-free in sunxi_pmx_free()
> On Thu, Jan 21, 2021 at 5:40 PM Maxime Ripard wrote: > On Tue, Jan 19, 2021 at 02:29:08PM +0800, Liu Xiang wrote: > > When CONFIG_REGULATOR is not set, sunxi_pmx_request() always return > > success. Even a group of pins call sunxi_pmx_request(), the refcount > > is only 1. This can cause a use-after-free warning in sunxi_pmx_free(). > > To solve this problem, go to err path if regulator_get() return NULL > > or error. > > > > Signed-off-by: Liu Xiang > > Is there any drawback to depending on CONFIG_REGULATOR? > > Given that we need those regulators enabled anyway, I guess we could > just select or depends on it > > I agree. > > Liu can you make a patch to Kconfig to just select REGULATOR? > Possibly even the specific regulator driver this SoC is using > if it is very specific for this purpose. > > Yours, > Linus Walleij I found that the regulator driver is related to the specific board, not the SoC. There is no board config for ARM64 SoC like ARM. Is a good idea to select the regulator driver in the pinctrl Konfig? Or just select CONFIG_REGULATOR_FIXED_VOLTAGE to avoid the use-after-free warning?
Re: [PATCH] pinctrl: sunxi: fix use-after-free in sunxi_pmx_free()
-- > On Thu, Jan 21, 2021 at 5:40 PM Maxime Ripard wrote: > On Tue, Jan 19, 2021 at 02:29:08PM +0800, Liu Xiang wrote: > > When CONFIG_REGULATOR is not set, sunxi_pmx_request() always return > > success. Even a group of pins call sunxi_pmx_request(), the refcount > > is only 1. This can cause a use-after-free warning in sunxi_pmx_free(). > > To solve this problem, go to err path if regulator_get() return NULL > > or error. > > > > Signed-off-by: Liu Xiang > > Is there any drawback to depending on CONFIG_REGULATOR? > > Given that we need those regulators enabled anyway, I guess we could > just select or depends on it > > I agree. > > Liu can you make a patch to Kconfig to just select REGULATOR? > Possibly even the specific regulator driver this SoC is using > if it is very specific for this purpose. > > Yours, > Linus Walleij Sure. I will send a new patch. Yours, Liu Xiang
Re: [PATCH] pinctrl: sunxi: fix use-after-free in sunxi_pmx_free()
> Hi, > On Tue, Jan 19, 2021 at 02:29:08PM +0800, Liu Xiang wrote: > When CONFIG_REGULATOR is not set, sunxi_pmx_request() always return > success. Even a group of pins call sunxi_pmx_request(), the refcount > is only 1. This can cause a use-after-free warning in sunxi_pmx_free(). > To solve this problem, go to err path if regulator_get() return NULL > or error. > > Signed-off-by: Liu Xiang > Is there any drawback to depending on CONFIG_REGULATOR? > Given that we need those regulators enabled anyway, I guess we could > just select or depends on it > > Maxime Yes, I think so. But CONFIG_REGULATOR is not enabled by default now. So I can find this problem during startup.
[PATCH] mmc: block: use REQ_HIPRI flag to complete request directly in own complete workqueue
After commit "40d09b53bfc557af7481b9d80f060a7ac9c7d314", request is completed in softirq. This may cause the system to suffer bad preemptoff time. The mmc driver has its own complete workqueue, but it can not work well now. The REQ_HIPRI flag can be used to complete request directly in its own complete workqueue and the preemptoff problem could be avoided. Signed-off-by: Liu Xiang --- drivers/mmc/core/block.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 42e27a298..c27239a89 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1985,8 +1985,10 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req) */ if (mq->in_recovery) mmc_blk_mq_complete_rq(mq, req); - else if (likely(!blk_should_fake_timeout(req->q))) + else if (likely(!blk_should_fake_timeout(req->q))) { + req->cmd_flags |= REQ_HIPRI; blk_mq_complete_request(req); + } mmc_blk_mq_dec_in_flight(mq, req); } -- 2.17.1
Re: [PATCH] blk-mq: introduce REQ_COMPLETE_WQ and add a workqueue to complete the request
On Wed, Jan 20, 2021 at 10:15:22AM +0800, Liu Xiang wrote: > The commit "40d09b53bfc557af7481b9d80f060a7ac9c7d314" has solved the > irqsoff problem by completing the request in softirq. But it may cause > the system to suffer bad preemptoff time. > Introduce the REQ_COMPLETE_WQ flag and blk_complete workqueue. > This flag makes the request to be completed in the blk_complete workqueue. > It can be used for requests that want to cut down both irqsoff and > preemptoff time. In addition to bloating the request_queue and introducing the completion fast path this seems to lack an actual user. I have tested mmc and virtio_blk drivers. They both have preemptoff problem. The mmc driver has its own complete workqueue. But it can not work well now. I think it is better to complete request directly with REQ_HIPRI flag. The virtio_blk driver can use REQ_COMPLETE_WQ flag to avoid preemptoff problem.
[PATCH] blk-mq: introduce REQ_COMPLETE_WQ and add a workqueue to complete the request
The commit "40d09b53bfc557af7481b9d80f060a7ac9c7d314" has solved the irqsoff problem by completing the request in softirq. But it may cause the system to suffer bad preemptoff time. Introduce the REQ_COMPLETE_WQ flag and blk_complete workqueue. This flag makes the request to be completed in the blk_complete workqueue. It can be used for requests that want to cut down both irqsoff and preemptoff time. Signed-off-by: Liu Xiang --- block/blk-mq.c| 46 +++ include/linux/blk_types.h | 4 include/linux/blkdev.h| 5 + 3 files changed, 55 insertions(+) diff --git a/block/blk-mq.c b/block/blk-mq.c index f285a9123..c707582ba 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -42,6 +42,10 @@ #include "blk-rq-qos.h" static DEFINE_PER_CPU(struct list_head, blk_cpu_done); +/* + * Controlling structure for block complete + */ +static struct workqueue_struct *blk_complete_wq; static void blk_mq_poll_stats_start(struct request_queue *q); static void blk_mq_poll_stats_fn(struct blk_stat_callback *cb); @@ -567,6 +571,26 @@ void blk_mq_end_request(struct request *rq, blk_status_t error) } EXPORT_SYMBOL(blk_mq_end_request); +static void blk_mq_complete_work(struct work_struct *work) +{ + struct request_queue *q = + container_of(work, struct request_queue, complete_work); + struct list_head local_list; + unsigned long flags; + + spin_lock_irqsave(>complete_lock, flags); + list_replace_init(>complete_list, _list); + spin_unlock_irqrestore(>complete_lock, flags); + + while (!list_empty(_list)) { + struct request *rq; + + rq = list_entry(local_list.next, struct request, complete_list); + list_del_init(>complete_list); + rq->q->mq_ops->complete(rq); + } +} + /* * Softirq action handler - move entries to local list and loop over them * while passing them to the queue registered handler. @@ -680,6 +704,19 @@ bool blk_mq_complete_request_remote(struct request *rq) if (rq->cmd_flags & REQ_HIPRI) return false; + /* +* For a request that wants to complete in workqueue, +*/ + if (rq->cmd_flags & REQ_COMPLETE_WQ) { + unsigned long flags; + + spin_lock_irqsave(>q->complete_lock, flags); + list_add_tail(>complete_list, >q->complete_list); + spin_unlock_irqrestore(>q->complete_lock, flags); + queue_work(blk_complete_wq, >q->complete_work); + return true; + } + if (blk_mq_complete_need_ipi(rq)) { INIT_CSD(>csd, __blk_mq_complete_request_remote, rq); smp_call_function_single_async(rq->mq_ctx->cpu, >csd); @@ -3211,6 +3248,10 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, INIT_LIST_HEAD(>requeue_list); spin_lock_init(>requeue_lock); + INIT_WORK(>complete_work, blk_mq_complete_work); + INIT_LIST_HEAD(>complete_list); + spin_lock_init(>complete_lock); + q->nr_requests = set->queue_depth; /* @@ -3907,6 +3948,11 @@ static int __init blk_mq_init(void) INIT_LIST_HEAD(_cpu(blk_cpu_done, i)); open_softirq(BLOCK_SOFTIRQ, blk_done_softirq); + blk_complete_wq = alloc_workqueue("blk_complete", + WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + if (!blk_complete_wq) + panic("Failed to create blk_complete\n"); + cpuhp_setup_state_nocalls(CPUHP_BLOCK_SOFTIRQ_DEAD, "block/softirq:dead", NULL, blk_softirq_cpu_dead); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 866f74261..251110fd9 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -421,6 +421,9 @@ enum req_flag_bits { __REQ_HIPRI, + /* do req complete in workqueue */ + __REQ_COMPLETE_WQ, + /* for driver use */ __REQ_DRV, __REQ_SWAP, /* swapping request. */ @@ -445,6 +448,7 @@ enum req_flag_bits { #define REQ_NOUNMAP(1ULL << __REQ_NOUNMAP) #define REQ_HIPRI (1ULL << __REQ_HIPRI) +#define REQ_COMPLETE_WQ(1ULL << __REQ_COMPLETE_WQ) #define REQ_DRV(1ULL << __REQ_DRV) #define REQ_SWAP (1ULL << __REQ_SWAP) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index f94ee3089..758aff8f0 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -143,6 +143,7 @@ struct request { struct bio *biotail; struct list_head queuelist; + struct list_head complete_list; /* * T
[PATCH] pinctrl: sunxi: fix use-after-free in sunxi_pmx_free()
When CONFIG_REGULATOR is not set, sunxi_pmx_request() always return success. Even a group of pins call sunxi_pmx_request(), the refcount is only 1. This can cause a use-after-free warning in sunxi_pmx_free(). To solve this problem, go to err path if regulator_get() return NULL or error. Signed-off-by: Liu Xiang --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index dc8d39ae0..d1a8974eb 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -777,7 +777,7 @@ static int sunxi_pmx_request(struct pinctrl_dev *pctldev, unsigned offset) snprintf(supply, sizeof(supply), "vcc-p%c", 'a' + bank); reg = regulator_get(pctl->dev, supply); - if (IS_ERR(reg)) { + if (IS_ERR_OR_NULL(reg)) { dev_err(pctl->dev, "Couldn't get bank P%c regulator\n", 'A' + bank); return PTR_ERR(reg); @@ -811,7 +811,7 @@ static int sunxi_pmx_free(struct pinctrl_dev *pctldev, unsigned offset) PINS_PER_BANK; struct sunxi_pinctrl_regulator *s_reg = >regulators[bank_offset]; - if (!refcount_dec_and_test(_reg->refcount)) + if (!s_reg->regulator || !refcount_dec_and_test(_reg->refcount)) return 0; regulator_disable(s_reg->regulator); -- 2.17.1
[PATCH v2] mm: hugetlb: fix type of delta parameter and related local variables in gather_surplus_pages()
On 64-bit machine, delta variable in hugetlb_acct_memory() may be larger than 0x, but gather_surplus_pages() can only use the low 32-bit value now. So we need to fix type of delta parameter and related local variables in gather_surplus_pages(). Reported-by: Ma Chenggong Signed-off-by: Liu Xiang Signed-off-by: Pan Jiagen --- Changes in v2: as suggested by Mike, apply the same fix to the related local variables in gather_surplus_pages(). --- --- mm/hugetlb.c | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 37f15c3..3797401 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1943,13 +1943,14 @@ struct page *alloc_huge_page_vma(struct hstate *h, struct vm_area_struct *vma, * Increase the hugetlb pool such that it can accommodate a reservation * of size 'delta'. */ -static int gather_surplus_pages(struct hstate *h, int delta) +static int gather_surplus_pages(struct hstate *h, long delta) __must_hold(_lock) { struct list_head surplus_list; struct page *page, *tmp; - int ret, i; - int needed, allocated; + int ret; + long i; + long needed, allocated; bool alloc_ok = true; needed = (h->resv_huge_pages + delta) - h->free_huge_pages; -- 1.9.1
回复:[PATCH] mm: hugetlb: fix type of delta parameter in gather_surplus_pages()
Thanks for your advice. I will send a v2 patch. -- 发件人:Mike Kravetz 发送时间:2020年11月19日(星期四) 02:44 收件人:liu xiang ; linux-mm 抄 送:akpm ; linux-kernel ; liuxiang_1999 ; pan jiagen 主 题:Re: [PATCH] mm: hugetlb: fix type of delta parameter in gather_surplus_pages() On 11/18/20 5:14 AM, Liu Xiang wrote: > On 64-bit machine, delta variable in hugetlb_acct_memory() may be larger > than 0x, but gather_surplus_pages() can only use the low 32-bit > value now. > > Reported-by: Ma Chenggong > Signed-off-by: Liu Xiang > Signed-off-by: Pan Jiagen > --- > mm/hugetlb.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/mm/hugetlb.c b/mm/hugetlb.c > index 37f15c3..293b36d 100644 > --- a/mm/hugetlb.c > +++ b/mm/hugetlb.c > @@ -1943,7 +1943,7 @@ struct page *alloc_huge_page_vma(struct hstate *h, > struct vm_area_struct *vma, > * Increase the hugetlb pool such that it can accommodate a reservation > * of size 'delta'. > */ > -static int gather_surplus_pages(struct hstate *h, int delta) > +static int gather_surplus_pages(struct hstate *h, long delta) > __must_hold(_lock) > { > struct list_head surplus_list; Thank you for noticing the type difference. However, if the parameter delta is changed to long then we should also change the local variables in gather_surplus_pages that are used with delta. Specifically, the local variables 'needed', 'allocated' and 'i' should also be of type long. -- Mike Kravetz
[PATCH] mm: hugetlb: fix type of delta parameter in gather_surplus_pages()
On 64-bit machine, delta variable in hugetlb_acct_memory() may be larger than 0x, but gather_surplus_pages() can only use the low 32-bit value now. Reported-by: Ma Chenggong Signed-off-by: Liu Xiang Signed-off-by: Pan Jiagen --- mm/hugetlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 37f15c3..293b36d 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1943,7 +1943,7 @@ struct page *alloc_huge_page_vma(struct hstate *h, struct vm_area_struct *vma, * Increase the hugetlb pool such that it can accommodate a reservation * of size 'delta'. */ -static int gather_surplus_pages(struct hstate *h, int delta) +static int gather_surplus_pages(struct hstate *h, long delta) __must_hold(_lock) { struct list_head surplus_list; -- 1.9.1
[PATCH] tty: serial: linflexuart: Remove unnecessary '|' operation and add error count
The '|' operation of status in linflex_rxint is unnecessary, so it can be removed. Signed-off-by: Liu Xiang --- drivers/tty/serial/fsl_linflexuart.c | 19 +-- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 3e28be4..d870480 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -252,23 +252,22 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id) flg = TTY_NORMAL; sport->icount.rx++; - if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_SZF | - LINFLEXD_UARTSR_FEF | LINFLEXD_UARTSR_PE)) { - if (status & LINFLEXD_UARTSR_SZF) - status |= LINFLEXD_UARTSR_SZF; + if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_FEF | + LINFLEXD_UARTSR_PE)) { if (status & LINFLEXD_UARTSR_BOF) - status |= LINFLEXD_UARTSR_BOF; + sport->icount.overrun++; if (status & LINFLEXD_UARTSR_FEF) { - if (!rx) + if (!rx) { brk = true; - status |= LINFLEXD_UARTSR_FEF; + sport->icount.brk++; + } else + sport->icount.frame++; } if (status & LINFLEXD_UARTSR_PE) - status |= LINFLEXD_UARTSR_PE; + sport->icount.parity++; } - writel(status | LINFLEXD_UARTSR_RMB | LINFLEXD_UARTSR_DRFRFE, - sport->membase + UARTSR); + writel(status, sport->membase + UARTSR); status = readl(sport->membase + UARTSR); if (brk) { -- 1.9.1
[PATCH] net: fec: disable correct clk in the err path of fec_enet_clk_enable
When enable clk_ref failed, clk_ptp should be disabled rather than clk_ref itself. Signed-off-by: Liu Xiang --- drivers/net/ethernet/freescale/fec_main.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index dc6f876..ac8d868 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1986,8 +1986,12 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable) return 0; failed_clk_ref: - if (fep->clk_ref) - clk_disable_unprepare(fep->clk_ref); + if (fep->clk_ptp) { + mutex_lock(>ptp_clk_mutex); + clk_disable_unprepare(fep->clk_ptp); + fep->ptp_clk_on = false; + mutex_unlock(>ptp_clk_mutex); + } failed_clk_ptp: if (fep->clk_enet_out) clk_disable_unprepare(fep->clk_enet_out); -- 1.9.1
[PATCH] mm: gup: fix comment of __get_user_pages()
Because nr_pages is unsigned long, it can not be negative. Signed-off-by: Liu Xiang --- mm/gup.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 8f236a3..0236954 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -735,10 +735,10 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags) * @nonblocking: whether waiting for disk IO or mmap_sem contention * * Returns number of pages pinned. This may be fewer than the number - * requested. If nr_pages is 0 or negative, returns 0. If no pages - * were pinned, returns -errno. Each page returned must be released - * with a put_page() call when it is finished with. vmas will only - * remain valid while mmap_sem is held. + * requested. If nr_pages is 0, returns 0. If no pages were pinned, + * returns -errno. Each page returned must be released with a + * put_page() call when it is finished with. vmas will only remain + * valid while mmap_sem is held. * * Must be called with mmap_sem held. It may be released. See below. * -- 1.9.1
[PATCH] mm: vmalloc: remove unnecessary highmem_mask from parameter of gfpflags_allow_blocking()
gfpflags_allow_blocking() does not care about __GFP_HIGHMEM, so highmem_mask can be removed. Signed-off-by: Liu Xiang --- mm/vmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 7ba11e1..143c636 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -2432,7 +2432,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, goto fail; } area->pages[i] = page; - if (gfpflags_allow_blocking(gfp_mask|highmem_mask)) + if (gfpflags_allow_blocking(gfp_mask)) cond_resched(); } atomic_long_add(area->nr_pages, _vmalloc_pages); -- 1.9.1
[PATCH v4] mtd: spi-nor: fix nor->addr_width when its value configured from SFDP does not match the actual width
IS25LP256 gets BFPT_DWORD1_ADDRESS_BYTES_3_ONLY from BFPT table for address width. But in actual fact the flash can support 4-byte address. Use a post bfpt fixup hook to overwrite the address width advertised by the BFPT. Suggested-by: Tudor Ambarus Signed-off-by: Liu Xiang --- Changes in v4: update the comment suggested by Tudor. --- drivers/mtd/spi-nor/spi-nor.c | 25 - 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 73172d7..ce153c4 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1687,6 +1687,28 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor) .flags = SPI_NOR_NO_FR | SPI_S3AN, static int +is25lp256_post_bfpt_fixups(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + /* +* IS25LP256 supports 4B opcodes, but the BFPT advertises a +* BFPT_DWORD1_ADDRESS_BYTES_3_ONLY address width. +* Overwrite the address width advertised by the BFPT. +*/ + if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) == + BFPT_DWORD1_ADDRESS_BYTES_3_ONLY) + nor->addr_width = 4; + + return 0; +} + +static struct spi_nor_fixups is25lp256_fixups = { + .post_bfpt = is25lp256_post_bfpt_fixups, +}; + +static int mx25l25635_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt, @@ -1827,7 +1849,8 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor) SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_4B_OPCODES) }, + SPI_NOR_4B_OPCODES) + .fixups = _fixups }, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, -- 1.9.1
Re:Re: [PATCH v3] mtd: spi-nor: fix nor->addr_width when its value configured from SFDP does not match the actual width
Hi, ta Thanks for your advice! I will send the update patch in soon. At 2019-06-22 19:49:25, tudor.amba...@microchip.com wrote: >Hi, Liu, > >On 03/31/2019 10:42 AM, Liu Xiang wrote: > >> Some is25lp256 get BFPT_DWORD1_ADDRESS_BYTES_3_ONLY from BFPT table for >> address width. But in actual fact the flash can support 4-byte address. >> So we should fix it. > >It's better to be imperative. Substitute "So we should fix it" with something >like "Use a post bfpt fixup hook to overwrite the address width advertised by >the BFPT". > >> > >We'll need a fixes tag here.> Suggested-by: Boris Brezillon > >> Suggested-by: Vignesh Raghavendra > >When? If they didn't explicitly suggested this approach, lets drop the S-b >tags. > >> Signed-off-by: Liu Xiang >> --- >> >> Changes in v3: >> add a fixup for is25lp256 to solve the address width problem. >> >> drivers/mtd/spi-nor/spi-nor.c | 25 - >> 1 file changed, 24 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c >> index 6e13bbd..d252a66 100644 >> --- a/drivers/mtd/spi-nor/spi-nor.c >> +++ b/drivers/mtd/spi-nor/spi-nor.c >> @@ -1682,6 +1682,28 @@ static int sr2_bit7_quad_enable(struct spi_nor *nor) >> .flags = SPI_NOR_NO_FR | SPI_S3AN, >> >> static int >> +is25lp256_post_bfpt_fixups(struct spi_nor *nor, >> + const struct sfdp_parameter_header *bfpt_header, >> + const struct sfdp_bfpt *bfpt, >> + struct spi_nor_flash_parameter *params) >> +{ >> +/* >> + * IS25LP256 supports 4B opcodes. >> + * Unfortunately, some devices get BFPT_DWORD1_ADDRESS_BYTES_3_ONLY >^ which devices, did you get a list from issi? > >> + * from BFPT table for address width. We should fix it. > >How about "IS25LP256 supports 4B opcodes, but the BFPT advertises a >BFPT_DWORD1_ADDRESS_BYTES_3_ONLY address width. Overwrite the address width >advertised by the BFPT." > >> + */ >> +if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) == >> +BFPT_DWORD1_ADDRESS_BYTES_3_ONLY) >> +nor->addr_width = 4; >> + >> +return 0; >> +} >> + >> +static struct spi_nor_fixups is25lp256_fixups = { > >Naga will use "is25lp256_fixups" for the is25wp256 too, but it's not the case >to >change the name yet. All good here. > >I really want to have this in next, can I have an update in the next few days? > >Cheers, >ta
[PATCH v2] fs: buffer: fix fully_mapped reset in block_read_full_page()
Because get_block() might set the buffer mapped, fully_mapped reset should be done according to the result of buffer_mapped(bh) which check the buffer mapped attribute again after get_block(). Signed-off-by: Liu Xiang --- Changes in v2: change comment fs/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/buffer.c b/fs/buffer.c index e450c55..987aadb 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2243,7 +2243,6 @@ int block_read_full_page(struct page *page, get_block_t *get_block) if (!buffer_mapped(bh)) { int err = 0; - fully_mapped = 0; if (iblock < lblock) { WARN_ON(bh->b_size != blocksize); err = get_block(inode, iblock, bh, 0); @@ -2251,6 +2250,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block) SetPageError(page); } if (!buffer_mapped(bh)) { + fully_mapped = 0; zero_user(page, i * blocksize, blocksize); if (!err) set_buffer_uptodate(bh); -- 1.9.1
[PATCH v2] ext4: fix prefetchw of NULL page
In ext4_mpage_readpages(), if the parameter pages is not NULL, another parameter page is NULL. At the first time prefetchw(>flags) works on NULL. From second time, prefetchw(>flags) always works on the last consumed page. This might do little improvment for handling current page. So prefetchw() should be called while the page pointer has just been updated. Signed-off-by: Liu Xiang --- Changes in v2: remove prefetchw() when pages is NULL and change comment fs/ext4/readpage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index 6aa282e..f138c47 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -126,9 +126,10 @@ int ext4_mpage_readpages(struct address_space *mapping, int fully_mapped = 1; unsigned first_hole = blocks_per_page; - prefetchw(>flags); if (pages) { page = lru_to_page(pages); + + prefetchw(>flags); list_del(>lru); if (add_to_page_cache_lru(page, mapping, page->index, readahead_gfp_mask(mapping))) -- 1.9.1
[PATCH] slub: update the comment about slab frozen
Now frozen slab can only be on the per cpu partial list. Signed-off-by: Liu Xiang --- mm/slub.c | 9 + 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index dc6..9e2f220 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -58,10 +58,11 @@ * D. page->frozen -> frozen state * * If a slab is frozen then it is exempt from list management. It is not - * on any list. The processor that froze the slab is the one who can - * perform list operations on the page. Other processors may put objects - * onto the freelist but the processor that froze the slab is the only - * one that can retrieve the objects from the page's freelist. + * on any list except per cpu partial list. The processor that froze the + * slab is the one who can perform list operations on the page. Other + * processors may put objects onto the freelist but the processor that + * froze the slab is the only one that can retrieve the objects from the + * page's freelist. * * The list_lock protects the partial and full list on each node and * the partial slab counter. If taken then no new slabs may be added or -- 1.9.1
Re:Re: [PATCH v2] mtd: spi-nor: Return error when nor->addr_width does not match the device size
Hi, Vignesh At 2019-03-19 13:22:15, "Vignesh Raghavendra" wrote: >Hi, > >On 13/03/19 7:15 PM, Liu Xiang wrote: >> In some is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header >> is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, >> means that 3-Byte only addressing. But the device size is larger >> than 16MB, nor->addr_width must be 4 to access the whole address. >> An error should be returned when nor->addr_width does not match >> the device size in spi_nor_parse_bfpt(). Then it can go back to >> use spi_nor_ids[] for setting the right addr_width. >> >> Suggested-by: Boris Brezillon >> Signed-off-by: Liu Xiang >> --- >> drivers/mtd/spi-nor/spi-nor.c | 8 >> 1 file changed, 8 insertions(+) >> >> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c >> index 6e13bbd..63933c7 100644 >> --- a/drivers/mtd/spi-nor/spi-nor.c >> +++ b/drivers/mtd/spi-nor/spi-nor.c >> @@ -2811,6 +2811,14 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, >> } >> params->size >>= 3; /* Convert to bytes. */ >> >> +/* >> + * If the device exceeds 16MiB, addr_width must be 4. >> + * addr_width == 3 means the Address Bytes we are >> + * reading from BFPT is wrong. >> + */ > >JESD216 standard does not mandate flash devices >16MiB to always support >4 byte addressing opcode. So, its okay for flash vendor to support >>16MiB flash with 3 byte addressing and Bank/extended address register. > >> +if (params->size > 0x100 && nor->addr_width == 3) >> +return -EINVAL; >> + > >Assuming only DWORD1[18:17] bits are wrong, then returning from here >would mean we miss parsing Sector Erase settings, Quad Enable >Requirements etc from BFPT which is kind of bad. >I suggest to move the fix to[1], addr_width indicated in flash_info >struct of the device can take precedence over SFDP. > >[1]https://elixir.bootlin.com/linux/latest/source/drivers/mtd/spi-nor/spi-nor.c#L4106 Boris has added a fixup function, do you think this is more better: static int is25lp256_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt, struct spi_nor_flash_parameter *params) { /* * IS25LP256 supports 4B opcodes. * Unfortunately, some devices get BFPT_DWORD1_ADDRESS_BYTES_3_ONLY * from BFPT table for address width. We should fix it. */ if (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK == BFPT_DWORD1_ADDRESS_BYTES_3_ONLY) nor->addr_width = 4; return 0; } static struct spi_nor_fixups is25lp256_fixups = { .post_bfpt = is25lp256_post_bfpt_fixups, }; > > >> /* Fast Read settings. */ >> for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { >> const struct sfdp_bfpt_read *rd = _bfpt_reads[i]; >> > >-- >Regards >Vignesh
Re:Re: [PATCH v2] mtd: spi-nor: Return error when nor->addr_width does not match the device size
Hi, Vignesh Thanks for your suggestion. I will send a new patch. At 2019-03-19 13:22:15, "Vignesh Raghavendra" wrote: >Hi, > >On 13/03/19 7:15 PM, Liu Xiang wrote: >> In some is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header >> is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, >> means that 3-Byte only addressing. But the device size is larger >> than 16MB, nor->addr_width must be 4 to access the whole address. >> An error should be returned when nor->addr_width does not match >> the device size in spi_nor_parse_bfpt(). Then it can go back to >> use spi_nor_ids[] for setting the right addr_width. >> >> Suggested-by: Boris Brezillon >> Signed-off-by: Liu Xiang >> --- >> drivers/mtd/spi-nor/spi-nor.c | 8 >> 1 file changed, 8 insertions(+) >> >> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c >> index 6e13bbd..63933c7 100644 >> --- a/drivers/mtd/spi-nor/spi-nor.c >> +++ b/drivers/mtd/spi-nor/spi-nor.c >> @@ -2811,6 +2811,14 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, >> } >> params->size >>= 3; /* Convert to bytes. */ >> >> +/* >> + * If the device exceeds 16MiB, addr_width must be 4. >> + * addr_width == 3 means the Address Bytes we are >> + * reading from BFPT is wrong. >> + */ > >JESD216 standard does not mandate flash devices >16MiB to always support >4 byte addressing opcode. So, its okay for flash vendor to support >>16MiB flash with 3 byte addressing and Bank/extended address register. > >> +if (params->size > 0x100 && nor->addr_width == 3) >> +return -EINVAL; >> + > >Assuming only DWORD1[18:17] bits are wrong, then returning from here >would mean we miss parsing Sector Erase settings, Quad Enable >Requirements etc from BFPT which is kind of bad. >I suggest to move the fix to[1], addr_width indicated in flash_info >struct of the device can take precedence over SFDP. > >[1]https://elixir.bootlin.com/linux/latest/source/drivers/mtd/spi-nor/spi-nor.c#L4106 > > >> /* Fast Read settings. */ >> for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { >> const struct sfdp_bfpt_read *rd = _bfpt_reads[i]; >> > >-- >Regards >Vignesh
[PATCH v2] mtd: spi-nor: Return error when nor->addr_width does not match the device size
In some is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, means that 3-Byte only addressing. But the device size is larger than 16MB, nor->addr_width must be 4 to access the whole address. An error should be returned when nor->addr_width does not match the device size in spi_nor_parse_bfpt(). Then it can go back to use spi_nor_ids[] for setting the right addr_width. Suggested-by: Boris Brezillon Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/spi-nor.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 6e13bbd..63933c7 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2811,6 +2811,14 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, } params->size >>= 3; /* Convert to bytes. */ + /* +* If the device exceeds 16MiB, addr_width must be 4. +* addr_width == 3 means the Address Bytes we are +* reading from BFPT is wrong. +*/ + if (params->size > 0x100 && nor->addr_width == 3) + return -EINVAL; + /* Fast Read settings. */ for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { const struct sfdp_bfpt_read *rd = _bfpt_reads[i]; -- 1.9.1
Re:Re:Re: [PATCH] mtd: spi-nor: Return error when nor->addr_width not match the device size
Hi, Boris I am sorry I have not got any further information from ISSI since last reply. As your suggest, when the Address Bytes we are reading from BFPT is wrong, an error is returned from spi_nor_parse_bfpt(). Then it can go back to use spi_nor_ids[] for setting addr_width. If we make sure the spi_nor_ids[] is right, it can work well. I will send a v2 patch. At 2018-11-16 21:24:10, "Liu Xiang" wrote: > >Hi Tudor, Boris, Cyrille, >There is no JEDEC BFPT tables in the datasheet. >In my test platform, I sent RDSFDP command to the flash and got the >parameters back. >My device type is IS25LP256D-JMLA, which is not in H/E/G/F series of flash >that is described in chapter 11 of the datasheet. The reply from ISSI suggests >only these certain devices can support SFDP table. >I am confused why my device can support RDSFDP command and give >parameters back. I will ask ISSI for more details. > > > >At 2018-11-15 19:02:56, "Boris Brezillon" wrote: >>On Thu, 15 Nov 2018 10:54:39 + >> wrote: >> >>> Hi, Liu, Boris, Cyrille, >>> >>> On 11/14/2018 03:51 PM, Boris Brezillon wrote: >>> > On Wed, 14 Nov 2018 20:56:05 +0800 >>> > Liu Xiang wrote: >>> > >>> >> In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header >>> >> is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, >>> >>> Liu, can you point us to a datasheet that has the JEDEC BFPT tables >>> described? I >>> couldn't find one ... >>> >>> >> means that 3-Byte only addressing. >>> > >>> > According to your other patch this NOR supports 4B opcode, which means >>> > the SFDP table is wrong. >>> > >>> >> But the device size is larger >>> >> than 16MB, nor->addr_width must be 4 to access the whole address. >>> >> An error should be returned when nor->addr_width not match >>> > >>> > ^does not >>> > >>> >> the device size in spi_nor_parse_sfdp(). >>> >> >>> >> Suggested-by: Boris Brezillon >>> >> Signed-off-by: Liu Xiang >>> >> --- >>> >> drivers/mtd/spi-nor/spi-nor.c | 4 >>> >> 1 file changed, 4 insertions(+) >>> >> >>> >> diff --git a/drivers/mtd/spi-nor/spi-nor.c >>> >> b/drivers/mtd/spi-nor/spi-nor.c >>> >> index 3eba13a..77eaf22 100644 >>> >> --- a/drivers/mtd/spi-nor/spi-nor.c >>> >> +++ b/drivers/mtd/spi-nor/spi-nor.c >>> >> @@ -2669,6 +2669,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, >>> >> } >>> >> params->size >>= 3; /* Convert to bytes. */ >>> >> >>> >> +/*if the device exceeds 16MiB, addr_width must be 4*/ >>> > >>> > Please add a white space after '/*' and before '*/': >>> > >>> > /* If the device exceeds 16MiB, ->addr_width must be 4. */ >>> > >>> >> +if ((params->size > 0x100) && (nor->addr_width == 3)) >>> > >>> > Parens are not needed around sub-conditions: >>> > >>> > if (params->size > 0x100 && nor->addr_width == 3) >>> > >>> >> +return -EINVAL; >>> >> + >>> > >>> > I'm not sure this is correct. Looks like some NORs only support 3B >>> > opcodes but have a "4-byte addressing" mode (see set_4byte() [1]). >>> > Don't know what's reported by the BFPT section in this case though >>> > (BFPT_DWORD1_ADDRESS_BYTES_3_ONLY or BFPT_DWORD1_ADDRESS_BYTES_3_OR_4). >>> >>> Boris, this is in close relation with your second patch: [PATCH v3 2/2] mtd: >>> spi-nor: Use 4B opcodes when the NOR advertises both 3B and 4B. >>> >>> When looking again at this, I would say that for the flashes that have a >>> "4-byte >>> addressing" mode, but just 3B opcodes, I would expect the DWORD1[18:17] to >>> be of >>> value BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (enters 4-Byte mode on command - >>> uses 3B >>> opcodes). >> >>The NOR we have and which is exposing BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 >>actually supports both 3B and 4B commands, so, in this particular case, >>BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 does not mean "3B opcode+4-byte >>addressing mode" >> >>> >>> If BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 and 4B opcodes, then we can query BFPT >>> DWORD16[31:24]: it should have value xx1x_b to indicate that 4B opcodes >>> are >>> supported. But which 4B opcodes are supported? >> >>I hope all of them. Wouldn't make sense to have only some of them >>supported. >> >>> Do all 3B opcodes have a 4B >>> opcode correspondent if SFDP 4-byte table is not available? This might be a >>> good >>> assumption, but I can't see it anywhere in jesd216c. >> >>I hope so...
Re:Re: [PATCH] irqchip/gic: fix passing wrong start irq number to irq_alloc_descs() for secondary GICs
Hi, Marc Thanks for your reply! At 2019-03-11 23:55:11, "Marc Zyngier" wrote: >On 11/03/2019 14:52, Liu Xiang wrote: >> For secondary GICs, the start irq number should skip over SGIs >> and PPIs. Its value should be 32. So we should pass hwirq_base to >> irq_alloc_descs() rather than a constant number 16. >> >> Signed-off-by: Liu Xiang >> --- >> drivers/irqchip/irq-gic.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c >> index ba2a37a..351f576 100644 >> --- a/drivers/irqchip/irq-gic.c >> +++ b/drivers/irqchip/irq-gic.c >> @@ -1157,7 +1157,7 @@ static int gic_init_bases(struct gic_chip_data *gic, >> int irq_start, >> >> gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ >> >> -irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, >> +irq_base = irq_alloc_descs(irq_start, hwirq_base, gic_irqs, >> numa_node_id()); >> if (irq_base < 0) { >> WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming >> pre-allocated\n", >> > >I suggest you look at __irq_alloc_descs(), and understand what the >various parameters mean. What you're doing here has absolutely no >effect. > >The right thing to do would be to get rid of this altogether, except >that we have exactly *one* platform in the tree that is still non-DT >(some unmaintained Cavium piece of junk). But we can still simplify it, >as this guy doesn't have a secondary GIC (it is braindead enough). > >What I'm suggesting instead is: > >From b41fdc4a7bf9045e4871c5b15905ea732ffd044f Mon Sep 17 00:00:00 2001 >From: Marc Zyngier >Date: Mon, 11 Mar 2019 15:38:10 + >Subject: [PATCH] irqchip/gic: Drop support for secondary GIC in non-DT systems > >We do not have any in-tree platform with this pathological setup, >and only a single system (Cavium's cns3xxx) isn't DT aware. > >Let's drop the secondary GIC support for now, until we remove >the above horror altogether. > >Signed-off-by: Marc Zyngier >--- > arch/arm/mach-cns3xxx/core.c| 2 +- > drivers/irqchip/irq-gic.c | 45 - > include/linux/irqchip/arm-gic.h | 3 +-- > 3 files changed, 18 insertions(+), 32 deletions(-) > >diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c >index 7d5a44a06648..f676592d8402 100644 >--- a/arch/arm/mach-cns3xxx/core.c >+++ b/arch/arm/mach-cns3xxx/core.c >@@ -90,7 +90,7 @@ void __init cns3xxx_map_io(void) > /* used by entry-macro.S */ > void __init cns3xxx_init_irq(void) > { >- gic_init(0, 29, IOMEM(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT), >+ gic_init(IOMEM(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT), >IOMEM(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT)); > } > >diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c >index ba2a37a27a54..fd3110c171ba 100644 >--- a/drivers/irqchip/irq-gic.c >+++ b/drivers/irqchip/irq-gic.c >@@ -1089,11 +1089,10 @@ static void gic_init_chip(struct gic_chip_data *gic, >struct device *dev, > #endif > } > >-static int gic_init_bases(struct gic_chip_data *gic, int irq_start, >+static int gic_init_bases(struct gic_chip_data *gic, > struct fwnode_handle *handle) > { >- irq_hw_number_t hwirq_base; >- int gic_irqs, irq_base, ret; >+ int gic_irqs, ret; > > if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) { > /* Frankein-GIC without banked registers... */ >@@ -1145,28 +1144,21 @@ static int gic_init_bases(struct gic_chip_data *gic, >int irq_start, > } else {/* Legacy support */ > /* >* For primary GICs, skip over SGIs. >- * For secondary GICs, skip over PPIs, too. >+ * No secondary GIC support whatsoever. >*/ >- if (gic == _data[0] && (irq_start & 31) > 0) { >- hwirq_base = 16; >- if (irq_start != -1) >- irq_start = (irq_start & ~31) + 16; >- } else { >- hwirq_base = 32; >- } >+ int irq_base; > >- gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ >+ gic_irqs -= 16; /* calculate # of irqs to allocate */ > >- irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, >+ irq_base = irq_alloc_descs(16, 16, gic_irqs, >
[PATCH] irqchip/gic: fix passing wrong start irq number to irq_alloc_descs() for secondary GICs
For secondary GICs, the start irq number should skip over SGIs and PPIs. Its value should be 32. So we should pass hwirq_base to irq_alloc_descs() rather than a constant number 16. Signed-off-by: Liu Xiang --- drivers/irqchip/irq-gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index ba2a37a..351f576 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1157,7 +1157,7 @@ static int gic_init_bases(struct gic_chip_data *gic, int irq_start, gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ - irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, + irq_base = irq_alloc_descs(irq_start, hwirq_base, gic_irqs, numa_node_id()); if (irq_base < 0) { WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", -- 1.9.1
[PATCH] ext4: do prefetchw while the page pointer has been updated
When pages is not NULL, prefetchw(>flags) always works on the last consumed page. This might do little improvment for handling current page. It is better to do prefetchw while the page pointer has just been updated. Signed-off-by: Liu Xiang --- fs/ext4/readpage.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index 6aa282e..0b68dbe 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -126,14 +126,17 @@ int ext4_mpage_readpages(struct address_space *mapping, int fully_mapped = 1; unsigned first_hole = blocks_per_page; - prefetchw(>flags); if (pages) { page = lru_to_page(pages); + + prefetchw(>flags); list_del(>lru); if (add_to_page_cache_lru(page, mapping, page->index, readahead_gfp_mask(mapping))) goto next_page; - } + } else + prefetchw(>flags); + if (page_has_buffers(page)) goto confused; -- 1.9.1
[PATCH] ext2: Fix a typo in comment
Fix a typo in ext2_get_blocks comment. Signed-off-by: Liu Xiang --- fs/ext2/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index e4bb938..11da3fb 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -717,7 +717,7 @@ static int ext2_get_blocks(struct inode *inode, /* the number of blocks need to allocate for [d,t]indirect blocks */ indirect_blks = (chain + depth) - partial - 1; /* -* Next look up the indirect map to count the totoal number of +* Next look up the indirect map to count the total number of * direct blocks to allocate for this branch. */ count = ext2_blks_to_allocate(partial, indirect_blks, -- 1.9.1
[PATCH] fs: Reset fully_mapped more accurately
Because get_block() might set the buffer mapped, reset fully_mapped after it is more accurately. Signed-off-by: Liu Xiang --- fs/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/buffer.c b/fs/buffer.c index 52d024b..b2e9167 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2241,7 +2241,6 @@ int block_read_full_page(struct page *page, get_block_t *get_block) if (!buffer_mapped(bh)) { int err = 0; - fully_mapped = 0; if (iblock < lblock) { WARN_ON(bh->b_size != blocksize); err = get_block(inode, iblock, bh, 0); @@ -2249,6 +2248,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block) SetPageError(page); } if (!buffer_mapped(bh)) { + fully_mapped = 0; zero_user(page, i * blocksize, blocksize); if (!err) set_buffer_uptodate(bh); -- 1.9.1
[PATCH] ext2: Remove redundant check for finding no group
When best_desc keeps NULL, best_group keeps -1, too. So we can return best_group directly. Signed-off-by: Liu Xiang --- fs/ext2/ialloc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 5c3d7b7..a0c5ea9 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -222,8 +222,6 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) best_desc = desc; } } - if (!best_desc) - return -1; return best_group; } -- 1.9.1
[PATCH] ext2: Remove useless reset code
If ((char *)de == dir_end) is true, the name_len will not be used in the subsequent routine. So the reset code can be removed. Signed-off-by: Liu Xiang --- fs/ext2/dir.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 3b8114d..5ec497f 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -517,7 +517,6 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode) while ((char *)de <= kaddr) { if ((char *)de == dir_end) { /* We hit i_size */ - name_len = 0; rec_len = chunk_size; de->rec_len = ext2_rec_len_to_disk(chunk_size); de->inode = 0; -- 1.9.1
[PATCH] mm/filemap.c: Simplify the calculation of ra->prev_pos
The calculation of ra->prev_pos can be simplified. Signed-off-by: Liu Xiang --- mm/filemap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 9f5e323..7f30844 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2279,9 +2279,7 @@ static ssize_t generic_file_buffered_read(struct kiocb *iocb, would_block: error = -EAGAIN; out: - ra->prev_pos = prev_index; - ra->prev_pos <<= PAGE_SHIFT; - ra->prev_pos |= prev_offset; + ra->prev_pos = (prev_index << PAGE_SHIFT) | prev_offset; *ppos = ((loff_t)index << PAGE_SHIFT) + offset; file_accessed(filp); -- 1.9.1
[PATCH] ext2: Remove redundant check on s_inode_size
The case of (EXT2_INODE_SIZE(sb) == 0) is included in (sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE). So there is no need to check again. Signed-off-by: Liu Xiang --- fs/ext2/super.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 73b2d52..c71c2e3 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1024,8 +1024,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); - if (EXT2_INODE_SIZE(sb) == 0) - goto cantfind_ext2; sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb); if (sbi->s_inodes_per_block == 0 || sbi->s_inodes_per_group == 0) goto cantfind_ext2; -- 1.9.1
[PATCH] openrisc: Add spaces around & operator
Add spaces around '&' to follow kernel coding style. Signed-off-by: Liu Xiang --- arch/openrisc/include/asm/fixmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/openrisc/include/asm/fixmap.h b/arch/openrisc/include/asm/fixmap.h index 5a01595..75c7a77 100644 --- a/arch/openrisc/include/asm/fixmap.h +++ b/arch/openrisc/include/asm/fixmap.h @@ -55,7 +55,7 @@ enum fixed_addresses { #define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) -#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)_MASK)) >> PAGE_SHIFT) +#define __virt_to_fix(x) ((FIXADDR_TOP - ((x) & PAGE_MASK)) >> PAGE_SHIFT) /* * 'index to address' translation. If anyone tries to use the idx -- 1.9.1
[PATCH] openrisc: Add spaces around & operator
Add spaces around '&' to follow kernel coding style. Signed-off-by: Liu Xiang --- arch/openrisc/include/asm/fixmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/openrisc/include/asm/fixmap.h b/arch/openrisc/include/asm/fixmap.h index 5a01595..75c7a77 100644 --- a/arch/openrisc/include/asm/fixmap.h +++ b/arch/openrisc/include/asm/fixmap.h @@ -55,7 +55,7 @@ enum fixed_addresses { #define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) -#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)_MASK)) >> PAGE_SHIFT) +#define __virt_to_fix(x) ((FIXADDR_TOP - ((x) & PAGE_MASK)) >> PAGE_SHIFT) /* * 'index to address' translation. If anyone tries to use the idx -- 1.9.1
[PATCH] asm-generic: Add spaces around & operator
Add spaces around '&' to follow kernel coding style. Signed-off-by: Liu Xiang --- include/asm-generic/fixmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-generic/fixmap.h b/include/asm-generic/fixmap.h index 827e4d3..d6e8da3 100644 --- a/include/asm-generic/fixmap.h +++ b/include/asm-generic/fixmap.h @@ -18,7 +18,7 @@ #include #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) -#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)_MASK)) >> PAGE_SHIFT) +#define __virt_to_fix(x) ((FIXADDR_TOP - ((x) & PAGE_MASK)) >> PAGE_SHIFT) #ifndef __ASSEMBLY__ /* -- 1.9.1
[PATCH] asm-generic: Add spaces around & operator
Add spaces around '&' to follow kernel coding style. Signed-off-by: Liu Xiang --- include/asm-generic/fixmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-generic/fixmap.h b/include/asm-generic/fixmap.h index 827e4d3..d6e8da3 100644 --- a/include/asm-generic/fixmap.h +++ b/include/asm-generic/fixmap.h @@ -18,7 +18,7 @@ #include #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) -#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)_MASK)) >> PAGE_SHIFT) +#define __virt_to_fix(x) ((FIXADDR_TOP - ((x) & PAGE_MASK)) >> PAGE_SHIFT) #ifndef __ASSEMBLY__ /* -- 1.9.1
[PATCH] arm64: mm: Add spaces around + operator
Add spaces around '+' to follow kernel coding style. Signed-off-by: Liu Xiang --- arch/arm64/mm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index d1d6601..1dbd7be 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -853,7 +853,7 @@ void __set_fixmap(enum fixed_addresses idx, set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, flags)); } else { pte_clear(_mm, addr, ptep); - flush_tlb_kernel_range(addr, addr+PAGE_SIZE); + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); } } -- 1.9.1
[PATCH] arm64: mm: Add spaces around + operator
Add spaces around '+' to follow kernel coding style. Signed-off-by: Liu Xiang --- arch/arm64/mm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index d1d6601..1dbd7be 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -853,7 +853,7 @@ void __set_fixmap(enum fixed_addresses idx, set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, flags)); } else { pte_clear(_mm, addr, ptep); - flush_tlb_kernel_range(addr, addr+PAGE_SIZE); + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); } } -- 1.9.1
Re:Re: [PATCH] mtd: spi-nor: Return error when nor->addr_width not match the device size
Hi Tudor, Boris, Cyrille, There is no JEDEC BFPT tables in the datasheet. In my test platform, I sent RDSFDP command to the flash and got the parameters back. My device type is IS25LP256D-JMLA, which is not in H/E/G/F series of flash that is described in chapter 11 of the datasheet. The reply from ISSI suggests only these certain devices can support SFDP table. I am confused why my device can support RDSFDP command and give parameters back. I will ask ISSI for more details. At 2018-11-15 19:02:56, "Boris Brezillon" wrote: >On Thu, 15 Nov 2018 10:54:39 + > wrote: > >> Hi, Liu, Boris, Cyrille, >> >> On 11/14/2018 03:51 PM, Boris Brezillon wrote: >> > On Wed, 14 Nov 2018 20:56:05 +0800 >> > Liu Xiang wrote: >> > >> >> In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header >> >> is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, >> >> Liu, can you point us to a datasheet that has the JEDEC BFPT tables >> described? I >> couldn't find one ... >> >> >> means that 3-Byte only addressing. >> > >> > According to your other patch this NOR supports 4B opcode, which means >> > the SFDP table is wrong. >> > >> >> But the device size is larger >> >> than 16MB, nor->addr_width must be 4 to access the whole address. >> >> An error should be returned when nor->addr_width not match >> > >> > ^does not >> > >> >> the device size in spi_nor_parse_sfdp(). >> >> >> >> Suggested-by: Boris Brezillon >> >> Signed-off-by: Liu Xiang >> >> --- >> >> drivers/mtd/spi-nor/spi-nor.c | 4 >> >> 1 file changed, 4 insertions(+) >> >> >> >> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c >> >> index 3eba13a..77eaf22 100644 >> >> --- a/drivers/mtd/spi-nor/spi-nor.c >> >> +++ b/drivers/mtd/spi-nor/spi-nor.c >> >> @@ -2669,6 +2669,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, >> >> } >> >> params->size >>= 3; /* Convert to bytes. */ >> >> >> >> + /*if the device exceeds 16MiB, addr_width must be 4*/ >> > >> > Please add a white space after '/*' and before '*/': >> > >> >/* If the device exceeds 16MiB, ->addr_width must be 4. */ >> > >> >> + if ((params->size > 0x100) && (nor->addr_width == 3)) >> > >> > Parens are not needed around sub-conditions: >> > >> >if (params->size > 0x100 && nor->addr_width == 3) >> > >> >> + return -EINVAL; >> >> + >> > >> > I'm not sure this is correct. Looks like some NORs only support 3B >> > opcodes but have a "4-byte addressing" mode (see set_4byte() [1]). >> > Don't know what's reported by the BFPT section in this case though >> > (BFPT_DWORD1_ADDRESS_BYTES_3_ONLY or BFPT_DWORD1_ADDRESS_BYTES_3_OR_4). >> >> Boris, this is in close relation with your second patch: [PATCH v3 2/2] mtd: >> spi-nor: Use 4B opcodes when the NOR advertises both 3B and 4B. >> >> When looking again at this, I would say that for the flashes that have a >> "4-byte >> addressing" mode, but just 3B opcodes, I would expect the DWORD1[18:17] to >> be of >> value BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (enters 4-Byte mode on command - uses >> 3B >> opcodes). > >The NOR we have and which is exposing BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 >actually supports both 3B and 4B commands, so, in this particular case, >BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 does not mean "3B opcode+4-byte >addressing mode" > >> >> If BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 and 4B opcodes, then we can query BFPT >> DWORD16[31:24]: it should have value xx1x_b to indicate that 4B opcodes >> are >> supported. But which 4B opcodes are supported? > >I hope all of them. Wouldn't make sense to have only some of them >supported. > >> Do all 3B opcodes have a 4B >> opcode correspondent if SFDP 4-byte table is not available? This might be a >> good >> assumption, but I can't see it anywhere in jesd216c. > >I hope so...
Re:Re: [PATCH] mtd: spi-nor: Return error when nor->addr_width not match the device size
Hi Tudor, Boris, Cyrille, There is no JEDEC BFPT tables in the datasheet. In my test platform, I sent RDSFDP command to the flash and got the parameters back. My device type is IS25LP256D-JMLA, which is not in H/E/G/F series of flash that is described in chapter 11 of the datasheet. The reply from ISSI suggests only these certain devices can support SFDP table. I am confused why my device can support RDSFDP command and give parameters back. I will ask ISSI for more details. At 2018-11-15 19:02:56, "Boris Brezillon" wrote: >On Thu, 15 Nov 2018 10:54:39 + > wrote: > >> Hi, Liu, Boris, Cyrille, >> >> On 11/14/2018 03:51 PM, Boris Brezillon wrote: >> > On Wed, 14 Nov 2018 20:56:05 +0800 >> > Liu Xiang wrote: >> > >> >> In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header >> >> is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, >> >> Liu, can you point us to a datasheet that has the JEDEC BFPT tables >> described? I >> couldn't find one ... >> >> >> means that 3-Byte only addressing. >> > >> > According to your other patch this NOR supports 4B opcode, which means >> > the SFDP table is wrong. >> > >> >> But the device size is larger >> >> than 16MB, nor->addr_width must be 4 to access the whole address. >> >> An error should be returned when nor->addr_width not match >> > >> > ^does not >> > >> >> the device size in spi_nor_parse_sfdp(). >> >> >> >> Suggested-by: Boris Brezillon >> >> Signed-off-by: Liu Xiang >> >> --- >> >> drivers/mtd/spi-nor/spi-nor.c | 4 >> >> 1 file changed, 4 insertions(+) >> >> >> >> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c >> >> index 3eba13a..77eaf22 100644 >> >> --- a/drivers/mtd/spi-nor/spi-nor.c >> >> +++ b/drivers/mtd/spi-nor/spi-nor.c >> >> @@ -2669,6 +2669,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, >> >> } >> >> params->size >>= 3; /* Convert to bytes. */ >> >> >> >> + /*if the device exceeds 16MiB, addr_width must be 4*/ >> > >> > Please add a white space after '/*' and before '*/': >> > >> >/* If the device exceeds 16MiB, ->addr_width must be 4. */ >> > >> >> + if ((params->size > 0x100) && (nor->addr_width == 3)) >> > >> > Parens are not needed around sub-conditions: >> > >> >if (params->size > 0x100 && nor->addr_width == 3) >> > >> >> + return -EINVAL; >> >> + >> > >> > I'm not sure this is correct. Looks like some NORs only support 3B >> > opcodes but have a "4-byte addressing" mode (see set_4byte() [1]). >> > Don't know what's reported by the BFPT section in this case though >> > (BFPT_DWORD1_ADDRESS_BYTES_3_ONLY or BFPT_DWORD1_ADDRESS_BYTES_3_OR_4). >> >> Boris, this is in close relation with your second patch: [PATCH v3 2/2] mtd: >> spi-nor: Use 4B opcodes when the NOR advertises both 3B and 4B. >> >> When looking again at this, I would say that for the flashes that have a >> "4-byte >> addressing" mode, but just 3B opcodes, I would expect the DWORD1[18:17] to >> be of >> value BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (enters 4-Byte mode on command - uses >> 3B >> opcodes). > >The NOR we have and which is exposing BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 >actually supports both 3B and 4B commands, so, in this particular case, >BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 does not mean "3B opcode+4-byte >addressing mode" > >> >> If BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 and 4B opcodes, then we can query BFPT >> DWORD16[31:24]: it should have value xx1x_b to indicate that 4B opcodes >> are >> supported. But which 4B opcodes are supported? > >I hope all of them. Wouldn't make sense to have only some of them >supported. > >> Do all 3B opcodes have a 4B >> opcode correspondent if SFDP 4-byte table is not available? This might be a >> good >> assumption, but I can't see it anywhere in jesd216c. > >I hope so...
Re:Re: [PATCH] mtd: spi-nor: Return error when nor->addr_width not match the device size
Hi, If the check is moved to [2]https://elixir.bootlin.com/linux/v4.20-rc2/source/drivers/mtd/spi-nor/spi-nor.c#L3758, the nor->addr_width selection logic may be needed to rework. I have sent an email to ISSI for the register value, but haven't got the reply. Do you think it is better to add this check until I get the right answer from ISSI? At 2018-11-14 21:51:29, "Boris Brezillon" wrote: >On Wed, 14 Nov 2018 20:56:05 +0800 >Liu Xiang wrote: > >> In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header >> is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, >> means that 3-Byte only addressing. > >According to your other patch this NOR supports 4B opcode, which means >the SFDP table is wrong. > >> But the device size is larger >> than 16MB, nor->addr_width must be 4 to access the whole address. >> An error should be returned when nor->addr_width not match > > ^does not > >> the device size in spi_nor_parse_sfdp(). >> >> Suggested-by: Boris Brezillon >> Signed-off-by: Liu Xiang >> --- >> drivers/mtd/spi-nor/spi-nor.c | 4 >> 1 file changed, 4 insertions(+) >> >> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c >> index 3eba13a..77eaf22 100644 >> --- a/drivers/mtd/spi-nor/spi-nor.c >> +++ b/drivers/mtd/spi-nor/spi-nor.c >> @@ -2669,6 +2669,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, >> } >> params->size >>= 3; /* Convert to bytes. */ >> >> +/*if the device exceeds 16MiB, addr_width must be 4*/ > >Please add a white space after '/*' and before '*/': > > /* If the device exceeds 16MiB, ->addr_width must be 4. */ > >> +if ((params->size > 0x100) && (nor->addr_width == 3)) > >Parens are not needed around sub-conditions: > > if (params->size > 0x100 && nor->addr_width == 3) > >> +return -EINVAL; >> + > >I'm not sure this is correct. Looks like some NORs only support 3B >opcodes but have a "4-byte addressing" mode (see set_4byte() [1]). >Don't know what's reported by the BFPT section in this case though >(BFPT_DWORD1_ADDRESS_BYTES_3_ONLY or BFPT_DWORD1_ADDRESS_BYTES_3_OR_4). > >Anyway, I think this check should be moved here [2] to cover the >non-SFDP case. > >> /* Fast Read settings. */ >> for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { >> const struct sfdp_bfpt_read *rd = _bfpt_reads[i]; > >[1]https://elixir.bootlin.com/linux/v4.20-rc2/source/drivers/mtd/spi-nor/spi-nor.c#L278 >[2]https://elixir.bootlin.com/linux/v4.20-rc2/source/drivers/mtd/spi-nor/spi-nor.c#L3758
Re:Re: [PATCH] mtd: spi-nor: Return error when nor->addr_width not match the device size
Hi, If the check is moved to [2]https://elixir.bootlin.com/linux/v4.20-rc2/source/drivers/mtd/spi-nor/spi-nor.c#L3758, the nor->addr_width selection logic may be needed to rework. I have sent an email to ISSI for the register value, but haven't got the reply. Do you think it is better to add this check until I get the right answer from ISSI? At 2018-11-14 21:51:29, "Boris Brezillon" wrote: >On Wed, 14 Nov 2018 20:56:05 +0800 >Liu Xiang wrote: > >> In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header >> is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, >> means that 3-Byte only addressing. > >According to your other patch this NOR supports 4B opcode, which means >the SFDP table is wrong. > >> But the device size is larger >> than 16MB, nor->addr_width must be 4 to access the whole address. >> An error should be returned when nor->addr_width not match > > ^does not > >> the device size in spi_nor_parse_sfdp(). >> >> Suggested-by: Boris Brezillon >> Signed-off-by: Liu Xiang >> --- >> drivers/mtd/spi-nor/spi-nor.c | 4 >> 1 file changed, 4 insertions(+) >> >> diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c >> index 3eba13a..77eaf22 100644 >> --- a/drivers/mtd/spi-nor/spi-nor.c >> +++ b/drivers/mtd/spi-nor/spi-nor.c >> @@ -2669,6 +2669,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, >> } >> params->size >>= 3; /* Convert to bytes. */ >> >> +/*if the device exceeds 16MiB, addr_width must be 4*/ > >Please add a white space after '/*' and before '*/': > > /* If the device exceeds 16MiB, ->addr_width must be 4. */ > >> +if ((params->size > 0x100) && (nor->addr_width == 3)) > >Parens are not needed around sub-conditions: > > if (params->size > 0x100 && nor->addr_width == 3) > >> +return -EINVAL; >> + > >I'm not sure this is correct. Looks like some NORs only support 3B >opcodes but have a "4-byte addressing" mode (see set_4byte() [1]). >Don't know what's reported by the BFPT section in this case though >(BFPT_DWORD1_ADDRESS_BYTES_3_ONLY or BFPT_DWORD1_ADDRESS_BYTES_3_OR_4). > >Anyway, I think this check should be moved here [2] to cover the >non-SFDP case. > >> /* Fast Read settings. */ >> for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { >> const struct sfdp_bfpt_read *rd = _bfpt_reads[i]; > >[1]https://elixir.bootlin.com/linux/v4.20-rc2/source/drivers/mtd/spi-nor/spi-nor.c#L278 >[2]https://elixir.bootlin.com/linux/v4.20-rc2/source/drivers/mtd/spi-nor/spi-nor.c#L3758
[PATCH] mtd: spi-nor: Add 4B_OPCODES flag to is25lp256
The is25lp256 supports 4-byte opcodes and quad output. Suggested-by: Boris Brezillon Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 3e54e31..3eba13a 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1357,7 +1357,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ) }, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, -- 1.9.1
[PATCH] mtd: spi-nor: Add 4B_OPCODES flag to is25lp256
The is25lp256 supports 4-byte opcodes and quad output. Suggested-by: Boris Brezillon Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 3e54e31..3eba13a 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1357,7 +1357,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ) }, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, -- 1.9.1
[PATCH] mtd: spi-nor: Return error when nor->addr_width not match the device size
In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, means that 3-Byte only addressing. But the device size is larger than 16MB, nor->addr_width must be 4 to access the whole address. An error should be returned when nor->addr_width not match the device size in spi_nor_parse_sfdp(). Suggested-by: Boris Brezillon Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/spi-nor.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 3eba13a..77eaf22 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2669,6 +2669,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, } params->size >>= 3; /* Convert to bytes. */ + /*if the device exceeds 16MiB, addr_width must be 4*/ + if ((params->size > 0x100) && (nor->addr_width == 3)) + return -EINVAL; + /* Fast Read settings. */ for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { const struct sfdp_bfpt_read *rd = _bfpt_reads[i]; -- 1.9.1
[PATCH] mtd: spi-nor: Return error when nor->addr_width not match the device size
In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, means that 3-Byte only addressing. But the device size is larger than 16MB, nor->addr_width must be 4 to access the whole address. An error should be returned when nor->addr_width not match the device size in spi_nor_parse_sfdp(). Suggested-by: Boris Brezillon Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/spi-nor.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 3eba13a..77eaf22 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2669,6 +2669,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, } params->size >>= 3; /* Convert to bytes. */ + /*if the device exceeds 16MiB, addr_width must be 4*/ + if ((params->size > 0x100) && (nor->addr_width == 3)) + return -EINVAL; + /* Fast Read settings. */ for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { const struct sfdp_bfpt_read *rd = _bfpt_reads[i]; -- 1.9.1
[PATCH v3] mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
If the size of spi-nor flash is larger than 16MB, the read_opcode is set to SPINOR_OP_READ_1_1_4_4B, and fsl_qspi_get_seqid() will return -EINVAL when cmd is SPINOR_OP_READ_1_1_4_4B. This can cause read operation fail. Fixes: e46ecda764dc ("mtd: spi-nor: Add Freescale QuadSPI driver") Cc: Signed-off-by: Liu Xiang --- Changes in v3: move changelog position. drivers/mtd/spi-nor/fsl-quadspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 7d9620c..64304a3 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) { switch (cmd) { case SPINOR_OP_READ_1_1_4: + case SPINOR_OP_READ_1_1_4_4B: return SEQID_READ; case SPINOR_OP_WREN: return SEQID_WREN; -- 1.9.1
[PATCH v3] mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
If the size of spi-nor flash is larger than 16MB, the read_opcode is set to SPINOR_OP_READ_1_1_4_4B, and fsl_qspi_get_seqid() will return -EINVAL when cmd is SPINOR_OP_READ_1_1_4_4B. This can cause read operation fail. Fixes: e46ecda764dc ("mtd: spi-nor: Add Freescale QuadSPI driver") Cc: Signed-off-by: Liu Xiang --- Changes in v3: move changelog position. drivers/mtd/spi-nor/fsl-quadspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 7d9620c..64304a3 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) { switch (cmd) { case SPINOR_OP_READ_1_1_4: + case SPINOR_OP_READ_1_1_4_4B: return SEQID_READ; case SPINOR_OP_WREN: return SEQID_WREN; -- 1.9.1
Re:Re: [PATCH v2] mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
Thanks for your suggestion. Should I send another patch? At 2018-08-28 21:23:05, "Boris Brezillon" wrote: >On Tue, 28 Aug 2018 21:21:16 +0800 >Liu Xiang wrote: > >> If the size of spi-nor flash is larger than 16MB, the read_opcode >> is set to SPINOR_OP_READ_1_1_4_4B, and fsl_qspi_get_seqid() will >> return -EINVAL when cmd is SPINOR_OP_READ_1_1_4_4B. This can >> cause read operation fail. >> >> --- >> v2: >> add Fixes tag and CC stable suggested by Boris. >> --- > >The above changelog > >> >> Fixes: e46ecda764dc ("mtd: spi-nor: Add Freescale QuadSPI driver") >> Cc: >> Signed-off-by: Liu Xiang >> --- > >should be placed here. > >> drivers/mtd/spi-nor/fsl-quadspi.c | 1 + >> 1 file changed, 1 insertion(+) >> >> diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c >> b/drivers/mtd/spi-nor/fsl-quadspi.c >> index 7d9620c..64304a3 100644 >> --- a/drivers/mtd/spi-nor/fsl-quadspi.c >> +++ b/drivers/mtd/spi-nor/fsl-quadspi.c >> @@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) >> { >> switch (cmd) { >> case SPINOR_OP_READ_1_1_4: >> +case SPINOR_OP_READ_1_1_4_4B: >> return SEQID_READ; >> case SPINOR_OP_WREN: >> return SEQID_WREN;
Re:Re: [PATCH v2] mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
Thanks for your suggestion. Should I send another patch? At 2018-08-28 21:23:05, "Boris Brezillon" wrote: >On Tue, 28 Aug 2018 21:21:16 +0800 >Liu Xiang wrote: > >> If the size of spi-nor flash is larger than 16MB, the read_opcode >> is set to SPINOR_OP_READ_1_1_4_4B, and fsl_qspi_get_seqid() will >> return -EINVAL when cmd is SPINOR_OP_READ_1_1_4_4B. This can >> cause read operation fail. >> >> --- >> v2: >> add Fixes tag and CC stable suggested by Boris. >> --- > >The above changelog > >> >> Fixes: e46ecda764dc ("mtd: spi-nor: Add Freescale QuadSPI driver") >> Cc: >> Signed-off-by: Liu Xiang >> --- > >should be placed here. > >> drivers/mtd/spi-nor/fsl-quadspi.c | 1 + >> 1 file changed, 1 insertion(+) >> >> diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c >> b/drivers/mtd/spi-nor/fsl-quadspi.c >> index 7d9620c..64304a3 100644 >> --- a/drivers/mtd/spi-nor/fsl-quadspi.c >> +++ b/drivers/mtd/spi-nor/fsl-quadspi.c >> @@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) >> { >> switch (cmd) { >> case SPINOR_OP_READ_1_1_4: >> +case SPINOR_OP_READ_1_1_4_4B: >> return SEQID_READ; >> case SPINOR_OP_WREN: >> return SEQID_WREN;
[PATCH v2] mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
If the size of spi-nor flash is larger than 16MB, the read_opcode is set to SPINOR_OP_READ_1_1_4_4B, and fsl_qspi_get_seqid() will return -EINVAL when cmd is SPINOR_OP_READ_1_1_4_4B. This can cause read operation fail. --- v2: add Fixes tag and CC stable suggested by Boris. --- Fixes: e46ecda764dc ("mtd: spi-nor: Add Freescale QuadSPI driver") Cc: Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/fsl-quadspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 7d9620c..64304a3 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) { switch (cmd) { case SPINOR_OP_READ_1_1_4: + case SPINOR_OP_READ_1_1_4_4B: return SEQID_READ; case SPINOR_OP_WREN: return SEQID_WREN; -- 1.9.1
[PATCH v2] mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
If the size of spi-nor flash is larger than 16MB, the read_opcode is set to SPINOR_OP_READ_1_1_4_4B, and fsl_qspi_get_seqid() will return -EINVAL when cmd is SPINOR_OP_READ_1_1_4_4B. This can cause read operation fail. --- v2: add Fixes tag and CC stable suggested by Boris. --- Fixes: e46ecda764dc ("mtd: spi-nor: Add Freescale QuadSPI driver") Cc: Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/fsl-quadspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 7d9620c..64304a3 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) { switch (cmd) { case SPINOR_OP_READ_1_1_4: + case SPINOR_OP_READ_1_1_4_4B: return SEQID_READ; case SPINOR_OP_WREN: return SEQID_WREN; -- 1.9.1
[PATCH] mtd: spi-nor: Add 4-byte address support for is25lp256
The is25lp256 supports 4-byte opcodes and quad output. In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, means that 3-Byte only addressing. Now this limits nor->addr_width to 3 and makes it inpossible to access the address above 16MB. I think the size of flash is the most important judgement for nor->addr_width. Once the size is larger than 16MB, nor->addr_width must be 4. This can avoid the bad situation that manufacturer sets incorrect value of register. Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/spi-nor.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d9c368c..0203b09 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1065,7 +1065,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ) }, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, @@ -2926,16 +2926,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; - if (nor->addr_width) { - /* already configured from SFDP */ - } else if (info->addr_width) { - nor->addr_width = info->addr_width; - } else if (mtd->size > 0x100) { + if (mtd->size > 0x100) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || - info->flags & SPI_NOR_4B_OPCODES) + info->flags & SPI_NOR_4B_OPCODES) spi_nor_set_4byte_opcodes(nor, info); + } else if (nor->addr_width) { + /* already configured from SFDP */ + } else if (info->addr_width) { + nor->addr_width = info->addr_width; } else { nor->addr_width = 3; } -- 1.9.1
[PATCH] mtd: spi-nor: Add 4-byte address support for is25lp256
The is25lp256 supports 4-byte opcodes and quad output. In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, means that 3-Byte only addressing. Now this limits nor->addr_width to 3 and makes it inpossible to access the address above 16MB. I think the size of flash is the most important judgement for nor->addr_width. Once the size is larger than 16MB, nor->addr_width must be 4. This can avoid the bad situation that manufacturer sets incorrect value of register. Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/spi-nor.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d9c368c..0203b09 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1065,7 +1065,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ) }, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, @@ -2926,16 +2926,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; - if (nor->addr_width) { - /* already configured from SFDP */ - } else if (info->addr_width) { - nor->addr_width = info->addr_width; - } else if (mtd->size > 0x100) { + if (mtd->size > 0x100) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || - info->flags & SPI_NOR_4B_OPCODES) + info->flags & SPI_NOR_4B_OPCODES) spi_nor_set_4byte_opcodes(nor, info); + } else if (nor->addr_width) { + /* already configured from SFDP */ + } else if (info->addr_width) { + nor->addr_width = info->addr_width; } else { nor->addr_width = 3; } -- 1.9.1
[PATCH] mtd: spi-nor: Add 4-byte address support for is25lp256
The is25lp256 supports 4-byte opcodes and quad output. In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, means that 3-Byte only addressing. Now this limits nor->addr_width to 3 and makes it inpossible to access the address above 16MB. I think the size of flash is the most important judgement for nor->addr_width. Once the size is larger than 16MB, nor->addr_width must be 4. This can avoid the bad situation that manufacturer sets incorrect value of register. Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/spi-nor.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d9c368c..0203b09 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1065,7 +1065,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ) }, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, @@ -2926,16 +2926,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; - if (nor->addr_width) { - /* already configured from SFDP */ - } else if (info->addr_width) { - nor->addr_width = info->addr_width; - } else if (mtd->size > 0x100) { + if (mtd->size > 0x100) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || - info->flags & SPI_NOR_4B_OPCODES) + info->flags & SPI_NOR_4B_OPCODES) spi_nor_set_4byte_opcodes(nor, info); + } else if (nor->addr_width) { + /* already configured from SFDP */ + } else if (info->addr_width) { + nor->addr_width = info->addr_width; } else { nor->addr_width = 3; } -- 1.9.1
[PATCH] mtd: spi-nor: Add 4-byte address support for is25lp256
The is25lp256 supports 4-byte opcodes and quad output. In is25lp256, the DWORD1 of JEDEC Basic Flash Parameter Header is 0xfff920e5. So the DWORD1[18:17] Address Bytes bits are 0b00, means that 3-Byte only addressing. Now this limits nor->addr_width to 3 and makes it inpossible to access the address above 16MB. I think the size of flash is the most important judgement for nor->addr_width. Once the size is larger than 16MB, nor->addr_width must be 4. This can avoid the bad situation that manufacturer sets incorrect value of register. Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/spi-nor.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d9c368c..0203b09 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1065,7 +1065,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, - SECT_4K | SPI_NOR_DUAL_READ) }, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, @@ -2926,16 +2926,16 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; - if (nor->addr_width) { - /* already configured from SFDP */ - } else if (info->addr_width) { - nor->addr_width = info->addr_width; - } else if (mtd->size > 0x100) { + if (mtd->size > 0x100) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || - info->flags & SPI_NOR_4B_OPCODES) + info->flags & SPI_NOR_4B_OPCODES) spi_nor_set_4byte_opcodes(nor, info); + } else if (nor->addr_width) { + /* already configured from SFDP */ + } else if (info->addr_width) { + nor->addr_width = info->addr_width; } else { nor->addr_width = 3; } -- 1.9.1
[PATCH] mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
If the size of spi-nor flash is larger than 16MB, the read_opcode is set to SPINOR_OP_READ_1_1_4_4B, and fsl_qspi_get_seqid() will return -EINVAL when cmd is SPINOR_OP_READ_1_1_4_4B. This can cause read operation fail. Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/fsl-quadspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 7d9620c..64304a3 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) { switch (cmd) { case SPINOR_OP_READ_1_1_4: + case SPINOR_OP_READ_1_1_4_4B: return SEQID_READ; case SPINOR_OP_WREN: return SEQID_WREN; -- 1.9.1
[PATCH] mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB
If the size of spi-nor flash is larger than 16MB, the read_opcode is set to SPINOR_OP_READ_1_1_4_4B, and fsl_qspi_get_seqid() will return -EINVAL when cmd is SPINOR_OP_READ_1_1_4_4B. This can cause read operation fail. Signed-off-by: Liu Xiang --- drivers/mtd/spi-nor/fsl-quadspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 7d9620c..64304a3 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -478,6 +478,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) { switch (cmd) { case SPINOR_OP_READ_1_1_4: + case SPINOR_OP_READ_1_1_4_4B: return SEQID_READ; case SPINOR_OP_WREN: return SEQID_WREN; -- 1.9.1
[PATCH] power: supply: bq27xxx: Add support for BQ27411
According to the datasheet, bq27411 is similar to bq27421. Signed-off-by: Liu Xiang --- Documentation/devicetree/bindings/power/supply/bq27xxx.txt | 1 + drivers/power/supply/bq27xxx_battery.c | 9 + drivers/power/supply/bq27xxx_battery_i2c.c | 2 ++ include/linux/power/bq27xxx_battery.h | 1 + 4 files changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt index 37994fd..4fa8e08 100644 --- a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt +++ b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt @@ -23,6 +23,7 @@ Required properties: * "ti,bq27546" - BQ27546 * "ti,bq27742" - BQ27742 * "ti,bq27545" - BQ27545 + * "ti,bq27411" - BQ27411 * "ti,bq27421" - BQ27421 * "ti,bq27425" - BQ27425 * "ti,bq27426" - BQ27426 diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index f022e1b..6dbbe95 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -432,6 +432,7 @@ enum bq27xxx_reg_index { [BQ27XXX_REG_AP] = 0x18, BQ27XXX_DM_REG_ROWS, }; +#define bq27411_regs bq27421_regs #define bq27425_regs bq27421_regs #define bq27426_regs bq27421_regs #define bq27441_regs bq27421_regs @@ -665,6 +666,7 @@ enum bq27xxx_reg_index { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_MANUFACTURER, }; +#define bq27411_props bq27421_props #define bq27425_props bq27421_props #define bq27426_props bq27421_props #define bq27441_props bq27421_props @@ -725,6 +727,12 @@ enum bq27xxx_dm_reg_id { #define bq27545_dm_regs 0 #endif +static struct bq27xxx_dm_reg bq27411_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2,0, 32767 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2,0, 32767 }, + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2800, 3700 }, +}; + static struct bq27xxx_dm_reg bq27421_dm_regs[] = { [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2,0, 8000 }, [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2,0, 32767 }, @@ -802,6 +810,7 @@ enum bq27xxx_dm_reg_id { [BQ27546] = BQ27XXX_DATA(bq27546, 0 , BQ27XXX_O_OTDC), [BQ27742] = BQ27XXX_DATA(bq27742, 0 , BQ27XXX_O_OTDC), [BQ27545] = BQ27XXX_DATA(bq27545, 0x04143672, BQ27XXX_O_OTDC), + [BQ27411] = BQ27XXX_DATA(bq27411, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27421] = BQ27XXX_DATA(bq27421, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP), [BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 4006912..2677c38 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -247,6 +247,7 @@ static int bq27xxx_battery_i2c_remove(struct i2c_client *client) { "bq27546", BQ27546 }, { "bq27742", BQ27742 }, { "bq27545", BQ27545 }, + { "bq27411", BQ27411 }, { "bq27421", BQ27421 }, { "bq27425", BQ27425 }, { "bq27426", BQ27426 }, @@ -279,6 +280,7 @@ static int bq27xxx_battery_i2c_remove(struct i2c_client *client) { .compatible = "ti,bq27546" }, { .compatible = "ti,bq27742" }, { .compatible = "ti,bq27545" }, + { .compatible = "ti,bq27411" }, { .compatible = "ti,bq27421" }, { .compatible = "ti,bq27425" }, { .compatible = "ti,bq27426" }, diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index d6355f4..507c5e2 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -24,6 +24,7 @@ enum bq27xxx_chip { BQ27546, BQ27742, BQ27545, /* bq27545 */ + BQ27411, BQ27421, /* bq27421, bq27441, bq27621 */ BQ27425, BQ27426, -- 1.9.1
[PATCH] power: supply: bq27xxx: Add support for BQ27411
According to the datasheet, bq27411 is similar to bq27421. Signed-off-by: Liu Xiang --- Documentation/devicetree/bindings/power/supply/bq27xxx.txt | 1 + drivers/power/supply/bq27xxx_battery.c | 9 + drivers/power/supply/bq27xxx_battery_i2c.c | 2 ++ include/linux/power/bq27xxx_battery.h | 1 + 4 files changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt index 37994fd..4fa8e08 100644 --- a/Documentation/devicetree/bindings/power/supply/bq27xxx.txt +++ b/Documentation/devicetree/bindings/power/supply/bq27xxx.txt @@ -23,6 +23,7 @@ Required properties: * "ti,bq27546" - BQ27546 * "ti,bq27742" - BQ27742 * "ti,bq27545" - BQ27545 + * "ti,bq27411" - BQ27411 * "ti,bq27421" - BQ27421 * "ti,bq27425" - BQ27425 * "ti,bq27426" - BQ27426 diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index f022e1b..6dbbe95 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -432,6 +432,7 @@ enum bq27xxx_reg_index { [BQ27XXX_REG_AP] = 0x18, BQ27XXX_DM_REG_ROWS, }; +#define bq27411_regs bq27421_regs #define bq27425_regs bq27421_regs #define bq27426_regs bq27421_regs #define bq27441_regs bq27421_regs @@ -665,6 +666,7 @@ enum bq27xxx_reg_index { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_MANUFACTURER, }; +#define bq27411_props bq27421_props #define bq27425_props bq27421_props #define bq27426_props bq27421_props #define bq27441_props bq27421_props @@ -725,6 +727,12 @@ enum bq27xxx_dm_reg_id { #define bq27545_dm_regs 0 #endif +static struct bq27xxx_dm_reg bq27411_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2,0, 32767 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2,0, 32767 }, + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2800, 3700 }, +}; + static struct bq27xxx_dm_reg bq27421_dm_regs[] = { [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2,0, 8000 }, [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2,0, 32767 }, @@ -802,6 +810,7 @@ enum bq27xxx_dm_reg_id { [BQ27546] = BQ27XXX_DATA(bq27546, 0 , BQ27XXX_O_OTDC), [BQ27742] = BQ27XXX_DATA(bq27742, 0 , BQ27XXX_O_OTDC), [BQ27545] = BQ27XXX_DATA(bq27545, 0x04143672, BQ27XXX_O_OTDC), + [BQ27411] = BQ27XXX_DATA(bq27411, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27421] = BQ27XXX_DATA(bq27421, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP), [BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 4006912..2677c38 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -247,6 +247,7 @@ static int bq27xxx_battery_i2c_remove(struct i2c_client *client) { "bq27546", BQ27546 }, { "bq27742", BQ27742 }, { "bq27545", BQ27545 }, + { "bq27411", BQ27411 }, { "bq27421", BQ27421 }, { "bq27425", BQ27425 }, { "bq27426", BQ27426 }, @@ -279,6 +280,7 @@ static int bq27xxx_battery_i2c_remove(struct i2c_client *client) { .compatible = "ti,bq27546" }, { .compatible = "ti,bq27742" }, { .compatible = "ti,bq27545" }, + { .compatible = "ti,bq27411" }, { .compatible = "ti,bq27421" }, { .compatible = "ti,bq27425" }, { .compatible = "ti,bq27426" }, diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index d6355f4..507c5e2 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -24,6 +24,7 @@ enum bq27xxx_chip { BQ27546, BQ27742, BQ27545, /* bq27545 */ + BQ27411, BQ27421, /* bq27421, bq27441, bq27621 */ BQ27425, BQ27426, -- 1.9.1
[PATCH] power: supply: bq27xxx: Update comments
The URL of bq27441-g1 and bq27426 are missing and bq27520-g4 is duplicated. Signed-off-by: Liu Xiang --- drivers/power/supply/bq27xxx_battery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index d44ed8e..f022e1b 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -26,7 +26,6 @@ * http://www.ti.com/product/bq27510-g1 * http://www.ti.com/product/bq27510-g2 * http://www.ti.com/product/bq27510-g3 - * http://www.ti.com/product/bq27520-g4 * http://www.ti.com/product/bq27520-g1 * http://www.ti.com/product/bq27520-g2 * http://www.ti.com/product/bq27520-g3 @@ -40,7 +39,9 @@ * http://www.ti.com/product/bq27545-g1 * http://www.ti.com/product/bq27421-g1 * http://www.ti.com/product/bq27425-g1 + * http://www.ti.com/product/bq27426 * http://www.ti.com/product/bq27411-g1 + * http://www.ti.com/product/bq27441-g1 * http://www.ti.com/product/bq27621-g1 */ -- 1.9.1
[PATCH] power: supply: bq27xxx: Update comments
The URL of bq27441-g1 and bq27426 are missing and bq27520-g4 is duplicated. Signed-off-by: Liu Xiang --- drivers/power/supply/bq27xxx_battery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index d44ed8e..f022e1b 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -26,7 +26,6 @@ * http://www.ti.com/product/bq27510-g1 * http://www.ti.com/product/bq27510-g2 * http://www.ti.com/product/bq27510-g3 - * http://www.ti.com/product/bq27520-g4 * http://www.ti.com/product/bq27520-g1 * http://www.ti.com/product/bq27520-g2 * http://www.ti.com/product/bq27520-g3 @@ -40,7 +39,9 @@ * http://www.ti.com/product/bq27545-g1 * http://www.ti.com/product/bq27421-g1 * http://www.ti.com/product/bq27425-g1 + * http://www.ti.com/product/bq27426 * http://www.ti.com/product/bq27411-g1 + * http://www.ti.com/product/bq27441-g1 * http://www.ti.com/product/bq27621-g1 */ -- 1.9.1
[PATCH] of: irq: Add a helper function for irq_of_parse_and_map
Implement a resource managed irq_of_parse_and_map function. Signed-off-by: Liu Xiang --- drivers/of/irq.c | 38 ++ include/linux/of_irq.h | 7 +++ 2 files changed, 45 insertions(+) diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 02ad93a..947fe41 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -45,6 +45,44 @@ unsigned int irq_of_parse_and_map(struct device_node *dev, int index) } EXPORT_SYMBOL_GPL(irq_of_parse_and_map); +static void devm_irq_dispose_mapping(struct device *dev, void *res) +{ + irq_dispose_mapping(*(unsigned int *)res); +} + +/** + * devm_irq_of_parse_and_map - Resource-managed irq_of_parse_and_map + * @dev: Device whose interrupt is to be mapped + * @index: Index of the interrupt to map + * + * Managed irq_of_parse_and_map. Irq mapping created by this function is + * automatically disposed on driver detach. + * + * RETURNS: + * Returns a linux irq number on success, 0 on failure. + */ +unsigned int devm_irq_of_parse_and_map(struct device *dev, int index) +{ + struct device_node *np = dev->of_node; + unsigned int *dr = NULL; + unsigned int rc = 0; + + dr = devres_alloc(devm_irq_dispose_mapping, sizeof(unsigned int), + GFP_KERNEL); + if (!dr) + return 0; + + rc = irq_of_parse_and_map(np, index); + if (rc > 0) { + *dr = rc; + devres_add(dev, dr); + } else + devres_free(dr); + + return rc; +} +EXPORT_SYMBOL_GPL(devm_irq_of_parse_and_map); + /** * of_irq_find_parent - Given a device node, find its interrupt parent node * @child: pointer to device node diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index 1214cab..1ac26ff 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -55,6 +55,7 @@ extern struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 rid); extern void of_msi_configure(struct device *dev, struct device_node *np); u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in); +extern unsigned int devm_irq_of_parse_and_map(struct device *dev, int index); #else static inline int of_irq_count(struct device_node *dev) { @@ -97,6 +98,12 @@ static inline u32 of_msi_map_rid(struct device *dev, { return rid_in; } + +static inline unsigned int devm_irq_of_parse_and_map(struct device *dev, +int index) +{ + return 0; +} #endif #if defined(CONFIG_OF_IRQ) || defined(CONFIG_SPARC) -- 1.9.1
[PATCH] of: irq: Add a helper function for irq_of_parse_and_map
Implement a resource managed irq_of_parse_and_map function. Signed-off-by: Liu Xiang --- drivers/of/irq.c | 38 ++ include/linux/of_irq.h | 7 +++ 2 files changed, 45 insertions(+) diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 02ad93a..947fe41 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -45,6 +45,44 @@ unsigned int irq_of_parse_and_map(struct device_node *dev, int index) } EXPORT_SYMBOL_GPL(irq_of_parse_and_map); +static void devm_irq_dispose_mapping(struct device *dev, void *res) +{ + irq_dispose_mapping(*(unsigned int *)res); +} + +/** + * devm_irq_of_parse_and_map - Resource-managed irq_of_parse_and_map + * @dev: Device whose interrupt is to be mapped + * @index: Index of the interrupt to map + * + * Managed irq_of_parse_and_map. Irq mapping created by this function is + * automatically disposed on driver detach. + * + * RETURNS: + * Returns a linux irq number on success, 0 on failure. + */ +unsigned int devm_irq_of_parse_and_map(struct device *dev, int index) +{ + struct device_node *np = dev->of_node; + unsigned int *dr = NULL; + unsigned int rc = 0; + + dr = devres_alloc(devm_irq_dispose_mapping, sizeof(unsigned int), + GFP_KERNEL); + if (!dr) + return 0; + + rc = irq_of_parse_and_map(np, index); + if (rc > 0) { + *dr = rc; + devres_add(dev, dr); + } else + devres_free(dr); + + return rc; +} +EXPORT_SYMBOL_GPL(devm_irq_of_parse_and_map); + /** * of_irq_find_parent - Given a device node, find its interrupt parent node * @child: pointer to device node diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index 1214cab..1ac26ff 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -55,6 +55,7 @@ extern struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 rid); extern void of_msi_configure(struct device *dev, struct device_node *np); u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in); +extern unsigned int devm_irq_of_parse_and_map(struct device *dev, int index); #else static inline int of_irq_count(struct device_node *dev) { @@ -97,6 +98,12 @@ static inline u32 of_msi_map_rid(struct device *dev, { return rid_in; } + +static inline unsigned int devm_irq_of_parse_and_map(struct device *dev, +int index) +{ + return 0; +} #endif #if defined(CONFIG_OF_IRQ) || defined(CONFIG_SPARC) -- 1.9.1
[PATCH v3] net: davicom: dm9000: Avoid spinlock recursion during dm9000_timeout routine
On the DM9000B, dm9000_phy_write() is called after the main spinlock is held, during the dm9000_timeout() routine. Spinlock recursion occurs because the main spinlock is requested again in dm9000_phy_write(). So spinlock should be avoided in phy operation during the dm9000_timeout() routine. --- v3: When a task enters dm9000_timeout() and gets the main spinlock, another task that wants to do asynchronous phy operation must be running on another cpu.Because of different cpus, this asynchronous task will be blocked in dm9000_phy_write() until dm9000_timeout() routine is completed. --- Signed-off-by: Liu Xiang <liu.xia...@zte.com.cn> --- drivers/net/ethernet/davicom/dm9000.c | 39 +-- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 50222b7..56df77d 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -112,7 +112,7 @@ struct board_info { u8 imr_all; unsigned intflags; - unsigned intin_timeout:1; + int timeout_cpu; unsigned intin_suspend:1; unsigned intwake_supported:1; @@ -158,6 +158,17 @@ static inline struct board_info *to_dm9000_board(struct net_device *dev) return netdev_priv(dev); } +static bool dm9000_current_in_timeout(struct board_info *db) +{ + bool ret = false; + + preempt_disable(); + ret = (db->timeout_cpu == smp_processor_id()); + preempt_enable(); + + return ret; +} + /* DM9000 network board routine */ /* @@ -276,7 +287,7 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count) */ static void dm9000_msleep(struct board_info *db, unsigned int ms) { - if (db->in_suspend || db->in_timeout) + if (db->in_suspend || dm9000_current_in_timeout(db)) mdelay(ms); else msleep(ms); @@ -335,12 +346,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) struct board_info *db = netdev_priv(dev); unsigned long flags; unsigned long reg_save; + bool in_timeout = dm9000_current_in_timeout(db); dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); - if (!db->in_timeout) + if (!in_timeout) { mutex_lock(>addr_lock); - - spin_lock_irqsave(>lock, flags); + spin_lock_irqsave(>lock, flags); + } /* Save previous register address */ reg_save = readb(db->io_addr); @@ -356,11 +368,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); + if (!in_timeout) + spin_unlock_irqrestore(>lock, flags); dm9000_msleep(db, 1); /* Wait write complete */ - spin_lock_irqsave(>lock, flags); + if (!in_timeout) + spin_lock_irqsave(>lock, flags); reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ @@ -368,9 +382,10 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) /* restore the previous address */ writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); - if (!db->in_timeout) + if (!in_timeout) { + spin_unlock_irqrestore(>lock, flags); mutex_unlock(>addr_lock); + } } /* dm9000_set_io @@ -980,7 +995,7 @@ static void dm9000_timeout(struct net_device *dev) /* Save previous register address */ spin_lock_irqsave(>lock, flags); - db->in_timeout = 1; + db->timeout_cpu = smp_processor_id(); reg_save = readb(db->io_addr); netif_stop_queue(dev); @@ -992,7 +1007,7 @@ static void dm9000_timeout(struct net_device *dev) /* Restore previous register address */ writeb(reg_save, db->io_addr); - db->in_timeout = 0; + db->timeout_cpu = -1; spin_unlock_irqrestore(>lock, flags); } @@ -1670,6 +1685,8 @@ static struct dm9000_plat_data *dm9000_parse_dt(struct device *dev) db->mii.mdio_read= dm9000_phy_read; db->mii.mdio_write = dm9000_phy_write; + db->timeout_cpu = -1; + mac_src = "eeprom"; /* try reading the node address from the attached EEPROM */ -- 1.9.1
[PATCH v3] net: davicom: dm9000: Avoid spinlock recursion during dm9000_timeout routine
On the DM9000B, dm9000_phy_write() is called after the main spinlock is held, during the dm9000_timeout() routine. Spinlock recursion occurs because the main spinlock is requested again in dm9000_phy_write(). So spinlock should be avoided in phy operation during the dm9000_timeout() routine. --- v3: When a task enters dm9000_timeout() and gets the main spinlock, another task that wants to do asynchronous phy operation must be running on another cpu.Because of different cpus, this asynchronous task will be blocked in dm9000_phy_write() until dm9000_timeout() routine is completed. --- Signed-off-by: Liu Xiang --- drivers/net/ethernet/davicom/dm9000.c | 39 +-- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 50222b7..56df77d 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -112,7 +112,7 @@ struct board_info { u8 imr_all; unsigned intflags; - unsigned intin_timeout:1; + int timeout_cpu; unsigned intin_suspend:1; unsigned intwake_supported:1; @@ -158,6 +158,17 @@ static inline struct board_info *to_dm9000_board(struct net_device *dev) return netdev_priv(dev); } +static bool dm9000_current_in_timeout(struct board_info *db) +{ + bool ret = false; + + preempt_disable(); + ret = (db->timeout_cpu == smp_processor_id()); + preempt_enable(); + + return ret; +} + /* DM9000 network board routine */ /* @@ -276,7 +287,7 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count) */ static void dm9000_msleep(struct board_info *db, unsigned int ms) { - if (db->in_suspend || db->in_timeout) + if (db->in_suspend || dm9000_current_in_timeout(db)) mdelay(ms); else msleep(ms); @@ -335,12 +346,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) struct board_info *db = netdev_priv(dev); unsigned long flags; unsigned long reg_save; + bool in_timeout = dm9000_current_in_timeout(db); dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); - if (!db->in_timeout) + if (!in_timeout) { mutex_lock(>addr_lock); - - spin_lock_irqsave(>lock, flags); + spin_lock_irqsave(>lock, flags); + } /* Save previous register address */ reg_save = readb(db->io_addr); @@ -356,11 +368,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); + if (!in_timeout) + spin_unlock_irqrestore(>lock, flags); dm9000_msleep(db, 1); /* Wait write complete */ - spin_lock_irqsave(>lock, flags); + if (!in_timeout) + spin_lock_irqsave(>lock, flags); reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ @@ -368,9 +382,10 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) /* restore the previous address */ writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); - if (!db->in_timeout) + if (!in_timeout) { + spin_unlock_irqrestore(>lock, flags); mutex_unlock(>addr_lock); + } } /* dm9000_set_io @@ -980,7 +995,7 @@ static void dm9000_timeout(struct net_device *dev) /* Save previous register address */ spin_lock_irqsave(>lock, flags); - db->in_timeout = 1; + db->timeout_cpu = smp_processor_id(); reg_save = readb(db->io_addr); netif_stop_queue(dev); @@ -992,7 +1007,7 @@ static void dm9000_timeout(struct net_device *dev) /* Restore previous register address */ writeb(reg_save, db->io_addr); - db->in_timeout = 0; + db->timeout_cpu = -1; spin_unlock_irqrestore(>lock, flags); } @@ -1670,6 +1685,8 @@ static struct dm9000_plat_data *dm9000_parse_dt(struct device *dev) db->mii.mdio_read= dm9000_phy_read; db->mii.mdio_write = dm9000_phy_write; + db->timeout_cpu = -1; + mac_src = "eeprom"; /* try reading the node address from the attached EEPROM */ -- 1.9.1
[PATCH] power: supply: bq27xxx: Update comments
The URL of bq27441-g1 is missing and bq27520-g4 is duplicated. Signed-off-by: Liu Xiang <liu.xia...@zte.com.cn> --- drivers/power/supply/bq27xxx_battery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 2de378a..c0e7c5b 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -26,7 +26,6 @@ * http://www.ti.com/product/bq27510-g1 * http://www.ti.com/product/bq27510-g2 * http://www.ti.com/product/bq27510-g3 - * http://www.ti.com/product/bq27520-g4 * http://www.ti.com/product/bq27520-g1 * http://www.ti.com/product/bq27520-g2 * http://www.ti.com/product/bq27520-g3 @@ -40,8 +39,9 @@ * http://www.ti.com/product/bq27545-g1 * http://www.ti.com/product/bq27421-g1 * http://www.ti.com/product/bq27425-g1 - * http://www.ti.com/product/bq27411-g1 + * http://www.ti.com/product/bq27441-g1 * http://www.ti.com/product/bq27621-g1 + * http://www.ti.com/product/bq27411-g1 */ #include -- 1.9.1
[PATCH] power: supply: bq27xxx: Add bq27411 support
According to the datasheet, bq27411 is similar to bq27421. Signed-off-by: Liu Xiang <liu.xia...@zte.com.cn> --- drivers/power/supply/bq27xxx_battery.c | 14 ++ include/linux/power/bq27xxx_battery.h | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 51f0961..2de378a 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -410,6 +410,7 @@ enum bq27xxx_reg_index { #define bq27425_regs bq27421_regs #define bq27441_regs bq27421_regs #define bq27621_regs bq27421_regs +#define bq27411_regs bq27421_regs static enum power_supply_property bq27000_props[] = { POWER_SUPPLY_PROP_STATUS, @@ -633,6 +634,7 @@ enum bq27xxx_reg_index { #define bq27425_props bq27421_props #define bq27441_props bq27421_props #define bq27621_props bq27421_props +#define bq27411_props bq27421_props struct bq27xxx_dm_reg { u8 subclass_id; @@ -716,6 +718,17 @@ enum bq27xxx_dm_reg_id { #define bq27621_dm_regs 0 #endif +#if 0 /* not yet tested */ +static struct bq27xxx_dm_reg bq27411_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2,0, 32767 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2,0, 32767 }, + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2800, 3700 }, +}; +#else +#define bq27411_dm_regs 0 +#endif + + #define BQ27XXX_O_ZERO 0x0001 #define BQ27XXX_O_OTDC 0x0002 #define BQ27XXX_O_UTOT 0x0004 @@ -762,6 +775,7 @@ enum bq27xxx_dm_reg_id { [BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP), [BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), + [BQ27411] = BQ27XXX_DATA(bq27411, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), }; static DEFINE_MUTEX(bq27xxx_list_lock); diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index e6187f5..5f48eb0 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -23,10 +23,11 @@ enum bq27xxx_chip { BQ27546, BQ27742, BQ27545, /* bq27545 */ - BQ27421, /* bq27421, bq27425, bq27441, bq27621 */ + BQ27421, /* bq27421, bq27425, bq27441, bq27621, bq27411 */ BQ27425, BQ27441, BQ27621, + BQ27411, }; struct bq27xxx_device_info; -- 1.9.1
[PATCH] power: supply: bq27xxx: Update comments
The URL of bq27441-g1 is missing and bq27520-g4 is duplicated. Signed-off-by: Liu Xiang --- drivers/power/supply/bq27xxx_battery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 2de378a..c0e7c5b 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -26,7 +26,6 @@ * http://www.ti.com/product/bq27510-g1 * http://www.ti.com/product/bq27510-g2 * http://www.ti.com/product/bq27510-g3 - * http://www.ti.com/product/bq27520-g4 * http://www.ti.com/product/bq27520-g1 * http://www.ti.com/product/bq27520-g2 * http://www.ti.com/product/bq27520-g3 @@ -40,8 +39,9 @@ * http://www.ti.com/product/bq27545-g1 * http://www.ti.com/product/bq27421-g1 * http://www.ti.com/product/bq27425-g1 - * http://www.ti.com/product/bq27411-g1 + * http://www.ti.com/product/bq27441-g1 * http://www.ti.com/product/bq27621-g1 + * http://www.ti.com/product/bq27411-g1 */ #include -- 1.9.1
[PATCH] power: supply: bq27xxx: Add bq27411 support
According to the datasheet, bq27411 is similar to bq27421. Signed-off-by: Liu Xiang --- drivers/power/supply/bq27xxx_battery.c | 14 ++ include/linux/power/bq27xxx_battery.h | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 51f0961..2de378a 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -410,6 +410,7 @@ enum bq27xxx_reg_index { #define bq27425_regs bq27421_regs #define bq27441_regs bq27421_regs #define bq27621_regs bq27421_regs +#define bq27411_regs bq27421_regs static enum power_supply_property bq27000_props[] = { POWER_SUPPLY_PROP_STATUS, @@ -633,6 +634,7 @@ enum bq27xxx_reg_index { #define bq27425_props bq27421_props #define bq27441_props bq27421_props #define bq27621_props bq27421_props +#define bq27411_props bq27421_props struct bq27xxx_dm_reg { u8 subclass_id; @@ -716,6 +718,17 @@ enum bq27xxx_dm_reg_id { #define bq27621_dm_regs 0 #endif +#if 0 /* not yet tested */ +static struct bq27xxx_dm_reg bq27411_dm_regs[] = { + [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2,0, 32767 }, + [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2,0, 32767 }, + [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2800, 3700 }, +}; +#else +#define bq27411_dm_regs 0 +#endif + + #define BQ27XXX_O_ZERO 0x0001 #define BQ27XXX_O_OTDC 0x0002 #define BQ27XXX_O_UTOT 0x0004 @@ -762,6 +775,7 @@ enum bq27xxx_dm_reg_id { [BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP), [BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), + [BQ27411] = BQ27XXX_DATA(bq27411, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), }; static DEFINE_MUTEX(bq27xxx_list_lock); diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index e6187f5..5f48eb0 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -23,10 +23,11 @@ enum bq27xxx_chip { BQ27546, BQ27742, BQ27545, /* bq27545 */ - BQ27421, /* bq27421, bq27425, bq27441, bq27621 */ + BQ27421, /* bq27421, bq27425, bq27441, bq27621, bq27411 */ BQ27425, BQ27441, BQ27621, + BQ27411, }; struct bq27xxx_device_info; -- 1.9.1
[PATCH v2] net: davicom: dm9000: Avoid spinlock recursion during dm9000_timeout routine
On the DM9000B, dm9000_phy_write() is called after the main spinlock is held, during the dm9000_timeout() routine. Spinlock recursion occurs because the main spinlock is requested again in dm9000_phy_write(). So spinlock should be avoided in phy operation during the dm9000_timeout() routine. --- v2: dm9000_phy_write_reg is extracted from dm9000_phy_write, with no lock, do the real phy operation. --- Signed-off-by: Liu Xiang <liu.xia...@zte.com.cn> --- drivers/net/ethernet/davicom/dm9000.c | 37 +-- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 008dc81..0aa2900 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -327,21 +327,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) return ret; } -/* Write a word to phyxcer */ static void -dm9000_phy_write(struct net_device *dev, -int phyaddr_unused, int reg, int value) +dm9000_phy_write_reg(struct net_device *dev, +int phyaddr_unused, int reg, int value) { struct board_info *db = netdev_priv(dev); - unsigned long flags; unsigned long reg_save; - dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); - if (!db->in_timeout) - mutex_lock(>addr_lock); - - spin_lock_irqsave(>lock, flags); - /* Save previous register address */ reg_save = readb(db->io_addr); @@ -356,17 +348,32 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); - dm9000_msleep(db, 1); /* Wait write complete */ + mdelay(1); /* Wait write complete */ - spin_lock_irqsave(>lock, flags); reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ /* restore the previous address */ writeb(reg_save, db->io_addr); +} + +/* Write a word to phyxcer */ +static void +dm9000_phy_write(struct net_device *dev, +int phyaddr_unused, int reg, int value) +{ + struct board_info *db = netdev_priv(dev); + unsigned long flags; + + dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); + if (!db->in_timeout) + mutex_lock(>addr_lock); + + spin_lock_irqsave(>lock, flags); + + dm9000_phy_write_reg(dev, phyaddr_unused, reg, value); spin_unlock_irqrestore(>lock, flags); if (!db->in_timeout) @@ -933,8 +940,8 @@ static unsigned char dm9000_type_to_char(enum dm9000_type type) * manual phy reset, and setting init params. */ if (db->type == TYPE_DM9000B) { - dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); - dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); + dm9000_phy_write_reg(dev, 0, MII_BMCR, BMCR_RESET); + dm9000_phy_write_reg(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); } ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0; -- 1.9.1
[PATCH v2] net: davicom: dm9000: Avoid spinlock recursion during dm9000_timeout routine
On the DM9000B, dm9000_phy_write() is called after the main spinlock is held, during the dm9000_timeout() routine. Spinlock recursion occurs because the main spinlock is requested again in dm9000_phy_write(). So spinlock should be avoided in phy operation during the dm9000_timeout() routine. --- v2: dm9000_phy_write_reg is extracted from dm9000_phy_write, with no lock, do the real phy operation. --- Signed-off-by: Liu Xiang --- drivers/net/ethernet/davicom/dm9000.c | 37 +-- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 008dc81..0aa2900 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -327,21 +327,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) return ret; } -/* Write a word to phyxcer */ static void -dm9000_phy_write(struct net_device *dev, -int phyaddr_unused, int reg, int value) +dm9000_phy_write_reg(struct net_device *dev, +int phyaddr_unused, int reg, int value) { struct board_info *db = netdev_priv(dev); - unsigned long flags; unsigned long reg_save; - dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); - if (!db->in_timeout) - mutex_lock(>addr_lock); - - spin_lock_irqsave(>lock, flags); - /* Save previous register address */ reg_save = readb(db->io_addr); @@ -356,17 +348,32 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); - dm9000_msleep(db, 1); /* Wait write complete */ + mdelay(1); /* Wait write complete */ - spin_lock_irqsave(>lock, flags); reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ /* restore the previous address */ writeb(reg_save, db->io_addr); +} + +/* Write a word to phyxcer */ +static void +dm9000_phy_write(struct net_device *dev, +int phyaddr_unused, int reg, int value) +{ + struct board_info *db = netdev_priv(dev); + unsigned long flags; + + dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); + if (!db->in_timeout) + mutex_lock(>addr_lock); + + spin_lock_irqsave(>lock, flags); + + dm9000_phy_write_reg(dev, phyaddr_unused, reg, value); spin_unlock_irqrestore(>lock, flags); if (!db->in_timeout) @@ -933,8 +940,8 @@ static unsigned char dm9000_type_to_char(enum dm9000_type type) * manual phy reset, and setting init params. */ if (db->type == TYPE_DM9000B) { - dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); - dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); + dm9000_phy_write_reg(dev, 0, MII_BMCR, BMCR_RESET); + dm9000_phy_write_reg(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); } ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0; -- 1.9.1
[PATCH] net: davicom: dm9000: Avoid spinlock recursion during dm9000_timeout routine
On the DM9000B, dm9000_phy_write() is called after the main spinlock is held, during the dm9000_timeout() routine. Spinlock recursion occurs because the main spinlock is requested again in dm9000_phy_write(). So spinlock should be avoided in dm9000_phy_write() during the dm9000_timeout() routine. Signed-off-by: Liu Xiang <liu.xia...@zte.com.cn> --- drivers/net/ethernet/davicom/dm9000.c | 18 +++--- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 008dc81..afe33de 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -337,11 +337,11 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) unsigned long reg_save; dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); - if (!db->in_timeout) + if (!db->in_timeout) { mutex_lock(>addr_lock); - spin_lock_irqsave(>lock, flags); - + spin_lock_irqsave(>lock, flags); + } /* Save previous register address */ reg_save = readb(db->io_addr); @@ -356,11 +356,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); + if (!db->in_timeout) + spin_unlock_irqrestore(>lock, flags); dm9000_msleep(db, 1); /* Wait write complete */ - spin_lock_irqsave(>lock, flags); + if (!db->in_timeout) + spin_lock_irqsave(>lock, flags); reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ @@ -368,9 +370,11 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) /* restore the previous address */ writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); - if (!db->in_timeout) + if (!db->in_timeout) { + spin_unlock_irqrestore(>lock, flags); + mutex_unlock(>addr_lock); + } } /* dm9000_set_io -- 1.9.1
[PATCH] net: davicom: dm9000: Avoid spinlock recursion during dm9000_timeout routine
On the DM9000B, dm9000_phy_write() is called after the main spinlock is held, during the dm9000_timeout() routine. Spinlock recursion occurs because the main spinlock is requested again in dm9000_phy_write(). So spinlock should be avoided in dm9000_phy_write() during the dm9000_timeout() routine. Signed-off-by: Liu Xiang --- drivers/net/ethernet/davicom/dm9000.c | 18 +++--- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 008dc81..afe33de 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -337,11 +337,11 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) unsigned long reg_save; dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); - if (!db->in_timeout) + if (!db->in_timeout) { mutex_lock(>addr_lock); - spin_lock_irqsave(>lock, flags); - + spin_lock_irqsave(>lock, flags); + } /* Save previous register address */ reg_save = readb(db->io_addr); @@ -356,11 +356,13 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); + if (!db->in_timeout) + spin_unlock_irqrestore(>lock, flags); dm9000_msleep(db, 1); /* Wait write complete */ - spin_lock_irqsave(>lock, flags); + if (!db->in_timeout) + spin_lock_irqsave(>lock, flags); reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ @@ -368,9 +370,11 @@ static void dm9000_msleep(struct board_info *db, unsigned int ms) /* restore the previous address */ writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(>lock, flags); - if (!db->in_timeout) + if (!db->in_timeout) { + spin_unlock_irqrestore(>lock, flags); + mutex_unlock(>addr_lock); + } } /* dm9000_set_io -- 1.9.1
[PATCH] power: max17040: Change register transaction length from 8 bits to 16 bits
According to the datasheet, MAX17040 has six 16-bit registers. Register reads and writes are only valid if all 16 bits are transferred. Any write command that is terminated early is ignored. So it's better to change register transacton length from 8 bits to 16 bits. Signed-off-by: Liu Xiang <liu.xia...@zte.com.cn> --- drivers/power/max17040_battery.c | 52 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index 8689c80..e7c3649 100644 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -21,18 +21,13 @@ #include #include -#define MAX17040_VCELL_MSB 0x02 -#define MAX17040_VCELL_LSB 0x03 -#define MAX17040_SOC_MSB 0x04 -#define MAX17040_SOC_LSB 0x05 -#define MAX17040_MODE_MSB 0x06 -#define MAX17040_MODE_LSB 0x07 -#define MAX17040_VER_MSB 0x08 -#define MAX17040_VER_LSB 0x09 -#define MAX17040_RCOMP_MSB 0x0C -#define MAX17040_RCOMP_LSB 0x0D -#define MAX17040_CMD_MSB 0xFE -#define MAX17040_CMD_LSB 0xFF +#define MAX17040_VCELL 0x02 +#define MAX17040_SOC 0x04 +#define MAX17040_MODE 0x06 +#define MAX17040_VER 0x08 +#define MAX17040_RCOMP 0x0C +#define MAX17040_CMD 0xFE + #define MAX17040_DELAY 1000 #define MAX17040_BATTERY_FULL 95 @@ -78,11 +73,11 @@ static int max17040_get_property(struct power_supply *psy, return 0; } -static int max17040_write_reg(struct i2c_client *client, int reg, u8 value) +static int max17040_write_reg(struct i2c_client *client, int reg, u16 value) { int ret; - ret = i2c_smbus_write_byte_data(client, reg, value); + ret = i2c_smbus_write_word_swapped(client, reg, value); if (ret < 0) dev_err(>dev, "%s: err %d\n", __func__, ret); @@ -94,7 +89,7 @@ static int max17040_read_reg(struct i2c_client *client, int reg) { int ret; - ret = i2c_smbus_read_byte_data(client, reg); + ret = i2c_smbus_read_word_swapped(client, reg); if (ret < 0) dev_err(>dev, "%s: err %d\n", __func__, ret); @@ -104,43 +99,36 @@ static int max17040_read_reg(struct i2c_client *client, int reg) static void max17040_reset(struct i2c_client *client) { - max17040_write_reg(client, MAX17040_CMD_MSB, 0x54); - max17040_write_reg(client, MAX17040_CMD_LSB, 0x00); + max17040_write_reg(client, MAX17040_CMD, 0x0054); } static void max17040_get_vcell(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; + u16 vcell; - msb = max17040_read_reg(client, MAX17040_VCELL_MSB); - lsb = max17040_read_reg(client, MAX17040_VCELL_LSB); + vcell = max17040_read_reg(client, MAX17040_VCELL); - chip->vcell = (msb << 4) + (lsb >> 4); + chip->vcell = vcell; } static void max17040_get_soc(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; + u16 soc; - msb = max17040_read_reg(client, MAX17040_SOC_MSB); - lsb = max17040_read_reg(client, MAX17040_SOC_LSB); + soc = max17040_read_reg(client, MAX17040_SOC); - chip->soc = msb; + chip->soc = (soc >> 8); } static void max17040_get_version(struct i2c_client *client) { - u8 msb; - u8 lsb; + u16 version; - msb = max17040_read_reg(client, MAX17040_VER_MSB); - lsb = max17040_read_reg(client, MAX17040_VER_LSB); + version = max17040_read_reg(client, MAX17040_VER); - dev_info(>dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb); + dev_info(>dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", version); } static void max17040_get_online(struct i2c_client *client) -- 1.9.1
[PATCH] power: max17040: Change register transaction length from 8 bits to 16 bits
According to the datasheet, MAX17040 has six 16-bit registers. Register reads and writes are only valid if all 16 bits are transferred. Any write command that is terminated early is ignored. So it's better to change register transacton length from 8 bits to 16 bits. Signed-off-by: Liu Xiang --- drivers/power/max17040_battery.c | 52 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index 8689c80..e7c3649 100644 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -21,18 +21,13 @@ #include #include -#define MAX17040_VCELL_MSB 0x02 -#define MAX17040_VCELL_LSB 0x03 -#define MAX17040_SOC_MSB 0x04 -#define MAX17040_SOC_LSB 0x05 -#define MAX17040_MODE_MSB 0x06 -#define MAX17040_MODE_LSB 0x07 -#define MAX17040_VER_MSB 0x08 -#define MAX17040_VER_LSB 0x09 -#define MAX17040_RCOMP_MSB 0x0C -#define MAX17040_RCOMP_LSB 0x0D -#define MAX17040_CMD_MSB 0xFE -#define MAX17040_CMD_LSB 0xFF +#define MAX17040_VCELL 0x02 +#define MAX17040_SOC 0x04 +#define MAX17040_MODE 0x06 +#define MAX17040_VER 0x08 +#define MAX17040_RCOMP 0x0C +#define MAX17040_CMD 0xFE + #define MAX17040_DELAY 1000 #define MAX17040_BATTERY_FULL 95 @@ -78,11 +73,11 @@ static int max17040_get_property(struct power_supply *psy, return 0; } -static int max17040_write_reg(struct i2c_client *client, int reg, u8 value) +static int max17040_write_reg(struct i2c_client *client, int reg, u16 value) { int ret; - ret = i2c_smbus_write_byte_data(client, reg, value); + ret = i2c_smbus_write_word_swapped(client, reg, value); if (ret < 0) dev_err(>dev, "%s: err %d\n", __func__, ret); @@ -94,7 +89,7 @@ static int max17040_read_reg(struct i2c_client *client, int reg) { int ret; - ret = i2c_smbus_read_byte_data(client, reg); + ret = i2c_smbus_read_word_swapped(client, reg); if (ret < 0) dev_err(>dev, "%s: err %d\n", __func__, ret); @@ -104,43 +99,36 @@ static int max17040_read_reg(struct i2c_client *client, int reg) static void max17040_reset(struct i2c_client *client) { - max17040_write_reg(client, MAX17040_CMD_MSB, 0x54); - max17040_write_reg(client, MAX17040_CMD_LSB, 0x00); + max17040_write_reg(client, MAX17040_CMD, 0x0054); } static void max17040_get_vcell(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; + u16 vcell; - msb = max17040_read_reg(client, MAX17040_VCELL_MSB); - lsb = max17040_read_reg(client, MAX17040_VCELL_LSB); + vcell = max17040_read_reg(client, MAX17040_VCELL); - chip->vcell = (msb << 4) + (lsb >> 4); + chip->vcell = vcell; } static void max17040_get_soc(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; + u16 soc; - msb = max17040_read_reg(client, MAX17040_SOC_MSB); - lsb = max17040_read_reg(client, MAX17040_SOC_LSB); + soc = max17040_read_reg(client, MAX17040_SOC); - chip->soc = msb; + chip->soc = (soc >> 8); } static void max17040_get_version(struct i2c_client *client) { - u8 msb; - u8 lsb; + u16 version; - msb = max17040_read_reg(client, MAX17040_VER_MSB); - lsb = max17040_read_reg(client, MAX17040_VER_LSB); + version = max17040_read_reg(client, MAX17040_VER); - dev_info(>dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb); + dev_info(>dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", version); } static void max17040_get_online(struct i2c_client *client) -- 1.9.1
[PATCH] serial: max310x: Set IRQF_TRIGGER_FALLING flag when dev.of_node is not NULL
When dev.of_node is not NULL, we also need to set IRQF_TRIGGER_FALLING flag, otherwise it may cause uncertain interrupts. Signed-off-by: Liu Xiang <liu.xia...@zte.com.cn> --- drivers/tty/serial/max310x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 9360801..8a3e926 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1329,9 +1329,9 @@ static int max310x_spi_probe(struct spi_device *spi) const struct spi_device_id *id_entry = spi_get_device_id(spi); devtype = (struct max310x_devtype *)id_entry->driver_data; - flags = IRQF_TRIGGER_FALLING; } + flags = IRQF_TRIGGER_FALLING; regcfg.max_register = devtype->nr * 0x20 - 1; regmap = devm_regmap_init_spi(spi, ); -- 1.9.1
[PATCH] serial: max310x: Set IRQF_TRIGGER_FALLING flag when dev.of_node is not NULL
When dev.of_node is not NULL, we also need to set IRQF_TRIGGER_FALLING flag, otherwise it may cause uncertain interrupts. Signed-off-by: Liu Xiang --- drivers/tty/serial/max310x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 9360801..8a3e926 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1329,9 +1329,9 @@ static int max310x_spi_probe(struct spi_device *spi) const struct spi_device_id *id_entry = spi_get_device_id(spi); devtype = (struct max310x_devtype *)id_entry->driver_data; - flags = IRQF_TRIGGER_FALLING; } + flags = IRQF_TRIGGER_FALLING; regcfg.max_register = devtype->nr * 0x20 - 1; regmap = devm_regmap_init_spi(spi, ); -- 1.9.1
[PATCH v2] usb: musb: host: Fix NULL pointer dereference in SMP environment
In multi-core SoC, if enable USB endpoint/transmit urb/disable USB endpoint repeatedly,it can cause a NULL pointer dereference bug: Unable to handle kernel NULL pointer dereference at virtual address 0010 pgd = d3eb4000 [0010] *pgd= Internal error: Oops: 5 [#1] PREEMPT SMP Pid: 1017, comm: mediaserver CPU: 0Not tainted (3.0.101-ZXICTOS_V2.00.20_P2B4_ZTE_ZX296700_ASIC+ #2) PC is at musb_h_disable+0xfc/0x15c LR is at musb_h_disable+0xfc/0x15c pc : []lr : []psr: 60070093 sp : d3e5bc80 ip : 0027 fp : d3e5bca4 r10: r9 : ff94 r8 : 0080 r7 : 60070013 r6 : d45900f0 r5 : d4717720 r4 : cee2d860 r3 : r2 : c0875628 r1 : d3e5bbc0 r0 : 002a Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 18c53c7d Table: b3eb404a DAC: 0015 [] (__dabt_svc+0x70/0xa0) from [] (musb_h_disable+0xfc/0x15c) [] (musb_h_disable+0xfc/0x15c) from [] (usb_hcd_disable_endpoint+0x3c/0x44) [] (usb_hcd_disable_endpoint+0x3c/0x44) from [] (usb_disable_endpoint+0x64/0x7c) [] (usb_disable_endpoint+0x64/0x7c) from [] (usb_disable_interface+0x48/0x58) [] (usb_disable_interface+0x48/0x58) from [] (usb_set_interface+0x158/0x274) [] (usb_set_interface+0x158/0x274) from [] (uvc_video_enable+0x78/0x9c) [] (uvc_video_enable+0x78/0x9c) from [] (uvc_v4l2_do_ioctl+0xd08/0x12ec) [] (uvc_v4l2_do_ioctl+0xd08/0x12ec) from [] (video_usercopy+0x144/0x500) [] (video_usercopy+0x144/0x500) from [] (uvc_v4l2_ioctl+0x2c/0x74) [] (uvc_v4l2_ioctl+0x2c/0x74) from [] (v4l2_ioctl+0x94/0x154) [] (v4l2_ioctl+0x94/0x154) from [] (do_vfs_ioctl+0x84/0x5ac) [] (do_vfs_ioctl+0x84/0x5ac) from [] (sys_ioctl+0x78/0x80) [] (sys_ioctl+0x78/0x80) from [] (ret_fast_syscall+0x0/0x30) Considering the following execution sequence: CPU0 CPU1 musb_urb_dequeue spin_lock_irqsave(>lock, flags); ready = qh->is_ready; qh->is_ready = 0; musb_giveback(musb, urb, 0); spin_unlock(>lock); zx296702_musb_interrupt musb_interrupt spin_lock_irqsave(>lock, flags); musb_advance_schedule ready = qh->is_ready; qh->is_ready = 0; musb_giveback(musb, urb, status); spin_unlock(>lock); spin_lock(>lock); qh->is_ready = ready; spin_unlock_irqrestore(>lock, flags); spin_lock(>lock); qh->is_ready = ready; When musb_urb_dequeue is called finally, the qh->is_ready has already been set to 0 in error.Thus the recycling qh job in musb_urb_dequeue can not be done. That results in accessing empty qh in musb_h_disable. So the qh in musb_h_disable should be checked.If the qh is emtpy, then recycle it and go to exit directly. --- v2: - Modify the urb empty condition --- Signed-off-by: Liu Xiang <liu.xia...@zte.com.cn> --- drivers/usb/musb/musb_host.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 795a45b..8445db3 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2515,7 +2515,12 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) qh->is_ready = 0; if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) { urb = next_urb(qh); - + if (!urb) { + qh->hep->hcpriv = NULL; + list_del(>ring); + kfree(qh); + goto exit; + } /* make software (then hardware) stop ASAP */ if (!urb->unlinked) urb->status = -ESHUTDOWN; -- 1.9.1
[PATCH v2] usb: musb: host: Fix NULL pointer dereference in SMP environment
In multi-core SoC, if enable USB endpoint/transmit urb/disable USB endpoint repeatedly,it can cause a NULL pointer dereference bug: Unable to handle kernel NULL pointer dereference at virtual address 0010 pgd = d3eb4000 [0010] *pgd= Internal error: Oops: 5 [#1] PREEMPT SMP Pid: 1017, comm: mediaserver CPU: 0Not tainted (3.0.101-ZXICTOS_V2.00.20_P2B4_ZTE_ZX296700_ASIC+ #2) PC is at musb_h_disable+0xfc/0x15c LR is at musb_h_disable+0xfc/0x15c pc : []lr : []psr: 60070093 sp : d3e5bc80 ip : 0027 fp : d3e5bca4 r10: r9 : ff94 r8 : 0080 r7 : 60070013 r6 : d45900f0 r5 : d4717720 r4 : cee2d860 r3 : r2 : c0875628 r1 : d3e5bbc0 r0 : 002a Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 18c53c7d Table: b3eb404a DAC: 0015 [] (__dabt_svc+0x70/0xa0) from [] (musb_h_disable+0xfc/0x15c) [] (musb_h_disable+0xfc/0x15c) from [] (usb_hcd_disable_endpoint+0x3c/0x44) [] (usb_hcd_disable_endpoint+0x3c/0x44) from [] (usb_disable_endpoint+0x64/0x7c) [] (usb_disable_endpoint+0x64/0x7c) from [] (usb_disable_interface+0x48/0x58) [] (usb_disable_interface+0x48/0x58) from [] (usb_set_interface+0x158/0x274) [] (usb_set_interface+0x158/0x274) from [] (uvc_video_enable+0x78/0x9c) [] (uvc_video_enable+0x78/0x9c) from [] (uvc_v4l2_do_ioctl+0xd08/0x12ec) [] (uvc_v4l2_do_ioctl+0xd08/0x12ec) from [] (video_usercopy+0x144/0x500) [] (video_usercopy+0x144/0x500) from [] (uvc_v4l2_ioctl+0x2c/0x74) [] (uvc_v4l2_ioctl+0x2c/0x74) from [] (v4l2_ioctl+0x94/0x154) [] (v4l2_ioctl+0x94/0x154) from [] (do_vfs_ioctl+0x84/0x5ac) [] (do_vfs_ioctl+0x84/0x5ac) from [] (sys_ioctl+0x78/0x80) [] (sys_ioctl+0x78/0x80) from [] (ret_fast_syscall+0x0/0x30) Considering the following execution sequence: CPU0 CPU1 musb_urb_dequeue spin_lock_irqsave(>lock, flags); ready = qh->is_ready; qh->is_ready = 0; musb_giveback(musb, urb, 0); spin_unlock(>lock); zx296702_musb_interrupt musb_interrupt spin_lock_irqsave(>lock, flags); musb_advance_schedule ready = qh->is_ready; qh->is_ready = 0; musb_giveback(musb, urb, status); spin_unlock(>lock); spin_lock(>lock); qh->is_ready = ready; spin_unlock_irqrestore(>lock, flags); spin_lock(>lock); qh->is_ready = ready; When musb_urb_dequeue is called finally, the qh->is_ready has already been set to 0 in error.Thus the recycling qh job in musb_urb_dequeue can not be done. That results in accessing empty qh in musb_h_disable. So the qh in musb_h_disable should be checked.If the qh is emtpy, then recycle it and go to exit directly. --- v2: - Modify the urb empty condition --- Signed-off-by: Liu Xiang --- drivers/usb/musb/musb_host.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 795a45b..8445db3 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2515,7 +2515,12 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) qh->is_ready = 0; if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) { urb = next_urb(qh); - + if (!urb) { + qh->hep->hcpriv = NULL; + list_del(>ring); + kfree(qh); + goto exit; + } /* make software (then hardware) stop ASAP */ if (!urb->unlinked) urb->status = -ESHUTDOWN; -- 1.9.1
[PATCH] usb: musb: host: Fix NULL pointer dereference in SMP environment
In multi-core SoC, if enable USB endpoint/transmit urb/disable USB endpoint repeatedly,it can cause a NULL pointer dereference bug: Unable to handle kernel NULL pointer dereference at virtual address 0010 pgd = d3eb4000 [0010] *pgd= Internal error: Oops: 5 [#1] PREEMPT SMP Pid: 1017, comm: mediaserver CPU: 0Not tainted (3.0.101-ZXICTOS_V2.00.20_P2B4_ZTE_ZX296700_ASIC+ #2) PC is at musb_h_disable+0xfc/0x15c LR is at musb_h_disable+0xfc/0x15c pc : []lr : []psr: 60070093 sp : d3e5bc80 ip : 0027 fp : d3e5bca4 r10: r9 : ff94 r8 : 0080 r7 : 60070013 r6 : d45900f0 r5 : d4717720 r4 : cee2d860 r3 : r2 : c0875628 r1 : d3e5bbc0 r0 : 002a Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 18c53c7d Table: b3eb404a DAC: 0015 [] (__dabt_svc+0x70/0xa0) from [] (musb_h_disable+0xfc/0x15c) [] (musb_h_disable+0xfc/0x15c) from [] (usb_hcd_disable_endpoint+0x3c/0x44) [] (usb_hcd_disable_endpoint+0x3c/0x44) from [] (usb_disable_endpoint+0x64/0x7c) [] (usb_disable_endpoint+0x64/0x7c) from [] (usb_disable_interface+0x48/0x58) [] (usb_disable_interface+0x48/0x58) from [] (usb_set_interface+0x158/0x274) [] (usb_set_interface+0x158/0x274) from [] (uvc_video_enable+0x78/0x9c) [] (uvc_video_enable+0x78/0x9c) from [] (uvc_v4l2_do_ioctl+0xd08/0x12ec) [] (uvc_v4l2_do_ioctl+0xd08/0x12ec) from [] (video_usercopy+0x144/0x500) [] (video_usercopy+0x144/0x500) from [] (uvc_v4l2_ioctl+0x2c/0x74) [] (uvc_v4l2_ioctl+0x2c/0x74) from [] (v4l2_ioctl+0x94/0x154) [] (v4l2_ioctl+0x94/0x154) from [] (do_vfs_ioctl+0x84/0x5ac) [] (do_vfs_ioctl+0x84/0x5ac) from [] (sys_ioctl+0x78/0x80) [] (sys_ioctl+0x78/0x80) from [] (ret_fast_syscall+0x0/0x30) Considering the following execution sequence: CPU0 CPU1 musb_urb_dequeue spin_lock_irqsave(>lock, flags); ready = qh->is_ready; qh->is_ready = 0; musb_giveback(musb, urb, 0); spin_unlock(>lock); zx296702_musb_interrupt musb_interrupt spin_lock_irqsave(>lock, flags); musb_advance_schedule ready = qh->is_ready; qh->is_ready = 0; musb_giveback(musb, urb, status); spin_unlock(>lock); spin_lock(>lock); qh->is_ready = ready; spin_unlock_irqrestore(>lock, flags); spin_lock(>lock); qh->is_ready = ready; When musb_urb_dequeue is called finally, the qh->is_ready has already been set to 0 in error.Thus the recycling qh job in musb_urb_dequeue can not be done. That results in accessing empty qh in musb_h_disable. So the qh in musb_h_disable should be checked.If the qh is emtpy, then recycle it and go to exit directly. Signed-off-by: Liu Xiang <liu.xia...@zte.com.cn> --- drivers/usb/musb/musb_host.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 795a45b..438f5b4 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2515,7 +2515,12 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) qh->is_ready = 0; if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) { urb = next_urb(qh); - + if (urb == NULL) { + qh->hep->hcpriv = NULL; + list_del(>ring); + kfree(qh); + goto exit; + } /* make software (then hardware) stop ASAP */ if (!urb->unlinked) urb->status = -ESHUTDOWN; -- 1.9.1
[PATCH] usb: musb: host: Fix NULL pointer dereference in SMP environment
In multi-core SoC, if enable USB endpoint/transmit urb/disable USB endpoint repeatedly,it can cause a NULL pointer dereference bug: Unable to handle kernel NULL pointer dereference at virtual address 0010 pgd = d3eb4000 [0010] *pgd= Internal error: Oops: 5 [#1] PREEMPT SMP Pid: 1017, comm: mediaserver CPU: 0Not tainted (3.0.101-ZXICTOS_V2.00.20_P2B4_ZTE_ZX296700_ASIC+ #2) PC is at musb_h_disable+0xfc/0x15c LR is at musb_h_disable+0xfc/0x15c pc : []lr : []psr: 60070093 sp : d3e5bc80 ip : 0027 fp : d3e5bca4 r10: r9 : ff94 r8 : 0080 r7 : 60070013 r6 : d45900f0 r5 : d4717720 r4 : cee2d860 r3 : r2 : c0875628 r1 : d3e5bbc0 r0 : 002a Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 18c53c7d Table: b3eb404a DAC: 0015 [] (__dabt_svc+0x70/0xa0) from [] (musb_h_disable+0xfc/0x15c) [] (musb_h_disable+0xfc/0x15c) from [] (usb_hcd_disable_endpoint+0x3c/0x44) [] (usb_hcd_disable_endpoint+0x3c/0x44) from [] (usb_disable_endpoint+0x64/0x7c) [] (usb_disable_endpoint+0x64/0x7c) from [] (usb_disable_interface+0x48/0x58) [] (usb_disable_interface+0x48/0x58) from [] (usb_set_interface+0x158/0x274) [] (usb_set_interface+0x158/0x274) from [] (uvc_video_enable+0x78/0x9c) [] (uvc_video_enable+0x78/0x9c) from [] (uvc_v4l2_do_ioctl+0xd08/0x12ec) [] (uvc_v4l2_do_ioctl+0xd08/0x12ec) from [] (video_usercopy+0x144/0x500) [] (video_usercopy+0x144/0x500) from [] (uvc_v4l2_ioctl+0x2c/0x74) [] (uvc_v4l2_ioctl+0x2c/0x74) from [] (v4l2_ioctl+0x94/0x154) [] (v4l2_ioctl+0x94/0x154) from [] (do_vfs_ioctl+0x84/0x5ac) [] (do_vfs_ioctl+0x84/0x5ac) from [] (sys_ioctl+0x78/0x80) [] (sys_ioctl+0x78/0x80) from [] (ret_fast_syscall+0x0/0x30) Considering the following execution sequence: CPU0 CPU1 musb_urb_dequeue spin_lock_irqsave(>lock, flags); ready = qh->is_ready; qh->is_ready = 0; musb_giveback(musb, urb, 0); spin_unlock(>lock); zx296702_musb_interrupt musb_interrupt spin_lock_irqsave(>lock, flags); musb_advance_schedule ready = qh->is_ready; qh->is_ready = 0; musb_giveback(musb, urb, status); spin_unlock(>lock); spin_lock(>lock); qh->is_ready = ready; spin_unlock_irqrestore(>lock, flags); spin_lock(>lock); qh->is_ready = ready; When musb_urb_dequeue is called finally, the qh->is_ready has already been set to 0 in error.Thus the recycling qh job in musb_urb_dequeue can not be done. That results in accessing empty qh in musb_h_disable. So the qh in musb_h_disable should be checked.If the qh is emtpy, then recycle it and go to exit directly. Signed-off-by: Liu Xiang --- drivers/usb/musb/musb_host.c | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 795a45b..438f5b4 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2515,7 +2515,12 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) qh->is_ready = 0; if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) { urb = next_urb(qh); - + if (urb == NULL) { + qh->hep->hcpriv = NULL; + list_del(>ring); + kfree(qh); + goto exit; + } /* make software (then hardware) stop ASAP */ if (!urb->unlinked) urb->status = -ESHUTDOWN; -- 1.9.1