[PATCH net] ixgbe: fix unbalanced device enable/disable in suspend/resume

2021-03-22 Thread Yongxin Liu
pci_disable_device() called in __ixgbe_shutdown() decreases
dev->enable_cnt by 1. pci_enable_device_mem() which increases
dev->enable_cnt by 1, was removed from ixgbe_resume() in commit
6f82b2558735 ("ixgbe: use generic power management"). This caused
unbalanced increase/decrease. So add pci_enable_device_mem() back.

Fix the following call trace.

  ixgbe :17:00.1: disabling already-disabled device
  Call Trace:
   __ixgbe_shutdown+0x10a/0x1e0 [ixgbe]
   ixgbe_suspend+0x32/0x70 [ixgbe]
   pci_pm_suspend+0x87/0x160
   ? pci_pm_freeze+0xd0/0xd0
   dpm_run_callback+0x42/0x170
   __device_suspend+0x114/0x460
   async_suspend+0x1f/0xa0
   async_run_entry_fn+0x3c/0xf0
   process_one_work+0x1dd/0x410
   worker_thread+0x34/0x3f0
   ? cancel_delayed_work+0x90/0x90
   kthread+0x14c/0x170
   ? kthread_park+0x90/0x90
   ret_from_fork+0x1f/0x30

Fixes: 6f82b2558735 ("ixgbe: use generic power management")
Signed-off-by: Yongxin Liu 
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 9f3f12e2ccf2..b0a8f7a43f06 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -6891,6 +6891,11 @@ static int __maybe_unused ixgbe_resume(struct device 
*dev_d)
 
adapter->hw.hw_addr = adapter->io_addr;
 
+   err = pci_enable_device_mem(pdev);
+   if (err) {
+   e_dev_err("Cannot enable PCI device from suspend\n");
+   return err;
+   }
smp_mb__before_atomic();
clear_bit(__IXGBE_DISABLED, &adapter->state);
pci_set_master(pdev);
-- 
2.14.5



[PATCH] Revert "net: ethernet: ixgbe: check the return value of ixgbe_mii_bus_init()"

2020-09-24 Thread Yongxin Liu
This reverts commit 09ef193fef7efb0175a04634853862d717adbb95.

For C3000 family of SoCs, they have four ixgbe devices sharing a single MDIO 
bus.
ixgbe_mii_bus_init() returns -ENODEV for other three devices. The propagation
of the error code makes other three ixgbe devices unregistered.

Signed-off-by: Yongxin Liu 
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 +-
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 2f8a4cfc5fa1..5e5223becf86 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -11031,14 +11031,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const 
struct pci_device_id *ent)
IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
true);
 
-   err = ixgbe_mii_bus_init(hw);
-   if (err)
-   goto err_netdev;
+   ixgbe_mii_bus_init(hw);
 
return 0;
 
-err_netdev:
-   unregister_netdev(netdev);
 err_register:
ixgbe_release_hw_control(adapter);
ixgbe_clear_interrupt_scheme(adapter);
-- 
2.14.4



[PATCH RT] kmemleak: Change the lock of kmemleak_object to raw_spinlock_t

2019-09-27 Thread Yongxin Liu
From: Liu Haitao 

The following call trace would be triggered as kmemleak is running.

  BUG: sleeping function called from invalid context at 
kernel/locking/rtmutex.c:968
  in_atomic(): 1, irqs_disabled(): 1, pid: 902, name: kmemleak
  4 locks held by kmemleak/902:
   #0:
   1f69be68
(
  scan_mutex
  ){+.+.}
  , at: kmemleak_scan_thread+0x7c/0xc3
   #1:
  a795ae4c
   (
  mem_hotplug_lock.rw_sem
  ){}
   , at: kmemleak_scan+0x1ba/0x7a0
   #2:
  79c12e8b
   (
  kmemleak_lock
  ){}
  , at: scan_block+0x31/0x120
   #3:
  191afe4b
   (
  &object->lock
  /1
  ){}
  , at: scan_block+0x8b/0x120
  irq event stamp: 16791384
  hardirqs last  enabled at (16791383): [] 
_raw_spin_unlock_irqrestore+0x82/0x90
  hardirqs last disabled at (16791384): [] 
_raw_spin_lock_irqsave+0x1a/0x80
  softirqs last  enabled at (0): [] 
copy_process.part.5+0x760/0x2000
  softirqs last disabled at (0): [<>] 0x0
  Preemption disabled at:
  [] scan_block+0x31/0x120

  CPU: 63 PID: 902 Comm: kmemleak Tainted: GW 
5.2.14-rt7-preempt-rt+ #2
  Hardware name: Intel Corporation S2600WFS/S2600WFS, BIOS 
SE5C620.86B.01.00.0694.120620170818 12/06/2017
  Call Trace:
   dump_stack+0x70/0xa5
   ___might_sleep+0x140/0x1e0
   rt_spin_lock_nested+0x59/0x70
   ? scan_block+0x8b/0x120
   scan_block+0x8b/0x120
   kmemleak_scan+0x285/0x7a0
   kmemleak_scan_thread+0x81/0xc3
   kthread+0x12f/0x150
   ? kmemleak_write+0x460/0x460
   ? kthread_park+0xb0/0xb0
   ret_from_fork+0x3a/0x50

