From: Greg Kroah-Hartman Date: Fri, 17 Jul 2015 03:13:30 +0000 (-0700) Subject: 4.0-stable patches X-Git-Tag: v4.0.9~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=112fe2e3bfc21b4e417073607f866da99028a8bf;p=thirdparty%2Fkernel%2Fstable-queue.git 4.0-stable patches added patches: genirq-devres-fix-testing-return-value-of-request_any_context_irq.patch ib-srp-fix-a-connection-setup-race.patch ib-srp-fix-connection-state-tracking.patch ib-srp-fix-reconnection-failure-handling.patch ib-srp-remove-an-extraneous-scsi_host_put-from-an-error-path.patch input-pixcir_i2c_ts-fix-receive-error.patch iser-target-release-stale-iser-connections.patch leds-pm-fix-hibernation-on-arm-when-gpio-led-used-with-cpu-led-trigger.patch livepatch-add-module-locking-around-kallsyms-calls.patch mtd-dc21285-use-raw-spinlock-functions-for-nw_gpio_lock.patch mtd-fix-avoid-race-condition-when-accessing-mtd-usecount.patch of-pci-fix-pci_address_to_pio-conversion-of-cpu-address-to-i-o-port.patch pci-add-pci_bus_addr_t.patch pci-pciehp-wait-for-hotplug-command-completion-where-necessary.patch pci-propagate-the-ignore-hotplug-setting-to-parent.patch regmap-fix-possible-shift-overflow-in-regmap_field_init.patch regmap-fix-regmap_bulk_read-in-be-mode.patch regulator-core-fix-constraints-output-buffer.patch regulator-max77686-fix-gpio_enabled-shift-wrapping-bug.patch scsi_transport_srp-fix-a-race-condition.patch scsi_transport_srp-introduce-srp_wait_for_queuecommand.patch spi-fix-race-freeing-dummy_tx-rx-before-it-is-unmapped.patch spi-orion-fix-maximum-baud-rates-for-armada-370-xp.patch spi-pl022-specify-num-cs-property-as-required-in-devicetree-binding.patch video-mxsfb-make-sure-axi-clock-is-enabled-when-accessing-registers.patch --- diff --git a/queue-4.0/genirq-devres-fix-testing-return-value-of-request_any_context_irq.patch b/queue-4.0/genirq-devres-fix-testing-return-value-of-request_any_context_irq.patch new file mode 100644 index 00000000000..f363c4e675d --- /dev/null +++ b/queue-4.0/genirq-devres-fix-testing-return-value-of-request_any_context_irq.patch @@ -0,0 +1,47 @@ +From 63781394c540dd9e666a6b21d70b64dd52bce76e Mon Sep 17 00:00:00 2001 +From: Axel Lin +Date: Mon, 11 May 2015 17:02:58 +0800 +Subject: genirq: devres: Fix testing return value of request_any_context_irq() + +From: Axel Lin + +commit 63781394c540dd9e666a6b21d70b64dd52bce76e upstream. + +request_any_context_irq() returns a negative value on failure. +It returns either IRQC_IS_HARDIRQ or IRQC_IS_NESTED on success. +So fix testing return value of request_any_context_irq(). + +Also fixup the return value of devm_request_any_context_irq() to make it +consistent with request_any_context_irq(). + +Fixes: 0668d3065128 ("genirq: Add devm_request_any_context_irq()") +Signed-off-by: Axel Lin +Reviewed-by: Stephen Boyd +Link: http://lkml.kernel.org/r/1431334978.17783.4.camel@ingics.com +Signed-off-by: Thomas Gleixner +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/irq/devres.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/kernel/irq/devres.c ++++ b/kernel/irq/devres.c +@@ -104,7 +104,7 @@ int devm_request_any_context_irq(struct + return -ENOMEM; + + rc = request_any_context_irq(irq, handler, irqflags, devname, dev_id); +- if (rc) { ++ if (rc < 0) { + devres_free(dr); + return rc; + } +@@ -113,7 +113,7 @@ int devm_request_any_context_irq(struct + dr->dev_id = dev_id; + devres_add(dev, dr); + +- return 0; ++ return rc; + } + EXPORT_SYMBOL(devm_request_any_context_irq); + diff --git a/queue-4.0/ib-srp-fix-a-connection-setup-race.patch b/queue-4.0/ib-srp-fix-a-connection-setup-race.patch new file mode 100644 index 00000000000..9e92135929e --- /dev/null +++ b/queue-4.0/ib-srp-fix-a-connection-setup-race.patch @@ -0,0 +1,43 @@ +From 8de9fe3a1d4ac8c3e4953fa4b7d81f863f5196ad Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Mon, 18 May 2015 13:23:36 +0200 +Subject: IB/srp: Fix a connection setup race + +From: Bart Van Assche + +commit 8de9fe3a1d4ac8c3e4953fa4b7d81f863f5196ad upstream. + +Avoid that receiving a DREQ while RDMA channels are being +established causes target->qp_in_error to be reset. + +Signed-off-by: Bart Van Assche +Cc: Sagi Grimberg +Cc: Sebastian Parschauer +Signed-off-by: Doug Ledford +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/infiniband/ulp/srp/ib_srp.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/infiniband/ulp/srp/ib_srp.c ++++ b/drivers/infiniband/ulp/srp/ib_srp.c +@@ -992,8 +992,6 @@ static int srp_connect_ch(struct srp_rdm + + WARN_ON_ONCE(!multich && target->connected); + +- target->qp_in_error = false; +- + ret = srp_lookup_path(ch); + if (ret) + return ret; +@@ -1242,6 +1240,9 @@ static int srp_rport_reconnect(struct sr + for (j = 0; j < target->queue_size; ++j) + list_add(&ch->tx_ring[j]->list, &ch->free_tx); + } ++ ++ target->qp_in_error = false; ++ + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; + if (ret || !ch->target) { diff --git a/queue-4.0/ib-srp-fix-connection-state-tracking.patch b/queue-4.0/ib-srp-fix-connection-state-tracking.patch new file mode 100644 index 00000000000..039e8639f03 --- /dev/null +++ b/queue-4.0/ib-srp-fix-connection-state-tracking.patch @@ -0,0 +1,191 @@ +From c014c8cd31b161e12deb81c0f7f477811bd1eddc Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Mon, 18 May 2015 13:23:57 +0200 +Subject: IB/srp: Fix connection state tracking + +From: Bart Van Assche + +commit c014c8cd31b161e12deb81c0f7f477811bd1eddc upstream. + +Reception of a DREQ message only causes the state of a single +channel to change. Hence move the 'connected' member variable +from the target to the channel data structure. This patch +avoids that following false positive warning can be reported +by srp_destroy_qp(): + +WARNING: at drivers/infiniband/ulp/srp/ib_srp.c:617 srp_destroy_qp+0xa6/0x120 [ib_srp]() +Call Trace: +[] warn_slowpath_common+0x7f/0xc0 +[] warn_slowpath_null+0x1a/0x20 +[] srp_destroy_qp+0xa6/0x120 [ib_srp] +[] srp_free_ch_ib+0x82/0x1e0 [ib_srp] +[] srp_create_target+0x7ab/0x998 [ib_srp] +[] dev_attr_store+0x20/0x30 +[] sysfs_write_file+0xef/0x170 +[] vfs_write+0xc8/0x190 +[] sys_write+0x51/0x90 + +Signed-off-by: Bart Van Assche +Cc: Sagi Grimberg +Cc: Sebastian Parschauer +Signed-off-by: Doug Ledford +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/infiniband/ulp/srp/ib_srp.c | 60 +++++++++++++++++------------------- + drivers/infiniband/ulp/srp/ib_srp.h | 2 - + 2 files changed, 30 insertions(+), 32 deletions(-) + +--- a/drivers/infiniband/ulp/srp/ib_srp.c ++++ b/drivers/infiniband/ulp/srp/ib_srp.c +@@ -464,14 +464,13 @@ static struct srp_fr_pool *srp_alloc_fr_ + */ + static void srp_destroy_qp(struct srp_rdma_ch *ch) + { +- struct srp_target_port *target = ch->target; + static struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR }; + static struct ib_recv_wr wr = { .wr_id = SRP_LAST_WR_ID }; + struct ib_recv_wr *bad_wr; + int ret; + + /* Destroying a QP and reusing ch->done is only safe if not connected */ +- WARN_ON_ONCE(target->connected); ++ WARN_ON_ONCE(ch->connected); + + ret = ib_modify_qp(ch->qp, &attr, IB_QP_STATE); + WARN_ONCE(ret, "ib_cm_init_qp_attr() returned %d\n", ret); +@@ -810,35 +809,19 @@ static bool srp_queue_remove_work(struct + return changed; + } + +-static bool srp_change_conn_state(struct srp_target_port *target, +- bool connected) +-{ +- bool changed = false; +- +- spin_lock_irq(&target->lock); +- if (target->connected != connected) { +- target->connected = connected; +- changed = true; +- } +- spin_unlock_irq(&target->lock); +- +- return changed; +-} +- + static void srp_disconnect_target(struct srp_target_port *target) + { + struct srp_rdma_ch *ch; + int i; + +- if (srp_change_conn_state(target, false)) { +- /* XXX should send SRP_I_LOGOUT request */ ++ /* XXX should send SRP_I_LOGOUT request */ + +- for (i = 0; i < target->ch_count; i++) { +- ch = &target->ch[i]; +- if (ch->cm_id && ib_send_cm_dreq(ch->cm_id, NULL, 0)) { +- shost_printk(KERN_DEBUG, target->scsi_host, +- PFX "Sending CM DREQ failed\n"); +- } ++ for (i = 0; i < target->ch_count; i++) { ++ ch = &target->ch[i]; ++ ch->connected = false; ++ if (ch->cm_id && ib_send_cm_dreq(ch->cm_id, NULL, 0)) { ++ shost_printk(KERN_DEBUG, target->scsi_host, ++ PFX "Sending CM DREQ failed\n"); + } + } + } +@@ -985,12 +968,26 @@ static void srp_rport_delete(struct srp_ + srp_queue_remove_work(target); + } + ++/** ++ * srp_connected_ch() - number of connected channels ++ * @target: SRP target port. ++ */ ++static int srp_connected_ch(struct srp_target_port *target) ++{ ++ int i, c = 0; ++ ++ for (i = 0; i < target->ch_count; i++) ++ c += target->ch[i].connected; ++ ++ return c; ++} ++ + static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich) + { + struct srp_target_port *target = ch->target; + int ret; + +- WARN_ON_ONCE(!multich && target->connected); ++ WARN_ON_ONCE(!multich && srp_connected_ch(target) > 0); + + ret = srp_lookup_path(ch); + if (ret) +@@ -1013,7 +1010,7 @@ static int srp_connect_ch(struct srp_rdm + */ + switch (ch->status) { + case 0: +- srp_change_conn_state(target, true); ++ ch->connected = true; + return 0; + + case SRP_PORT_REDIRECT: +@@ -1929,7 +1926,7 @@ static void srp_handle_qp_err(u64 wr_id, + return; + } + +- if (target->connected && !target->qp_in_error) { ++ if (ch->connected && !target->qp_in_error) { + if (wr_id & LOCAL_INV_WR_ID_MASK) { + shost_printk(KERN_ERR, target->scsi_host, PFX + "LOCAL_INV failed with status %d\n", +@@ -2367,7 +2364,7 @@ static int srp_cm_handler(struct ib_cm_i + case IB_CM_DREQ_RECEIVED: + shost_printk(KERN_WARNING, target->scsi_host, + PFX "DREQ received - connection closed\n"); +- srp_change_conn_state(target, false); ++ ch->connected = false; + if (ib_send_cm_drep(cm_id, NULL, 0)) + shost_printk(KERN_ERR, target->scsi_host, + PFX "Sending CM DREP failed\n"); +@@ -2423,7 +2420,7 @@ static int srp_send_tsk_mgmt(struct srp_ + struct srp_iu *iu; + struct srp_tsk_mgmt *tsk_mgmt; + +- if (!target->connected || target->qp_in_error) ++ if (!ch->connected || target->qp_in_error) + return -1; + + init_completion(&ch->tsk_mgmt_done); +@@ -2797,7 +2794,8 @@ static int srp_add_target(struct srp_hos + scsi_scan_target(&target->scsi_host->shost_gendev, + 0, target->scsi_id, SCAN_WILD_CARD, 0); + +- if (!target->connected || target->qp_in_error) { ++ if (srp_connected_ch(target) < target->ch_count || ++ target->qp_in_error) { + shost_printk(KERN_INFO, target->scsi_host, + PFX "SCSI scan failed - removing SCSI host\n"); + srp_queue_remove_work(target); +--- a/drivers/infiniband/ulp/srp/ib_srp.h ++++ b/drivers/infiniband/ulp/srp/ib_srp.h +@@ -170,6 +170,7 @@ struct srp_rdma_ch { + + struct completion tsk_mgmt_done; + u8 tsk_mgmt_status; ++ bool connected; + }; + + /** +@@ -214,7 +215,6 @@ struct srp_target_port { + __be16 pkey; + + u32 rq_tmo_jiffies; +- bool connected; + + int zero_req_lim; + diff --git a/queue-4.0/ib-srp-fix-reconnection-failure-handling.patch b/queue-4.0/ib-srp-fix-reconnection-failure-handling.patch new file mode 100644 index 00000000000..d340176985f --- /dev/null +++ b/queue-4.0/ib-srp-fix-reconnection-failure-handling.patch @@ -0,0 +1,40 @@ +From a44074f14ba1ea0747ea737026eb929b81993dc3 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Mon, 18 May 2015 13:24:17 +0200 +Subject: IB/srp: Fix reconnection failure handling + +From: Bart Van Assche + +commit a44074f14ba1ea0747ea737026eb929b81993dc3 upstream. + +Although it is possible to let SRP I/O continue if a reconnect +results in a reduction of the number of channels, the current +code does not handle this scenario correctly. Instead of making +the reconnect code more complex, consider this as a reconnection +failure. + +Signed-off-by: Bart Van Assche +Cc: Sagi Grimberg +Cc: Sebastian Parschauer +Signed-off-by: Doug Ledford +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/infiniband/ulp/srp/ib_srp.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/drivers/infiniband/ulp/srp/ib_srp.c ++++ b/drivers/infiniband/ulp/srp/ib_srp.c +@@ -1242,11 +1242,8 @@ static int srp_rport_reconnect(struct sr + + for (i = 0; i < target->ch_count; i++) { + ch = &target->ch[i]; +- if (ret || !ch->target) { +- if (i > 1) +- ret = 0; ++ if (ret || !ch->target) + break; +- } + ret = srp_connect_ch(ch, multich); + multich = true; + } diff --git a/queue-4.0/ib-srp-remove-an-extraneous-scsi_host_put-from-an-error-path.patch b/queue-4.0/ib-srp-remove-an-extraneous-scsi_host_put-from-an-error-path.patch new file mode 100644 index 00000000000..e86f598e8cb --- /dev/null +++ b/queue-4.0/ib-srp-remove-an-extraneous-scsi_host_put-from-an-error-path.patch @@ -0,0 +1,77 @@ +From fb49c8bbaae70b14fea2b4590a90a21539f88526 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Mon, 18 May 2015 13:23:14 +0200 +Subject: IB/srp: Remove an extraneous scsi_host_put() from an error path + +From: Bart Van Assche + +commit fb49c8bbaae70b14fea2b4590a90a21539f88526 upstream. + +Fix a scsi_get_host() / scsi_host_put() imbalance in the error +path of srp_create_target(). See also patch "IB/srp: Avoid that +I/O hangs due to a cable pull during LUN scanning" (commit ID +34aa654ecb8e). + +Signed-off-by: Bart Van Assche +Reviewed-by: Sagi Grimberg +Cc: Sebastian Parschauer +Signed-off-by: Doug Ledford +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/infiniband/ulp/srp/ib_srp.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +--- a/drivers/infiniband/ulp/srp/ib_srp.c ++++ b/drivers/infiniband/ulp/srp/ib_srp.c +@@ -3171,11 +3171,11 @@ static ssize_t srp_create_target(struct + + ret = srp_parse_options(buf, target); + if (ret) +- goto err; ++ goto out; + + ret = scsi_init_shared_tag_map(target_host, target_host->can_queue); + if (ret) +- goto err; ++ goto out; + + target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE; + +@@ -3186,7 +3186,7 @@ static ssize_t srp_create_target(struct + be64_to_cpu(target->ioc_guid), + be64_to_cpu(target->initiator_ext)); + ret = -EEXIST; +- goto err; ++ goto out; + } + + if (!srp_dev->has_fmr && !srp_dev->has_fr && !target->allow_ext_sg && +@@ -3207,7 +3207,7 @@ static ssize_t srp_create_target(struct + spin_lock_init(&target->lock); + ret = ib_query_gid(ibdev, host->port, 0, &target->sgid); + if (ret) +- goto err; ++ goto out; + + ret = -ENOMEM; + target->ch_count = max_t(unsigned, num_online_nodes(), +@@ -3218,7 +3218,7 @@ static ssize_t srp_create_target(struct + target->ch = kcalloc(target->ch_count, sizeof(*target->ch), + GFP_KERNEL); + if (!target->ch) +- goto err; ++ goto out; + + node_idx = 0; + for_each_online_node(node) { +@@ -3314,9 +3314,6 @@ err_disconnect: + } + + kfree(target->ch); +- +-err: +- scsi_host_put(target_host); + goto out; + } + diff --git a/queue-4.0/input-pixcir_i2c_ts-fix-receive-error.patch b/queue-4.0/input-pixcir_i2c_ts-fix-receive-error.patch new file mode 100644 index 00000000000..8fbe8f48763 --- /dev/null +++ b/queue-4.0/input-pixcir_i2c_ts-fix-receive-error.patch @@ -0,0 +1,35 @@ +From 469d7d22cea146e40efe8c330e5164b4d8f13934 Mon Sep 17 00:00:00 2001 +From: Frodo Lai +Date: Tue, 16 Jun 2015 15:03:53 -0700 +Subject: Input: pixcir_i2c_ts - fix receive error + +From: Frodo Lai + +commit 469d7d22cea146e40efe8c330e5164b4d8f13934 upstream. + +The i2c_master_recv() uses readsize to receive data from i2c but compares +to size of rdbuf which is always 27. This would cause problem when the +max_fingers is not 5. Change the comparison value to readsize instead. + +Fixes: 36874c7e219 ("Input: pixcir_i2c_ts - support up to 5 fingers and +hardware tracking IDs:) + +Signed-off-by: Frodo Lai +Signed-off-by: Dmitry Torokhov +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/input/touchscreen/pixcir_i2c_ts.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/input/touchscreen/pixcir_i2c_ts.c ++++ b/drivers/input/touchscreen/pixcir_i2c_ts.c +@@ -78,7 +78,7 @@ static void pixcir_ts_parse(struct pixci + } + + ret = i2c_master_recv(tsdata->client, rdbuf, readsize); +- if (ret != sizeof(rdbuf)) { ++ if (ret != readsize) { + dev_err(&tsdata->client->dev, + "%s: i2c_master_recv failed(), ret=%d\n", + __func__, ret); diff --git a/queue-4.0/iser-target-release-stale-iser-connections.patch b/queue-4.0/iser-target-release-stale-iser-connections.patch new file mode 100644 index 00000000000..59d8c3e79e2 --- /dev/null +++ b/queue-4.0/iser-target-release-stale-iser-connections.patch @@ -0,0 +1,91 @@ +From 2f1b6b7d9a815f341b18dfd26a363f37d4d3c96a Mon Sep 17 00:00:00 2001 +From: Sagi Grimberg +Date: Thu, 4 Jun 2015 19:49:20 +0300 +Subject: iser-target: release stale iser connections + +From: Sagi Grimberg + +commit 2f1b6b7d9a815f341b18dfd26a363f37d4d3c96a upstream. + +When receiving a new iser connect request we serialize +the pending requests by adding the newly created iser connection +to the np accept list and let the login thread process the connect +request one by one (np_accept_wait). + +In case we received a disconnect request before the iser_conn +has begun processing (still linked in np_accept_list) we should +detach it from the list and clean it up and not have the login +thread process a stale connection. We do it only when the connection +state is not already terminating (initiator driven disconnect) as +this might lead us to access np_accept_mutex after the np was released +in live shutdown scenarios. + +Signed-off-by: Sagi Grimberg +Signed-off-by: Jenny Falkovich +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman +--- + drivers/infiniband/ulp/isert/ib_isert.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +--- a/drivers/infiniband/ulp/isert/ib_isert.c ++++ b/drivers/infiniband/ulp/isert/ib_isert.c +@@ -65,6 +65,8 @@ static int + isert_rdma_accept(struct isert_conn *isert_conn); + struct rdma_cm_id *isert_setup_id(struct isert_np *isert_np); + ++static void isert_release_work(struct work_struct *work); ++ + static inline bool + isert_prot_cmd(struct isert_conn *conn, struct se_cmd *cmd) + { +@@ -604,6 +606,7 @@ isert_connect_request(struct rdma_cm_id + mutex_init(&isert_conn->conn_mutex); + spin_lock_init(&isert_conn->conn_lock); + INIT_LIST_HEAD(&isert_conn->conn_fr_pool); ++ INIT_WORK(&isert_conn->release_work, isert_release_work); + + isert_conn->conn_cm_id = cma_id; + +@@ -863,6 +866,7 @@ isert_disconnected_handler(struct rdma_c + { + struct isert_np *isert_np = cma_id->context; + struct isert_conn *isert_conn; ++ bool terminating = false; + + if (isert_np->np_cm_id == cma_id) + return isert_np_cma_handler(cma_id->context, event); +@@ -870,12 +874,25 @@ isert_disconnected_handler(struct rdma_c + isert_conn = cma_id->qp->qp_context; + + mutex_lock(&isert_conn->conn_mutex); ++ terminating = (isert_conn->state == ISER_CONN_TERMINATING); + isert_conn_terminate(isert_conn); + mutex_unlock(&isert_conn->conn_mutex); + + isert_info("conn %p completing conn_wait\n", isert_conn); + complete(&isert_conn->conn_wait); + ++ if (terminating) ++ goto out; ++ ++ mutex_lock(&isert_np->np_accept_mutex); ++ if (!list_empty(&isert_conn->conn_accept_node)) { ++ list_del_init(&isert_conn->conn_accept_node); ++ isert_put_conn(isert_conn); ++ queue_work(isert_release_wq, &isert_conn->release_work); ++ } ++ mutex_unlock(&isert_np->np_accept_mutex); ++ ++out: + return 0; + } + +@@ -3305,7 +3322,6 @@ static void isert_wait_conn(struct iscsi + isert_wait4flush(isert_conn); + isert_wait4logout(isert_conn); + +- INIT_WORK(&isert_conn->release_work, isert_release_work); + queue_work(isert_release_wq, &isert_conn->release_work); + } + diff --git a/queue-4.0/leds-pm-fix-hibernation-on-arm-when-gpio-led-used-with-cpu-led-trigger.patch b/queue-4.0/leds-pm-fix-hibernation-on-arm-when-gpio-led-used-with-cpu-led-trigger.patch new file mode 100644 index 00000000000..ac2b5d10377 --- /dev/null +++ b/queue-4.0/leds-pm-fix-hibernation-on-arm-when-gpio-led-used-with-cpu-led-trigger.patch @@ -0,0 +1,67 @@ +From 084609bf727981c7a2e6e69aefe0052c9d793300 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko +Date: Fri, 24 Apr 2015 14:57:10 +0300 +Subject: leds / PM: fix hibernation on arm when gpio-led used with CPU led trigger + +From: Grygorii Strashko + +commit 084609bf727981c7a2e6e69aefe0052c9d793300 upstream. + +Setting a dev_pm_ops suspend/resume pair of callbacks but not a set of +hibernation callbacks means those pm functions will not be +called upon hibernation - that leads to system crash on ARM during +freezing if gpio-led is used in combination with CPU led trigger. +It may happen after freeze_noirq stage (GPIO is suspended) +and before syscore_suspend stage (CPU led trigger is suspended) +- usually when disable_nonboot_cpus() is called. + +Log: + PM: noirq freeze of devices complete after 1.425 msecs + Disabling non-boot CPUs ... + ^ system may crash or stuck here with message (TI AM572x) + + WARNING: CPU: 0 PID: 3100 at drivers/bus/omap_l3_noc.c:148 l3_interrupt_handler+0x22c/0x370() + 44000000.ocp:L3 Custom Error: MASTER MPU TARGET L4_PER1_P3 (Idle): Data Access in Supervisor mode during Functional access + + CPU1: shutdown + ^ or here + +Fix this by using SIMPLE_DEV_PM_OPS, which appropriately +assigns the suspend and hibernation callbacks and move +led_suspend/led_resume under CONFIG_PM_SLEEP to avoid +build warnings. + +Fixes: 73e1ab41a80d (leds: Convert led class driver from legacy pm ops to dev_pm_ops) +Signed-off-by: Grygorii Strashko +Acked-by: Jacek Anaszewski +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/leds/led-class.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/leds/led-class.c ++++ b/drivers/leds/led-class.c +@@ -187,6 +187,7 @@ void led_classdev_resume(struct led_clas + } + EXPORT_SYMBOL_GPL(led_classdev_resume); + ++#ifdef CONFIG_PM_SLEEP + static int led_suspend(struct device *dev) + { + struct led_classdev *led_cdev = dev_get_drvdata(dev); +@@ -206,11 +207,9 @@ static int led_resume(struct device *dev + + return 0; + } ++#endif + +-static const struct dev_pm_ops leds_class_dev_pm_ops = { +- .suspend = led_suspend, +- .resume = led_resume, +-}; ++static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume); + + /** + * led_classdev_register - register a new object of led_classdev class. diff --git a/queue-4.0/livepatch-add-module-locking-around-kallsyms-calls.patch b/queue-4.0/livepatch-add-module-locking-around-kallsyms-calls.patch new file mode 100644 index 00000000000..213ce025124 --- /dev/null +++ b/queue-4.0/livepatch-add-module-locking-around-kallsyms-calls.patch @@ -0,0 +1,64 @@ +From 9a1bd63cdae4b623494c4ebaf723a91c35ec49fb Mon Sep 17 00:00:00 2001 +From: Miroslav Benes +Date: Mon, 1 Jun 2015 17:48:37 +0200 +Subject: livepatch: add module locking around kallsyms calls + +From: Miroslav Benes + +commit 9a1bd63cdae4b623494c4ebaf723a91c35ec49fb upstream. + +The list of loaded modules is walked through in +module_kallsyms_on_each_symbol (called by kallsyms_on_each_symbol). The +module_mutex lock should be acquired to prevent potential corruptions +in the list. + +This was uncovered with new lockdep asserts in module code introduced by +the commit 0be964be0d45 ("module: Sanitize RCU usage and locking") in +recent next- trees. + +Signed-off-by: Miroslav Benes +Acked-by: Josh Poimboeuf +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/livepatch/core.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +--- a/kernel/livepatch/core.c ++++ b/kernel/livepatch/core.c +@@ -179,7 +179,9 @@ static int klp_find_object_symbol(const + .count = 0 + }; + ++ mutex_lock(&module_mutex); + kallsyms_on_each_symbol(klp_find_callback, &args); ++ mutex_unlock(&module_mutex); + + if (args.count == 0) + pr_err("symbol '%s' not found in symbol table\n", name); +@@ -219,13 +221,19 @@ static int klp_verify_vmlinux_symbol(con + .name = name, + .addr = addr, + }; ++ int ret; + +- if (kallsyms_on_each_symbol(klp_verify_callback, &args)) +- return 0; ++ mutex_lock(&module_mutex); ++ ret = kallsyms_on_each_symbol(klp_verify_callback, &args); ++ mutex_unlock(&module_mutex); ++ ++ if (!ret) { ++ pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n", ++ name, addr); ++ return -EINVAL; ++ } + +- pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n", +- name, addr); +- return -EINVAL; ++ return 0; + } + + static int klp_find_verify_func_addr(struct klp_object *obj, diff --git a/queue-4.0/mtd-dc21285-use-raw-spinlock-functions-for-nw_gpio_lock.patch b/queue-4.0/mtd-dc21285-use-raw-spinlock-functions-for-nw_gpio_lock.patch new file mode 100644 index 00000000000..9cb0fd31279 --- /dev/null +++ b/queue-4.0/mtd-dc21285-use-raw-spinlock-functions-for-nw_gpio_lock.patch @@ -0,0 +1,63 @@ +From e5babdf928e5d0c432a8d4b99f20421ce14d1ab6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= +Date: Thu, 28 May 2015 10:22:10 +0200 +Subject: mtd: dc21285: use raw spinlock functions for nw_gpio_lock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= + +commit e5babdf928e5d0c432a8d4b99f20421ce14d1ab6 upstream. + +Since commit bd31b85960a7 (which is in 3.2-rc1) nw_gpio_lock is a raw spinlock +that needs usage of the corresponding raw functions. + +This fixes: + + drivers/mtd/maps/dc21285.c: In function 'nw_en_write': + drivers/mtd/maps/dc21285.c:41:340: warning: passing argument 1 of 'spinlock_check' from incompatible pointer type + spin_lock_irqsave(&nw_gpio_lock, flags); + + In file included from include/linux/seqlock.h:35:0, + from include/linux/time.h:5, + from include/linux/stat.h:18, + from include/linux/module.h:10, + from drivers/mtd/maps/dc21285.c:8: + include/linux/spinlock.h:299:102: note: expected 'struct spinlock_t *' but argument is of type 'struct raw_spinlock_t *' + static inline raw_spinlock_t *spinlock_check(spinlock_t *lock) + ^ + drivers/mtd/maps/dc21285.c:43:25: warning: passing argument 1 of 'spin_unlock_irqrestore' from incompatible pointer type + spin_unlock_irqrestore(&nw_gpio_lock, flags); + ^ + In file included from include/linux/seqlock.h:35:0, + from include/linux/time.h:5, + from include/linux/stat.h:18, + from include/linux/module.h:10, + from drivers/mtd/maps/dc21285.c:8: + include/linux/spinlock.h:370:91: note: expected 'struct spinlock_t *' but argument is of type 'struct raw_spinlock_t *' + static inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) + +Fixes: bd31b85960a7 ("locking, ARM: Annotate low level hw locks as raw") +Signed-off-by: Uwe Kleine-König +Signed-off-by: Brian Norris +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mtd/maps/dc21285.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/mtd/maps/dc21285.c ++++ b/drivers/mtd/maps/dc21285.c +@@ -38,9 +38,9 @@ static void nw_en_write(void) + * we want to write a bit pattern XXX1 to Xilinx to enable + * the write gate, which will be open for about the next 2ms. + */ +- spin_lock_irqsave(&nw_gpio_lock, flags); ++ raw_spin_lock_irqsave(&nw_gpio_lock, flags); + nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE); +- spin_unlock_irqrestore(&nw_gpio_lock, flags); ++ raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); + + /* + * let the ISA bus to catch on... diff --git a/queue-4.0/mtd-fix-avoid-race-condition-when-accessing-mtd-usecount.patch b/queue-4.0/mtd-fix-avoid-race-condition-when-accessing-mtd-usecount.patch new file mode 100644 index 00000000000..007b7d5d5a1 --- /dev/null +++ b/queue-4.0/mtd-fix-avoid-race-condition-when-accessing-mtd-usecount.patch @@ -0,0 +1,96 @@ +From 073db4a51ee43ccb827f54a4261c0583b028d5ab Mon Sep 17 00:00:00 2001 +From: Brian Norris +Date: Thu, 7 May 2015 17:55:16 -0700 +Subject: mtd: fix: avoid race condition when accessing mtd->usecount + +From: Brian Norris + +commit 073db4a51ee43ccb827f54a4261c0583b028d5ab upstream. + +On A MIPS 32-cores machine a BUG_ON was triggered because some acesses to +mtd->usecount were done without taking mtd_table_mutex. +kernel: Call Trace: +kernel: [] __put_mtd_device+0x20/0x50 +kernel: [] blktrans_release+0x8c/0xd8 +kernel: [] __blkdev_put+0x1a8/0x200 +kernel: [] blkdev_close+0x1c/0x30 +kernel: [] __fput+0xac/0x250 +kernel: [] task_work_run+0xd8/0x120 +kernel: [] work_notifysig+0x10/0x18 +kernel: +kernel: + Code: 2442ffff ac8202d8 000217fe <00020336> dc820128 10400003 + 00000000 0040f809 00000000 +kernel: ---[ end trace 080fbb4579b47a73 ]--- + +Fixed by taking the mutex in blktrans_open and blktrans_release. + +Note that this locking is already suggested in +include/linux/mtd/blktrans.h: + +struct mtd_blktrans_ops { +... + /* Called with mtd_table_mutex held; no race with add/remove */ + int (*open)(struct mtd_blktrans_dev *dev); + void (*release)(struct mtd_blktrans_dev *dev); +... +}; + +But we weren't following it. + +Originally reported by (and patched by) Zhang and Giuseppe, +independently. Improved and rewritten. + +Reported-by: Zhang Xingcai +Reported-by: Giuseppe Cantavenera +Tested-by: Giuseppe Cantavenera +Acked-by: Alexander Sverdlin +Signed-off-by: Brian Norris +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/mtd/mtd_blkdevs.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/mtd/mtd_blkdevs.c ++++ b/drivers/mtd/mtd_blkdevs.c +@@ -200,6 +200,7 @@ static int blktrans_open(struct block_de + return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ + + mutex_lock(&dev->lock); ++ mutex_lock(&mtd_table_mutex); + + if (dev->open) + goto unlock; +@@ -223,6 +224,7 @@ static int blktrans_open(struct block_de + + unlock: + dev->open++; ++ mutex_unlock(&mtd_table_mutex); + mutex_unlock(&dev->lock); + blktrans_dev_put(dev); + return ret; +@@ -233,6 +235,7 @@ error_release: + error_put: + module_put(dev->tr->owner); + kref_put(&dev->ref, blktrans_dev_release); ++ mutex_unlock(&mtd_table_mutex); + mutex_unlock(&dev->lock); + blktrans_dev_put(dev); + return ret; +@@ -246,6 +249,7 @@ static void blktrans_release(struct gend + return; + + mutex_lock(&dev->lock); ++ mutex_lock(&mtd_table_mutex); + + if (--dev->open) + goto unlock; +@@ -259,6 +263,7 @@ static void blktrans_release(struct gend + __put_mtd_device(dev->mtd); + } + unlock: ++ mutex_unlock(&mtd_table_mutex); + mutex_unlock(&dev->lock); + blktrans_dev_put(dev); + } diff --git a/queue-4.0/of-pci-fix-pci_address_to_pio-conversion-of-cpu-address-to-i-o-port.patch b/queue-4.0/of-pci-fix-pci_address_to_pio-conversion-of-cpu-address-to-i-o-port.patch new file mode 100644 index 00000000000..af9aacc2726 --- /dev/null +++ b/queue-4.0/of-pci-fix-pci_address_to_pio-conversion-of-cpu-address-to-i-o-port.patch @@ -0,0 +1,38 @@ +From 5dbb4c6167229c8d4f528e8ec26699a7305000a3 Mon Sep 17 00:00:00 2001 +From: Zhichang Yuan +Date: Fri, 24 Apr 2015 17:05:09 +0800 +Subject: of/pci: Fix pci_address_to_pio() conversion of CPU address to I/O port + +From: Zhichang Yuan + +commit 5dbb4c6167229c8d4f528e8ec26699a7305000a3 upstream. + +41f8bba7f555 ("of/pci: Add pci_register_io_range() and +pci_pio_to_address()") added support for systems with several I/O ranges +described by OF bindings. It modified pci_address_to_pio() look up the +io_range for a given CPU physical address, but the conversion was wrong. + +Fix the conversion of address to I/O port. + +[bhelgaas: changelog] +Fixes: 41f8bba7f555 ("of/pci: Add pci_register_io_range() and pci_pio_to_address()") +Signed-off-by: Zhichang Yuan +Signed-off-by: Bjorn Helgaas +Acked-by: Liviu Dudau +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/of/address.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -765,7 +765,7 @@ unsigned long __weak pci_address_to_pio( + spin_lock(&io_range_lock); + list_for_each_entry(res, &io_range_list, list) { + if (address >= res->start && address < res->start + res->size) { +- addr = res->start - address + offset; ++ addr = address - res->start + offset; + break; + } + offset += res->size; diff --git a/queue-4.0/pci-add-pci_bus_addr_t.patch b/queue-4.0/pci-add-pci_bus_addr_t.patch new file mode 100644 index 00000000000..2456ae0e2da --- /dev/null +++ b/queue-4.0/pci-add-pci_bus_addr_t.patch @@ -0,0 +1,354 @@ +From 3a9ad0b4fdcd57f775d3615004c8c64c021a9e7d Mon Sep 17 00:00:00 2001 +From: Yinghai Lu +Date: Wed, 27 May 2015 17:23:51 -0700 +Subject: PCI: Add pci_bus_addr_t + +From: Yinghai Lu + +commit 3a9ad0b4fdcd57f775d3615004c8c64c021a9e7d upstream. + +David Ahern reported that d63e2e1f3df9 ("sparc/PCI: Clip bridge windows +to fit in upstream windows") fails to boot on sparc/T5-8: + + pci 0000:06:00.0: reg 0x184: can't handle BAR above 4GB (bus address 0x110204000) + +The problem is that sparc64 assumed that dma_addr_t only needed to hold DMA +addresses, i.e., bus addresses returned via the DMA API (dma_map_single(), +etc.), while the PCI core assumed dma_addr_t could hold *any* bus address, +including raw BAR values. On sparc64, all DMA addresses fit in 32 bits, so +dma_addr_t is a 32-bit type. However, BAR values can be 64 bits wide, so +they don't fit in a dma_addr_t. d63e2e1f3df9 added new checking that +tripped over this mismatch. + +Add pci_bus_addr_t, which is wide enough to hold any PCI bus address, +including both raw BAR values and DMA addresses. This will be 64 bits +on 64-bit platforms and on platforms with a 64-bit dma_addr_t. Then +dma_addr_t only needs to be wide enough to hold addresses from the DMA API. + +[bhelgaas: changelog, bugzilla, Kconfig to ensure pci_bus_addr_t is at +least as wide as dma_addr_t, documentation] +Fixes: d63e2e1f3df9 ("sparc/PCI: Clip bridge windows to fit in upstream windows") +Fixes: 23b13bc76f35 ("PCI: Fail safely if we can't handle BARs larger than 4GB") +Link: http://lkml.kernel.org/r/CAE9FiQU1gJY1LYrxs+ma5LCTEEe4xmtjRG0aXJ9K_Tsu+m9Wuw@mail.gmail.com +Link: http://lkml.kernel.org/r/1427857069-6789-1-git-send-email-yinghai@kernel.org +Link: https://bugzilla.kernel.org/show_bug.cgi?id=96231 +Reported-by: David Ahern +Tested-by: David Ahern +Signed-off-by: Yinghai Lu +Signed-off-by: Bjorn Helgaas +Acked-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/DMA-API-HOWTO.txt | 29 +++++++++++++++++------------ + Documentation/DMA-API.txt | 30 +++++++++++++++--------------- + drivers/pci/Kconfig | 4 ++++ + drivers/pci/bus.c | 10 +++++----- + drivers/pci/probe.c | 12 ++++++------ + include/linux/pci.h | 12 +++++++++--- + include/linux/types.h | 12 ++++++++++-- + 7 files changed, 66 insertions(+), 43 deletions(-) + +--- a/Documentation/DMA-API-HOWTO.txt ++++ b/Documentation/DMA-API-HOWTO.txt +@@ -25,13 +25,18 @@ physical addresses. These are the addre + address is not directly useful to a driver; it must use ioremap() to map + the space and produce a virtual address. + +-I/O devices use a third kind of address: a "bus address" or "DMA address". +-If a device has registers at an MMIO address, or if it performs DMA to read +-or write system memory, the addresses used by the device are bus addresses. +-In some systems, bus addresses are identical to CPU physical addresses, but +-in general they are not. IOMMUs and host bridges can produce arbitrary ++I/O devices use a third kind of address: a "bus address". If a device has ++registers at an MMIO address, or if it performs DMA to read or write system ++memory, the addresses used by the device are bus addresses. In some ++systems, bus addresses are identical to CPU physical addresses, but in ++general they are not. IOMMUs and host bridges can produce arbitrary + mappings between physical and bus addresses. + ++From a device's point of view, DMA uses the bus address space, but it may ++be restricted to a subset of that space. For example, even if a system ++supports 64-bit addresses for main memory and PCI BARs, it may use an IOMMU ++so devices only need to use 32-bit DMA addresses. ++ + Here's a picture and some examples: + + CPU CPU Bus +@@ -72,11 +77,11 @@ can use virtual address X to access the + cannot because DMA doesn't go through the CPU virtual memory system. + + In some simple systems, the device can do DMA directly to physical address +-Y. But in many others, there is IOMMU hardware that translates bus ++Y. But in many others, there is IOMMU hardware that translates DMA + addresses to physical addresses, e.g., it translates Z to Y. This is part + of the reason for the DMA API: the driver can give a virtual address X to + an interface like dma_map_single(), which sets up any required IOMMU +-mapping and returns the bus address Z. The driver then tells the device to ++mapping and returns the DMA address Z. The driver then tells the device to + do DMA to Z, and the IOMMU maps it to the buffer at address Y in system + RAM. + +@@ -98,7 +103,7 @@ First of all, you should make sure + #include + + is in your driver, which provides the definition of dma_addr_t. This type +-can hold any valid DMA or bus address for the platform and should be used ++can hold any valid DMA address for the platform and should be used + everywhere you hold a DMA address returned from the DMA mapping functions. + + What memory is DMA'able? +@@ -316,7 +321,7 @@ There are two types of DMA mappings: + Think of "consistent" as "synchronous" or "coherent". + + The current default is to return consistent memory in the low 32 +- bits of the bus space. However, for future compatibility you should ++ bits of the DMA space. However, for future compatibility you should + set the consistent mask even if this default is fine for your + driver. + +@@ -403,7 +408,7 @@ dma_alloc_coherent() returns two values: + can use to access it from the CPU and dma_handle which you pass to the + card. + +-The CPU virtual address and the DMA bus address are both ++The CPU virtual address and the DMA address are both + guaranteed to be aligned to the smallest PAGE_SIZE order which + is greater than or equal to the requested size. This invariant + exists (for example) to guarantee that if you allocate a chunk +@@ -645,8 +650,8 @@ PLEASE NOTE: The 'nents' argument to th + dma_map_sg call. + + Every dma_map_{single,sg}() call should have its dma_unmap_{single,sg}() +-counterpart, because the bus address space is a shared resource and +-you could render the machine unusable by consuming all bus addresses. ++counterpart, because the DMA address space is a shared resource and ++you could render the machine unusable by consuming all DMA addresses. + + If you need to use the same streaming DMA region multiple times and touch + the data in between the DMA transfers, the buffer needs to be synced +--- a/Documentation/DMA-API.txt ++++ b/Documentation/DMA-API.txt +@@ -18,10 +18,10 @@ Part I - dma_ API + To get the dma_ API, you must #include . This + provides dma_addr_t and the interfaces described below. + +-A dma_addr_t can hold any valid DMA or bus address for the platform. It +-can be given to a device to use as a DMA source or target. A CPU cannot +-reference a dma_addr_t directly because there may be translation between +-its physical address space and the bus address space. ++A dma_addr_t can hold any valid DMA address for the platform. It can be ++given to a device to use as a DMA source or target. A CPU cannot reference ++a dma_addr_t directly because there may be translation between its physical ++address space and the DMA address space. + + Part Ia - Using large DMA-coherent buffers + ------------------------------------------ +@@ -42,7 +42,7 @@ It returns a pointer to the allocated re + address space) or NULL if the allocation failed. + + It also returns a which may be cast to an unsigned integer the +-same width as the bus and given to the device as the bus address base of ++same width as the bus and given to the device as the DMA address base of + the region. + + Note: consistent memory can be expensive on some platforms, and the +@@ -193,7 +193,7 @@ dma_map_single(struct device *dev, void + enum dma_data_direction direction) + + Maps a piece of processor virtual memory so it can be accessed by the +-device and returns the bus address of the memory. ++device and returns the DMA address of the memory. + + The direction for both APIs may be converted freely by casting. + However the dma_ API uses a strongly typed enumerator for its +@@ -212,20 +212,20 @@ contiguous piece of memory. For this re + this API should be obtained from sources which guarantee it to be + physically contiguous (like kmalloc). + +-Further, the bus address of the memory must be within the ++Further, the DMA address of the memory must be within the + dma_mask of the device (the dma_mask is a bit mask of the +-addressable region for the device, i.e., if the bus address of +-the memory ANDed with the dma_mask is still equal to the bus ++addressable region for the device, i.e., if the DMA address of ++the memory ANDed with the dma_mask is still equal to the DMA + address, then the device can perform DMA to the memory). To + ensure that the memory allocated by kmalloc is within the dma_mask, + the driver may specify various platform-dependent flags to restrict +-the bus address range of the allocation (e.g., on x86, GFP_DMA +-guarantees to be within the first 16MB of available bus addresses, ++the DMA address range of the allocation (e.g., on x86, GFP_DMA ++guarantees to be within the first 16MB of available DMA addresses, + as required by ISA devices). + + Note also that the above constraints on physical contiguity and + dma_mask may not apply if the platform has an IOMMU (a device which +-maps an I/O bus address to a physical memory address). However, to be ++maps an I/O DMA address to a physical memory address). However, to be + portable, device driver writers may *not* assume that such an IOMMU + exists. + +@@ -296,7 +296,7 @@ reduce current DMA mapping usage or dela + dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) + +-Returns: the number of bus address segments mapped (this may be shorter ++Returns: the number of DMA address segments mapped (this may be shorter + than passed in if some elements of the scatter/gather list are + physically or virtually adjacent and an IOMMU maps them with a single + entry). +@@ -340,7 +340,7 @@ must be the same as those and passed in + API. + + Note: must be the number you passed in, *not* the number of +-bus address entries returned. ++DMA address entries returned. + + void + dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, +@@ -507,7 +507,7 @@ it's asked for coherent memory for this + phys_addr is the CPU physical address to which the memory is currently + assigned (this will be ioremapped so the CPU can access the region). + +-device_addr is the bus address the device needs to be programmed ++device_addr is the DMA address the device needs to be programmed + with to actually address this memory (this will be handed out as the + dma_addr_t in dma_alloc_coherent()). + +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -1,6 +1,10 @@ + # + # PCI configuration + # ++config PCI_BUS_ADDR_T_64BIT ++ def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT) ++ depends on PCI ++ + config PCI_MSI + bool "Message Signaled Interrupts (MSI and MSI-X)" + depends on PCI +--- a/drivers/pci/bus.c ++++ b/drivers/pci/bus.c +@@ -92,11 +92,11 @@ void pci_bus_remove_resources(struct pci + } + + static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL}; +-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT + static struct pci_bus_region pci_64_bit = {0, +- (dma_addr_t) 0xffffffffffffffffULL}; +-static struct pci_bus_region pci_high = {(dma_addr_t) 0x100000000ULL, +- (dma_addr_t) 0xffffffffffffffffULL}; ++ (pci_bus_addr_t) 0xffffffffffffffffULL}; ++static struct pci_bus_region pci_high = {(pci_bus_addr_t) 0x100000000ULL, ++ (pci_bus_addr_t) 0xffffffffffffffffULL}; + #endif + + /* +@@ -200,7 +200,7 @@ int pci_bus_alloc_resource(struct pci_bu + resource_size_t), + void *alignf_data) + { +-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ++#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT + int rc; + + if (res->flags & IORESOURCE_MEM_64) { +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -253,8 +253,8 @@ int __pci_read_base(struct pci_dev *dev, + } + + if (res->flags & IORESOURCE_MEM_64) { +- if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) && +- sz64 > 0x100000000ULL) { ++ if ((sizeof(pci_bus_addr_t) < 8 || sizeof(resource_size_t) < 8) ++ && sz64 > 0x100000000ULL) { + res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; + res->start = 0; + res->end = 0; +@@ -263,7 +263,7 @@ int __pci_read_base(struct pci_dev *dev, + goto out; + } + +- if ((sizeof(dma_addr_t) < 8) && l) { ++ if ((sizeof(pci_bus_addr_t) < 8) && l) { + /* Above 32-bit boundary; try to reallocate */ + res->flags |= IORESOURCE_UNSET; + res->start = 0; +@@ -398,7 +398,7 @@ static void pci_read_bridge_mmio_pref(st + struct pci_dev *dev = child->self; + u16 mem_base_lo, mem_limit_lo; + u64 base64, limit64; +- dma_addr_t base, limit; ++ pci_bus_addr_t base, limit; + struct pci_bus_region region; + struct resource *res; + +@@ -425,8 +425,8 @@ static void pci_read_bridge_mmio_pref(st + } + } + +- base = (dma_addr_t) base64; +- limit = (dma_addr_t) limit64; ++ base = (pci_bus_addr_t) base64; ++ limit = (pci_bus_addr_t) limit64; + + if (base != base64) { + dev_err(&dev->dev, "can't handle bridge window above 4GB (bus address %#010llx)\n", +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -573,9 +573,15 @@ int raw_pci_read(unsigned int domain, un + int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, + int reg, int len, u32 val); + ++#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT ++typedef u64 pci_bus_addr_t; ++#else ++typedef u32 pci_bus_addr_t; ++#endif ++ + struct pci_bus_region { +- dma_addr_t start; +- dma_addr_t end; ++ pci_bus_addr_t start; ++ pci_bus_addr_t end; + }; + + struct pci_dynids { +@@ -1120,7 +1126,7 @@ int __must_check pci_bus_alloc_resource( + + int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr); + +-static inline dma_addr_t pci_bus_address(struct pci_dev *pdev, int bar) ++static inline pci_bus_addr_t pci_bus_address(struct pci_dev *pdev, int bar) + { + struct pci_bus_region region; + +--- a/include/linux/types.h ++++ b/include/linux/types.h +@@ -139,12 +139,20 @@ typedef unsigned long blkcnt_t; + */ + #define pgoff_t unsigned long + +-/* A dma_addr_t can hold any valid DMA or bus address for the platform */ ++/* ++ * A dma_addr_t can hold any valid DMA address, i.e., any address returned ++ * by the DMA API. ++ * ++ * If the DMA API only uses 32-bit addresses, dma_addr_t need only be 32 ++ * bits wide. Bus addresses, e.g., PCI BARs, may be wider than 32 bits, ++ * but drivers do memory-mapped I/O to ioremapped kernel virtual addresses, ++ * so they don't care about the size of the actual bus addresses. ++ */ + #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + typedef u64 dma_addr_t; + #else + typedef u32 dma_addr_t; +-#endif /* dma_addr_t */ ++#endif + + #ifdef __CHECKER__ + #else diff --git a/queue-4.0/pci-pciehp-wait-for-hotplug-command-completion-where-necessary.patch b/queue-4.0/pci-pciehp-wait-for-hotplug-command-completion-where-necessary.patch new file mode 100644 index 00000000000..9edf07693af --- /dev/null +++ b/queue-4.0/pci-pciehp-wait-for-hotplug-command-completion-where-necessary.patch @@ -0,0 +1,166 @@ +From a5dd4b4b0570b3bf880d563969b245dfbd170c1e Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Mon, 8 Jun 2015 17:10:50 -0600 +Subject: PCI: pciehp: Wait for hotplug command completion where necessary + +From: Alex Williamson + +commit a5dd4b4b0570b3bf880d563969b245dfbd170c1e upstream. + +The commit referenced below deferred waiting for command completion until +the start of the next command, allowing hardware to do the latching +asynchronously. Unfortunately, being ready to accept a new command is the +only indication we have that the previous command is completed. In cases +where we need that state change to be enabled, we must still wait for +completion. For instance, pciehp_reset_slot() attempts to disable anything +that might generate a surprise hotplug on slots that support presence +detection. If we don't wait for those settings to latch before the +secondary bus reset, we negate any value in attempting to prevent the +spurious hotplug. + +Create a base function with optional wait and helper functions so that +pcie_write_cmd() turns back into the "safe" interface which waits before +and after issuing a command and add pcie_write_cmd_nowait(), which +eliminates the trailing wait for asynchronous completion. The following +functions are returned to their previous behavior: + + pciehp_power_on_slot + pciehp_power_off_slot + pcie_disable_notification + pciehp_reset_slot + +The rationale is that pciehp_power_on_slot() enables the link and therefore +relies on completion of power-on. pciehp_power_off_slot() and +pcie_disable_notification() need a wait because data structures may be +freed after these calls and continued signaling from the device would be +unexpected. And, of course, pciehp_reset_slot() needs to wait for the +scenario outlined above. + +Fixes: 3461a068661c ("PCI: pciehp: Wait for hotplug command completion lazily") +Signed-off-by: Alex Williamson +Signed-off-by: Bjorn Helgaas +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/hotplug/pciehp_hpc.c | 52 ++++++++++++++++++++++++++++----------- + 1 file changed, 38 insertions(+), 14 deletions(-) + +--- a/drivers/pci/hotplug/pciehp_hpc.c ++++ b/drivers/pci/hotplug/pciehp_hpc.c +@@ -176,20 +176,17 @@ static void pcie_wait_cmd(struct control + jiffies_to_msecs(jiffies - ctrl->cmd_started)); + } + +-/** +- * pcie_write_cmd - Issue controller command +- * @ctrl: controller to which the command is issued +- * @cmd: command value written to slot control register +- * @mask: bitmask of slot control register to be modified +- */ +-static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ++static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd, ++ u16 mask, bool wait) + { + struct pci_dev *pdev = ctrl_dev(ctrl); + u16 slot_ctrl; + + mutex_lock(&ctrl->ctrl_lock); + +- /* Wait for any previous command that might still be in progress */ ++ /* ++ * Always wait for any previous command that might still be in progress ++ */ + pcie_wait_cmd(ctrl); + + pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); +@@ -201,9 +198,33 @@ static void pcie_write_cmd(struct contro + ctrl->cmd_started = jiffies; + ctrl->slot_ctrl = slot_ctrl; + ++ /* ++ * Optionally wait for the hardware to be ready for a new command, ++ * indicating completion of the above issued command. ++ */ ++ if (wait) ++ pcie_wait_cmd(ctrl); ++ + mutex_unlock(&ctrl->ctrl_lock); + } + ++/** ++ * pcie_write_cmd - Issue controller command ++ * @ctrl: controller to which the command is issued ++ * @cmd: command value written to slot control register ++ * @mask: bitmask of slot control register to be modified ++ */ ++static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ++{ ++ pcie_do_write_cmd(ctrl, cmd, mask, true); ++} ++ ++/* Same as above without waiting for the hardware to latch */ ++static void pcie_write_cmd_nowait(struct controller *ctrl, u16 cmd, u16 mask) ++{ ++ pcie_do_write_cmd(ctrl, cmd, mask, false); ++} ++ + bool pciehp_check_link_active(struct controller *ctrl) + { + struct pci_dev *pdev = ctrl_dev(ctrl); +@@ -422,7 +443,7 @@ void pciehp_set_attention_status(struct + default: + return; + } +- pcie_write_cmd(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC); ++ pcie_write_cmd_nowait(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); + } +@@ -434,7 +455,8 @@ void pciehp_green_led_on(struct slot *sl + if (!PWR_LED(ctrl)) + return; + +- pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, PCI_EXP_SLTCTL_PIC); ++ pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, ++ PCI_EXP_SLTCTL_PIC); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PWR_IND_ON); +@@ -447,7 +469,8 @@ void pciehp_green_led_off(struct slot *s + if (!PWR_LED(ctrl)) + return; + +- pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, PCI_EXP_SLTCTL_PIC); ++ pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, ++ PCI_EXP_SLTCTL_PIC); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PWR_IND_OFF); +@@ -460,7 +483,8 @@ void pciehp_green_led_blink(struct slot + if (!PWR_LED(ctrl)) + return; + +- pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, PCI_EXP_SLTCTL_PIC); ++ pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, ++ PCI_EXP_SLTCTL_PIC); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PWR_IND_BLINK); +@@ -613,7 +637,7 @@ void pcie_enable_notification(struct con + PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | + PCI_EXP_SLTCTL_DLLSCE); + +- pcie_write_cmd(ctrl, cmd, mask); ++ pcie_write_cmd_nowait(ctrl, cmd, mask); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); + } +@@ -664,7 +688,7 @@ int pciehp_reset_slot(struct slot *slot, + pci_reset_bridge_secondary_bus(ctrl->pcie->port); + + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); +- pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask); ++ pcie_write_cmd_nowait(ctrl, ctrl_mask, ctrl_mask); + ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, + pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask); + if (pciehp_poll_mode) diff --git a/queue-4.0/pci-propagate-the-ignore-hotplug-setting-to-parent.patch b/queue-4.0/pci-propagate-the-ignore-hotplug-setting-to-parent.patch new file mode 100644 index 00000000000..d7a91d857b2 --- /dev/null +++ b/queue-4.0/pci-propagate-the-ignore-hotplug-setting-to-parent.patch @@ -0,0 +1,71 @@ +From 0824965140fff1bf640a987dc790d1594a8e0699 Mon Sep 17 00:00:00 2001 +From: "Rafael J. Wysocki" +Date: Mon, 13 Apr 2015 16:23:36 +0200 +Subject: PCI: Propagate the "ignore hotplug" setting to parent + +From: "Rafael J. Wysocki" + +commit 0824965140fff1bf640a987dc790d1594a8e0699 upstream. + +Refine the mechanism introduced by commit f244d8b623da ("ACPIPHP / radeon / +nouveau: Fix VGA switcheroo problem related to hotplug") to propagate the +ignore_hotplug setting of the device to its parent bridge in case hotplug +notifications related to the graphics adapter switching are given for the +bridge rather than for the device itself (they need to be ignored in both +cases). + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=61891 +Link: https://bugs.freedesktop.org/show_bug.cgi?id=88927 +Fixes: b440bde74f04 ("PCI: Add pci_ignore_hotplug() to ignore hotplug events for a device") +Reported-and-tested-by: tiagdtd-lava +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Bjorn Helgaas +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/pci.c | 11 +++++++++++ + include/linux/pci.h | 6 +----- + 2 files changed, 12 insertions(+), 5 deletions(-) + +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -4319,6 +4319,17 @@ bool pci_device_is_present(struct pci_de + } + EXPORT_SYMBOL_GPL(pci_device_is_present); + ++void pci_ignore_hotplug(struct pci_dev *dev) ++{ ++ struct pci_dev *bridge = dev->bus->self; ++ ++ dev->ignore_hotplug = 1; ++ /* Propagate the "ignore hotplug" setting to the parent bridge. */ ++ if (bridge) ++ bridge->ignore_hotplug = 1; ++} ++EXPORT_SYMBOL_GPL(pci_ignore_hotplug); ++ + #define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE + static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0}; + static DEFINE_SPINLOCK(resource_alignment_lock); +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -1002,6 +1002,7 @@ int __must_check pci_assign_resource(str + int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align); + int pci_select_bars(struct pci_dev *dev, unsigned long flags); + bool pci_device_is_present(struct pci_dev *pdev); ++void pci_ignore_hotplug(struct pci_dev *dev); + + /* ROM control related routines */ + int pci_enable_rom(struct pci_dev *pdev); +@@ -1039,11 +1040,6 @@ bool pci_dev_run_wake(struct pci_dev *de + bool pci_check_pme_status(struct pci_dev *dev); + void pci_pme_wakeup_bus(struct pci_bus *bus); + +-static inline void pci_ignore_hotplug(struct pci_dev *dev) +-{ +- dev->ignore_hotplug = 1; +-} +- + static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, + bool enable) + { diff --git a/queue-4.0/regmap-fix-possible-shift-overflow-in-regmap_field_init.patch b/queue-4.0/regmap-fix-possible-shift-overflow-in-regmap_field_init.patch new file mode 100644 index 00000000000..1e0f8e53c9c --- /dev/null +++ b/queue-4.0/regmap-fix-possible-shift-overflow-in-regmap_field_init.patch @@ -0,0 +1,42 @@ +From 921cc29473a0d7c109105c1876ddb432f4a4be7d Mon Sep 17 00:00:00 2001 +From: Maxime Coquelin +Date: Tue, 16 Jun 2015 13:53:19 +0200 +Subject: regmap: Fix possible shift overflow in regmap_field_init() + +From: Maxime Coquelin + +commit 921cc29473a0d7c109105c1876ddb432f4a4be7d upstream. + +The way the mask is generated in regmap_field_init() is wrong. +Indeed, a field initialized with msb = 31 and lsb = 0 provokes a shift +overflow while calculating the mask field. + +On some 32 bits architectures, such as x86, the generated mask is 0, +instead of the expected 0xffffffff. + +This patch uses GENMASK() to fix the problem, as this macro is already safe +regarding shift overflow. + +Signed-off-by: Maxime Coquelin +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/base/regmap/regmap.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -945,11 +945,10 @@ EXPORT_SYMBOL_GPL(devm_regmap_init); + static void regmap_field_init(struct regmap_field *rm_field, + struct regmap *regmap, struct reg_field reg_field) + { +- int field_bits = reg_field.msb - reg_field.lsb + 1; + rm_field->regmap = regmap; + rm_field->reg = reg_field.reg; + rm_field->shift = reg_field.lsb; +- rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb); ++ rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb); + rm_field->id_size = reg_field.id_size; + rm_field->id_offset = reg_field.id_offset; + } diff --git a/queue-4.0/regmap-fix-regmap_bulk_read-in-be-mode.patch b/queue-4.0/regmap-fix-regmap_bulk_read-in-be-mode.patch new file mode 100644 index 00000000000..59e11a59528 --- /dev/null +++ b/queue-4.0/regmap-fix-regmap_bulk_read-in-be-mode.patch @@ -0,0 +1,35 @@ +From 15b8d2c41fe5839582029f65c5f7004db451cc2b Mon Sep 17 00:00:00 2001 +From: Arun Chandran +Date: Mon, 15 Jun 2015 15:59:02 +0530 +Subject: regmap: Fix regmap_bulk_read in BE mode + +From: Arun Chandran + +commit 15b8d2c41fe5839582029f65c5f7004db451cc2b upstream. + +In big endian mode regmap_bulk_read gives incorrect data +for byte reads. + +This is because memcpy of a single byte from an address +after full word read gives different results when +endianness differs. ie. we get little-end in LE and big-end in BE. + +Signed-off-by: Arun Chandran +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/base/regmap/regmap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -2318,7 +2318,7 @@ int regmap_bulk_read(struct regmap *map, + &ival); + if (ret != 0) + return ret; +- memcpy(val + (i * val_bytes), &ival, val_bytes); ++ map->format.format_val(val + (i * val_bytes), ival, 0); + } + } + diff --git a/queue-4.0/regulator-core-fix-constraints-output-buffer.patch b/queue-4.0/regulator-core-fix-constraints-output-buffer.patch new file mode 100644 index 00000000000..a0fbcc11783 --- /dev/null +++ b/queue-4.0/regulator-core-fix-constraints-output-buffer.patch @@ -0,0 +1,31 @@ +From a7068e3932eee8268c4ce4e080a338ee7b8a27bf Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Tue, 9 Jun 2015 20:09:42 +0000 +Subject: regulator: core: fix constraints output buffer + +From: Stefan Wahren + +commit a7068e3932eee8268c4ce4e080a338ee7b8a27bf upstream. + +The buffer for condtraints debug isn't big enough to hold the output +in all cases. So fix this issue by increasing the buffer. + +Signed-off-by: Stefan Wahren +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/regulator/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -770,7 +770,7 @@ static int suspend_prepare(struct regula + static void print_constraints(struct regulator_dev *rdev) + { + struct regulation_constraints *constraints = rdev->constraints; +- char buf[80] = ""; ++ char buf[160] = ""; + int count = 0; + int ret; + diff --git a/queue-4.0/regulator-max77686-fix-gpio_enabled-shift-wrapping-bug.patch b/queue-4.0/regulator-max77686-fix-gpio_enabled-shift-wrapping-bug.patch new file mode 100644 index 00000000000..8bdba15ca1b --- /dev/null +++ b/queue-4.0/regulator-max77686-fix-gpio_enabled-shift-wrapping-bug.patch @@ -0,0 +1,55 @@ +From c53403a37cf083ce85da720f18918f73580d0064 Mon Sep 17 00:00:00 2001 +From: Joe Perches +Date: Mon, 18 May 2015 10:01:03 -0700 +Subject: regulator: max77686: fix gpio_enabled shift wrapping bug + +From: Joe Perches + +commit c53403a37cf083ce85da720f18918f73580d0064 upstream. + +The code should handle more than 32 bits here because "id" +can be a value up to MAX77686_REGULATORS (currently 34). + +Convert the gpio_enabled type to DECLARE_BITMAP and use +test_bit/set_bit. + +Fixes: 3307e9025d29 ("regulator: max77686: Add GPIO control") +Reported-by: Dan Carpenter +Signed-off-by: Joe Perches +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/regulator/max77686.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/regulator/max77686.c ++++ b/drivers/regulator/max77686.c +@@ -88,7 +88,7 @@ enum max77686_ramp_rate { + }; + + struct max77686_data { +- u64 gpio_enabled:MAX77686_REGULATORS; ++ DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS); + + /* Array indexed by regulator id */ + unsigned int opmode[MAX77686_REGULATORS]; +@@ -121,7 +121,7 @@ static unsigned int max77686_map_normal_ + case MAX77686_BUCK8: + case MAX77686_BUCK9: + case MAX77686_LDO20 ... MAX77686_LDO22: +- if (max77686->gpio_enabled & (1 << id)) ++ if (test_bit(id, max77686->gpio_enabled)) + return MAX77686_GPIO_CONTROL; + } + +@@ -277,7 +277,7 @@ static int max77686_of_parse_cb(struct d + } + + if (gpio_is_valid(config->ena_gpio)) { +- max77686->gpio_enabled |= (1 << desc->id); ++ set_bit(desc->id, max77686->gpio_enabled); + + return regmap_update_bits(config->regmap, desc->enable_reg, + desc->enable_mask, diff --git a/queue-4.0/scsi_transport_srp-fix-a-race-condition.patch b/queue-4.0/scsi_transport_srp-fix-a-race-condition.patch new file mode 100644 index 00000000000..9d0aa017c8a --- /dev/null +++ b/queue-4.0/scsi_transport_srp-fix-a-race-condition.patch @@ -0,0 +1,54 @@ +From 535fb906225fb7436cb658144d0c0cea14a26f3e Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Mon, 18 May 2015 13:22:44 +0200 +Subject: scsi_transport_srp: Fix a race condition + +From: Bart Van Assche + +commit 535fb906225fb7436cb658144d0c0cea14a26f3e upstream. + +Avoid that srp_terminate_io() can get invoked while srp_queuecommand() +is in progress. This patch avoids that an I/O timeout can trigger the +following kernel warning: + +WARNING: at drivers/infiniband/ulp/srp/ib_srp.c:1447 srp_terminate_io+0xef/0x100 [ib_srp]() +Call Trace: + [] dump_stack+0x4e/0x68 + [] warn_slowpath_common+0x81/0xa0 + [] warn_slowpath_null+0x1a/0x20 + [] srp_terminate_io+0xef/0x100 [ib_srp] + [] __rport_fail_io_fast+0xba/0xc0 [scsi_transport_srp] + [] rport_fast_io_fail_timedout+0xe0/0xf0 [scsi_transport_srp] + [] process_one_work+0x1db/0x780 + [] worker_thread+0x11b/0x450 + [] kthread+0xe4/0x100 + [] ret_from_fork+0x7c/0xb0 + +See also patch "scsi_transport_srp: Add transport layer error +handling" (commit ID 29c17324803c). + +Signed-off-by: Bart Van Assche +Cc: James Bottomley +Cc: Sagi Grimberg +Cc: Sebastian Parschauer +Signed-off-by: Doug Ledford +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/scsi_transport_srp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/scsi_transport_srp.c ++++ b/drivers/scsi/scsi_transport_srp.c +@@ -439,8 +439,10 @@ static void __rport_fail_io_fast(struct + + /* Involve the LLD if possible to terminate all I/O on the rport. */ + i = to_srp_internal(shost->transportt); +- if (i->f->terminate_rport_io) ++ if (i->f->terminate_rport_io) { ++ srp_wait_for_queuecommand(shost); + i->f->terminate_rport_io(rport); ++ } + } + + /** diff --git a/queue-4.0/scsi_transport_srp-introduce-srp_wait_for_queuecommand.patch b/queue-4.0/scsi_transport_srp-introduce-srp_wait_for_queuecommand.patch new file mode 100644 index 00000000000..c5394ccdb1b --- /dev/null +++ b/queue-4.0/scsi_transport_srp-introduce-srp_wait_for_queuecommand.patch @@ -0,0 +1,105 @@ +From be34c62ddf39d1931780b07a6f4241393e4ba2ee Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Mon, 18 May 2015 13:22:19 +0200 +Subject: scsi_transport_srp: Introduce srp_wait_for_queuecommand() + +From: Bart Van Assche + +commit be34c62ddf39d1931780b07a6f4241393e4ba2ee upstream. + +Introduce the helper function srp_wait_for_queuecommand(). +Move the definition of scsi_request_fn_active(). Add a comment +above srp_wait_for_queuecommand() that support for scsi-mq needs +to be added. + +This patch does not change any functionality. A second call to +srp_wait_for_queuecommand() will be introduced in the next patch. + +Signed-off-by: Bart Van Assche +Cc: James Bottomley +Cc: Sagi Grimberg +Cc: Sebastian Parschauer +Signed-off-by: Doug Ledford +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/scsi_transport_srp.c | 54 +++++++++++++++++++++----------------- + 1 file changed, 31 insertions(+), 23 deletions(-) + +--- a/drivers/scsi/scsi_transport_srp.c ++++ b/drivers/scsi/scsi_transport_srp.c +@@ -396,6 +396,36 @@ static void srp_reconnect_work(struct wo + } + } + ++/** ++ * scsi_request_fn_active() - number of kernel threads inside scsi_request_fn() ++ * @shost: SCSI host for which to count the number of scsi_request_fn() callers. ++ * ++ * To do: add support for scsi-mq in this function. ++ */ ++static int scsi_request_fn_active(struct Scsi_Host *shost) ++{ ++ struct scsi_device *sdev; ++ struct request_queue *q; ++ int request_fn_active = 0; ++ ++ shost_for_each_device(sdev, shost) { ++ q = sdev->request_queue; ++ ++ spin_lock_irq(q->queue_lock); ++ request_fn_active += q->request_fn_active; ++ spin_unlock_irq(q->queue_lock); ++ } ++ ++ return request_fn_active; ++} ++ ++/* Wait until ongoing shost->hostt->queuecommand() calls have finished. */ ++static void srp_wait_for_queuecommand(struct Scsi_Host *shost) ++{ ++ while (scsi_request_fn_active(shost)) ++ msleep(20); ++} ++ + static void __rport_fail_io_fast(struct srp_rport *rport) + { + struct Scsi_Host *shost = rport_to_shost(rport); +@@ -504,27 +534,6 @@ void srp_start_tl_fail_timers(struct srp + EXPORT_SYMBOL(srp_start_tl_fail_timers); + + /** +- * scsi_request_fn_active() - number of kernel threads inside scsi_request_fn() +- * @shost: SCSI host for which to count the number of scsi_request_fn() callers. +- */ +-static int scsi_request_fn_active(struct Scsi_Host *shost) +-{ +- struct scsi_device *sdev; +- struct request_queue *q; +- int request_fn_active = 0; +- +- shost_for_each_device(sdev, shost) { +- q = sdev->request_queue; +- +- spin_lock_irq(q->queue_lock); +- request_fn_active += q->request_fn_active; +- spin_unlock_irq(q->queue_lock); +- } +- +- return request_fn_active; +-} +- +-/** + * srp_reconnect_rport() - reconnect to an SRP target port + * @rport: SRP target port. + * +@@ -559,8 +568,7 @@ int srp_reconnect_rport(struct srp_rport + if (res) + goto out; + scsi_target_block(&shost->shost_gendev); +- while (scsi_request_fn_active(shost)) +- msleep(20); ++ srp_wait_for_queuecommand(shost); + res = rport->state != SRP_RPORT_LOST ? i->f->reconnect(rport) : -ENODEV; + pr_debug("%s (state %d): transport.reconnect() returned %d\n", + dev_name(&shost->shost_gendev), rport->state, res); diff --git a/queue-4.0/series b/queue-4.0/series index a76a213ca06..debf8cf76f8 100644 --- a/queue-4.0/series +++ b/queue-4.0/series @@ -31,3 +31,28 @@ arm64-vdso-work-around-broken-elf-toolchains-in-makefile.patch mm-kmemleak-allow-safe-memory-scanning-during-kmemleak-disabling.patch mm-kmemleak_alloc_percpu-should-follow-the-gfp-from-per_alloc.patch mm-thp-respect-mpol_preferred-policy-with-non-local-node.patch +iser-target-release-stale-iser-connections.patch +regmap-fix-regmap_bulk_read-in-be-mode.patch +regmap-fix-possible-shift-overflow-in-regmap_field_init.patch +regulator-max77686-fix-gpio_enabled-shift-wrapping-bug.patch +regulator-core-fix-constraints-output-buffer.patch +livepatch-add-module-locking-around-kallsyms-calls.patch +spi-fix-race-freeing-dummy_tx-rx-before-it-is-unmapped.patch +spi-orion-fix-maximum-baud-rates-for-armada-370-xp.patch +spi-pl022-specify-num-cs-property-as-required-in-devicetree-binding.patch +scsi_transport_srp-introduce-srp_wait_for_queuecommand.patch +scsi_transport_srp-fix-a-race-condition.patch +ib-srp-remove-an-extraneous-scsi_host_put-from-an-error-path.patch +ib-srp-fix-a-connection-setup-race.patch +ib-srp-fix-connection-state-tracking.patch +ib-srp-fix-reconnection-failure-handling.patch +genirq-devres-fix-testing-return-value-of-request_any_context_irq.patch +video-mxsfb-make-sure-axi-clock-is-enabled-when-accessing-registers.patch +leds-pm-fix-hibernation-on-arm-when-gpio-led-used-with-cpu-led-trigger.patch +mtd-fix-avoid-race-condition-when-accessing-mtd-usecount.patch +mtd-dc21285-use-raw-spinlock-functions-for-nw_gpio_lock.patch +pci-propagate-the-ignore-hotplug-setting-to-parent.patch +pci-add-pci_bus_addr_t.patch +pci-pciehp-wait-for-hotplug-command-completion-where-necessary.patch +of-pci-fix-pci_address_to_pio-conversion-of-cpu-address-to-i-o-port.patch +input-pixcir_i2c_ts-fix-receive-error.patch diff --git a/queue-4.0/spi-fix-race-freeing-dummy_tx-rx-before-it-is-unmapped.patch b/queue-4.0/spi-fix-race-freeing-dummy_tx-rx-before-it-is-unmapped.patch new file mode 100644 index 00000000000..7dd7ab51c4b --- /dev/null +++ b/queue-4.0/spi-fix-race-freeing-dummy_tx-rx-before-it-is-unmapped.patch @@ -0,0 +1,62 @@ +From 8e76ef88f607174082023f50b87fe12dcdbe5db5 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Sun, 10 May 2015 07:50:45 +0000 +Subject: spi: fix race freeing dummy_tx/rx before it is unmapped +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Martin Sperl + +commit 8e76ef88f607174082023f50b87fe12dcdbe5db5 upstream. + +Fix a race (with some kernel configurations) where a queued +master->pump_messages runs and frees dummy_tx/rx before +spi_unmap_msg is running (or is finished). + +This results in the following messages: + BUG: Bad page state in process + page:db7ba030 count:0 mapcount:0 mapping: (null) index:0x0 + flags: 0x200(arch_1) + page dumped because: PAGE_FLAGS_CHECK_AT_PREP flag set + ... + +Reported-by: Noralf Trønnes +Suggested-by: Noralf Trønnes +Tested-by: Noralf Trønnes +Signed-off-by: Martin Sperl +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/spi/spi.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -1091,9 +1091,6 @@ void spi_finalize_current_message(struct + + spin_lock_irqsave(&master->queue_lock, flags); + mesg = master->cur_msg; +- master->cur_msg = NULL; +- +- queue_kthread_work(&master->kworker, &master->pump_messages); + spin_unlock_irqrestore(&master->queue_lock, flags); + + spi_unmap_msg(master, mesg); +@@ -1106,9 +1103,13 @@ void spi_finalize_current_message(struct + } + } + +- trace_spi_message_done(mesg); +- ++ spin_lock_irqsave(&master->queue_lock, flags); ++ master->cur_msg = NULL; + master->cur_msg_prepared = false; ++ queue_kthread_work(&master->kworker, &master->pump_messages); ++ spin_unlock_irqrestore(&master->queue_lock, flags); ++ ++ trace_spi_message_done(mesg); + + mesg->state = NULL; + if (mesg->complete) diff --git a/queue-4.0/spi-orion-fix-maximum-baud-rates-for-armada-370-xp.patch b/queue-4.0/spi-orion-fix-maximum-baud-rates-for-armada-370-xp.patch new file mode 100644 index 00000000000..52e69afda3d --- /dev/null +++ b/queue-4.0/spi-orion-fix-maximum-baud-rates-for-armada-370-xp.patch @@ -0,0 +1,85 @@ +From ce2f6ea1cbd41d78224f703af980a6ceeb0eb56a Mon Sep 17 00:00:00 2001 +From: Gregory CLEMENT +Date: Tue, 26 May 2015 11:44:42 +0200 +Subject: spi: orion: Fix maximum baud rates for Armada 370/XP + +From: Gregory CLEMENT + +commit ce2f6ea1cbd41d78224f703af980a6ceeb0eb56a upstream. + +The commit df59fa7f4bca "spi: orion: support armada extended baud +rates" was too optimistic for the maximum baud rate that the Armada +SoCs can support. According to the hardware datasheet the maximum +frequency supported by the Armada 370 SoC is tclk/4. But for the +Armada XP, Armada 38x and Armada 39x SoCs the limitation is 50MHz and +for the Armada 375 it is tclk/15. + +Currently the armada-370-spi compatible is only used by the Armada 370 +and the Armada XP device tree. On Armada 370, tclk cannot be higher +than 200MHz. In order to be able to handle both SoCs, we can take the +minimum of 50MHz and tclk/4. + +A proper solution is adding a compatible string for each SoC, but it +can't be done as a fix for compatibility reason (we can't modify +device tree that have been already released) and it will be part of a +separate patch. + +Fixes: df59fa7f4bca (spi: orion: support armada extended baud rates) +Reported-by: Kostya Porotchkin +Signed-off-by: Gregory CLEMENT +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/spi/spi-orion.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +--- a/drivers/spi/spi-orion.c ++++ b/drivers/spi/spi-orion.c +@@ -61,6 +61,12 @@ enum orion_spi_type { + + struct orion_spi_dev { + enum orion_spi_type typ; ++ /* ++ * min_divisor and max_hz should be exclusive, the only we can ++ * have both is for managing the armada-370-spi case with old ++ * device tree ++ */ ++ unsigned long max_hz; + unsigned int min_divisor; + unsigned int max_divisor; + u32 prescale_mask; +@@ -387,8 +393,9 @@ static const struct orion_spi_dev orion_ + + static const struct orion_spi_dev armada_spi_dev_data = { + .typ = ARMADA_SPI, +- .min_divisor = 1, ++ .min_divisor = 4, + .max_divisor = 1920, ++ .max_hz = 50000000, + .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK, + }; + +@@ -454,7 +461,21 @@ static int orion_spi_probe(struct platfo + goto out; + + tclk_hz = clk_get_rate(spi->clk); +- master->max_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->min_divisor); ++ ++ /* ++ * With old device tree, armada-370-spi could be used with ++ * Armada XP, however for this SoC the maximum frequency is ++ * 50MHz instead of tclk/4. On Armada 370, tclk cannot be ++ * higher than 200MHz. So, in order to be able to handle both ++ * SoCs, we can take the minimum of 50MHz and tclk/4. ++ */ ++ if (of_device_is_compatible(pdev->dev.of_node, ++ "marvell,armada-370-spi")) ++ master->max_speed_hz = min(devdata->max_hz, ++ DIV_ROUND_UP(tclk_hz, devdata->min_divisor)); ++ else ++ master->max_speed_hz = ++ DIV_ROUND_UP(tclk_hz, devdata->min_divisor); + master->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/queue-4.0/spi-pl022-specify-num-cs-property-as-required-in-devicetree-binding.patch b/queue-4.0/spi-pl022-specify-num-cs-property-as-required-in-devicetree-binding.patch new file mode 100644 index 00000000000..16b8a7c4058 --- /dev/null +++ b/queue-4.0/spi-pl022-specify-num-cs-property-as-required-in-devicetree-binding.patch @@ -0,0 +1,37 @@ +From ea6055c46eda1e19e02209814955e13f334bbe1b Mon Sep 17 00:00:00 2001 +From: Ezequiel Garcia +Date: Mon, 11 May 2015 12:20:18 -0300 +Subject: spi: pl022: Specify 'num-cs' property as required in devicetree binding + +From: Ezequiel Garcia + +commit ea6055c46eda1e19e02209814955e13f334bbe1b upstream. + +Since commit 39a6ac11df65 ("spi/pl022: Devicetree support w/o platform data") +the 'num-cs' parameter cannot be passed through platform data when probing +with devicetree. Instead, it's a required devicetree property. + +Fix the binding documentation so the property is properly specified. + +Fixes: 39a6ac11df65 ("spi/pl022: Devicetree support w/o platform data") +Signed-off-by: Ezequiel Garcia +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/devicetree/bindings/spi/spi_pl022.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/spi/spi_pl022.txt ++++ b/Documentation/devicetree/bindings/spi/spi_pl022.txt +@@ -4,9 +4,9 @@ Required properties: + - compatible : "arm,pl022", "arm,primecell" + - reg : Offset and length of the register set for the device + - interrupts : Should contain SPI controller interrupt ++- num-cs : total number of chipselects + + Optional properties: +-- num-cs : total number of chipselects + - cs-gpios : should specify GPIOs used for chipselects. + The gpios will be referred to as reg = in the SPI child nodes. + If unspecified, a single SPI device without a chip select can be used. diff --git a/queue-4.0/video-mxsfb-make-sure-axi-clock-is-enabled-when-accessing-registers.patch b/queue-4.0/video-mxsfb-make-sure-axi-clock-is-enabled-when-accessing-registers.patch new file mode 100644 index 00000000000..7014598ccd2 --- /dev/null +++ b/queue-4.0/video-mxsfb-make-sure-axi-clock-is-enabled-when-accessing-registers.patch @@ -0,0 +1,216 @@ +From 2fa3b4c4a78a5db3502ab9e32630ea660ff923d0 Mon Sep 17 00:00:00 2001 +From: Liu Ying +Date: Fri, 3 Apr 2015 12:51:05 +0800 +Subject: video: mxsfb: Make sure axi clock is enabled when accessing registers + +From: Liu Ying + +commit 2fa3b4c4a78a5db3502ab9e32630ea660ff923d0 upstream. + +The LCDIF engines embedded in i.MX6sl and i.MX6sx SoCs need the axi clock +as the engine's system clock. The clock should be enabled when accessing +LCDIF registers, otherwise the kernel would hang up. We should also keep +the clock enabled when the engine is being active to scan out frames from +memory. This patch makes sure the axi clock is enabled when accessing +registers so that the kernel hang up issue can be fixed. + +Reported-by: Peter Chen +Tested-by: Peter Chen +Signed-off-by: Liu Ying +Signed-off-by: Tomi Valkeinen +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/video/fbdev/mxsfb.c | 68 ++++++++++++++++++++++++++++++++++---------- + 1 file changed, 54 insertions(+), 14 deletions(-) + +--- a/drivers/video/fbdev/mxsfb.c ++++ b/drivers/video/fbdev/mxsfb.c +@@ -316,6 +316,18 @@ static int mxsfb_check_var(struct fb_var + return 0; + } + ++static inline void mxsfb_enable_axi_clk(struct mxsfb_info *host) ++{ ++ if (host->clk_axi) ++ clk_prepare_enable(host->clk_axi); ++} ++ ++static inline void mxsfb_disable_axi_clk(struct mxsfb_info *host) ++{ ++ if (host->clk_axi) ++ clk_disable_unprepare(host->clk_axi); ++} ++ + static void mxsfb_enable_controller(struct fb_info *fb_info) + { + struct mxsfb_info *host = to_imxfb_host(fb_info); +@@ -333,14 +345,13 @@ static void mxsfb_enable_controller(stru + } + } + +- if (host->clk_axi) +- clk_prepare_enable(host->clk_axi); +- + if (host->clk_disp_axi) + clk_prepare_enable(host->clk_disp_axi); + clk_prepare_enable(host->clk); + clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U); + ++ mxsfb_enable_axi_clk(host); ++ + /* if it was disabled, re-enable the mode again */ + writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET); + +@@ -380,11 +391,11 @@ static void mxsfb_disable_controller(str + reg = readl(host->base + LCDC_VDCTRL4); + writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4); + ++ mxsfb_disable_axi_clk(host); ++ + clk_disable_unprepare(host->clk); + if (host->clk_disp_axi) + clk_disable_unprepare(host->clk_disp_axi); +- if (host->clk_axi) +- clk_disable_unprepare(host->clk_axi); + + host->enabled = 0; + +@@ -421,6 +432,8 @@ static int mxsfb_set_par(struct fb_info + mxsfb_disable_controller(fb_info); + } + ++ mxsfb_enable_axi_clk(host); ++ + /* clear the FIFOs */ + writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET); + +@@ -438,6 +451,7 @@ static int mxsfb_set_par(struct fb_info + ctrl |= CTRL_SET_WORD_LENGTH(3); + switch (host->ld_intf_width) { + case STMLCDIF_8BIT: ++ mxsfb_disable_axi_clk(host); + dev_err(&host->pdev->dev, + "Unsupported LCD bus width mapping\n"); + return -EINVAL; +@@ -451,6 +465,7 @@ static int mxsfb_set_par(struct fb_info + writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1); + break; + default: ++ mxsfb_disable_axi_clk(host); + dev_err(&host->pdev->dev, "Unhandled color depth of %u\n", + fb_info->var.bits_per_pixel); + return -EINVAL; +@@ -504,6 +519,8 @@ static int mxsfb_set_par(struct fb_info + fb_info->fix.line_length * fb_info->var.yoffset, + host->base + host->devdata->next_buf); + ++ mxsfb_disable_axi_clk(host); ++ + if (reenable) + mxsfb_enable_controller(fb_info); + +@@ -582,10 +599,14 @@ static int mxsfb_pan_display(struct fb_v + + offset = fb_info->fix.line_length * var->yoffset; + ++ mxsfb_enable_axi_clk(host); ++ + /* update on next VSYNC */ + writel(fb_info->fix.smem_start + offset, + host->base + host->devdata->next_buf); + ++ mxsfb_disable_axi_clk(host); ++ + return 0; + } + +@@ -608,13 +629,17 @@ static int mxsfb_restore_mode(struct mxs + unsigned line_count; + unsigned period; + unsigned long pa, fbsize; +- int bits_per_pixel, ofs; ++ int bits_per_pixel, ofs, ret = 0; + u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; + ++ mxsfb_enable_axi_clk(host); ++ + /* Only restore the mode when the controller is running */ + ctrl = readl(host->base + LCDC_CTRL); +- if (!(ctrl & CTRL_RUN)) +- return -EINVAL; ++ if (!(ctrl & CTRL_RUN)) { ++ ret = -EINVAL; ++ goto err; ++ } + + vdctrl0 = readl(host->base + LCDC_VDCTRL0); + vdctrl2 = readl(host->base + LCDC_VDCTRL2); +@@ -635,7 +660,8 @@ static int mxsfb_restore_mode(struct mxs + break; + case 1: + default: +- return -EINVAL; ++ ret = -EINVAL; ++ goto err; + } + + fb_info->var.bits_per_pixel = bits_per_pixel; +@@ -673,10 +699,14 @@ static int mxsfb_restore_mode(struct mxs + + pa = readl(host->base + host->devdata->cur_buf); + fbsize = fb_info->fix.line_length * vmode->yres; +- if (pa < fb_info->fix.smem_start) +- return -EINVAL; +- if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) +- return -EINVAL; ++ if (pa < fb_info->fix.smem_start) { ++ ret = -EINVAL; ++ goto err; ++ } ++ if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) { ++ ret = -EINVAL; ++ goto err; ++ } + ofs = pa - fb_info->fix.smem_start; + if (ofs) { + memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize); +@@ -689,7 +719,11 @@ static int mxsfb_restore_mode(struct mxs + clk_prepare_enable(host->clk); + host->enabled = 1; + +- return 0; ++err: ++ if (ret) ++ mxsfb_disable_axi_clk(host); ++ ++ return ret; + } + + static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host, +@@ -915,7 +949,9 @@ static int mxsfb_probe(struct platform_d + } + + if (!host->enabled) { ++ mxsfb_enable_axi_clk(host); + writel(0, host->base + LCDC_CTRL); ++ mxsfb_disable_axi_clk(host); + mxsfb_set_par(fb_info); + mxsfb_enable_controller(fb_info); + } +@@ -954,11 +990,15 @@ static void mxsfb_shutdown(struct platfo + struct fb_info *fb_info = platform_get_drvdata(pdev); + struct mxsfb_info *host = to_imxfb_host(fb_info); + ++ mxsfb_enable_axi_clk(host); ++ + /* + * Force stop the LCD controller as keeping it running during reboot + * might interfere with the BootROM's boot mode pads sampling. + */ + writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR); ++ ++ mxsfb_disable_axi_clk(host); + } + + static struct platform_driver mxsfb_driver = {