[PATCH net] ixgbe: fix unbalanced device enable/disable in suspend/resume
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()"
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
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()
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
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