The commit 3520604cc08dd63c057296c34756da1b6a655f71 changed the kmemleak_lock
to raw spinlock. However the kmemleak_object->lock is held after the
kmemleak_lock is held in scan_block().

scan_block()
|
raw_spin_lock_irqsave(&kmemleak_lock, flags)
   |
   spin_lock_nested(&object->lock, SINGLE_DEPTH_NESTING);

In this case, the object->lock is implemented by mutex in RT. It could casue a 
sleeping problem.

Fixes: 3520604cc08d ("kmemleak: Turn kmemleak_lock to raw spinlock on RT")

Signed-off-by: Liu Haitao 
Signed-off-by: Yongxin Liu 
---
 mm/kmemleak.c | 72 +--
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index aaee59c0306a..355dd95d0611 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -135,7 +135,7 @@ struct kmemleak_scan_area {
  * (use_count) and freed using the RCU mechanism.
  */
 struct kmemleak_object {
-   spinlock_t lock;
+   raw_spinlock_t lock;
unsigned int flags; /* object status flags */
struct list_head object_list;
struct list_head gray_list;
@@ -560,7 +560,7 @@ static struct kmemleak_object *create_object(unsigned long 
ptr, size_t size,
INIT_LIST_HEAD(&object->object_list);
INIT_LIST_HEAD(&object->gray_list);
INIT_HLIST_HEAD(&object->area_list);
-   spin_lock_init(&object->lock);
+   raw_spin_lock_init(&object->lock);
atomic_set(&object->use_count, 1);
object->flags = OBJECT_ALLOCATED;
object->pointer = ptr;
@@ -642,9 +642,9 @@ static void __delete_object(struct kmemleak_object *object)
 * Locking here also ensures that the corresponding memory block
 * cannot be freed when it is being scanned.
 */
-   spin_lock_irqsave(&object->lock, flags);
+   raw_spin_lock_irqsave(&object->lock, flags);
object->flags &= ~OBJECT_ALLOCATED;
-   spin_unlock_irqrestore(&object->lock, flags);
+   raw_spin_unlock_irqrestore(&object->lock, flags);
put_object(object);
 }
 
@@ -716,9 +716,9 @@ static void paint_it(struct kmemleak_object *object, int 
color)
 {
unsigned long flags;
 
-   spin_lock_irqsave(&object->lock, flags);
+   raw_spin_lock_irqsave(&object->lock, flags);
__paint_it(object, color);
-   spin_unlock_irqrestore(&object->lock, flags);
+   raw_spin_unlock_irqrestore(&object->lock, flags);
 }
 
 static void paint_ptr(unsigned long ptr, int color)
@@ -778,7 +778,7 @@ static void add_scan_area(unsigned long ptr, size_t size, 
gfp_t gfp)
goto out;
}
 
-   spin_lock_irqsave(&object->lock, flags);
+   raw_spin_lock_irqsave(&object->lock, flags);
if (size == SIZE_MAX) {
size = object->pointer + object->size - ptr;
} else if (ptr + size > object->pointer + object->size) {
@@ -794,7 +794,7 @@ static void add_scan_area(unsigned long ptr, size_t size, 
gfp_t gfp)
 
hlist_add_head(&area->node, &object->area_list);
 out_unlock:
-   spin_unlock_irqrestore(&object->lock, flags);
+   raw_spin_unlock_irqrestore(&object->lock, flags);
 out:
put_object(object);
 }
@@ -817,9 +817,9 @@ static void object_set_e

[PATCH] drm/nouveau: fix memory leak in nouveau_conn_reset()

2019-06-30 Thread Yongxin Liu
In nouveau_conn_reset(), if connector->state is true,
__drm_atomic_helper_connector_destroy_state() will be called,
but the memory pointed by asyc isn't freed. Memory leak happens
in the following function __drm_atomic_helper_connector_reset(),
where newly allocated asyc->state will be assigned to connector->state.

So using nouveau_conn_atomic_destroy_state() instead of
__drm_atomic_helper_connector_destroy_state to free the "old" asyc.

Here the is the log showing memory leak.

unreferenced object 0x8c5480483c80 (size 192):
  comm "kworker/0:2", pid 188, jiffies 4294695279 (age 53.179s)
  hex dump (first 32 bytes):
00 f0 ba 7b 54 8c ff ff 00 00 00 00 00 00 00 00  ...{T...
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
  backtrace:
[<5005c0d0>] kmem_cache_alloc_trace+0x195/0x2c0
[<a122baed>] nouveau_conn_reset+0x25/0xc0 [nouveau]
[<4fd189a2>] nouveau_connector_create+0x3a7/0x610 [nouveau]
[<c73343a8>] nv50_display_create+0x343/0x980 [nouveau]
[<2e2b03c3>] nouveau_display_create+0x51f/0x660 [nouveau]
[<c924699b>] nouveau_drm_device_init+0x182/0x7f0 [nouveau]
[<cc029436>] nouveau_drm_probe+0x20c/0x2c0 [nouveau]
[<7e961c3e>] local_pci_probe+0x47/0xa0
[<da14d569>] work_for_cpu_fn+0x1a/0x30
[<28da4805>] process_one_work+0x27c/0x660
[<1d415b04>] worker_thread+0x22b/0x3f0
[<000003b69f1f>] kthread+0x12f/0x150
[<c94c29b7>] ret_from_fork+0x3a/0x50

Signed-off-by: Yongxin Liu 
---
 drivers/gpu/drm/nouveau/nouveau_connector.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c 
b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 4116ee62adaf..f69ff22beee0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -252,7 +252,7 @@ nouveau_conn_reset(struct drm_connector *connector)
return;
 
if (connector->state)
-   __drm_atomic_helper_connector_destroy_state(connector->state);
+   nouveau_conn_atomic_destroy_state(connector, connector->state);
__drm_atomic_helper_connector_reset(connector, &asyc->state);
asyc->dither.mode = DITHERING_MODE_AUTO;
asyc->dither.depth = DITHERING_DEPTH_AUTO;
-- 
2.14.4



[PATCH RT] nvdimm: make lane acquirement RT aware

2019-03-06 Thread Yongxin Liu
Currently, nvdimm driver isn't RT compatible.
nd_region_acquire_lane() disables preemption with get_cpu() which
causes "scheduling while atomic" spews on RT, when using fio to test
pmem as block device.

In this change, we replace get_cpu/put_cpu with local_lock_cpu/
local_unlock_cpu, and introduce per CPU variable "ndl_local_lock".
Due to preemption on RT, this lock can avoid race condition for the
same lane on the same CPU. When CPU number is greater than the lane
number, lane can be shared among CPUs. "ndl_lock->lock" is used to
protect the lane in this situation.

This patch is derived from Dan Williams and Pankaj Gupta's proposal from
https://www.mail-archive.com/linux-nvdimm@lists.01.org/msg13359.html
and https://www.spinics.net/lists/linux-rt-users/msg20280.html.
Many thanks to them.

Cc: Dan Williams 
Cc: Pankaj Gupta 
Cc: linux-rt-users 
Cc: linux-nvdimm 
Signed-off-by: Yongxin Liu 
---
 drivers/nvdimm/region_devs.c | 40 +++-
 1 file changed, 19 insertions(+), 21 deletions(-)

diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index fa37afcd43ff..6c5388cf2477 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -18,9 +18,13 @@
 #include 
 #include 
 #include 
+#include 
 #include "nd-core.h"
 #include "nd.h"
 
+/* lock for tasks on the same CPU to sequence the access to the lane */
+static DEFINE_LOCAL_IRQ_LOCK(ndl_local_lock);
+
 /*
  * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is
  * irrelevant.
@@ -935,18 +939,15 @@ int nd_blk_region_init(struct nd_region *nd_region)
 unsigned int nd_region_acquire_lane(struct nd_region *nd_region)
 {
unsigned int cpu, lane;
+   struct nd_percpu_lane *ndl_lock, *ndl_count;
 
-   cpu = get_cpu();
-   if (nd_region->num_lanes < nr_cpu_ids) {
-   struct nd_percpu_lane *ndl_lock, *ndl_count;
+   cpu = local_lock_cpu(ndl_local_lock);
 
-   lane = cpu % nd_region->num_lanes;
-   ndl_count = per_cpu_ptr(nd_region->lane, cpu);
-   ndl_lock = per_cpu_ptr(nd_region->lane, lane);
-   if (ndl_count->count++ == 0)
-   spin_lock(&ndl_lock->lock);
-   } else
-   lane = cpu;
+   lane = cpu % nd_region->num_lanes;
+   ndl_count = per_cpu_ptr(nd_region->lane, cpu);
+   ndl_lock = per_cpu_ptr(nd_region->lane, lane);
+   if (ndl_count->count++ == 0)
+   spin_lock(&ndl_lock->lock);
 
return lane;
 }
@@ -954,17 +955,14 @@ EXPORT_SYMBOL(nd_region_acquire_lane);
 
 void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane)
 {
-   if (nd_region->num_lanes < nr_cpu_ids) {
-   unsigned int cpu = get_cpu();
-   struct nd_percpu_lane *ndl_lock, *ndl_count;
-
-   ndl_count = per_cpu_ptr(nd_region->lane, cpu);
-   ndl_lock = per_cpu_ptr(nd_region->lane, lane);
-   if (--ndl_count->count == 0)
-   spin_unlock(&ndl_lock->lock);
-   put_cpu();
-   }
-   put_cpu();
+   struct nd_percpu_lane *ndl_lock, *ndl_count;
+   unsigned int cpu = smp_processor_id();
+
+   ndl_count = per_cpu_ptr(nd_region->lane, cpu);
+   ndl_lock = per_cpu_ptr(nd_region->lane, lane);
+   if (--ndl_count->count == 0)
+   spin_unlock(&ndl_lock->lock);
+   local_unlock_cpu(ndl_local_lock);
 }
 EXPORT_SYMBOL(nd_region_release_lane);
 
-- 
2.14.4