From 45ec9bd0fd7abf8705e7cf12205ff69fe9d51181 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 10 Dec 2014 17:06:57 +0000 Subject: [PATCH 1/8] dm thin: fix inability to discard blocks when in out-of-data-space mode When the pool was in PM_OUT_OF_SPACE mode its process_prepared_discard function pointer was incorrectly being set to process_prepared_discard_passdown rather than process_prepared_discard. This incorrect function pointer meant the discard was being passed down, but not effecting the mapping. As such any discard that was issued, in an attempt to reclaim blocks, would not successfully free data space. Reported-by: Eric Sandeen Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org --- drivers/md/dm-thin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 8735543eacdb..14b51a4fdf6b 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -2155,7 +2155,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) pool->process_cell = process_cell_read_only; pool->process_discard_cell = process_discard_cell; pool->process_prepared_mapping = process_prepared_mapping; - pool->process_prepared_discard = process_prepared_discard_passdown; + pool->process_prepared_discard = process_prepared_discard; if (!pool->pf.error_if_no_space && no_space_timeout) queue_delayed_work(pool->wq, &pool->no_space_timeout, no_space_timeout); From 2c43fd26e46734430122b8d2ad3024bb532df3ef Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 11 Dec 2014 11:12:19 +0000 Subject: [PATCH 2/8] dm thin: fix missing out-of-data-space to write mode transition if blocks are released Discard bios and thin device deletion have the potential to release data blocks. If the thin-pool is in out-of-data-space mode, and blocks were released, transition the thin-pool back to full write mode. The correct time to do this is just after the thin-pool metadata commit. It cannot be done before the commit because the space maps will not allow immediate reuse of the data blocks in case there's a rollback following power failure. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org --- drivers/md/dm-thin.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 14b51a4fdf6b..922aa553e9e0 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1127,6 +1127,24 @@ static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block, schedule_zero(tc, virt_block, data_dest, cell, bio); } +static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); + +static void check_for_space(struct pool *pool) +{ + int r; + dm_block_t nr_free; + + if (get_pool_mode(pool) != PM_OUT_OF_DATA_SPACE) + return; + + r = dm_pool_get_free_block_count(pool->pmd, &nr_free); + if (r) + return; + + if (nr_free) + set_pool_mode(pool, PM_WRITE); +} + /* * A non-zero return indicates read_only or fail_io mode. * Many callers don't care about the return value. @@ -1141,6 +1159,8 @@ static int commit(struct pool *pool) r = dm_pool_commit_metadata(pool->pmd); if (r) metadata_operation_failed(pool, "dm_pool_commit_metadata", r); + else + check_for_space(pool); return r; } @@ -1159,8 +1179,6 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks) } } -static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); - static int alloc_data_block(struct thin_c *tc, dm_block_t *result) { int r; From 2b94e8960cc3f225dec058f27570505351f4bc13 Mon Sep 17 00:00:00 2001 From: Marc Dionne Date: Wed, 17 Dec 2014 07:59:59 -0500 Subject: [PATCH 3/8] dm thin: fix crash by initializing thin device's refcount and completion earlier Commit 80e96c5484be ("dm thin: do not allow thin device activation while pool is suspended") delayed the initialization of a new thin device's refcount and completion until after this new thin was added to the pool's active_thins list and the pool lock is released. This opens a race with a worker thread that walks the list and calls thin_get/put, noticing that the refcount goes to 0 and calling complete, freezing up the system and giving the oops below: kernel: BUG: unable to handle kernel NULL pointer dereference at (null) kernel: IP: [] __wake_up_common+0x2b/0x90 kernel: Call Trace: kernel: [] __wake_up_locked+0x13/0x20 kernel: [] complete+0x37/0x50 kernel: [] thin_put+0x20/0x30 [dm_thin_pool] kernel: [] do_worker+0x667/0x870 [dm_thin_pool] kernel: [] ? __schedule+0x3ac/0x9a0 kernel: [] process_one_work+0x14f/0x400 kernel: [] worker_thread+0x6b/0x490 kernel: [] ? rescuer_thread+0x260/0x260 kernel: [] kthread+0xdb/0x100 kernel: [] ? kthread_create_on_node+0x170/0x170 kernel: [] ret_from_fork+0x7c/0xb0 kernel: [] ? kthread_create_on_node+0x170/0x170 Set the thin device's initial refcount and initialize the completion before adding it to the pool's active_thins list in thin_ctr(). Signed-off-by: Marc Dionne Signed-off-by: Mike Snitzer --- drivers/md/dm-thin.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 922aa553e9e0..493478989dbd 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -3832,6 +3832,8 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) r = -EINVAL; goto bad; } + atomic_set(&tc->refcount, 1); + init_completion(&tc->can_destroy); list_add_tail_rcu(&tc->list, &tc->pool->active_thins); spin_unlock_irqrestore(&tc->pool->lock, flags); /* @@ -3844,9 +3846,6 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) dm_put(pool_md); - atomic_set(&tc->refcount, 1); - init_completion(&tc->can_destroy); - return 0; bad: From 5164bece1673cdf04782f8ed3fba70743700f5da Mon Sep 17 00:00:00 2001 From: zhendong chen Date: Wed, 17 Dec 2014 14:37:04 +0800 Subject: [PATCH 4/8] dm: fix missed error code if .end_io isn't implemented by target_type In bio-based DM's clone_endio(), when target_type doesn't implement .end_io (e.g. linear) r will be always be initialized 0. So if a WRITE SAME bio fails WRITE SAME will not be disabled as intended. Fix this by initializing r to error, rather than 0, in clone_endio(). Signed-off-by: Alex Chen Signed-off-by: Mike Snitzer Fixes: 7eee4ae2db ("dm: disable WRITE SAME if it fails") Cc: stable@vger.kernel.org --- drivers/md/dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4c06585bf165..b98cd9d84435 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -899,7 +899,7 @@ static void disable_write_same(struct mapped_device *md) static void clone_endio(struct bio *bio, int error) { - int r = 0; + int r = error; struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone); struct dm_io *io = tio->io; struct mapped_device *md = tio->io->md; From 48ec833b7851438f02164ea846852ce4696f09ad Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 22 Dec 2014 21:01:54 +0200 Subject: [PATCH 5/8] Revert "mm/memory.c: share the i_mmap_rwsem" This reverts commit c8475d144abb1e62958cc5ec281d2a9e161c1946. There are several[1][2] of bug reports which points to this commit as potential cause[3]. Let's revert it until we figure out what's going on. [1] https://lkml.org/lkml/2014/11/14/342 [2] https://lkml.org/lkml/2014/12/22/213 [3] https://lkml.org/lkml/2014/12/9/741 Signed-off-by: Kirill A. Shutemov Reported-by: Sasha Levin Acked-by: Davidlohr Bueso Cc: Hugh Dickins Cc: Oleg Nesterov Cc: Peter Zijlstra (Intel) Cc: Rik van Riel Cc: Srikar Dronamraju Cc: Mel Gorman Signed-off-by: Linus Torvalds --- mm/memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 649e7d440bd7..ca920d1fd314 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2378,12 +2378,12 @@ void unmap_mapping_range(struct address_space *mapping, details.last_index = ULONG_MAX; - i_mmap_lock_read(mapping); + i_mmap_lock_write(mapping); if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap))) unmap_mapping_range_tree(&mapping->i_mmap, &details); if (unlikely(!list_empty(&mapping->i_mmap_nonlinear))) unmap_mapping_range_list(&mapping->i_mmap_nonlinear, &details); - i_mmap_unlock_read(mapping); + i_mmap_unlock_write(mapping); } EXPORT_SYMBOL(unmap_mapping_range); From 4e038e8919e072c9fa1b5462a7c89d8c95ac8657 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 17 Dec 2014 02:55:23 +0300 Subject: [PATCH 6/8] phy: miphy28lp: unlock on error in miphy28lp_init() We need to unlock before returning the -EINVAL here. Signed-off-by: Dan Carpenter Acked-by: Gabriel Fernandez Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-miphy28lp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index e34da13885e8..27fa62ce6136 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -1050,7 +1050,8 @@ static int miphy28lp_init(struct phy *phy) ret = miphy28lp_init_usb3(miphy_phy); break; default: - return -EINVAL; + ret = -EINVAL; + break; } mutex_unlock(&miphy_dev->miphy_mutex); From 372400344afb60e275a271f3f5ccce17af0e45cb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 17 Dec 2014 15:39:37 +0100 Subject: [PATCH 7/8] phy-sun4i-usb: Change disconnect threshold value for sun6i The allwinner SDK uses a value of 3 for the disconnect threshold setting on sun6i, do the same in the kernel. In my previous experience with sun5i problems getting the threshold right is important to avoid usb2 devices being unplugged sometimes going unnoticed. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index fb02a67c9181..a2b08f3ccb03 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -244,7 +244,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) else data->num_phys = 3; - if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy")) + if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy") || + of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) data->disc_thresh = 3; else data->disc_thresh = 2; From 0bc09f9cdc589e0b54724096138996a00b19babb Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 16 Dec 2014 14:52:50 +0530 Subject: [PATCH 8/8] phy: phy-ti-pipe3: fix inconsistent enumeration of PCIe gen2 cards Prior to DRA74x silicon rev 1.1, pcie_pcs register bits 8-15 and bits 16-23 were used to configure RC delay count for phy1 and phy2 respectively. phyid was used as index to distinguish the phys and to configure the delay values appropriately. As of DRA74x silicon rev 1.1, pcie_pcs register definition has changed. Bits 16-23 are used to configure delay values for *both* phy1 and phy2. Hence phyid is no longer required. So, drop id field from ti_pipe3 structure and its subsequent references for configuring pcie_pcs register. Also, pcie_pcs register now needs to be configured with delay value of 0x96 at bit positions 16-23. See register description of CTRL_CORE_PCIE_PCS in ARM572x TRM, SPRUHZ6, October 2014, section 18.5.2.2, table 18-1804. This is needed to ensure Gen2 cards are enumerated consistently. DRA72x silicon behaves same way as DRA74x rev 1.1 as far as this functionality is considered. Test results on DRA74x and DRA72x EVMs: Before patch ------------ DRA74x ES 1.0: Gen1 cards work, Gen2 cards do not work (expected result due to silicon errata) DRA74x ES 1.1: Gen1 cards work, Gen2 cards do not work sometimes due to incorrect programming of register DRA72x: Gen1 cards work, Gen2 cards do not work sometimes due to incorrect programming of register After patch ----------- DRA74x ES 1.0: Gen1 cards work, Gen2 cards do not work (expected result due to silicon errata) DRA74x ES 1.1: Gen1 cards work, Gen2 cards work consistently. DRA72x: Gen1 and Gen2 cards enumerate consistently. Signed-off-by: Vignesh R Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-omap-control.c | 7 +++---- drivers/phy/phy-ti-pipe3.c | 10 ++++++---- include/linux/phy/omap_control_phy.h | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/phy/phy-omap-control.c b/drivers/phy/phy-omap-control.c index c96e8183a8ff..efe724f97e02 100644 --- a/drivers/phy/phy-omap-control.c +++ b/drivers/phy/phy-omap-control.c @@ -29,10 +29,9 @@ /** * omap_control_pcie_pcs - set the PCS delay count * @dev: the control module device - * @id: index of the pcie PHY (should be 1 or 2) * @delay: 8 bit delay value */ -void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay) +void omap_control_pcie_pcs(struct device *dev, u8 delay) { u32 val; struct omap_control_phy *control_phy; @@ -55,8 +54,8 @@ void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay) val = readl(control_phy->pcie_pcs); val &= ~(OMAP_CTRL_PCIE_PCS_MASK << - (id * OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT)); - val |= delay << (id * OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT); + OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT); + val |= (delay << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT); writel(val, control_phy->pcie_pcs); } EXPORT_SYMBOL_GPL(omap_control_pcie_pcs); diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 1387b4d4afe3..465de2c800f2 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -82,7 +82,6 @@ struct ti_pipe3 { struct clk *refclk; struct clk *div_clk; struct pipe3_dpll_map *dpll_map; - u8 id; }; static struct pipe3_dpll_map dpll_map_usb[] = { @@ -217,8 +216,13 @@ static int ti_pipe3_init(struct phy *x) u32 val; int ret = 0; + /* + * Set pcie_pcs register to 0x96 for proper functioning of phy + * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table + * 18-1804. + */ if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) { - omap_control_pcie_pcs(phy->control_dev, phy->id, 0xF1); + omap_control_pcie_pcs(phy->control_dev, 0x96); return 0; } @@ -347,8 +351,6 @@ static int ti_pipe3_probe(struct platform_device *pdev) } if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { - if (of_property_read_u8(node, "id", &phy->id) < 0) - phy->id = 1; clk = devm_clk_get(phy->dev, "dpll_ref"); if (IS_ERR(clk)) { diff --git a/include/linux/phy/omap_control_phy.h b/include/linux/phy/omap_control_phy.h index e9e6cfbfbb58..eb7d4a135a9e 100644 --- a/include/linux/phy/omap_control_phy.h +++ b/include/linux/phy/omap_control_phy.h @@ -66,7 +66,7 @@ enum omap_control_usb_mode { #define OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF 0x0 #define OMAP_CTRL_PCIE_PCS_MASK 0xff -#define OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT 0x8 +#define OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT 16 #define OMAP_CTRL_USB2_PHY_PD BIT(28) @@ -79,7 +79,7 @@ enum omap_control_usb_mode { void omap_control_phy_power(struct device *dev, int on); void omap_control_usb_set_mode(struct device *dev, enum omap_control_usb_mode mode); -void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay); +void omap_control_pcie_pcs(struct device *dev, u8 delay); #else static inline void omap_control_phy_power(struct device *dev, int on) @@ -91,7 +91,7 @@ static inline void omap_control_usb_set_mode(struct device *dev, { } -static inline void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay) +static inline void omap_control_pcie_pcs(struct device *dev, u8 delay) { } #endif