[PATCH] virtio-balloon: fix a typo in comment of virtballoon_migratepage()

2021-03-26 Thread Liu Xiang
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)

2021-03-26 Thread Liu Xiang
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()

2021-03-25 Thread Liu Xiang
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()

2021-03-25 Thread Liu Xiang
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()

2021-03-25 Thread Liu Xiang
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()

2021-01-26 Thread liu xiang
> 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()

2021-01-26 Thread liu xiang
--

> 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()

2021-01-21 Thread liu xiang
> 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

2021-01-21 Thread Liu Xiang
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

2021-01-20 Thread liu xiang
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

2021-01-19 Thread Liu Xiang
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()

2021-01-18 Thread Liu Xiang
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()

2020-11-19 Thread Liu Xiang
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()

2020-11-19 Thread liu xiang
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()

2020-11-18 Thread Liu Xiang
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

2020-10-30 Thread Liu Xiang
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

2020-05-29 Thread Liu Xiang
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()

2019-10-23 Thread Liu Xiang
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()

2019-09-18 Thread Liu Xiang
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

2019-06-24 Thread Liu Xiang
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

2019-06-24 Thread Liu Xiang


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()

2019-05-31 Thread Liu Xiang
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

2019-03-31 Thread Liu Xiang
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

2019-03-31 Thread Liu Xiang
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

2019-03-26 Thread Liu Xiang



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

2019-03-26 Thread Liu Xiang

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

2019-03-13 Thread Liu Xiang
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

2019-03-13 Thread Liu Xiang



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

2019-03-12 Thread Liu Xiang


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

2019-03-11 Thread Liu Xiang
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

2019-03-03 Thread Liu Xiang
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

2019-01-29 Thread Liu Xiang
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

2019-01-27 Thread Liu Xiang
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

2019-01-25 Thread Liu Xiang
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

2019-01-25 Thread Liu Xiang
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

2019-01-25 Thread Liu Xiang
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

2019-01-15 Thread Liu Xiang
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

2018-11-25 Thread Liu Xiang
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

2018-11-25 Thread Liu Xiang
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

2018-11-25 Thread Liu Xiang
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

2018-11-25 Thread Liu Xiang
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

2018-11-25 Thread Liu Xiang
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

2018-11-25 Thread Liu Xiang
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

2018-11-16 Thread Liu Xiang

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

2018-11-16 Thread Liu Xiang

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

2018-11-14 Thread Liu Xiang

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

2018-11-14 Thread Liu Xiang

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

2018-11-14 Thread Liu Xiang
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

2018-11-14 Thread Liu Xiang
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

2018-11-14 Thread Liu Xiang
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

2018-11-14 Thread Liu Xiang
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

2018-08-28 Thread Liu Xiang
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

2018-08-28 Thread Liu Xiang
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

2018-08-28 Thread Liu Xiang


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

2018-08-28 Thread Liu Xiang


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

2018-08-28 Thread Liu Xiang
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

2018-08-28 Thread Liu Xiang
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

2018-08-24 Thread Liu Xiang
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

2018-08-24 Thread Liu Xiang
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

2018-08-24 Thread Liu Xiang
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

2018-08-24 Thread Liu Xiang
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

2018-08-18 Thread Liu Xiang
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

2018-08-18 Thread Liu Xiang
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

2018-07-22 Thread Liu Xiang
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

2018-07-22 Thread Liu Xiang
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

2018-07-22 Thread Liu Xiang
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

2018-07-22 Thread Liu Xiang
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

2018-07-20 Thread Liu Xiang
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

2018-07-20 Thread Liu Xiang
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

2018-04-14 Thread Liu Xiang
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

2018-04-14 Thread Liu Xiang
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

2018-01-27 Thread Liu Xiang
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

2018-01-27 Thread Liu Xiang
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

2018-01-27 Thread Liu Xiang
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

2018-01-27 Thread Liu Xiang
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

2017-06-06 Thread Liu Xiang
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

2017-06-06 Thread Liu Xiang
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

2017-05-31 Thread Liu Xiang
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

2017-05-31 Thread Liu Xiang
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

2016-09-21 Thread Liu Xiang
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

2016-09-21 Thread Liu Xiang
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

2016-09-07 Thread Liu Xiang
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

2016-09-07 Thread Liu Xiang
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

2016-02-27 Thread Liu Xiang
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

2016-02-27 Thread Liu Xiang
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

2016-02-19 Thread Liu Xiang
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

2016-02-19 Thread Liu Xiang
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