summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/power.c1
-rw-r--r--drivers/bluetooth/btfm_slim.h2
-rw-r--r--drivers/bluetooth/btfm_slim_wcn3990.c31
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_snapshot.c32
-rw-r--r--drivers/gpu/drm/msm/msm_snapshot.h4
-rw-r--r--drivers/gpu/drm/msm/msm_snapshot_api.h13
-rw-r--r--drivers/hv/channel.c16
-rw-r--r--drivers/hv/connection.c8
-rw-r--r--drivers/hv/hv.c5
-rw-r--r--drivers/hv/hv_balloon.c136
-rw-r--r--drivers/input/mouse/elantech.c8
-rw-r--r--drivers/iommu/arm-smmu.c20
-rw-r--r--drivers/iommu/io-pgtable-arm.c14
-rw-r--r--drivers/iommu/io-pgtable.h2
-rw-r--r--drivers/iommu/iommu-debug.c533
-rw-r--r--drivers/iommu/iommu.c9
-rw-r--r--drivers/md/Makefile4
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c35
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h3
-rw-r--r--drivers/media/platform/msm/camera_v2/msm.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c82
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_utils_aio.c6
-rw-r--r--drivers/misc/uid_sys_stats.c9
-rw-r--r--drivers/mmc/core/core.c13
-rw-r--r--drivers/mmc/core/mmc.c43
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c1
-rw-r--r--drivers/mtd/ubi/upd.c8
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c15
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c2
-rw-r--r--drivers/power/reset/msm-poweroff.c6
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c128
-rw-r--r--drivers/power/supply/qcom/smb-lib.c27
-rw-r--r--drivers/power/supply/qcom/smb-lib.h5
-rw-r--r--drivers/power/supply/qcom/smb-reg.h10
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c334
-rw-r--r--drivers/regulator/Kconfig9
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/onsemi-ncp6335d.c775
-rw-r--r--drivers/soc/qcom/icnss.c2
-rw-r--r--drivers/soc/qcom/memory_dump_v2.c4
-rw-r--r--drivers/soc/qcom/msm_minidump.c153
-rw-r--r--drivers/soc/qcom/qbt1000.c21
-rw-r--r--drivers/staging/android/ion/ion.c71
-rw-r--r--drivers/tty/nozomi.c2
-rw-r--r--drivers/tty/serial/msm_serial.c26
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c3
-rw-r--r--drivers/usb/pd/policy_engine.c2
-rw-r--r--drivers/vfio/pci/vfio_pci.c33
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_wfd.c8
-rw-r--r--drivers/video/fbdev/msm/mdss_rotator.c20
52 files changed, 2162 insertions, 545 deletions
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index fcd4ce6f78d5..1c2b846c5776 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -200,6 +200,7 @@ static int acpi_power_get_list_state(struct list_head *list, int *state)
return -EINVAL;
/* The state of the list is 'on' IFF all resources are 'on'. */
+ cur_state = 0;
list_for_each_entry(entry, list, node) {
struct acpi_power_resource *resource = entry->resource;
acpi_handle handle = resource->device.handle;
diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h
index 5d105fba2193..e67c6964ee65 100644
--- a/drivers/bluetooth/btfm_slim.h
+++ b/drivers/bluetooth/btfm_slim.h
@@ -13,7 +13,7 @@
#define BTFM_SLIM_H
#include <linux/slimbus/slimbus.h>
-#define BTFMSLIM_DBG(fmt, arg...) pr_debug(fmt "\n", ## arg)
+#define BTFMSLIM_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
#define BTFMSLIM_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg)
#define BTFMSLIM_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg)
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index c93b29281e35..a451ff33103c 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -83,19 +83,34 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
{
int ret = 0;
uint8_t reg_val = 0;
+ uint8_t port_bit = 0;
uint16_t reg;
BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable);
if (rxport) {
+ if (enable) {
+ /* For SCO Rx, A2DP Rx */
+ reg_val = 0x1;
+ port_bit = port_num - 0x10;
+ reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(port_bit);
+ BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
+ reg_val, reg);
+ ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
+ if (ret) {
+ BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
+ ret, reg);
+ goto error;
+ }
+ }
/* Port enable */
reg = CHRK_SB_PGD_PORT_RX_CFGN(port_num - 0x10);
goto enable_disable_rxport;
}
- /* txport */
if (!enable)
goto enable_disable_txport;
- /* Multiple Channel Setting - only for FM Tx */
+ /* txport */
+ /* Multiple Channel Setting */
if (is_fm_port(port_num)) {
reg_val = (0x1 << CHRK_SB_PGD_PORT_TX1_FM) |
(0x1 << CHRK_SB_PGD_PORT_TX2_FM);
@@ -105,6 +120,18 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
goto error;
}
+ } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) {
+ /* SCO Tx */
+ reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO;
+ reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
+ BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
+ reg_val, reg);
+ ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
+ if (ret) {
+ BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
+ ret, reg);
+ goto error;
+ }
}
/* Enable Tx port hw auto recovery for underrun or overrun error */
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c b/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c
index 5a2edb0ea518..690e6f546e60 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c
@@ -733,6 +733,35 @@ static void a5xx_snapshot_indexed_registers(struct msm_gpu *gpu,
}
}
+static void a5xx_snapshot_preemption(struct msm_gpu *gpu, struct msm_snapshot
+ *snapshot)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
+ struct msm_snapshot_gpu_object header = {
+ .type = SNAPSHOT_GPU_OBJECT_GLOBAL,
+ .size = A5XX_PREEMPT_RECORD_SIZE >> 2,
+ .pt_base = 0,
+ };
+ int index;
+
+ if (gpu->nr_rings <= 1)
+ return;
+
+ for (index = 0; index < gpu->nr_rings; index++) {
+
+ header.gpuaddr = a5xx_gpu->preempt_iova[index];
+
+ if (!SNAPSHOT_HEADER(snapshot, header,
+ SNAPSHOT_SECTION_GPU_OBJECT_V2,
+ A5XX_PREEMPT_RECORD_SIZE >> 2))
+ return;
+
+ SNAPSHOT_MEMCPY(snapshot, a5xx_gpu->preempt[index],
+ A5XX_PREEMPT_RECORD_SIZE);
+ }
+}
+
int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot)
{
struct crashdump crashdump = { 0 };
@@ -787,6 +816,9 @@ int a5xx_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot)
/* CP MERCIU */
a5xx_snapshot_cp_merciu(gpu, snapshot);
+ /* Preemption records*/
+ a5xx_snapshot_preemption(gpu, snapshot);
+
crashdump_destroy(gpu, &crashdump);
snapshot->priv = NULL;
diff --git a/drivers/gpu/drm/msm/msm_snapshot.h b/drivers/gpu/drm/msm/msm_snapshot.h
index 247e1358c885..fd560b2129f1 100644
--- a/drivers/gpu/drm/msm/msm_snapshot.h
+++ b/drivers/gpu/drm/msm/msm_snapshot.h
@@ -71,8 +71,8 @@ static inline bool _snapshot_header(struct msm_snapshot *snapshot,
*/
#define SNAPSHOT_HEADER(_snapshot, _header, _id, _dwords) \
_snapshot_header((_snapshot), \
- (struct msm_snapshot_section_header *) &(header), \
- sizeof(header), (_dwords) << 2, (_id))
+ (struct msm_snapshot_section_header *) &(_header), \
+ sizeof(_header), (_dwords) << 2, (_id))
struct msm_gpu;
diff --git a/drivers/gpu/drm/msm/msm_snapshot_api.h b/drivers/gpu/drm/msm/msm_snapshot_api.h
index 9f0adb9ee784..7ad6f0498423 100644
--- a/drivers/gpu/drm/msm/msm_snapshot_api.h
+++ b/drivers/gpu/drm/msm/msm_snapshot_api.h
@@ -118,4 +118,17 @@ struct msm_snapshot_shader {
__u32 size;
} __packed;
+#define SNAPSHOT_GPU_OBJECT_SHADER 1
+#define SNAPSHOT_GPU_OBJECT_IB 2
+#define SNAPSHOT_GPU_OBJECT_GENERIC 3
+#define SNAPSHOT_GPU_OBJECT_DRAW 4
+#define SNAPSHOT_GPU_OBJECT_GLOBAL 5
+
+struct msm_snapshot_gpu_object {
+ struct msm_snapshot_section_header header;
+ __u32 type;
+ __u64 gpuaddr;
+ __u64 pt_base;
+ __u64 size;
+} __packed;
#endif
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 1ef37c727572..d037454fe7b8 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -73,7 +73,6 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
void *in, *out;
unsigned long flags;
int ret, err = 0;
- unsigned long t;
struct page *page;
spin_lock_irqsave(&newchannel->lock, flags);
@@ -183,11 +182,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
goto error1;
}
- t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ);
- if (t == 0) {
- err = -ETIMEDOUT;
- goto error1;
- }
+ wait_for_completion(&open_info->waitevent);
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&open_info->msglistentry);
@@ -375,7 +370,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
struct vmbus_channel_gpadl_header *gpadlmsg;
struct vmbus_channel_gpadl_body *gpadl_body;
struct vmbus_channel_msginfo *msginfo = NULL;
- struct vmbus_channel_msginfo *submsginfo;
+ struct vmbus_channel_msginfo *submsginfo, *tmp;
u32 msgcount;
struct list_head *curr;
u32 next_gpadl_handle;
@@ -437,6 +432,13 @@ cleanup:
list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+ if (msgcount > 1) {
+ list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist,
+ msglistentry) {
+ kfree(submsginfo);
+ }
+ }
+
kfree(msginfo);
return ret;
}
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 4fc2e8836e60..2bbc53025549 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -429,7 +429,7 @@ int vmbus_post_msg(void *buffer, size_t buflen)
union hv_connection_id conn_id;
int ret = 0;
int retries = 0;
- u32 msec = 1;
+ u32 usec = 1;
conn_id.asu32 = 0;
conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID;
@@ -462,9 +462,9 @@ int vmbus_post_msg(void *buffer, size_t buflen)
}
retries++;
- msleep(msec);
- if (msec < 2048)
- msec *= 2;
+ udelay(usec);
+ if (usec < 2048)
+ usec *= 2;
}
return ret;
}
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index ddbf7e7e0d98..8ce1f2e22912 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -305,9 +305,10 @@ void hv_cleanup(bool crash)
hypercall_msr.as_uint64 = 0;
wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
- if (!crash)
+ if (!crash) {
vfree(hv_context.tsc_page);
- hv_context.tsc_page = NULL;
+ hv_context.tsc_page = NULL;
+ }
}
#endif
}
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 43af91362be5..354da7f207b7 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -430,16 +430,27 @@ struct dm_info_msg {
* currently hot added. We hot add in multiples of 128M
* chunks; it is possible that we may not be able to bring
* online all the pages in the region. The range
- * covered_end_pfn defines the pages that can
+ * covered_start_pfn:covered_end_pfn defines the pages that can
* be brough online.
*/
struct hv_hotadd_state {
struct list_head list;
unsigned long start_pfn;
+ unsigned long covered_start_pfn;
unsigned long covered_end_pfn;
unsigned long ha_end_pfn;
unsigned long end_pfn;
+ /*
+ * A list of gaps.
+ */
+ struct list_head gap_list;
+};
+
+struct hv_hotadd_gap {
+ struct list_head list;
+ unsigned long start_pfn;
+ unsigned long end_pfn;
};
struct balloon_state {
@@ -595,18 +606,46 @@ static struct notifier_block hv_memory_nb = {
.priority = 0
};
+/* Check if the particular page is backed and can be onlined and online it. */
+static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg)
+{
+ unsigned long cur_start_pgp;
+ unsigned long cur_end_pgp;
+ struct hv_hotadd_gap *gap;
+
+ cur_start_pgp = (unsigned long)pfn_to_page(has->covered_start_pfn);
+ cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+
+ /* The page is not backed. */
+ if (((unsigned long)pg < cur_start_pgp) ||
+ ((unsigned long)pg >= cur_end_pgp))
+ return;
+
+ /* Check for gaps. */
+ list_for_each_entry(gap, &has->gap_list, list) {
+ cur_start_pgp = (unsigned long)
+ pfn_to_page(gap->start_pfn);
+ cur_end_pgp = (unsigned long)
+ pfn_to_page(gap->end_pfn);
+ if (((unsigned long)pg >= cur_start_pgp) &&
+ ((unsigned long)pg < cur_end_pgp)) {
+ return;
+ }
+ }
-static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
+ /* This frame is currently backed; online the page. */
+ __online_page_set_limits(pg);
+ __online_page_increment_counters(pg);
+ __online_page_free(pg);
+}
+
+static void hv_bring_pgs_online(struct hv_hotadd_state *has,
+ unsigned long start_pfn, unsigned long size)
{
int i;
- for (i = 0; i < size; i++) {
- struct page *pg;
- pg = pfn_to_page(start_pfn + i);
- __online_page_set_limits(pg);
- __online_page_increment_counters(pg);
- __online_page_free(pg);
- }
+ for (i = 0; i < size; i++)
+ hv_page_online_one(has, pfn_to_page(start_pfn + i));
}
static void hv_mem_hot_add(unsigned long start, unsigned long size,
@@ -682,26 +721,25 @@ static void hv_online_page(struct page *pg)
list_for_each(cur, &dm_device.ha_region_list) {
has = list_entry(cur, struct hv_hotadd_state, list);
- cur_start_pgp = (unsigned long)pfn_to_page(has->start_pfn);
- cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+ cur_start_pgp = (unsigned long)
+ pfn_to_page(has->start_pfn);
+ cur_end_pgp = (unsigned long)pfn_to_page(has->end_pfn);
- if (((unsigned long)pg >= cur_start_pgp) &&
- ((unsigned long)pg < cur_end_pgp)) {
- /*
- * This frame is currently backed; online the
- * page.
- */
- __online_page_set_limits(pg);
- __online_page_increment_counters(pg);
- __online_page_free(pg);
- }
+ /* The page belongs to a different HAS. */
+ if (((unsigned long)pg < cur_start_pgp) ||
+ ((unsigned long)pg >= cur_end_pgp))
+ continue;
+
+ hv_page_online_one(has, pg);
+ break;
}
}
-static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
+static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
{
struct list_head *cur;
struct hv_hotadd_state *has;
+ struct hv_hotadd_gap *gap;
unsigned long residual, new_inc;
if (list_empty(&dm_device.ha_region_list))
@@ -716,6 +754,24 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
*/
if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
continue;
+
+ /*
+ * If the current start pfn is not where the covered_end
+ * is, create a gap and update covered_end_pfn.
+ */
+ if (has->covered_end_pfn != start_pfn) {
+ gap = kzalloc(sizeof(struct hv_hotadd_gap), GFP_ATOMIC);
+ if (!gap)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&gap->list);
+ gap->start_pfn = has->covered_end_pfn;
+ gap->end_pfn = start_pfn;
+ list_add_tail(&gap->list, &has->gap_list);
+
+ has->covered_end_pfn = start_pfn;
+ }
+
/*
* If the current hot add-request extends beyond
* our current limit; extend it.
@@ -732,19 +788,10 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
has->end_pfn += new_inc;
}
- /*
- * If the current start pfn is not where the covered_end
- * is, update it.
- */
-
- if (has->covered_end_pfn != start_pfn)
- has->covered_end_pfn = start_pfn;
-
- return true;
-
+ return 1;
}
- return false;
+ return 0;
}
static unsigned long handle_pg_range(unsigned long pg_start,
@@ -783,6 +830,8 @@ static unsigned long handle_pg_range(unsigned long pg_start,
if (pgs_ol > pfn_cnt)
pgs_ol = pfn_cnt;
+ has->covered_end_pfn += pgs_ol;
+ pfn_cnt -= pgs_ol;
/*
* Check if the corresponding memory block is already
* online by checking its last previously backed page.
@@ -791,10 +840,8 @@ static unsigned long handle_pg_range(unsigned long pg_start,
*/
if (start_pfn > has->start_pfn &&
!PageReserved(pfn_to_page(start_pfn - 1)))
- hv_bring_pgs_online(start_pfn, pgs_ol);
+ hv_bring_pgs_online(has, start_pfn, pgs_ol);
- has->covered_end_pfn += pgs_ol;
- pfn_cnt -= pgs_ol;
}
if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) {
@@ -832,13 +879,19 @@ static unsigned long process_hot_add(unsigned long pg_start,
unsigned long rg_size)
{
struct hv_hotadd_state *ha_region = NULL;
+ int covered;
if (pfn_cnt == 0)
return 0;
- if (!dm_device.host_specified_ha_region)
- if (pfn_covered(pg_start, pfn_cnt))
+ if (!dm_device.host_specified_ha_region) {
+ covered = pfn_covered(pg_start, pfn_cnt);
+ if (covered < 0)
+ return 0;
+
+ if (covered)
goto do_pg_range;
+ }
/*
* If the host has specified a hot-add range; deal with it first.
@@ -850,10 +903,12 @@ static unsigned long process_hot_add(unsigned long pg_start,
return 0;
INIT_LIST_HEAD(&ha_region->list);
+ INIT_LIST_HEAD(&ha_region->gap_list);
list_add_tail(&ha_region->list, &dm_device.ha_region_list);
ha_region->start_pfn = rg_start;
ha_region->ha_end_pfn = rg_start;
+ ha_region->covered_start_pfn = pg_start;
ha_region->covered_end_pfn = pg_start;
ha_region->end_pfn = rg_start + rg_size;
}
@@ -1581,6 +1636,7 @@ static int balloon_remove(struct hv_device *dev)
struct hv_dynmem_device *dm = hv_get_drvdata(dev);
struct list_head *cur, *tmp;
struct hv_hotadd_state *has;
+ struct hv_hotadd_gap *gap, *tmp_gap;
if (dm->num_pages_ballooned != 0)
pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned);
@@ -1597,6 +1653,10 @@ static int balloon_remove(struct hv_device *dev)
#endif
list_for_each_safe(cur, tmp, &dm->ha_region_list) {
has = list_entry(cur, struct hv_hotadd_state, list);
+ list_for_each_entry_safe(gap, tmp_gap, &has->gap_list, list) {
+ list_del(&gap->list);
+ kfree(gap);
+ }
list_del(&has->list);
kfree(has);
}
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 43482ae1e049..1a2b2620421e 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1122,6 +1122,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
* Asus UX32VD 0x361f02 00, 15, 0e clickpad
* Avatar AVIU-145A2 0x361f00 ? clickpad
* Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons
* Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
* Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
* Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
@@ -1528,6 +1529,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
},
},
{
+ /* Fujitsu LIFEBOOK E547 does not work with crc_enabled == 0 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E547"),
+ },
+ },
+ {
/* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 7f39ea93e110..dc44b40a85f3 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -522,6 +522,8 @@ static bool arm_smmu_is_slave_side_secure(struct arm_smmu_domain *smmu_domain);
static bool arm_smmu_has_secure_vmid(struct arm_smmu_domain *smmu_domain);
static bool arm_smmu_is_iova_coherent(struct iommu_domain *domain,
dma_addr_t iova);
+static uint64_t arm_smmu_iova_to_pte(struct iommu_domain *domain,
+ dma_addr_t iova);
static int arm_smmu_enable_s1_translations(struct arm_smmu_domain *smmu_domain);
@@ -2536,6 +2538,23 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
return ret;
}
+static uint64_t arm_smmu_iova_to_pte(struct iommu_domain *domain,
+ dma_addr_t iova)
+{
+ uint64_t ret;
+ unsigned long flags;
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
+
+ if (!ops)
+ return 0;
+
+ flags = arm_smmu_pgtbl_lock(smmu_domain);
+ ret = ops->iova_to_pte(ops, iova);
+ arm_smmu_pgtbl_unlock(smmu_domain, flags);
+ return ret;
+}
+
static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova,
struct scatterlist *sg, unsigned int nents, int prot)
{
@@ -3437,6 +3456,7 @@ static struct iommu_ops arm_smmu_ops = {
.enable_config_clocks = arm_smmu_enable_config_clocks,
.disable_config_clocks = arm_smmu_disable_config_clocks,
.is_iova_coherent = arm_smmu_is_iova_coherent,
+ .iova_to_pte = arm_smmu_iova_to_pte,
};
static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 6a8a9492c771..2d2583c78bdb 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -903,6 +903,19 @@ found_translation:
return 0;
}
+static uint64_t arm_lpae_iova_get_pte(struct io_pgtable_ops *ops,
+ unsigned long iova)
+{
+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+ arm_lpae_iopte pte;
+ int lvl;
+
+ if (!arm_lpae_iova_to_pte(data, iova, &lvl, &pte))
+ return pte;
+
+ return 0;
+}
+
static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
unsigned long iova)
{
@@ -1033,6 +1046,7 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg)
.unmap = arm_lpae_unmap,
.iova_to_phys = arm_lpae_iova_to_phys,
.is_iova_coherent = arm_lpae_is_iova_coherent,
+ .iova_to_pte = arm_lpae_iova_get_pte,
};
return data;
diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h
index e6939c2212d4..2cf213514221 100644
--- a/drivers/iommu/io-pgtable.h
+++ b/drivers/iommu/io-pgtable.h
@@ -124,6 +124,8 @@ struct io_pgtable_ops {
unsigned long iova);
bool (*is_iova_coherent)(struct io_pgtable_ops *ops,
unsigned long iova);
+ uint64_t (*iova_to_pte)(struct io_pgtable_ops *ops,
+ unsigned long iova);
};
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index 28a817aba3fc..776e06facc11 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -470,6 +470,7 @@ static inline void iommu_debug_destroy_tracking(void) { }
static LIST_HEAD(iommu_debug_devices);
static struct dentry *debugfs_tests_dir;
static u32 iters_per_op = 1;
+static void *virt_addr;
struct iommu_debug_device {
struct device *dev;
@@ -1537,6 +1538,68 @@ out_domain_free:
return -EIO;
}
+static ssize_t __iommu_debug_dma_attach_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ struct iommu_debug_device *ddev = file->private_data;
+ struct device *dev = ddev->dev;
+ struct dma_iommu_mapping *dma_mapping;
+ ssize_t retval = -EINVAL;
+ int val;
+
+ if (kstrtoint_from_user(ubuf, count, 0, &val)) {
+ pr_err("Invalid format. Expected a hex or decimal integer");
+ retval = -EFAULT;
+ goto out;
+ }
+
+ if (val) {
+ if (dev->archdata.mapping)
+ if (dev->archdata.mapping->domain) {
+ pr_err("Already attached.\n");
+ retval = -EINVAL;
+ goto out;
+ }
+ if (WARN(dev->archdata.iommu,
+ "Attachment tracking out of sync with device\n")) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ dma_mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
+ (SZ_1G * 4ULL));
+
+ if (!dma_mapping)
+ goto out;
+
+ if (arm_iommu_attach_device(dev, dma_mapping))
+ goto out_release_mapping;
+ pr_err("Attached\n");
+ } else {
+ if (!dev->archdata.mapping) {
+ pr_err("No mapping. Did you already attach?\n");
+ retval = -EINVAL;
+ goto out;
+ }
+ if (!dev->archdata.mapping->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ retval = -EINVAL;
+ goto out;
+ }
+ arm_iommu_detach_device(dev);
+ arm_iommu_release_mapping(dev->archdata.mapping);
+ pr_err("Detached\n");
+ }
+ retval = count;
+ return retval;
+
+out_release_mapping:
+ arm_iommu_release_mapping(dma_mapping);
+out:
+ return retval;
+}
+
static ssize_t __iommu_debug_attach_write(struct file *file,
const char __user *ubuf,
size_t count, loff_t *offset,
@@ -1585,6 +1648,79 @@ out:
return retval;
}
+static ssize_t iommu_debug_dma_attach_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ return __iommu_debug_dma_attach_write(file, ubuf, count, offset);
+
+}
+
+static ssize_t iommu_debug_dma_attach_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ struct iommu_debug_device *ddev = file->private_data;
+ struct device *dev = ddev->dev;
+ char c[2];
+
+ if (*offset)
+ return 0;
+
+ if (!dev->archdata.mapping)
+ c[0] = '0';
+ else
+ c[0] = dev->archdata.mapping->domain ? '1' : '0';
+
+ c[1] = '\n';
+ if (copy_to_user(ubuf, &c, 2)) {
+ pr_err("copy_to_user failed\n");
+ return -EFAULT;
+ }
+ *offset = 1; /* non-zero means we're done */
+
+ return 2;
+}
+
+static const struct file_operations iommu_debug_dma_attach_fops = {
+ .open = simple_open,
+ .write = iommu_debug_dma_attach_write,
+ .read = iommu_debug_dma_attach_read,
+};
+
+static ssize_t iommu_debug_virt_addr_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ char buf[100];
+ ssize_t retval;
+ size_t buflen;
+
+ if (*offset)
+ return 0;
+
+ memset(buf, 0, 100);
+
+ if (!virt_addr)
+ strlcpy(buf, "FAIL\n", 100);
+ else
+ snprintf(buf, 100, "0x%pK\n", virt_addr);
+
+ buflen = strlen(buf);
+ if (copy_to_user(ubuf, buf, buflen)) {
+ pr_err("Couldn't copy_to_user\n");
+ retval = -EFAULT;
+ } else {
+ *offset = 1; /* non-zero means we're done */
+ retval = buflen;
+ }
+
+ return retval;
+}
+
+static const struct file_operations iommu_debug_virt_addr_fops = {
+ .open = simple_open,
+ .read = iommu_debug_virt_addr_read,
+};
+
static ssize_t iommu_debug_attach_write(struct file *file,
const char __user *ubuf,
size_t count, loff_t *offset)
@@ -1635,6 +1771,75 @@ static const struct file_operations iommu_debug_secure_attach_fops = {
.read = iommu_debug_attach_read,
};
+static ssize_t iommu_debug_pte_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ struct iommu_debug_device *ddev = file->private_data;
+ dma_addr_t iova;
+
+ if (kstrtox_from_user(ubuf, count, 0, &iova)) {
+ pr_err("Invalid format for iova\n");
+ ddev->iova = 0;
+ return -EINVAL;
+ }
+
+ ddev->iova = iova;
+ pr_err("Saved iova=%pa for future PTE commands\n", &iova);
+ return count;
+}
+
+
+static ssize_t iommu_debug_pte_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ struct iommu_debug_device *ddev = file->private_data;
+ struct device *dev = ddev->dev;
+ uint64_t pte;
+ char buf[100];
+ ssize_t retval;
+ size_t buflen;
+
+ if (!dev->archdata.mapping) {
+ pr_err("No mapping. Did you already attach?\n");
+ return -EINVAL;
+ }
+ if (!dev->archdata.mapping->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ return -EINVAL;
+ }
+
+ if (*offset)
+ return 0;
+
+ memset(buf, 0, 100);
+
+ pte = iommu_iova_to_pte(dev->archdata.mapping->domain,
+ ddev->iova);
+
+ if (!pte)
+ strlcpy(buf, "FAIL\n", 100);
+ else
+ snprintf(buf, 100, "pte=%016llx\n", pte);
+
+ buflen = strlen(buf);
+ if (copy_to_user(ubuf, buf, buflen)) {
+ pr_err("Couldn't copy_to_user\n");
+ retval = -EFAULT;
+ } else {
+ *offset = 1; /* non-zero means we're done */
+ retval = buflen;
+ }
+
+ return retval;
+}
+
+static const struct file_operations iommu_debug_pte_fops = {
+ .open = simple_open,
+ .write = iommu_debug_pte_write,
+ .read = iommu_debug_pte_read,
+};
+
static ssize_t iommu_debug_atos_write(struct file *file,
const char __user *ubuf,
size_t count, loff_t *offset)
@@ -1700,6 +1905,55 @@ static const struct file_operations iommu_debug_atos_fops = {
.read = iommu_debug_atos_read,
};
+static ssize_t iommu_debug_dma_atos_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ struct iommu_debug_device *ddev = file->private_data;
+ struct device *dev = ddev->dev;
+ phys_addr_t phys;
+ char buf[100];
+ ssize_t retval;
+ size_t buflen;
+
+ if (!dev->archdata.mapping) {
+ pr_err("No mapping. Did you already attach?\n");
+ return -EINVAL;
+ }
+ if (!dev->archdata.mapping->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ return -EINVAL;
+ }
+
+ if (*offset)
+ return 0;
+
+ memset(buf, 0, 100);
+
+ phys = iommu_iova_to_phys_hard(dev->archdata.mapping->domain,
+ ddev->iova);
+ if (!phys)
+ strlcpy(buf, "FAIL\n", 100);
+ else
+ snprintf(buf, 100, "%pa\n", &phys);
+
+ buflen = strlen(buf);
+ if (copy_to_user(ubuf, buf, buflen)) {
+ pr_err("Couldn't copy_to_user\n");
+ retval = -EFAULT;
+ } else {
+ *offset = 1; /* non-zero means we're done */
+ retval = buflen;
+ }
+
+ return retval;
+}
+
+static const struct file_operations iommu_debug_dma_atos_fops = {
+ .open = simple_open,
+ .write = iommu_debug_atos_write,
+ .read = iommu_debug_dma_atos_read,
+};
+
static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *offset)
{
@@ -1780,6 +2034,152 @@ static const struct file_operations iommu_debug_map_fops = {
.write = iommu_debug_map_write,
};
+static ssize_t iommu_debug_dma_map_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *offset)
+{
+ ssize_t retval = -EINVAL;
+ int ret;
+ char *comma1, *comma2;
+ char buf[100];
+ unsigned long addr;
+ void *v_addr;
+ dma_addr_t iova;
+ size_t size;
+ unsigned int attr;
+ struct dma_attrs coherent_attr;
+ struct dma_attrs *dma_attrs = &coherent_attr;
+ struct iommu_debug_device *ddev = file->private_data;
+ struct device *dev = ddev->dev;
+
+ init_dma_attrs(dma_attrs);
+
+ if (count >= 100) {
+ pr_err("Value too large\n");
+ return -EINVAL;
+ }
+
+ if (!dev->archdata.mapping) {
+ pr_err("No mapping. Did you already attach?\n");
+ retval = -EINVAL;
+ goto out;
+ }
+ if (!dev->archdata.mapping->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ retval = -EINVAL;
+ goto out;
+ }
+
+ memset(buf, 0, 100);
+
+ if (copy_from_user(buf, ubuf, count)) {
+ pr_err("Couldn't copy from user\n");
+ retval = -EFAULT;
+ goto out;
+ }
+
+ comma1 = strnchr(buf, count, ',');
+ if (!comma1)
+ goto invalid_format;
+
+ comma2 = strnchr(comma1 + 1, count, ',');
+ if (!comma2)
+ goto invalid_format;
+
+ *comma1 = *comma2 = '\0';
+
+ if (kstrtoul(buf, 0, &addr))
+ goto invalid_format;
+ v_addr = (void *)addr;
+
+ if (kstrtosize_t(comma1 + 1, 0, &size))
+ goto invalid_format;
+
+ if (kstrtouint(comma2 + 1, 0, &attr))
+ goto invalid_format;
+
+ if (v_addr < virt_addr || v_addr > (virt_addr + SZ_1M - 1))
+ goto invalid_addr;
+
+ if (attr == 0)
+ dma_attrs = NULL;
+ else if (attr == 1)
+ dma_set_attr(DMA_ATTR_FORCE_COHERENT, dma_attrs);
+ else if (attr == 2)
+ dma_set_attr(DMA_ATTR_FORCE_NON_COHERENT, dma_attrs);
+ else
+ goto invalid_format;
+
+ iova = dma_map_single_attrs(dev, v_addr, size,
+ DMA_TO_DEVICE, dma_attrs);
+
+ if (dma_mapping_error(dev, iova)) {
+ pr_err("Failed to perform dma_map_single\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ retval = count;
+ pr_err("Mapped 0x%p to %pa (len=0x%zx)\n",
+ v_addr, &iova, size);
+ ddev->iova = iova;
+ pr_err("Saved iova=%pa for future PTE commands\n", &iova);
+out:
+ return retval;
+
+invalid_format:
+ pr_err("Invalid format. Expected: addr,len,dma attr where 'dma attr' is\n0: normal mapping\n1: force coherent\n2: force non-cohernet\n");
+ return retval;
+
+invalid_addr:
+ pr_err("Invalid addr given! Address should be within 1MB size from start addr returned by doing 'cat virt_addr'.\n");
+ return retval;
+}
+
+static ssize_t iommu_debug_dma_map_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ struct iommu_debug_device *ddev = file->private_data;
+ struct device *dev = ddev->dev;
+ char buf[100];
+ ssize_t retval;
+ size_t buflen;
+ dma_addr_t iova;
+
+ if (!dev->archdata.mapping) {
+ pr_err("No mapping. Did you already attach?\n");
+ return -EINVAL;
+ }
+ if (!dev->archdata.mapping->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ return -EINVAL;
+ }
+
+ if (*offset)
+ return 0;
+
+ memset(buf, 0, 100);
+
+ iova = ddev->iova;
+ snprintf(buf, 100, "%pa\n", &iova);
+
+ buflen = strlen(buf);
+ if (copy_to_user(ubuf, buf, buflen)) {
+ pr_err("Couldn't copy_to_user\n");
+ retval = -EFAULT;
+ } else {
+ *offset = 1; /* non-zero means we're done */
+ retval = buflen;
+ }
+
+ return retval;
+}
+
+static const struct file_operations iommu_debug_dma_map_fops = {
+ .open = simple_open,
+ .write = iommu_debug_dma_map_write,
+ .read = iommu_debug_dma_map_read,
+};
+
static ssize_t iommu_debug_unmap_write(struct file *file,
const char __user *ubuf,
size_t count, loff_t *offset)
@@ -1845,6 +2245,92 @@ static const struct file_operations iommu_debug_unmap_fops = {
.write = iommu_debug_unmap_write,
};
+static ssize_t iommu_debug_dma_unmap_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *offset)
+{
+ ssize_t retval = 0;
+ char *comma1, *comma2;
+ char buf[100];
+ size_t size;
+ unsigned int attr;
+ dma_addr_t iova;
+ struct dma_attrs coherent_attr;
+ struct dma_attrs *dma_attrs = &coherent_attr;
+ struct iommu_debug_device *ddev = file->private_data;
+ struct device *dev = ddev->dev;
+
+ init_dma_attrs(dma_attrs);
+
+ if (count >= 100) {
+ pr_err("Value too large\n");
+ return -EINVAL;
+ }
+
+ if (!dev->archdata.mapping) {
+ pr_err("No mapping. Did you already attach?\n");
+ retval = -EINVAL;
+ goto out;
+ }
+ if (!dev->archdata.mapping->domain) {
+ pr_err("No domain. Did you already attach?\n");
+ retval = -EINVAL;
+ goto out;
+ }
+
+ memset(buf, 0, 100);
+
+ if (copy_from_user(buf, ubuf, count)) {
+ pr_err("Couldn't copy from user\n");
+ retval = -EFAULT;
+ goto out;
+ }
+
+ comma1 = strnchr(buf, count, ',');
+ if (!comma1)
+ goto invalid_format;
+
+ comma2 = strnchr(comma1 + 1, count, ',');
+ if (!comma2)
+ goto invalid_format;
+
+ *comma1 = *comma2 = '\0';
+
+ if (kstrtoux(buf, 0, &iova))
+ goto invalid_format;
+
+ if (kstrtosize_t(comma1 + 1, 0, &size))
+ goto invalid_format;
+
+ if (kstrtouint(comma2 + 1, 0, &attr))
+ goto invalid_format;
+
+ if (attr == 0)
+ dma_attrs = NULL;
+ else if (attr == 1)
+ dma_set_attr(DMA_ATTR_FORCE_COHERENT, dma_attrs);
+ else if (attr == 2)
+ dma_set_attr(DMA_ATTR_FORCE_NON_COHERENT, dma_attrs);
+ else
+ goto invalid_format;
+
+ dma_unmap_single_attrs(dev, iova, size, DMA_TO_DEVICE, dma_attrs);
+
+ retval = count;
+ pr_err("Unmapped %pa (len=0x%zx)\n", &iova, size);
+out:
+ return retval;
+
+invalid_format:
+ pr_err("Invalid format. Expected: iova,len, dma attr\n");
+ return retval;
+}
+
+static const struct file_operations iommu_debug_dma_unmap_fops = {
+ .open = simple_open,
+ .write = iommu_debug_dma_unmap_write,
+};
+
static ssize_t iommu_debug_config_clocks_write(struct file *file,
const char __user *ubuf,
size_t count, loff_t *offset)
@@ -1923,6 +2409,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
goto err_rmdir;
}
+ if (!debugfs_create_file("virt_addr", S_IRUSR, dir, ddev,
+ &iommu_debug_virt_addr_fops)) {
+ pr_err("Couldn't create iommu/devices/%s/virt_addr debugfs file\n",
+ name);
+ goto err_rmdir;
+ }
+
if (!debugfs_create_file("profiling", S_IRUSR, dir, ddev,
&iommu_debug_profiling_fops)) {
pr_err("Couldn't create iommu/devices/%s/profiling debugfs file\n",
@@ -1965,6 +2458,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
goto err_rmdir;
}
+ if (!debugfs_create_file("dma_attach", S_IRUSR, dir, ddev,
+ &iommu_debug_dma_attach_fops)) {
+ pr_err("Couldn't create iommu/devices/%s/dma_attach debugfs file\n",
+ name);
+ goto err_rmdir;
+ }
+
if (!debugfs_create_file("attach", S_IRUSR, dir, ddev,
&iommu_debug_attach_fops)) {
pr_err("Couldn't create iommu/devices/%s/attach debugfs file\n",
@@ -1986,6 +2486,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
goto err_rmdir;
}
+ if (!debugfs_create_file("dma_atos", S_IWUSR, dir, ddev,
+ &iommu_debug_dma_atos_fops)) {
+ pr_err("Couldn't create iommu/devices/%s/dma_atos debugfs file\n",
+ name);
+ goto err_rmdir;
+ }
+
if (!debugfs_create_file("map", S_IWUSR, dir, ddev,
&iommu_debug_map_fops)) {
pr_err("Couldn't create iommu/devices/%s/map debugfs file\n",
@@ -1993,6 +2500,13 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
goto err_rmdir;
}
+ if (!debugfs_create_file("dma_map", S_IWUSR, dir, ddev,
+ &iommu_debug_dma_map_fops)) {
+ pr_err("Couldn't create iommu/devices/%s/dma_map debugfs file\n",
+ name);
+ goto err_rmdir;
+ }
+
if (!debugfs_create_file("unmap", S_IWUSR, dir, ddev,
&iommu_debug_unmap_fops)) {
pr_err("Couldn't create iommu/devices/%s/unmap debugfs file\n",
@@ -2000,6 +2514,20 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
goto err_rmdir;
}
+ if (!debugfs_create_file("dma_unmap", S_IWUSR, dir, ddev,
+ &iommu_debug_dma_unmap_fops)) {
+ pr_err("Couldn't create iommu/devices/%s/dma_unmap debugfs file\n",
+ name);
+ goto err_rmdir;
+ }
+
+ if (!debugfs_create_file("pte", S_IWUSR, dir, ddev,
+ &iommu_debug_pte_fops)) {
+ pr_err("Couldn't create iommu/devices/%s/pte debugfs file\n",
+ name);
+ goto err_rmdir;
+ }
+
if (!debugfs_create_file("config_clocks", S_IWUSR, dir, ddev,
&iommu_debug_config_clocks_fops)) {
pr_err("Couldn't create iommu/devices/%s/config_clocks debugfs file\n",
@@ -2054,6 +2582,11 @@ static int iommu_debug_init_tests(void)
return -ENODEV;
}
+ virt_addr = kzalloc(SZ_1M, GFP_KERNEL);
+
+ if (!virt_addr)
+ return -ENOMEM;
+
return iommu_debug_populate_devices();
}
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index a77a45088b9d..b831796b5b7d 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1336,6 +1336,15 @@ phys_addr_t iommu_iova_to_phys_hard(struct iommu_domain *domain,
return domain->ops->iova_to_phys_hard(domain, iova);
}
+uint64_t iommu_iova_to_pte(struct iommu_domain *domain,
+ dma_addr_t iova)
+{
+ if (unlikely(domain->ops->iova_to_pte == NULL))
+ return 0;
+
+ return domain->ops->iova_to_pte(domain, iova);
+}
+
bool iommu_is_iova_coherent(struct iommu_domain *domain, dma_addr_t iova)
{
if (unlikely(domain->ops->is_iova_coherent == NULL))
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index eef9097c60b3..41ba86576d04 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -71,10 +71,6 @@ ifeq ($(CONFIG_DM_VERITY_FEC),y)
dm-verity-objs += dm-verity-fec.o
endif
-ifeq ($(CONFIG_DM_ANDROID_VERITY),y)
-dm-verity-objs += dm-android-verity.o
-endif
-
ifeq ($(CONFIG_DM_VERITY_AVB),y)
dm-verity-objs += dm-verity-avb.o
endif
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index caf6639f5151..24e3223a79d0 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -67,6 +67,10 @@ static int pix_overflow_error_count[VFE_MAX] = { 0 };
#define CDBG(fmt, args...)
#endif
+/* Backward interface compatibility for 3D THRESHOLD calculation */
+#define ISPIF_USE_DEFAULT_THRESHOLD (0)
+#define ISPIF_CALCULATE_THRESHOLD (1)
+
static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable);
static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd,
@@ -452,7 +456,7 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif)
/* This is set when device is 8974 */
ispif->clk_idx = 1;
}
-
+ memset(ispif->stereo_configured, 0, sizeof(ispif->stereo_configured));
atomic_set(&ispif->reset_trig[VFE0], 1);
/* initiate reset of ISPIF */
msm_camera_io_w(ISPIF_RST_CMD_MASK,
@@ -1009,21 +1013,29 @@ static int msm_ispif_config(struct ispif_device *ispif,
}
static void msm_ispif_config_stereo(struct ispif_device *ispif,
- struct msm_ispif_param_data_ext *params) {
+ struct msm_ispif_param_data_ext *params, int use_line_width) {
int i;
enum msm_ispif_vfe_intf vfe_intf;
+ uint32_t stereo_3d_threshold = STEREO_DEFAULT_3D_THRESHOLD;
for (i = 0; i < params->num; i++) {
+ vfe_intf = params->entries[i].vfe_intf;
if (params->entries[i].intftype == PIX0 &&
- params->stereo_enable &&
- params->right_entries[i].csid < CSID_MAX) {
- vfe_intf = params->entries[i].vfe_intf;
+ params->stereo_enable &&
+ params->right_entries[i].csid < CSID_MAX &&
+ !ispif->stereo_configured[vfe_intf]) {
msm_camera_io_w_mb(0x3,
ispif->base + ISPIF_VFE_m_OUTPUT_SEL(vfe_intf));
- msm_camera_io_w_mb(STEREO_DEFAULT_3D_THRESHOLD,
+ if (use_line_width &&
+ (params->line_width[vfe_intf] > 0))
+ stereo_3d_threshold =
+ (params->line_width[vfe_intf] +
+ 2 * 6 - 1) / (2 * 6);
+ msm_camera_io_w_mb(stereo_3d_threshold,
ispif->base +
ISPIF_VFE_m_3D_THRESHOLD(vfe_intf));
+ ispif->stereo_configured[vfe_intf] = 1;
}
}
}
@@ -1132,6 +1144,8 @@ static int msm_ispif_stop_immediately(struct ispif_device *ispif,
msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
cid_mask, params->entries[i].vfe_intf, 0);
if (params->stereo_enable) {
+ ispif->stereo_configured[
+ params->entries[i].vfe_intf] = 0;
cid_mask = msm_ispif_get_right_cids_mask_from_cfg(
&params->right_entries[i],
params->entries[i].num_cids);
@@ -1162,7 +1176,8 @@ static int msm_ispif_start_frame_boundary(struct ispif_device *ispif,
rc = -EINVAL;
return rc;
}
- msm_ispif_config_stereo(ispif, params);
+
+ msm_ispif_config_stereo(ispif, params, ISPIF_USE_DEFAULT_THRESHOLD);
msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
return rc;
@@ -1392,6 +1407,8 @@ static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif,
if (rc < 0)
goto end;
if (cid_right_mask) {
+ ispif->stereo_configured[
+ params->entries[i].vfe_intf] = 0;
intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1);
rc = readl_poll_timeout(ispif->base + intf_addr,
stop_flag,
@@ -1807,6 +1824,10 @@ static long msm_ispif_dispatch_cmd(enum ispif_cfg_type_t cmd,
rc = msm_ispif_config2(ispif, params);
msm_ispif_io_dump_reg(ispif);
break;
+ case ISPIF_CFG_STEREO:
+ msm_ispif_config_stereo(ispif, params,
+ ISPIF_CALCULATE_THRESHOLD);
+ break;
default:
pr_err("%s: invalid cfg_type\n", __func__);
rc = -EINVAL;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
index 61e8f1dd7aff..3e6680c63ee5 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -77,5 +77,6 @@ struct ispif_device {
int ispif_vdd_count;
struct regulator *vfe_vdd[ISPIF_VFE_VDD_INFO_MAX];
int vfe_vdd_count;
+ int stereo_configured[VFE_MAX];
};
#endif
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 8596366a70f0..f95cc37f5c2c 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -1015,11 +1015,9 @@ static int msm_open(struct file *filep)
BUG_ON(!pvdev);
/* !!! only ONE open is allowed !!! */
- if (atomic_read(&pvdev->opened))
+ if (atomic_cmpxchg(&pvdev->opened, 0, 1))
return -EBUSY;
- atomic_set(&pvdev->opened, 1);
-
spin_lock_irqsave(&msm_pid_lock, flags);
msm_pid = get_pid(task_pid(current));
spin_unlock_irqrestore(&msm_pid_lock, flags);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8402e31364b9..b7feb126f707 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -2542,9 +2542,29 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev,
return -EINVAL;
}
- if (stripe_base == UINT_MAX || new_frame->num_strips >
- (UINT_MAX - 1 - stripe_base) / stripe_size) {
- pr_err("Invalid frame message,num_strips %d is large\n",
+ /* Stripe index starts at zero */
+ if ((!new_frame->num_strips) ||
+ (new_frame->first_stripe_index >= new_frame->num_strips) ||
+ (new_frame->last_stripe_index >= new_frame->num_strips) ||
+ (new_frame->first_stripe_index >
+ new_frame->last_stripe_index)) {
+ pr_err("Invalid frame message, #stripes=%d, stripe indices=[%d,%d]\n",
+ new_frame->num_strips,
+ new_frame->first_stripe_index,
+ new_frame->last_stripe_index);
+ return -EINVAL;
+ }
+
+ if (!stripe_size) {
+ pr_err("Invalid frame message, invalid stripe_size (%d)!\n",
+ stripe_size);
+ return -EINVAL;
+ }
+
+ if ((stripe_base == UINT_MAX) ||
+ (new_frame->num_strips >
+ (UINT_MAX - 1 - stripe_base) / stripe_size)) {
+ pr_err("Invalid frame message, num_strips %d is large\n",
new_frame->num_strips);
return -EINVAL;
}
@@ -2785,13 +2805,14 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev,
struct msm_cpp_frame_info_t *frame = NULL;
struct msm_cpp_frame_info_t k_frame_info;
int32_t rc = 0;
- int32_t i = 0;
- int32_t num_buff = sizeof(k_frame_info.output_buffer_info)/
+ uint32_t i = 0;
+ uint32_t num_buff = sizeof(k_frame_info.output_buffer_info) /
sizeof(struct msm_cpp_buffer_info_t);
+
if (copy_from_user(&k_frame_info,
(void __user *)ioctl_ptr->ioctl_ptr,
sizeof(k_frame_info)))
- return -EFAULT;
+ return -EFAULT;
frame = msm_cpp_get_frame(ioctl_ptr);
if (!frame) {
@@ -2953,8 +2974,9 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg,
}
*ioctl_ptr = arg;
- if ((*ioctl_ptr == NULL) ||
- ((*ioctl_ptr)->ioctl_ptr == NULL)) {
+ if (((*ioctl_ptr) == NULL) ||
+ ((*ioctl_ptr)->ioctl_ptr == NULL) ||
+ ((*ioctl_ptr)->len == 0)) {
pr_err("Error invalid ioctl argument cmd %u", cmd);
return -EINVAL;
}
@@ -3503,13 +3525,18 @@ STREAM_BUFF_END:
if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) {
struct msm_camera_smmu_attach_type cpp_attach_info;
+ if (ioctl_ptr->len !=
+ sizeof(struct msm_camera_smmu_attach_type)) {
+ rc = -EINVAL;
+ break;
+ }
+
memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info,
ioctl_ptr);
if (rc < 0) {
pr_err("CPP_IOMMU_ATTACH copy from user fail");
- ERR_COPY_FROM_USER();
- return -EINVAL;
+ break;
}
cpp_dev->security_mode = cpp_attach_info.attach;
@@ -3538,16 +3565,20 @@ STREAM_BUFF_END:
case VIDIOC_MSM_CPP_IOMMU_DETACH: {
if ((cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) &&
(cpp_dev->stream_cnt == 0)) {
-
struct msm_camera_smmu_attach_type cpp_attach_info;
+ if (ioctl_ptr->len !=
+ sizeof(struct msm_camera_smmu_attach_type)) {
+ rc = -EINVAL;
+ break;
+ }
+
memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info,
ioctl_ptr);
if (rc < 0) {
pr_err("CPP_IOMMU_DETTACH copy from user fail");
- ERR_COPY_FROM_USER();
- return -EINVAL;
+ break;
}
cpp_dev->security_mode = cpp_attach_info.attach;
@@ -3568,6 +3599,7 @@ STREAM_BUFF_END:
} else {
pr_err("%s:%d IOMMMU attach triggered in invalid state\n",
__func__, __LINE__);
+ rc = -EINVAL;
}
break;
}
@@ -3883,6 +3915,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
struct msm_cpp_stream_buff_info_t k_cpp_buff_info;
struct msm_cpp_frame_info32_t k32_frame_info;
struct msm_cpp_frame_info_t k64_frame_info;
+ struct msm_camera_smmu_attach_type kb_cpp_smmu_attach_info;
uint32_t identity_k = 0;
bool is_copytouser_req = true;
void __user *up = (void __user *)arg;
@@ -4187,11 +4220,23 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
break;
}
case VIDIOC_MSM_CPP_IOMMU_ATTACH32:
- cmd = VIDIOC_MSM_CPP_IOMMU_ATTACH;
- break;
case VIDIOC_MSM_CPP_IOMMU_DETACH32:
- cmd = VIDIOC_MSM_CPP_IOMMU_DETACH;
+ {
+ if ((kp_ioctl.len != sizeof(struct msm_camera_smmu_attach_type))
+ || (copy_from_user(&kb_cpp_smmu_attach_info,
+ (void __user *)kp_ioctl.ioctl_ptr,
+ sizeof(kb_cpp_smmu_attach_info)))) {
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+
+ kp_ioctl.ioctl_ptr = (void *)&kb_cpp_smmu_attach_info;
+ is_copytouser_req = false;
+ cmd = (cmd == VIDIOC_MSM_CPP_IOMMU_ATTACH32) ?
+ VIDIOC_MSM_CPP_IOMMU_ATTACH :
+ VIDIOC_MSM_CPP_IOMMU_DETACH;
break;
+ }
case MSM_SD_NOTIFY_FREEZE:
break;
case MSM_SD_UNNOTIFY_FREEZE:
@@ -4202,7 +4247,8 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
default:
pr_err_ratelimited("%s: unsupported compat type :%x LOAD %lu\n",
__func__, cmd, VIDIOC_MSM_CPP_LOAD_FIRMWARE);
- break;
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
}
mutex_unlock(&cpp_dev->mutex);
@@ -4233,7 +4279,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
default:
pr_err_ratelimited("%s: unsupported compat type :%d\n",
__func__, cmd);
- break;
+ return -EINVAL;
}
if (is_copytouser_req) {
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index b7af80854420..e3f23caac5b8 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -851,6 +851,7 @@ static long audio_aio_process_event_req_compat(struct q6audio_aio *audio,
long rc;
struct msm_audio_event32 usr_evt_32;
struct msm_audio_event usr_evt;
+ memset(&usr_evt, 0, sizeof(struct msm_audio_event));
if (copy_from_user(&usr_evt_32, arg,
sizeof(struct msm_audio_event32))) {
@@ -860,6 +861,11 @@ static long audio_aio_process_event_req_compat(struct q6audio_aio *audio,
usr_evt.timeout_ms = usr_evt_32.timeout_ms;
rc = audio_aio_process_event_req_common(audio, &usr_evt);
+ if (rc < 0) {
+ pr_err("%s: audio process event failed, rc = %ld",
+ __func__, rc);
+ return rc;
+ }
usr_evt_32.event_type = usr_evt.event_type;
switch (usr_evt_32.event_type) {
diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c
index 618617f3e867..ad21276c8d9e 100644
--- a/drivers/misc/uid_sys_stats.c
+++ b/drivers/misc/uid_sys_stats.c
@@ -95,9 +95,11 @@ static int uid_cputime_show(struct seq_file *m, void *v)
{
struct uid_entry *uid_entry;
struct task_struct *task, *temp;
+ struct user_namespace *user_ns = current_user_ns();
cputime_t utime;
cputime_t stime;
unsigned long bkt;
+ uid_t uid;
rt_mutex_lock(&uid_lock);
@@ -108,14 +110,13 @@ static int uid_cputime_show(struct seq_file *m, void *v)
read_lock(&tasklist_lock);
do_each_thread(temp, task) {
- uid_entry = find_or_register_uid(from_kuid_munged(
- current_user_ns(), task_uid(task)));
+ uid = from_kuid_munged(user_ns, task_uid(task));
+ uid_entry = find_or_register_uid(uid);
if (!uid_entry) {
read_unlock(&tasklist_lock);
rt_mutex_unlock(&uid_lock);
pr_err("%s: failed to find the uid_entry for uid %d\n",
- __func__, from_kuid_munged(current_user_ns(),
- task_uid(task)));
+ __func__, uid);
return -ENOMEM;
}
task_cputime_adjusted(task, &utime, &stime);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 41f0935440fd..c462eee4a5f7 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -3944,12 +3944,10 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)
*/
int mmc_cmdq_hw_reset(struct mmc_host *host)
{
- if (!host->bus_ops->power_restore)
- return -EOPNOTSUPP;
+ if (!host->bus_ops->reset)
+ return -EOPNOTSUPP;
- mmc_power_cycle(host, host->ocr_avail);
- mmc_select_voltage(host, host->card->ocr);
- return host->bus_ops->power_restore(host);
+ return host->bus_ops->reset(host);
}
EXPORT_SYMBOL(mmc_cmdq_hw_reset);
@@ -3969,8 +3967,9 @@ int mmc_hw_reset(struct mmc_host *host)
ret = host->bus_ops->reset(host);
mmc_bus_put(host);
- if (ret != -EOPNOTSUPP)
- pr_warn("%s: tried to reset card\n", mmc_hostname(host));
+ if (ret)
+ pr_warn("%s: tried to reset card, got error %d\n",
+ mmc_hostname(host), ret);
return ret;
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index afdf70000651..691287125895 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -2892,23 +2892,42 @@ EXPORT_SYMBOL(mmc_can_reset);
static int mmc_reset(struct mmc_host *host)
{
struct mmc_card *card = host->card;
+ int ret;
+
+ if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
+ mmc_can_reset(card)) {
+ /* If the card accept RST_n signal, send it. */
+ mmc_set_clock(host, host->f_init);
+ host->ops->hw_reset(host);
+ /* Set initial state and call mmc_set_ios */
+ mmc_set_initial_state(host);
+ } else {
+ /* Do a brute force power cycle */
+ mmc_power_cycle(host, card->ocr);
+ }
- if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
- return -EOPNOTSUPP;
-
- if (!mmc_can_reset(card))
- return -EOPNOTSUPP;
+ /* Suspend clk scaling to avoid switching frequencies intermittently */
- mmc_host_clk_hold(host);
- mmc_set_clock(host, host->f_init);
+ ret = mmc_suspend_clk_scaling(host);
+ if (ret) {
+ pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
+ mmc_hostname(host), __func__, ret);
+ return ret;
+ }
- host->ops->hw_reset(host);
+ ret = mmc_init_card(host, host->card->ocr, host->card);
+ if (ret) {
+ pr_err("%s: %s: mmc_init_card failed (%d)\n",
+ mmc_hostname(host), __func__, ret);
+ return ret;
+ }
- /* Set initial state and call mmc_set_ios */
- mmc_set_initial_state(host);
- mmc_host_clk_release(host);
+ ret = mmc_resume_clk_scaling(host);
+ if (ret)
+ pr_err("%s: %s: fail to resume clock scaling (%d)\n",
+ mmc_hostname(host), __func__, ret);
- return mmc_init_card(host, card->ocr, card);
+ return ret;
}
static const struct mmc_bus_ops mmc_ops = {
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 1f1582f6cccb..8d838779fd1b 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -804,6 +804,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
switch (uhs) {
case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_DDR50:
pinctrl = imx_data->pins_100mhz;
break;
case MMC_TIMING_UHS_SDR104:
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 0134ba32a057..39712560b4c1 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -148,11 +148,11 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
return err;
}
- if (bytes == 0) {
- err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
- if (err)
- return err;
+ err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
+ if (err)
+ return err;
+ if (bytes == 0) {
err = clear_update_marker(ubi, vol, 0);
if (err)
return err;
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 6df3ee561d52..515aa3f993f3 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -836,25 +836,30 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
spin_lock_bh(&local->baplock);
res = hfa384x_setup_bap(dev, BAP0, rid, 0);
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+ if (res)
+ goto unlock;
+
+ res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+ if (res)
+ goto unlock;
if (le16_to_cpu(rec.len) == 0) {
/* RID not available */
res = -ENODATA;
+ goto unlock;
}
rlen = (le16_to_cpu(rec.len) - 1) * 2;
- if (!res && exact_len && rlen != len) {
+ if (exact_len && rlen != len) {
printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
"rid=0x%04x, len=%d (expected %d)\n",
dev->name, rid, rlen, len);
res = -ENODATA;
}
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, buf, len);
+ res = hfa384x_from_bap(dev, BAP0, buf, len);
+unlock:
spin_unlock_bh(&local->baplock);
mutex_unlock(&local->rid_bap_mtx);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index 57fa2465c9ea..e49bdc8c7083 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1205,6 +1205,8 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in,
IPADBG("Skipping endpoint configuration.\n");
}
+ ipa3_enable_data_path(ipa_ep_idx);
+
out->clnt_hdl = ipa_ep_idx;
if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client))
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index 8d038ba0770d..acea4f213484 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -497,13 +497,13 @@ static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr,
if (sysfs_streq(buf, "full")) {
dload_type = SCM_DLOAD_FULLDUMP;
} else if (sysfs_streq(buf, "mini")) {
- if (!msm_minidump_enabled()) {
- pr_info("Minidump is not enabled\n");
+ if (!minidump_enabled) {
+ pr_err("Minidump is not enabled\n");
return -ENODEV;
}
dload_type = SCM_DLOAD_MINIDUMP;
} else {
- pr_info("Invalid value. Use 'full' or 'mini'\n");
+ pr_err("Invalid value. Use 'full' or 'mini'\n");
return -EINVAL;
}
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 024c968e484a..94b9e9c4d912 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -427,6 +427,7 @@ static enum power_supply_property smb2_usb_props[] = {
POWER_SUPPLY_PROP_PE_START,
POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+ POWER_SUPPLY_PROP_REAL_TYPE,
};
static int smb2_usb_get_prop(struct power_supply *psy,
@@ -446,6 +447,16 @@ static int smb2_usb_get_prop(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_ONLINE:
rc = smblib_get_prop_usb_online(chg, val);
+ if (!val->intval)
+ break;
+
+ rc = smblib_get_prop_typec_mode(chg, val);
+ if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+ chg->micro_usb_mode) &&
+ chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+ val->intval = 0;
+ else
+ val->intval = 1;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
val->intval = chg->voltage_min_uv;
@@ -463,10 +474,13 @@ static int smb2_usb_get_prop(struct power_supply *psy,
rc = smblib_get_prop_usb_current_max(chg, val);
break;
case POWER_SUPPLY_PROP_TYPE:
+ val->intval = POWER_SUPPLY_TYPE_USB_PD;
+ break;
+ case POWER_SUPPLY_PROP_REAL_TYPE:
if (chip->bad_part)
- val->intval = POWER_SUPPLY_TYPE_USB;
+ val->intval = POWER_SUPPLY_TYPE_USB_PD;
else
- val->intval = chg->usb_psy_desc.type;
+ val->intval = chg->real_charger_type;
break;
case POWER_SUPPLY_PROP_TYPEC_MODE:
if (chg->micro_usb_mode)
@@ -608,7 +622,7 @@ static int smb2_init_usb_psy(struct smb2 *chip)
struct smb_charger *chg = &chip->chg;
chg->usb_psy_desc.name = "usb";
- chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
+ chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
chg->usb_psy_desc.properties = smb2_usb_props;
chg->usb_psy_desc.num_properties = ARRAY_SIZE(smb2_usb_props);
chg->usb_psy_desc.get_property = smb2_usb_get_prop;
@@ -628,6 +642,97 @@ static int smb2_init_usb_psy(struct smb2 *chip)
return 0;
}
+/********************************
+ * USB PC_PORT PSY REGISTRATION *
+ ********************************/
+static enum power_supply_property smb2_usb_port_props[] = {
+ POWER_SUPPLY_PROP_TYPE,
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int smb2_usb_port_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct smb2 *chip = power_supply_get_drvdata(psy);
+ struct smb_charger *chg = &chip->chg;
+ int rc = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_TYPE:
+ val->intval = POWER_SUPPLY_TYPE_USB;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ rc = smblib_get_prop_usb_online(chg, val);
+ if (!val->intval)
+ break;
+
+ rc = smblib_get_prop_typec_mode(chg, val);
+ if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+ chg->micro_usb_mode) &&
+ chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+ val->intval = 1;
+ else
+ val->intval = 0;
+ break;
+ default:
+ pr_err_ratelimited("Get prop %d is not supported in pc_port\n",
+ psp);
+ return -EINVAL;
+ }
+
+ if (rc < 0) {
+ pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+static int smb2_usb_port_set_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ int rc = 0;
+
+ switch (psp) {
+ default:
+ pr_err_ratelimited("Set prop %d is not supported in pc_port\n",
+ psp);
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static const struct power_supply_desc usb_port_psy_desc = {
+ .name = "pc_port",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = smb2_usb_port_props,
+ .num_properties = ARRAY_SIZE(smb2_usb_port_props),
+ .get_property = smb2_usb_port_get_prop,
+ .set_property = smb2_usb_port_set_prop,
+};
+
+static int smb2_init_usb_port_psy(struct smb2 *chip)
+{
+ struct power_supply_config usb_port_cfg = {};
+ struct smb_charger *chg = &chip->chg;
+
+ usb_port_cfg.drv_data = chip;
+ usb_port_cfg.of_node = chg->dev->of_node;
+ chg->usb_port_psy = power_supply_register(chg->dev,
+ &usb_port_psy_desc,
+ &usb_port_cfg);
+ if (IS_ERR(chg->usb_port_psy)) {
+ pr_err("Couldn't register USB pc_port power supply\n");
+ return PTR_ERR(chg->usb_port_psy);
+ }
+
+ return 0;
+}
+
/*****************************
* USB MAIN PSY REGISTRATION *
*****************************/
@@ -1061,6 +1166,9 @@ static int smb2_batt_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_DP_DM:
rc = smblib_dp_dm(chg, val->intval);
break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+ rc = smblib_set_prop_input_current_limited(chg, val);
+ break;
default:
rc = -EINVAL;
}
@@ -1078,6 +1186,7 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy,
case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
case POWER_SUPPLY_PROP_DP_DM:
case POWER_SUPPLY_PROP_RERUN_AICL:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
return 1;
default:
break;
@@ -2266,7 +2375,13 @@ static int smb2_probe(struct platform_device *pdev)
rc = smb2_init_usb_main_psy(chip);
if (rc < 0) {
- pr_err("Couldn't initialize usb psy rc=%d\n", rc);
+ pr_err("Couldn't initialize usb main psy rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb2_init_usb_port_psy(chip);
+ if (rc < 0) {
+ pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc);
goto cleanup;
}
@@ -2324,7 +2439,7 @@ static int smb2_probe(struct platform_device *pdev)
device_init_wakeup(chg->dev, true);
pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
- usb_present, chg->usb_psy_desc.type,
+ usb_present, chg->real_charger_type,
batt_present, batt_health, batt_charge_type);
return rc;
@@ -2336,6 +2451,8 @@ cleanup:
power_supply_unregister(chg->usb_main_psy);
if (chg->usb_psy)
power_supply_unregister(chg->usb_psy);
+ if (chg->usb_port_psy)
+ power_supply_unregister(chg->usb_port_psy);
if (chg->dc_psy)
power_supply_unregister(chg->dc_psy);
if (chg->vconn_vreg && chg->vconn_vreg->rdev)
@@ -2356,6 +2473,7 @@ static int smb2_remove(struct platform_device *pdev)
power_supply_unregister(chg->batt_psy);
power_supply_unregister(chg->usb_psy);
+ power_supply_unregister(chg->usb_port_psy);
regulator_unregister(chg->vconn_vreg->rdev);
regulator_unregister(chg->vbus_vreg->rdev);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index ecfb532e5b3c..a191391a3904 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -550,9 +550,9 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
/* if PD is active, APSD is disabled so won't have a valid result */
if (chg->pd_active)
- chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
+ chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
else
- chg->usb_psy_desc.type = apsd_result->pst;
+ chg->real_charger_type = apsd_result->pst;
smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
apsd_result->name, chg->pd_active);
@@ -858,7 +858,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
/* configure current */
if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
- && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
+ && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
rc = set_sdp_current(chg, icl_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
@@ -879,10 +879,10 @@ override_suspend_config:
/* remove override if no voters - hw defaults is desired */
override = false;
} else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
- if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
/* For std cable with type = SDP never override */
override = false;
- else if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP
+ else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
&& icl_ua == 1500000)
/*
* For std cable with type = CDP override only if
@@ -1707,6 +1707,11 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg,
u8 stat;
int rc;
+ if (chg->fake_input_current_limited >= 0) {
+ val->intval = chg->fake_input_current_limited;
+ return 0;
+ }
+
rc = smblib_read(chg, AICL_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
@@ -1898,6 +1903,13 @@ int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
return rc;
}
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+ const union power_supply_propval *val)
+{
+ chg->fake_input_current_limited = val->intval;
+ return 0;
+}
+
int smblib_rerun_aicl(struct smb_charger *chg)
{
int rc, settled_icl_ua;
@@ -3314,7 +3326,7 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
int pulses;
power_supply_changed(chg->usb_main_psy);
- if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP) {
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg,
@@ -3342,7 +3354,7 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
}
}
- if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
+ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg,
@@ -4471,6 +4483,7 @@ int smblib_init(struct smb_charger *chg)
INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
chg->fake_capacity = -EINVAL;
+ chg->fake_input_current_limited = -EINVAL;
switch (chg->mode) {
case PARALLEL_MASTER:
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index d14ea86bf0c6..5dc60ecb9436 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -244,6 +244,8 @@ struct smb_charger {
struct power_supply *bms_psy;
struct power_supply_desc usb_psy_desc;
struct power_supply *usb_main_psy;
+ struct power_supply *usb_port_psy;
+ enum power_supply_type real_charger_type;
/* notifiers */
struct notifier_block nb;
@@ -316,6 +318,7 @@ struct smb_charger {
bool typec_present;
u8 typec_status[5];
bool typec_legacy_valid;
+ int fake_input_current_limited;
/* workaround flag */
u32 wa_flags;
@@ -419,6 +422,8 @@ int smblib_set_prop_batt_capacity(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val);
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+ const union power_supply_propval *val);
int smblib_get_prop_dc_present(struct smb_charger *chg,
union power_supply_propval *val);
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index 3f260a407721..167666a8c548 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -1025,14 +1025,4 @@ enum {
/* CHGR FREQ Peripheral registers */
#define FREQ_CLK_DIV_REG (CHGR_FREQ_BASE + 0x50)
-/* SMB1355 specific registers */
-#define SMB1355_TEMP_COMP_STATUS_REG (MISC_BASE + 0x07)
-#define SKIN_TEMP_RST_HOT_BIT BIT(6)
-#define SKIN_TEMP_UB_HOT_BIT BIT(5)
-#define SKIN_TEMP_LB_HOT_BIT BIT(4)
-#define DIE_TEMP_TSD_HOT_BIT BIT(3)
-#define DIE_TEMP_RST_HOT_BIT BIT(2)
-#define DIE_TEMP_UB_HOT_BIT BIT(1)
-#define DIE_TEMP_LB_HOT_BIT BIT(0)
-
#endif /* __SMB2_CHARGER_REG_H */
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index e4a876126444..694591c3ec56 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -104,8 +104,6 @@ struct smb138x {
struct smb_dt_props dt;
struct power_supply *parallel_psy;
u32 wa_flags;
- struct pmic_revid_data *pmic_rev_id;
- char *name;
};
static int __debug_mask;
@@ -169,14 +167,6 @@ static int smb138x_parse_dt(struct smb138x *chip)
if (rc < 0)
chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID;
- /* check that smb1355 is configured to run in mid-mid mode */
- if (chip->pmic_rev_id->pmic_subtype == SMB1355_SUBTYPE
- && chip->dt.pl_mode != POWER_SUPPLY_PL_USBMID_USBMID) {
- pr_err("Smb1355 can only run in MID-MID mode, saw = %d mode\n",
- chip->dt.pl_mode);
- return -EINVAL;
- }
-
chip->dt.suspend_input = of_property_read_bool(node,
"qcom,suspend-input");
@@ -489,30 +479,6 @@ static int smb138x_init_batt_psy(struct smb138x *chip)
* PARALLEL PSY REGISTRATION *
*****************************/
-static int smb1355_get_prop_connector_health(struct smb138x *chip)
-{
- struct smb_charger *chg = &chip->chg;
- u8 temp;
- int rc;
-
- rc = smblib_read(chg, SMB1355_TEMP_COMP_STATUS_REG, &temp);
- if (rc < 0) {
- pr_err("Couldn't read comp stat reg rc = %d\n", rc);
- return POWER_SUPPLY_HEALTH_UNKNOWN;
- }
-
- if (temp & SKIN_TEMP_RST_HOT_BIT)
- return POWER_SUPPLY_HEALTH_OVERHEAT;
-
- if (temp & SKIN_TEMP_UB_HOT_BIT)
- return POWER_SUPPLY_HEALTH_HOT;
-
- if (temp & SKIN_TEMP_LB_HOT_BIT)
- return POWER_SUPPLY_HEALTH_WARM;
-
- return POWER_SUPPLY_HEALTH_COOL;
-}
-
static int smb138x_get_prop_connector_health(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
@@ -570,54 +536,18 @@ static enum power_supply_property smb138x_parallel_props[] = {
POWER_SUPPLY_PROP_PIN_ENABLED,
POWER_SUPPLY_PROP_INPUT_SUSPEND,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
- POWER_SUPPLY_PROP_MODEL_NAME,
- POWER_SUPPLY_PROP_PARALLEL_MODE,
- POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
- POWER_SUPPLY_PROP_SET_SHIP_MODE,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CHARGER_TEMP,
POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
- POWER_SUPPLY_PROP_CURRENT_NOW,
- POWER_SUPPLY_PROP_CURRENT_MAX,
-};
-
-static enum power_supply_property smb1355_parallel_props[] = {
- POWER_SUPPLY_PROP_CHARGE_TYPE,
- POWER_SUPPLY_PROP_CHARGING_ENABLED,
- POWER_SUPPLY_PROP_PIN_ENABLED,
- POWER_SUPPLY_PROP_INPUT_SUSPEND,
- POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
- POWER_SUPPLY_PROP_VOLTAGE_MAX,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_PARALLEL_MODE,
POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
POWER_SUPPLY_PROP_SET_SHIP_MODE,
- POWER_SUPPLY_PROP_CHARGER_TEMP,
- POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
};
-static int smb138x_get_parallel_charging(struct smb138x *chip, int *disabled)
-{
- struct smb_charger *chg = &chip->chg;
- int rc = 0;
- u8 cfg2;
-
- rc = smblib_read(chg, CHGR_CFG2_REG, &cfg2);
- if (rc < 0) {
- pr_err("Couldn't read en_cmg_reg rc=%d\n", rc);
- return rc;
- }
-
- if (cfg2 & CHG_EN_SRC_BIT)
- *disabled = 0;
- else
- *disabled = 1;
-
- return 0;
-}
-
static int smb138x_parallel_get_prop(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
@@ -644,7 +574,7 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
val->intval = !(temp & DISABLE_CHARGING_BIT);
break;
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
- rc = smb138x_get_parallel_charging(chip, &val->intval);
+ rc = smblib_get_usb_suspend(chg, &val->intval);
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
@@ -653,6 +583,14 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
else
val->intval = 0;
break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
+ rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
+ &val->intval);
+ else
+ val->intval = 0;
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
break;
@@ -660,46 +598,28 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
rc = smblib_get_charge_param(chg, &chg->param.fcc,
&val->intval);
break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ rc = smblib_get_prop_slave_current_now(chg, val);
+ break;
+ case POWER_SUPPLY_PROP_CHARGER_TEMP:
+ rc = smb138x_get_prop_charger_temp(chip, val);
+ break;
+ case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
+ rc = smblib_get_prop_charger_temp_max(chg, val);
+ break;
case POWER_SUPPLY_PROP_MODEL_NAME:
- val->strval = chip->name;
+ val->strval = "smb138x";
break;
case POWER_SUPPLY_PROP_PARALLEL_MODE:
val->intval = chip->dt.pl_mode;
break;
case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
- if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
- val->intval = smb138x_get_prop_connector_health(chip);
- else
- val->intval = smb1355_get_prop_connector_health(chip);
+ val->intval = smb138x_get_prop_connector_health(chip);
break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as device is active */
val->intval = 0;
break;
- case POWER_SUPPLY_PROP_CHARGER_TEMP:
- if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
- rc = smb138x_get_prop_charger_temp(chip, val);
- else
- rc = smblib_get_prop_charger_temp(chg, val);
- break;
- case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
- rc = smblib_get_prop_charger_temp_max(chg, val);
- break;
- case POWER_SUPPLY_PROP_CURRENT_NOW:
- if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
- rc = smblib_get_prop_slave_current_now(chg, val);
- else
- rc = -ENODATA;
- break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- if ((chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
- && ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
- || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)))
- rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
- &val->intval);
- else
- rc = -ENODATA;
- break;
default:
pr_err("parallel power supply get prop %d not supported\n",
prop);
@@ -714,33 +634,28 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
return rc;
}
-static int smb138x_set_parallel_charging(struct smb138x *chip, bool disable)
+static int smb138x_set_parallel_suspend(struct smb138x *chip, bool suspend)
{
struct smb_charger *chg = &chip->chg;
int rc = 0;
rc = smblib_masked_write(chg, WD_CFG_REG, WDOG_TIMER_EN_BIT,
- disable ? 0 : WDOG_TIMER_EN_BIT);
+ suspend ? 0 : WDOG_TIMER_EN_BIT);
if (rc < 0) {
pr_err("Couldn't %s watchdog rc=%d\n",
- disable ? "disable" : "enable", rc);
- disable = true;
+ suspend ? "disable" : "enable", rc);
+ suspend = true;
}
- /*
- * Configure charge enable for high polarity and
- * When disabling charging set it to cmd register control(cmd bit=0)
- * When enabling charging set it to pin control
- */
- rc = smblib_masked_write(chg, CHGR_CFG2_REG,
- CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT,
- disable ? 0 : CHG_EN_SRC_BIT);
+ rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
+ suspend ? USBIN_SUSPEND_BIT : 0);
if (rc < 0) {
- pr_err("Couldn't configure charge enable source rc=%d\n", rc);
+ pr_err("Couldn't %s parallel charger rc=%d\n",
+ suspend ? "suspend" : "resume", rc);
return rc;
}
- return 0;
+ return rc;
}
static int smb138x_parallel_set_prop(struct power_supply *psy,
@@ -753,7 +668,7 @@ static int smb138x_parallel_set_prop(struct power_supply *psy,
switch (prop) {
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
- rc = smb138x_set_parallel_charging(chip, (bool)val->intval);
+ rc = smb138x_set_parallel_suspend(chip, (bool)val->intval);
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
@@ -788,7 +703,7 @@ static int smb138x_parallel_prop_is_writeable(struct power_supply *psy,
return 0;
}
-static struct power_supply_desc parallel_psy_desc = {
+static const struct power_supply_desc parallel_psy_desc = {
.name = "parallel",
.type = POWER_SUPPLY_TYPE_PARALLEL,
.properties = smb138x_parallel_props,
@@ -816,28 +731,6 @@ static int smb138x_init_parallel_psy(struct smb138x *chip)
return 0;
}
-static int smb1355_init_parallel_psy(struct smb138x *chip)
-{
- struct power_supply_config parallel_cfg = {};
- struct smb_charger *chg = &chip->chg;
-
- parallel_cfg.drv_data = chip;
- parallel_cfg.of_node = chg->dev->of_node;
-
- /* change to smb1355's property list */
- parallel_psy_desc.properties = smb1355_parallel_props;
- parallel_psy_desc.num_properties = ARRAY_SIZE(smb1355_parallel_props);
- chip->parallel_psy = devm_power_supply_register(chg->dev,
- &parallel_psy_desc,
- &parallel_cfg);
- if (IS_ERR(chip->parallel_psy)) {
- pr_err("Couldn't register parallel power supply\n");
- return PTR_ERR(chip->parallel_psy);
- }
-
- return 0;
-}
-
/******************************
* VBUS REGULATOR REGISTRATION *
******************************/
@@ -971,32 +864,35 @@ static int smb138x_init_slave_hw(struct smb138x *chip)
return rc;
}
- /* disable the charging path when under s/w control */
- rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
- CHARGING_ENABLE_CMD_BIT, 0);
+ /* suspend parallel charging */
+ rc = smb138x_set_parallel_suspend(chip, true);
if (rc < 0) {
- pr_err("Couldn't disable charging rc=%d\n", rc);
+ pr_err("Couldn't suspend parallel charging rc=%d\n", rc);
return rc;
}
- /* disable parallel charging path */
- rc = smb138x_set_parallel_charging(chip, true);
+ /* initialize FCC to 0 */
+ rc = smblib_set_charge_param(chg, &chg->param.fcc, 0);
if (rc < 0) {
- pr_err("Couldn't disable parallel path rc=%d\n", rc);
+ pr_err("Couldn't set 0 FCC rc=%d\n", rc);
return rc;
}
- /* unsuspend parallel charging */
- rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT, 0);
+ /* enable the charging path */
+ rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
+ CHARGING_ENABLE_CMD_BIT,
+ CHARGING_ENABLE_CMD_BIT);
if (rc < 0) {
- pr_err("Couldn't unsuspend parallel charging rc=%d\n", rc);
+ pr_err("Couldn't enable charging rc=%d\n", rc);
return rc;
}
- /* initialize FCC to 0 */
- rc = smblib_set_charge_param(chg, &chg->param.fcc, 0);
+ /* configure charge enable for software control; active high */
+ rc = smblib_masked_write(chg, CHGR_CFG2_REG,
+ CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0);
if (rc < 0) {
- pr_err("Couldn't set 0 FCC rc=%d\n", rc);
+ pr_err("Couldn't configure charge enable source rc=%d\n",
+ rc);
return rc;
}
@@ -1154,6 +1050,7 @@ static int smb138x_init_hw(struct smb138x *chip)
static int smb138x_setup_wa_flags(struct smb138x *chip)
{
+ struct pmic_revid_data *pmic_rev_id;
struct device_node *revid_dev_node;
revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
@@ -1163,8 +1060,8 @@ static int smb138x_setup_wa_flags(struct smb138x *chip)
return -EINVAL;
}
- chip->pmic_rev_id = get_revid_data(revid_dev_node);
- if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
+ pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR_OR_NULL(pmic_rev_id)) {
/*
* the revid peripheral must be registered, any failure
* here only indicates that the rev-id module has not
@@ -1173,14 +1070,14 @@ static int smb138x_setup_wa_flags(struct smb138x *chip)
return -EPROBE_DEFER;
}
- switch (chip->pmic_rev_id->pmic_subtype) {
+ switch (pmic_rev_id->pmic_subtype) {
case SMB1381_SUBTYPE:
- if (chip->pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
+ if (pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
chip->wa_flags |= OOB_COMP_WA_BIT;
break;
default:
pr_err("PMIC subtype %d not supported\n",
- chip->pmic_rev_id->pmic_subtype);
+ pmic_rev_id->pmic_subtype);
return -EINVAL;
}
@@ -1478,7 +1375,6 @@ static int smb138x_master_probe(struct smb138x *chip)
chg->param = v1_params;
- chip->name = "smb1381";
rc = smblib_init(chg);
if (rc < 0) {
pr_err("Couldn't initialize smblib rc=%d\n", rc);
@@ -1539,7 +1435,7 @@ static int smb138x_master_probe(struct smb138x *chip)
return rc;
}
-static int smb1355_slave_probe(struct smb138x *chip)
+static int smb138x_slave_probe(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
int rc = 0;
@@ -1552,55 +1448,6 @@ static int smb1355_slave_probe(struct smb138x *chip)
goto cleanup;
}
- rc = smb138x_parse_dt(chip);
- if (rc < 0) {
- pr_err("Couldn't parse device tree rc=%d\n", rc);
- goto cleanup;
- }
-
- rc = smb138x_init_slave_hw(chip);
- if (rc < 0) {
- pr_err("Couldn't initialize hardware rc=%d\n", rc);
- goto cleanup;
- }
-
- rc = smb1355_init_parallel_psy(chip);
- if (rc < 0) {
- pr_err("Couldn't initialize parallel psy rc=%d\n", rc);
- goto cleanup;
- }
-
- rc = smb138x_determine_initial_slave_status(chip);
- if (rc < 0) {
- pr_err("Couldn't determine initial status rc=%d\n", rc);
- goto cleanup;
- }
-
- rc = smb138x_request_interrupts(chip);
- if (rc < 0) {
- pr_err("Couldn't request interrupts rc=%d\n", rc);
- goto cleanup;
- }
-
- return 0;
-
-cleanup:
- smblib_deinit(chg);
- return rc;
-}
-
-static int smb1381_slave_probe(struct smb138x *chip)
-{
- struct smb_charger *chg = &chip->chg;
- int rc = 0;
-
- chg->param = v1_params;
-
- rc = smblib_init(chg);
- if (rc < 0) {
- pr_err("Couldn't initialize smblib rc=%d\n", rc);
- goto cleanup;
- }
chg->iio.temp_max_chan = iio_channel_get(chg->dev, "charger_temp_max");
if (IS_ERR(chg->iio.temp_max_chan)) {
rc = PTR_ERR(chg->iio.temp_max_chan);
@@ -1668,71 +1515,25 @@ static int smb1381_slave_probe(struct smb138x *chip)
goto cleanup;
}
- return 0;
+ return rc;
cleanup:
smblib_deinit(chg);
+ if (chip->parallel_psy)
+ power_supply_unregister(chip->parallel_psy);
+ if (chg->vbus_vreg && chg->vbus_vreg->rdev)
+ regulator_unregister(chg->vbus_vreg->rdev);
return rc;
}
-static int slave_probe(struct smb138x *chip)
-{
- struct device_node *revid_dev_node;
- int rc = 0;
-
- revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
- "qcom,pmic-revid", 0);
- if (!revid_dev_node) {
- pr_err("Missing qcom,pmic-revid property\n");
- return -EINVAL;
- }
-
- chip->pmic_rev_id = get_revid_data(revid_dev_node);
- if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
- /*
- * the revid peripheral must be registered, any failure
- * here only indicates that the rev-id module has not
- * probed yet.
- */
- return -EPROBE_DEFER;
- }
-
- switch (chip->pmic_rev_id->pmic_subtype) {
- case SMB1355_SUBTYPE:
- chip->name = "smb1355";
- rc = smb1355_slave_probe(chip);
- break;
- case SMB1381_SUBTYPE:
- chip->name = "smb1381";
- rc = smb1381_slave_probe(chip);
- break;
- default:
- pr_err("Unsupported pmic subtype = 0x%02x\n",
- chip->pmic_rev_id->pmic_subtype);
- rc = -EINVAL;
- }
-
- if (rc < 0) {
- if (rc != -EPROBE_DEFER)
- pr_err("Couldn't probe SMB138X rc=%d\n", rc);
- return rc;
- }
-
- return 0;
-}
-
static const struct of_device_id match_table[] = {
{
- .compatible = "qcom,smb138x-charger",
- .data = (void *) PARALLEL_MASTER,
- },
- {
- .compatible = "qcom,smb138x-parallel-slave",
- .data = (void *) PARALLEL_SLAVE,
+ .compatible = "qcom,smb138x-charger",
+ .data = (void *) PARALLEL_MASTER
},
{
- .compatible = "qcom,smb1355-parallel-slave",
- .data = (void *) PARALLEL_SLAVE,
+ .compatible = "qcom,smb138x-parallel-slave",
+ .data = (void *) PARALLEL_SLAVE
},
{ },
};
@@ -1779,7 +1580,7 @@ static int smb138x_probe(struct platform_device *pdev)
rc = smb138x_master_probe(chip);
break;
case PARALLEL_SLAVE:
- rc = slave_probe(chip);
+ rc = smb138x_slave_probe(chip);
break;
default:
pr_err("Couldn't find a matching mode %d\n", chip->chg.mode);
@@ -1793,8 +1594,7 @@ static int smb138x_probe(struct platform_device *pdev)
goto cleanup;
}
- pr_info("%s probed successfully mode=%d pl_mode = %d\n",
- chip->name, chip->chg.mode, chip->dt.pl_mode);
+ pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode);
return rc;
cleanup:
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index e5ba63171eba..88956d3ba674 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -472,6 +472,15 @@ config REGULATOR_MT6397
This driver supports the control of different power rails of device
through regulator interface.
+config REGULATOR_ONSEMI_NCP6335D
+ tristate "OnSemi NCP6335D regulator support"
+ depends on I2C
+ help
+ This driver supports the OnSemi NCP6335D switching voltage regulator
+ (buck converter). The regulator is controlled using an I2C interface
+ and supports a programmable voltage range from 0.6V to 1.4V in steps
+ of 6.25mV.
+
config REGULATOR_PALMAS
tristate "TI Palmas PMIC Regulators"
depends on MFD_PALMAS
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 20cf304a4714..e345f10f94af 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
+obj-$(CONFIG_REGULATOR_ONSEMI_NCP6335D) += onsemi-ncp6335d.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
diff --git a/drivers/regulator/onsemi-ncp6335d.c b/drivers/regulator/onsemi-ncp6335d.c
new file mode 100644
index 000000000000..3b4ca4f81527
--- /dev/null
+++ b/drivers/regulator/onsemi-ncp6335d.c
@@ -0,0 +1,775 @@
+/* Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/debugfs.h>
+#include <linux/regulator/onsemi-ncp6335d.h>
+#include <linux/string.h>
+
+/* registers */
+#define REG_NCP6335D_PID 0x03
+#define REG_NCP6335D_PROGVSEL1 0x10
+#define REG_NCP6335D_PROGVSEL0 0x11
+#define REG_NCP6335D_PGOOD 0x12
+#define REG_NCP6335D_TIMING 0x13
+#define REG_NCP6335D_COMMAND 0x14
+
+/* constraints */
+#define NCP6335D_MIN_VOLTAGE_UV 600000
+#define NCP6335D_STEP_VOLTAGE_UV 6250
+#define NCP6335D_VOLTAGE_STEPS 128
+#define NCP6335D_MIN_SLEW_NS 166
+#define NCP6335D_MAX_SLEW_NS 1333
+
+/* bits */
+#define NCP6335D_ENABLE BIT(7)
+#define NCP6335D_DVS_PWM_MODE BIT(5)
+#define NCP6335D_PWM_MODE1 BIT(6)
+#define NCP6335D_PWM_MODE0 BIT(7)
+#define NCP6335D_PGOOD_DISCHG BIT(4)
+#define NCP6335D_SLEEP_MODE BIT(4)
+
+#define NCP6335D_VOUT_SEL_MASK 0x7F
+#define NCP6335D_SLEW_MASK 0x18
+#define NCP6335D_SLEW_SHIFT 0x3
+
+struct ncp6335d_info {
+ struct regulator_dev *regulator;
+ struct regulator_init_data *init_data;
+ struct regmap *regmap;
+ struct device *dev;
+ unsigned int vsel_reg;
+ unsigned int vsel_backup_reg;
+ unsigned int mode_bit;
+ int curr_voltage;
+ int slew_rate;
+
+ unsigned int step_size;
+ unsigned int min_voltage;
+ unsigned int min_slew_ns;
+ unsigned int max_slew_ns;
+ unsigned int peek_poke_address;
+
+ struct dentry *debug_root;
+};
+
+static int delay_array[] = {10, 20, 30, 40, 50};
+
+static int ncp6335x_read(struct ncp6335d_info *dd, unsigned int reg,
+ unsigned int *val)
+{
+ int i = 0, rc = 0;
+
+ rc = regmap_read(dd->regmap, reg, val);
+ for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) {
+ pr_debug("Failed reading reg=%u - retry(%d)\n", reg, i);
+ msleep(delay_array[i]);
+ rc = regmap_read(dd->regmap, reg, val);
+ }
+
+ if (rc)
+ pr_err("Failed reading reg=%u rc=%d\n", reg, rc);
+
+ return rc;
+}
+
+static int ncp6335x_write(struct ncp6335d_info *dd, unsigned int reg,
+ unsigned int val)
+{
+ int i = 0, rc = 0;
+
+ rc = regmap_write(dd->regmap, reg, val);
+ for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) {
+ pr_debug("Failed writing reg=%u - retry(%d)\n", reg, i);
+ msleep(delay_array[i]);
+ rc = regmap_write(dd->regmap, reg, val);
+ }
+
+ if (rc)
+ pr_err("Failed writing reg=%u rc=%d\n", reg, rc);
+
+ return rc;
+}
+
+static int ncp6335x_update_bits(struct ncp6335d_info *dd, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ int i = 0, rc = 0;
+
+ rc = regmap_update_bits(dd->regmap, reg, mask, val);
+ for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) {
+ pr_debug("Failed updating reg=%u- retry(%d)\n", reg, i);
+ msleep(delay_array[i]);
+ rc = regmap_update_bits(dd->regmap, reg, mask, val);
+ }
+
+ if (rc)
+ pr_err("Failed updating reg=%u rc=%d\n", reg, rc);
+
+ return rc;
+}
+
+static void dump_registers(struct ncp6335d_info *dd,
+ unsigned int reg, const char *func)
+{
+ unsigned int val = 0;
+
+ ncp6335x_read(dd, reg, &val);
+ dev_dbg(dd->dev, "%s: NCP6335D: Reg = %x, Val = %x\n", func, reg, val);
+}
+
+static void ncp633d_slew_delay(struct ncp6335d_info *dd,
+ int prev_uV, int new_uV)
+{
+ u8 val;
+ int delay;
+
+ val = abs(prev_uV - new_uV) / dd->step_size;
+ delay = ((val * dd->slew_rate) / 1000) + 1;
+
+ dev_dbg(dd->dev, "Slew Delay = %d\n", delay);
+
+ udelay(delay);
+}
+
+static int ncp6335d_is_enabled(struct regulator_dev *rdev)
+{
+ int rc, val = 0;
+ struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+ rc = ncp6335x_read(dd, dd->vsel_reg, &val);
+ if (rc)
+ dev_err(dd->dev, "Unable to read enable register rc(%d)", rc);
+
+ dump_registers(dd, dd->vsel_reg, __func__);
+
+ return ((val & NCP6335D_ENABLE) ? 1 : 0);
+}
+
+static int ncp6335d_enable(struct regulator_dev *rdev)
+{
+ int rc;
+ struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+ rc = ncp6335x_update_bits(dd, dd->vsel_reg,
+ NCP6335D_ENABLE, NCP6335D_ENABLE);
+ if (rc)
+ dev_err(dd->dev, "Unable to enable regualtor rc(%d)", rc);
+
+ dump_registers(dd, dd->vsel_reg, __func__);
+
+ return rc;
+}
+
+static int ncp6335d_disable(struct regulator_dev *rdev)
+{
+ int rc;
+ struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+ rc = ncp6335x_update_bits(dd, dd->vsel_reg,
+ NCP6335D_ENABLE, 0);
+ if (rc)
+ dev_err(dd->dev, "Unable to disable regualtor rc(%d)", rc);
+
+ dump_registers(dd, dd->vsel_reg, __func__);
+
+ return rc;
+}
+
+static int ncp6335d_get_voltage(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int rc;
+ struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+ rc = ncp6335x_read(dd, dd->vsel_reg, &val);
+ if (rc) {
+ dev_err(dd->dev, "Unable to get volatge rc(%d)", rc);
+ return rc;
+ }
+ dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) * dd->step_size) +
+ dd->min_voltage;
+
+ dump_registers(dd, dd->vsel_reg, __func__);
+
+ return dd->curr_voltage;
+}
+
+static int ncp6335d_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ int rc, set_val, new_uV;
+ struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+ set_val = DIV_ROUND_UP(min_uV - dd->min_voltage, dd->step_size);
+ new_uV = (set_val * dd->step_size) + dd->min_voltage;
+ if (new_uV > max_uV) {
+ dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ rc = ncp6335x_update_bits(dd, dd->vsel_reg,
+ NCP6335D_VOUT_SEL_MASK, (set_val & NCP6335D_VOUT_SEL_MASK));
+ if (rc) {
+ dev_err(dd->dev, "Unable to set volatge (%d %d)\n",
+ min_uV, max_uV);
+ } else {
+ ncp633d_slew_delay(dd, dd->curr_voltage, new_uV);
+ dd->curr_voltage = new_uV;
+ }
+
+ dump_registers(dd, dd->vsel_reg, __func__);
+
+ return rc;
+}
+
+static int ncp6335d_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+ if (selector >= NCP6335D_VOLTAGE_STEPS)
+ return 0;
+
+ return selector * dd->step_size + dd->min_voltage;
+}
+
+static int ncp6335d_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ int rc;
+ struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+ /* only FAST and NORMAL mode types are supported */
+ if (mode != REGULATOR_MODE_FAST && mode != REGULATOR_MODE_NORMAL) {
+ dev_err(dd->dev, "Mode %d not supported\n", mode);
+ return -EINVAL;
+ }
+
+ rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND, dd->mode_bit,
+ (mode == REGULATOR_MODE_FAST) ? dd->mode_bit : 0);
+ if (rc) {
+ dev_err(dd->dev, "Unable to set operating mode rc(%d)", rc);
+ return rc;
+ }
+
+ rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND,
+ NCP6335D_DVS_PWM_MODE,
+ (mode == REGULATOR_MODE_FAST) ?
+ NCP6335D_DVS_PWM_MODE : 0);
+ if (rc)
+ dev_err(dd->dev, "Unable to set DVS trans. mode rc(%d)", rc);
+
+ dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
+
+ return rc;
+}
+
+static unsigned int ncp6335d_get_mode(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int rc;
+ struct ncp6335d_info *dd = rdev_get_drvdata(rdev);
+
+ rc = ncp6335x_read(dd, REG_NCP6335D_COMMAND, &val);
+ if (rc) {
+ dev_err(dd->dev, "Unable to get regulator mode rc(%d)\n", rc);
+ return rc;
+ }
+
+ dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
+
+ if (val & dd->mode_bit)
+ return REGULATOR_MODE_FAST;
+
+ return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops ncp6335d_ops = {
+ .set_voltage = ncp6335d_set_voltage,
+ .get_voltage = ncp6335d_get_voltage,
+ .list_voltage = ncp6335d_list_voltage,
+ .is_enabled = ncp6335d_is_enabled,
+ .enable = ncp6335d_enable,
+ .disable = ncp6335d_disable,
+ .set_mode = ncp6335d_set_mode,
+ .get_mode = ncp6335d_get_mode,
+};
+
+static struct regulator_desc rdesc = {
+ .name = "ncp6335d",
+ .supply_name = "vin",
+ .owner = THIS_MODULE,
+ .n_voltages = NCP6335D_VOLTAGE_STEPS,
+ .ops = &ncp6335d_ops,
+};
+
+static int ncp6335d_restore_working_reg(struct device_node *node,
+ struct ncp6335d_info *dd)
+{
+ int ret;
+ unsigned int val;
+
+ /* Restore register from back up register */
+ ret = ncp6335x_read(dd, dd->vsel_backup_reg, &val);
+ if (ret < 0) {
+ dev_err(dd->dev, "Failed to get backup data from reg %d, ret = %d\n",
+ dd->vsel_backup_reg, ret);
+ return ret;
+ }
+
+ ret = ncp6335x_update_bits(dd, dd->vsel_reg,
+ NCP6335D_VOUT_SEL_MASK, val);
+ if (ret < 0) {
+ dev_err(dd->dev, "Failed to update working reg %d, ret = %d\n",
+ dd->vsel_reg, ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int ncp6335d_parse_gpio(struct device_node *node,
+ struct ncp6335d_info *dd)
+{
+ int ret = 0, gpio;
+ enum of_gpio_flags flags;
+
+ if (!of_find_property(node, "onnn,vsel-gpio", NULL))
+ return ret;
+
+ /* Get GPIO connected to vsel and set its output */
+ gpio = of_get_named_gpio_flags(node,
+ "onnn,vsel-gpio", 0, &flags);
+ if (!gpio_is_valid(gpio)) {
+ if (gpio != -EPROBE_DEFER)
+ dev_err(dd->dev, "Could not get vsel, ret = %d\n",
+ gpio);
+ return gpio;
+ }
+
+ ret = devm_gpio_request(dd->dev, gpio, "ncp6335d_vsel");
+ if (ret) {
+ dev_err(dd->dev, "Failed to obtain gpio %d ret = %d\n",
+ gpio, ret);
+ return ret;
+ }
+
+ ret = gpio_direction_output(gpio, flags & OF_GPIO_ACTIVE_LOW ? 0 : 1);
+ if (ret) {
+ dev_err(dd->dev, "Failed to set GPIO %d to: %s, ret = %d",
+ gpio, flags & OF_GPIO_ACTIVE_LOW ?
+ "GPIO_LOW" : "GPIO_HIGH", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int ncp6335d_init(struct i2c_client *client, struct ncp6335d_info *dd,
+ const struct ncp6335d_platform_data *pdata)
+{
+ int rc;
+ unsigned int val;
+
+ switch (pdata->default_vsel) {
+ case NCP6335D_VSEL0:
+ dd->vsel_reg = REG_NCP6335D_PROGVSEL0;
+ dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL1;
+ dd->mode_bit = NCP6335D_PWM_MODE0;
+ break;
+ case NCP6335D_VSEL1:
+ dd->vsel_reg = REG_NCP6335D_PROGVSEL1;
+ dd->vsel_backup_reg = REG_NCP6335D_PROGVSEL0;
+ dd->mode_bit = NCP6335D_PWM_MODE1;
+ break;
+ default:
+ dev_err(dd->dev, "Invalid VSEL ID %d\n", pdata->default_vsel);
+ return -EINVAL;
+ }
+
+ if (of_property_read_bool(client->dev.of_node, "onnn,restore-reg")) {
+ rc = ncp6335d_restore_working_reg(client->dev.of_node, dd);
+ if (rc)
+ return rc;
+ }
+
+ rc = ncp6335d_parse_gpio(client->dev.of_node, dd);
+ if (rc)
+ return rc;
+
+ /* get the current programmed voltage */
+ rc = ncp6335x_read(dd, dd->vsel_reg, &val);
+ if (rc) {
+ dev_err(dd->dev, "Unable to get volatge rc(%d)", rc);
+ return rc;
+ }
+ dd->curr_voltage = ((val & NCP6335D_VOUT_SEL_MASK) *
+ dd->step_size) + dd->min_voltage;
+
+ /* set discharge */
+ rc = ncp6335x_update_bits(dd, REG_NCP6335D_PGOOD,
+ NCP6335D_PGOOD_DISCHG,
+ (pdata->discharge_enable ?
+ NCP6335D_PGOOD_DISCHG : 0));
+ if (rc) {
+ dev_err(dd->dev, "Unable to set Active Discharge rc(%d)\n", rc);
+ return -EINVAL;
+ }
+
+ /* set slew rate */
+ if (pdata->slew_rate_ns < dd->min_slew_ns ||
+ pdata->slew_rate_ns > dd->max_slew_ns) {
+ dev_err(dd->dev, "Invalid slew rate %d\n", pdata->slew_rate_ns);
+ return -EINVAL;
+ }
+
+ dd->slew_rate = pdata->slew_rate_ns;
+ val = DIV_ROUND_UP(pdata->slew_rate_ns, dd->min_slew_ns);
+ val = ilog2(val);
+
+ rc = ncp6335x_update_bits(dd, REG_NCP6335D_TIMING,
+ NCP6335D_SLEW_MASK, val << NCP6335D_SLEW_SHIFT);
+ if (rc)
+ dev_err(dd->dev, "Unable to set slew rate rc(%d)\n", rc);
+
+ /* Set Sleep mode bit */
+ rc = ncp6335x_update_bits(dd, REG_NCP6335D_COMMAND,
+ NCP6335D_SLEEP_MODE, pdata->sleep_enable ?
+ NCP6335D_SLEEP_MODE : 0);
+ if (rc)
+ dev_err(dd->dev, "Unable to set sleep mode (%d)\n", rc);
+
+ dump_registers(dd, REG_NCP6335D_COMMAND, __func__);
+ dump_registers(dd, REG_NCP6335D_PROGVSEL0, __func__);
+ dump_registers(dd, REG_NCP6335D_TIMING, __func__);
+ dump_registers(dd, REG_NCP6335D_PGOOD, __func__);
+
+ return rc;
+}
+
+static struct regmap_config ncp6335d_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int ncp6335d_parse_dt(struct i2c_client *client,
+ struct ncp6335d_info *dd)
+{
+ int rc;
+
+ rc = of_property_read_u32(client->dev.of_node,
+ "onnn,step-size", &dd->step_size);
+ if (rc < 0) {
+ dev_err(&client->dev, "step size missing: rc = %d.\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(client->dev.of_node,
+ "onnn,min-slew-ns", &dd->min_slew_ns);
+ if (rc < 0) {
+ dev_err(&client->dev, "min slew us missing: rc = %d.\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(client->dev.of_node,
+ "onnn,max-slew-ns", &dd->max_slew_ns);
+ if (rc < 0) {
+ dev_err(&client->dev, "max slew us missing: rc = %d.\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(client->dev.of_node,
+ "onnn,min-setpoint", &dd->min_voltage);
+ if (rc < 0) {
+ dev_err(&client->dev, "min set point missing: rc = %d.\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+static struct ncp6335d_platform_data *
+ ncp6335d_get_of_platform_data(struct i2c_client *client)
+{
+ struct ncp6335d_platform_data *pdata = NULL;
+ struct regulator_init_data *init_data;
+ const char *mode_name;
+ int rc;
+
+ init_data = of_get_regulator_init_data(&client->dev,
+ client->dev.of_node, &rdesc);
+ if (!init_data) {
+ dev_err(&client->dev, "regulator init data is missing\n");
+ return pdata;
+ }
+
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct ncp6335d_platform_data), GFP_KERNEL);
+ if (!pdata)
+ return pdata;
+
+ rc = of_property_read_u32(client->dev.of_node,
+ "onnn,vsel", &pdata->default_vsel);
+ if (rc < 0) {
+ dev_err(&client->dev, "onnn,vsel property missing: rc = %d.\n",
+ rc);
+ return NULL;
+ }
+
+ rc = of_property_read_u32(client->dev.of_node,
+ "onnn,slew-ns", &pdata->slew_rate_ns);
+ if (rc < 0) {
+ dev_err(&client->dev, "onnn,slew-ns property missing: rc = %d.\n",
+ rc);
+ return NULL;
+ }
+
+ pdata->discharge_enable = of_property_read_bool(client->dev.of_node,
+ "onnn,discharge-enable");
+
+ pdata->sleep_enable = of_property_read_bool(client->dev.of_node,
+ "onnn,sleep-enable");
+
+ pdata->init_data = init_data;
+
+ init_data->constraints.input_uV = init_data->constraints.max_uV;
+ init_data->constraints.valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE;
+ init_data->constraints.valid_modes_mask =
+ REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_FAST;
+
+ rc = of_property_read_string(client->dev.of_node, "onnn,mode",
+ &mode_name);
+ if (!rc) {
+ if (strcmp("pwm", mode_name) == 0) {
+ init_data->constraints.initial_mode =
+ REGULATOR_MODE_FAST;
+ } else if (strcmp("auto", mode_name) == 0) {
+ init_data->constraints.initial_mode =
+ REGULATOR_MODE_NORMAL;
+ } else {
+ dev_err(&client->dev, "onnn,mode, unknown regulator mode: %s\n",
+ mode_name);
+ return NULL;
+ }
+ }
+
+ return pdata;
+}
+
+static int get_reg(void *data, u64 *val)
+{
+ struct ncp6335d_info *dd = data;
+ int rc;
+ unsigned int temp = 0;
+
+ rc = ncp6335x_read(dd, dd->peek_poke_address, &temp);
+ if (rc < 0)
+ dev_err(dd->dev, "Couldn't read reg %x rc = %d\n",
+ dd->peek_poke_address, rc);
+ else
+ *val = temp;
+
+ return rc;
+}
+
+static int set_reg(void *data, u64 val)
+{
+ struct ncp6335d_info *dd = data;
+ int rc;
+ unsigned int temp = 0;
+
+ temp = (unsigned int) val;
+ rc = ncp6335x_write(dd, dd->peek_poke_address, temp);
+ if (rc < 0)
+ dev_err(dd->dev, "Couldn't write 0x%02x to 0x%02x rc= %d\n",
+ dd->peek_poke_address, temp, rc);
+
+ return rc;
+}
+DEFINE_SIMPLE_ATTRIBUTE(poke_poke_debug_ops, get_reg, set_reg, "0x%02llx\n");
+
+static int ncp6335d_regulator_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc;
+ unsigned int val = 0;
+ struct ncp6335d_info *dd;
+ const struct ncp6335d_platform_data *pdata;
+ struct regulator_config config = { };
+
+ if (client->dev.of_node)
+ pdata = ncp6335d_get_of_platform_data(client);
+ else
+ pdata = client->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&client->dev, "Platform data not specified\n");
+ return -EINVAL;
+ }
+
+ dd = devm_kzalloc(&client->dev, sizeof(*dd), GFP_KERNEL);
+ if (!dd)
+ return -ENOMEM;
+
+ if (client->dev.of_node) {
+ rc = ncp6335d_parse_dt(client, dd);
+ if (rc)
+ return rc;
+ } else {
+ dd->step_size = NCP6335D_STEP_VOLTAGE_UV;
+ dd->min_voltage = NCP6335D_MIN_VOLTAGE_UV;
+ dd->min_slew_ns = NCP6335D_MIN_SLEW_NS;
+ dd->max_slew_ns = NCP6335D_MAX_SLEW_NS;
+ }
+
+ dd->regmap = devm_regmap_init_i2c(client, &ncp6335d_regmap_config);
+ if (IS_ERR(dd->regmap)) {
+ dev_err(&client->dev, "Error allocating regmap\n");
+ return PTR_ERR(dd->regmap);
+ }
+
+ rc = ncp6335x_read(dd, REG_NCP6335D_PID, &val);
+ if (rc) {
+ dev_err(&client->dev, "Unable to identify NCP6335D, rc(%d)\n",
+ rc);
+ return rc;
+ }
+ dev_info(&client->dev, "Detected Regulator NCP6335D PID = %d\n", val);
+
+ dd->init_data = pdata->init_data;
+ dd->dev = &client->dev;
+ i2c_set_clientdata(client, dd);
+
+ rc = ncp6335d_init(client, dd, pdata);
+ if (rc) {
+ dev_err(&client->dev, "Unable to initialize the regulator\n");
+ return -EINVAL;
+ }
+
+ config.dev = &client->dev;
+ config.init_data = dd->init_data;
+ config.regmap = dd->regmap;
+ config.driver_data = dd;
+ config.of_node = client->dev.of_node;
+
+ dd->regulator = regulator_register(&rdesc, &config);
+
+ if (IS_ERR(dd->regulator)) {
+ dev_err(&client->dev, "Unable to register regulator rc(%ld)",
+ PTR_ERR(dd->regulator));
+
+ return PTR_ERR(dd->regulator);
+ }
+
+ dd->debug_root = debugfs_create_dir("ncp6335x", NULL);
+ if (!dd->debug_root)
+ dev_err(&client->dev, "Couldn't create debug dir\n");
+
+ if (dd->debug_root) {
+ struct dentry *ent;
+
+ ent = debugfs_create_x32("address", S_IFREG | S_IWUSR | S_IRUGO,
+ dd->debug_root,
+ &(dd->peek_poke_address));
+ if (!ent)
+ dev_err(&client->dev, "Couldn't create address debug file rc = %d\n",
+ rc);
+
+ ent = debugfs_create_file("data", S_IFREG | S_IWUSR | S_IRUGO,
+ dd->debug_root, dd,
+ &poke_poke_debug_ops);
+ if (!ent)
+ dev_err(&client->dev, "Couldn't create data debug file rc = %d\n",
+ rc);
+ }
+
+ return 0;
+}
+
+static int ncp6335d_regulator_remove(struct i2c_client *client)
+{
+ struct ncp6335d_info *dd = i2c_get_clientdata(client);
+
+ regulator_unregister(dd->regulator);
+
+ debugfs_remove_recursive(dd->debug_root);
+
+ return 0;
+}
+
+static const struct of_device_id ncp6335d_match_table[] = {
+ { .compatible = "onnn,ncp6335d-regulator", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ncp6335d_match_table);
+
+static const struct i2c_device_id ncp6335d_id[] = {
+ {"ncp6335d", -1},
+ { },
+};
+
+static struct i2c_driver ncp6335d_regulator_driver = {
+ .driver = {
+ .name = "ncp6335d-regulator",
+ .owner = THIS_MODULE,
+ .of_match_table = ncp6335d_match_table,
+ },
+ .probe = ncp6335d_regulator_probe,
+ .remove = ncp6335d_regulator_remove,
+ .id_table = ncp6335d_id,
+};
+
+/**
+ * ncp6335d_regulator_init() - initialized ncp6335d regulator driver
+ * This function registers the ncp6335d regulator platform driver.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init ncp6335d_regulator_init(void)
+{
+ static bool initialized;
+
+ if (initialized)
+ return 0;
+
+ initialized = true;
+
+ return i2c_add_driver(&ncp6335d_regulator_driver);
+}
+EXPORT_SYMBOL(ncp6335d_regulator_init);
+subsys_initcall(ncp6335d_regulator_init);
+
+static void __exit ncp6335d_regulator_exit(void)
+{
+ i2c_del_driver(&ncp6335d_regulator_driver);
+}
+module_exit(ncp6335d_regulator_exit);
+MODULE_DESCRIPTION("OnSemi-NCP6335D regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 69e0ebc78f6f..8c242bc7a702 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -691,6 +691,8 @@ static int icnss_qmi_pin_connect_result_ind(void *msg, unsigned int msg_len)
goto out;
}
+ memset(&ind_msg, 0, sizeof(ind_msg));
+
ind_desc.msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01;
ind_desc.max_msg_len = WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN;
ind_desc.ei_array = wlfw_pin_connect_result_ind_msg_v01_ei;
diff --git a/drivers/soc/qcom/memory_dump_v2.c b/drivers/soc/qcom/memory_dump_v2.c
index 092b1c1af44b..924c826208dd 100644
--- a/drivers/soc/qcom/memory_dump_v2.c
+++ b/drivers/soc/qcom/memory_dump_v2.c
@@ -95,7 +95,7 @@ int msm_dump_data_add_minidump(struct msm_dump_entry *entry)
data = (struct msm_dump_data *)(phys_to_virt(entry->addr));
if (!strcmp(data->name, "")) {
- pr_info("Entry name is NULL, Use ID %d for minidump\n",
+ pr_debug("Entry name is NULL, Use ID %d for minidump\n",
entry->id);
snprintf(md_entry.name, sizeof(md_entry.name), "KMDT0x%X",
entry->id);
@@ -133,7 +133,7 @@ int msm_dump_data_register(enum msm_dump_table_ids id,
dmac_flush_range(table, (void *)table + sizeof(struct msm_dump_table));
if (msm_dump_data_add_minidump(entry))
- pr_info("Failed to add entry in Minidump table\n");
+ pr_err("Failed to add entry in Minidump table\n");
return 0;
}
diff --git a/drivers/soc/qcom/msm_minidump.c b/drivers/soc/qcom/msm_minidump.c
index 1cb36bf98555..300233085161 100644
--- a/drivers/soc/qcom/msm_minidump.c
+++ b/drivers/soc/qcom/msm_minidump.c
@@ -62,24 +62,31 @@ struct md_table {
struct md_region entry[MAX_NUM_ENTRIES];
};
+/*
+ * md_elfhdr: Minidump table elf header
+ * @md_ehdr: elf main header
+ * @shdr: Section header
+ * @phdr: Program header
+ * @elf_offset: section offset in elf
+ * @strtable_idx: string table current index position
+ */
+struct md_elfhdr {
+ struct elfhdr *md_ehdr;
+ struct elf_shdr *shdr;
+ struct elf_phdr *phdr;
+ u64 elf_offset;
+ u64 strtable_idx;
+};
+
/* Protect elfheader and smem table from deferred calls contention */
static DEFINE_SPINLOCK(mdt_lock);
-static bool minidump_enabled;
-static struct md_table minidump_table;
+static struct md_table minidump_table;
+static struct md_elfhdr minidump_elfheader;
+
+bool minidump_enabled;
static unsigned int pendings;
static unsigned int region_idx = 1; /* First entry is ELF header*/
-/* ELF Header */
-static struct elfhdr *md_ehdr;
-/* ELF Program header */
-static struct elf_phdr *phdr;
-/* ELF Section header */
-static struct elf_shdr *shdr;
-/* Section offset in elf image */
-static u64 elf_offset;
-/* String table index, first byte must be '\0' */
-static unsigned int stringtable_idx = 1;
-
static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr)
{
return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff);
@@ -90,6 +97,16 @@ static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx)
return &elf_sheader(hdr)[idx];
}
+static inline struct elf_phdr *elf_pheader(struct elfhdr *hdr)
+{
+ return (struct elf_phdr *)((size_t)hdr + (size_t)hdr->e_phoff);
+}
+
+static inline struct elf_phdr *elf_program(struct elfhdr *hdr, int idx)
+{
+ return &elf_pheader(hdr)[idx];
+}
+
static inline char *elf_str_table(struct elfhdr *hdr)
{
if (hdr->e_shstrndx == SHN_UNDEF)
@@ -101,23 +118,24 @@ static inline char *elf_lookup_string(struct elfhdr *hdr, int offset)
{
char *strtab = elf_str_table(hdr);
- if ((strtab == NULL) | (stringtable_idx < offset))
+ if ((strtab == NULL) || (minidump_elfheader.strtable_idx < offset))
return NULL;
return strtab + offset;
}
static inline unsigned int set_section_name(const char *name)
{
- char *strtab = elf_str_table(md_ehdr);
+ char *strtab = elf_str_table(minidump_elfheader.md_ehdr);
+ int idx = minidump_elfheader.strtable_idx;
int ret = 0;
- if ((strtab == NULL) | (name == NULL))
+ if ((strtab == NULL) || (name == NULL))
return 0;
- ret = stringtable_idx;
- stringtable_idx += strlcpy((strtab + stringtable_idx),
- name, MAX_NAME_LENGTH);
- stringtable_idx += 1;
+ ret = idx;
+ idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH);
+ minidump_elfheader.strtable_idx = idx + 1;
+
return ret;
}
@@ -137,11 +155,9 @@ static inline bool md_check_name(const char *name)
static int md_update_smem_table(const struct md_region *entry)
{
struct md_smem_region *mdr;
-
- if (!minidump_enabled) {
- pr_info("Table in smem is not setup\n");
- return -ENODEV;
- }
+ struct elfhdr *hdr = minidump_elfheader.md_ehdr;
+ struct elf_shdr *shdr = elf_section(hdr, hdr->e_shnum++);
+ struct elf_phdr *phdr = elf_program(hdr, hdr->e_phnum++);
mdr = &minidump_table.region[region_idx++];
@@ -155,36 +171,21 @@ static int md_update_smem_table(const struct md_region *entry)
shdr->sh_addr = (elf_addr_t)entry->virt_addr;
shdr->sh_size = mdr->size;
shdr->sh_flags = SHF_WRITE;
- shdr->sh_offset = elf_offset;
+ shdr->sh_offset = minidump_elfheader.elf_offset;
shdr->sh_entsize = 0;
phdr->p_type = PT_LOAD;
- phdr->p_offset = elf_offset;
+ phdr->p_offset = minidump_elfheader.elf_offset;
phdr->p_vaddr = entry->virt_addr;
phdr->p_paddr = entry->phys_addr;
phdr->p_filesz = phdr->p_memsz = mdr->size;
phdr->p_flags = PF_R | PF_W;
- md_ehdr->e_shnum += 1;
- md_ehdr->e_phnum += 1;
- elf_offset += shdr->sh_size;
- shdr++;
- phdr++;
+ minidump_elfheader.elf_offset += shdr->sh_size;
return 0;
}
-bool msm_minidump_enabled(void)
-{
- bool ret;
-
- spin_lock(&mdt_lock);
- ret = minidump_enabled;
- spin_unlock(&mdt_lock);
- return ret;
-}
-EXPORT_SYMBOL(msm_minidump_enabled);
-
int msm_minidump_add_region(const struct md_region *entry)
{
u32 entries;
@@ -196,19 +197,19 @@ int msm_minidump_add_region(const struct md_region *entry)
if (((strlen(entry->name) > MAX_NAME_LENGTH) ||
md_check_name(entry->name)) && !entry->virt_addr) {
- pr_info("Invalid entry details\n");
+ pr_err("Invalid entry details\n");
return -EINVAL;
}
if (!IS_ALIGNED(entry->size, 4)) {
- pr_info("size should be 4 byte aligned\n");
+ pr_err("size should be 4 byte aligned\n");
return -EINVAL;
}
spin_lock(&mdt_lock);
entries = minidump_table.num_regions;
if (entries >= MAX_NUM_ENTRIES) {
- pr_info("Maximum entries reached.\n");
+ pr_err("Maximum entries reached.\n");
spin_unlock(&mdt_lock);
return -ENOMEM;
}
@@ -238,23 +239,32 @@ EXPORT_SYMBOL(msm_minidump_add_region);
static int msm_minidump_add_header(void)
{
struct md_smem_region *mdreg = &minidump_table.region[0];
- char *banner;
+ struct elfhdr *md_ehdr;
+ struct elf_shdr *shdr;
+ struct elf_phdr *phdr;
unsigned int strtbl_off, elfh_size, phdr_off;
+ char *banner;
+ /* Header buffer contains:
+ * elf header, MAX_NUM_ENTRIES+1 of section and program elf headers,
+ * string table section and linux banner.
+ */
elfh_size = sizeof(*md_ehdr) + MAX_STRTBL_SIZE + MAX_MEM_LENGTH +
((sizeof(*shdr) + sizeof(*phdr)) * (MAX_NUM_ENTRIES + 1));
- md_ehdr = kzalloc(elfh_size, GFP_KERNEL);
- if (!md_ehdr)
+ minidump_elfheader.md_ehdr = kzalloc(elfh_size, GFP_KERNEL);
+ if (!minidump_elfheader.md_ehdr)
return -ENOMEM;
strlcpy(mdreg->name, "KELF_HEADER", sizeof(mdreg->name));
- mdreg->address = virt_to_phys(md_ehdr);
+ mdreg->address = virt_to_phys(minidump_elfheader.md_ehdr);
mdreg->size = elfh_size;
- /* Section headers*/
- shdr = (struct elf_shdr *)(md_ehdr + 1);
- phdr = (struct elf_phdr *)(shdr + MAX_NUM_ENTRIES);
+ md_ehdr = minidump_elfheader.md_ehdr;
+ /* Assign section/program headers offset */
+ minidump_elfheader.shdr = shdr = (struct elf_shdr *)(md_ehdr + 1);
+ minidump_elfheader.phdr = phdr =
+ (struct elf_phdr *)(shdr + MAX_NUM_ENTRIES);
phdr_off = sizeof(*md_ehdr) + (sizeof(*shdr) * MAX_NUM_ENTRIES);
memcpy(md_ehdr->e_ident, ELFMAG, SELFMAG);
@@ -268,18 +278,19 @@ static int msm_minidump_add_header(void)
md_ehdr->e_ehsize = sizeof(*md_ehdr);
md_ehdr->e_phoff = phdr_off;
md_ehdr->e_phentsize = sizeof(*phdr);
- md_ehdr->e_phnum = 1;
md_ehdr->e_shoff = sizeof(*md_ehdr);
md_ehdr->e_shentsize = sizeof(*shdr);
- md_ehdr->e_shnum = 3; /* NULL, STR TABLE, Linux banner */
md_ehdr->e_shstrndx = 1;
- elf_offset = elfh_size;
+ minidump_elfheader.elf_offset = elfh_size;
+
+ /*
+ * First section header should be NULL,
+ * 2nd section is string table.
+ */
+ minidump_elfheader.strtable_idx = 1;
strtbl_off = sizeof(*md_ehdr) +
((sizeof(*phdr) + sizeof(*shdr)) * MAX_NUM_ENTRIES);
- /* First section header should be NULL
- * 2nd entry for string table
- */
shdr++;
shdr->sh_type = SHT_STRTAB;
shdr->sh_offset = (elf_addr_t)strtbl_off;
@@ -289,7 +300,15 @@ static int msm_minidump_add_header(void)
shdr->sh_name = set_section_name("STR_TBL");
shdr++;
- /* 3rd entry for linux banner */
+ /* 3rd section is for minidump_table VA, used by parsers */
+ shdr->sh_type = SHT_PROGBITS;
+ shdr->sh_entsize = 0;
+ shdr->sh_flags = 0;
+ shdr->sh_addr = (elf_addr_t)&minidump_table;
+ shdr->sh_name = set_section_name("minidump_table");
+ shdr++;
+
+ /* 4th section is linux banner */
banner = (char *)md_ehdr + strtbl_off + MAX_STRTBL_SIZE;
strlcpy(banner, linux_banner, MAX_MEM_LENGTH);
@@ -300,7 +319,6 @@ static int msm_minidump_add_header(void)
shdr->sh_entsize = 0;
shdr->sh_flags = SHF_WRITE;
shdr->sh_name = set_section_name("linux_banner");
- shdr++;
phdr->p_type = PT_LOAD;
phdr->p_offset = (elf_addr_t)(strtbl_off + MAX_STRTBL_SIZE);
@@ -309,8 +327,9 @@ static int msm_minidump_add_header(void)
phdr->p_filesz = phdr->p_memsz = strlen(linux_banner) + 1;
phdr->p_flags = PF_R | PF_W;
- md_ehdr->e_phnum += 1;
- phdr++;
+ /* Update headers count*/
+ md_ehdr->e_phnum = 1;
+ md_ehdr->e_shnum = 4;
return 0;
}
@@ -325,13 +344,13 @@ static int __init msm_minidump_init(void)
smem_table = smem_get_entry(SMEM_MINIDUMP_TABLE_ID, &size, 0,
SMEM_ANY_HOST_FLAG);
if (IS_ERR_OR_NULL(smem_table)) {
- pr_info("SMEM is not initialized.\n");
+ pr_err("SMEM is not initialized.\n");
return -ENODEV;
}
if ((smem_table->next_avail_offset + MAX_MEM_LENGTH) >
smem_table->smem_length) {
- pr_info("SMEM memory not available.\n");
+ pr_err("SMEM memory not available.\n");
return -ENOMEM;
}
@@ -353,10 +372,10 @@ static int __init msm_minidump_init(void)
for (i = 0; i < pendings; i++) {
mdr = &minidump_table.entry[i];
if (md_update_smem_table(mdr)) {
- pr_info("Unable to add entry %s to smem table\n",
+ pr_err("Unable to add entry %s to smem table\n",
mdr->name);
spin_unlock(&mdt_lock);
- return -ENODEV;
+ return -ENOENT;
}
}
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
index 4ba92436bd06..6e7d34ac9163 100644
--- a/drivers/soc/qcom/qbt1000.c
+++ b/drivers/soc/qcom/qbt1000.c
@@ -377,6 +377,12 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
drvdata = file->private_data;
+ if (IS_ERR(priv_arg)) {
+ dev_err(drvdata->dev, "%s: invalid user space pointer %lu\n",
+ __func__, arg);
+ return -EINVAL;
+ }
+
mutex_lock(&drvdata->mutex);
pr_debug("qbt1000_ioctl %d\n", cmd);
@@ -401,6 +407,13 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
goto end;
}
+ if (strcmp(app.name, FP_APP_NAME)) {
+ dev_err(drvdata->dev, "%s: Invalid app name\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
if (drvdata->app_handle) {
dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n",
__func__);
@@ -414,6 +427,7 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
pr_debug("app %s load before\n", app.name);
+ app.name[MAX_NAME_SIZE - 1] = '\0';
/* start the TZ app */
rc = qseecom_start_app(
@@ -427,7 +441,8 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
pr_err("App %s failed to set bw\n", app.name);
}
} else {
- pr_err("app %s failed to load\n", app.name);
+ dev_err(drvdata->dev, "%s: Fingerprint Trusted App failed to load\n",
+ __func__);
goto end;
}
@@ -447,9 +462,7 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
pr_debug("app %s load after\n", app.name);
- if (!strcmp(app.name, FP_APP_NAME))
- drvdata->fp_app_handle = drvdata->app_handle;
-
+ drvdata->fp_app_handle = drvdata->app_handle;
break;
}
case QBT1000_UNLOAD_APP:
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 58bf3d2f52bd..bfb7dd2d920d 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -3,7 +3,7 @@
* drivers/staging/android/ion/ion.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -122,8 +122,6 @@ struct ion_handle {
int id;
};
-static struct ion_device *ion_dev;
-
bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
{
return (buffer->flags & ION_FLAG_CACHED) &&
@@ -844,32 +842,45 @@ void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle)
}
EXPORT_SYMBOL(ion_unmap_kernel);
-static int ion_debug_client_show(struct seq_file *s, void *unused)
+static struct mutex debugfs_mutex;
+static struct rb_root *ion_root_client;
+static int is_client_alive(struct ion_client *client)
{
- struct ion_client *client = s->private;
- struct rb_node *n, *cnode;
- bool found = false;
-
- down_write(&ion_dev->lock);
+ struct rb_node *node;
+ struct ion_client *tmp;
+ struct ion_device *dev;
- if (!client || (client->dev != ion_dev)) {
- up_write(&ion_dev->lock);
- return -EINVAL;
- }
+ node = ion_root_client->rb_node;
+ dev = container_of(ion_root_client, struct ion_device, clients);
- cnode = rb_first(&ion_dev->clients);
- for ( ; cnode; cnode = rb_next(cnode)) {
- struct ion_client *c = rb_entry(cnode,
- struct ion_client, node);
- if (client == c) {
- found = true;
- break;
+ down_read(&dev->lock);
+ while (node) {
+ tmp = rb_entry(node, struct ion_client, node);
+ if (client < tmp) {
+ node = node->rb_left;
+ } else if (client > tmp) {
+ node = node->rb_right;
+ } else {
+ up_read(&dev->lock);
+ return 1;
}
}
- if (!found) {
- up_write(&ion_dev->lock);
- return -EINVAL;
+ up_read(&dev->lock);
+ return 0;
+}
+
+static int ion_debug_client_show(struct seq_file *s, void *unused)
+{
+ struct ion_client *client = s->private;
+ struct rb_node *n;
+
+ mutex_lock(&debugfs_mutex);
+ if (!is_client_alive(client)) {
+ seq_printf(s, "ion_client 0x%pK dead, can't dump its buffers\n",
+ client);
+ mutex_unlock(&debugfs_mutex);
+ return 0;
}
seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s\n",
@@ -890,7 +901,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused)
seq_printf(s, "\n");
}
mutex_unlock(&client->lock);
- up_write(&ion_dev->lock);
+ mutex_unlock(&debugfs_mutex);
return 0;
}
@@ -1021,7 +1032,7 @@ void ion_client_destroy(struct ion_client *client)
struct rb_node *n;
pr_debug("%s: %d\n", __func__, __LINE__);
- mutex_lock(&client->lock);
+ mutex_lock(&debugfs_mutex);
while ((n = rb_first(&client->handles))) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
node);
@@ -1029,7 +1040,6 @@ void ion_client_destroy(struct ion_client *client)
}
idr_destroy(&client->idr);
- mutex_unlock(&client->lock);
down_write(&dev->lock);
if (client->task)
@@ -1042,6 +1052,7 @@ void ion_client_destroy(struct ion_client *client)
kfree(client->display_name);
kfree(client->name);
kfree(client);
+ mutex_unlock(&debugfs_mutex);
}
EXPORT_SYMBOL(ion_client_destroy);
@@ -1838,7 +1849,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
seq_printf(s, "%16s %16s %16s\n", "client", "pid", "size");
seq_puts(s, "----------------------------------------------------\n");
- down_read(&dev->lock);
+ mutex_lock(&debugfs_mutex);
for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
struct ion_client *client = rb_entry(n, struct ion_client,
node);
@@ -1857,7 +1868,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
client->pid, size);
}
}
- up_read(&dev->lock);
+ mutex_unlock(&debugfs_mutex);
+
seq_puts(s, "----------------------------------------------------\n");
seq_puts(s, "orphaned allocations (info is from last known client):\n");
mutex_lock(&dev->buffer_lock);
@@ -2095,7 +2107,8 @@ debugfs_done:
init_rwsem(&idev->lock);
plist_head_init(&idev->heaps);
idev->clients = RB_ROOT;
- ion_dev = idev;
+ ion_root_client = &idev->clients;
+ mutex_init(&debugfs_mutex);
return idev;
}
EXPORT_SYMBOL(ion_device_create);
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index 80f9de907563..5cc80b80c82b 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -823,7 +823,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
struct tty_struct *tty = tty_port_tty_get(&port->port);
int i, ret;
- read_mem32((u32 *) &size, addr, 4);
+ size = __le32_to_cpu(readl(addr));
/* DBG1( "%d bytes port: %d", size, index); */
if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 343a32a4bad3..efaac5eb6592 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1170,26 +1170,17 @@ static int msm_startup(struct uart_port *port)
snprintf(msm_port->name, sizeof(msm_port->name),
"msm_serial%d", port->line);
- ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH,
- msm_port->name, port);
- if (unlikely(ret))
- return ret;
-
/*
* UART clk must be kept enabled to
* avoid losing received character
*/
ret = clk_prepare_enable(msm_port->clk);
- if (ret) {
- goto err_clk;
+ if (ret)
return ret;
- }
ret = clk_prepare_enable(msm_port->pclk);
- if (ret) {
+ if (ret)
goto err_pclk;
- return ret;
- }
msm_serial_set_mnd_regs(port);
@@ -1217,12 +1208,21 @@ static int msm_startup(struct uart_port *port)
msm_request_rx_dma(msm_port, msm_port->uart.mapbase);
}
+ ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH,
+ msm_port->name, port);
+ if (unlikely(ret))
+ goto err_irq;
+
return 0;
+err_irq:
+ if (msm_port->is_uartdm)
+ msm_release_dma(msm_port);
+
+ clk_disable_unprepare(msm_port->pclk);
+
err_pclk:
clk_disable_unprepare(msm_port->clk);
-err_clk:
- free_irq(port->irq, port);
return ret;
}
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index e394f123f918..ad9d6cc4e23f 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -3597,7 +3597,8 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA)
}
}
- power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_TYPE, &pval);
+ power_supply_get_property(mdwc->usb_psy,
+ POWER_SUPPLY_PROP_REAL_TYPE, &pval);
if (pval.intval != POWER_SUPPLY_TYPE_USB)
return 0;
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index c76ca5a94557..055c6203577a 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -2365,7 +2365,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
pd->vbus_present = val.intval;
ret = power_supply_get_property(pd->usb_psy,
- POWER_SUPPLY_PROP_TYPE, &val);
+ POWER_SUPPLY_PROP_REAL_TYPE, &val);
if (ret) {
usbpd_err(&pd->dev, "Unable to read USB TYPE: %d\n", ret);
return ret;
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 9982cb176ce8..830e2fd47642 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -562,8 +562,9 @@ static long vfio_pci_ioctl(void *device_data,
} else if (cmd == VFIO_DEVICE_SET_IRQS) {
struct vfio_irq_set hdr;
+ size_t size;
u8 *data = NULL;
- int ret = 0;
+ int max, ret = 0;
minsz = offsetofend(struct vfio_irq_set, count);
@@ -571,23 +572,31 @@ static long vfio_pci_ioctl(void *device_data,
return -EFAULT;
if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS ||
+ hdr.count >= (U32_MAX - hdr.start) ||
hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
VFIO_IRQ_SET_ACTION_TYPE_MASK))
return -EINVAL;
- if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
- size_t size;
- int max = vfio_pci_get_irq_count(vdev, hdr.index);
+ max = vfio_pci_get_irq_count(vdev, hdr.index);
+ if (hdr.start >= max || hdr.start + hdr.count > max)
+ return -EINVAL;
- if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
- size = sizeof(uint8_t);
- else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
- size = sizeof(int32_t);
- else
- return -EINVAL;
+ switch (hdr.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) {
+ case VFIO_IRQ_SET_DATA_NONE:
+ size = 0;
+ break;
+ case VFIO_IRQ_SET_DATA_BOOL:
+ size = sizeof(uint8_t);
+ break;
+ case VFIO_IRQ_SET_DATA_EVENTFD:
+ size = sizeof(int32_t);
+ break;
+ default:
+ return -EINVAL;
+ }
- if (hdr.argsz - minsz < hdr.count * size ||
- hdr.start >= max || hdr.start + hdr.count > max)
+ if (size) {
+ if (hdr.argsz - minsz < hdr.count * size)
return -EINVAL;
data = memdup_user((void __user *)(arg + minsz),
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 20e9a86d2dcf..5c8f767b6368 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -255,7 +255,7 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
if (!is_irq_none(vdev))
return -EINVAL;
- vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
+ vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
if (!vdev->ctx)
return -ENOMEM;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 09a34223c2a5..5e96a08b77ed 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -3035,6 +3035,12 @@ int mdss_mdp_layer_pre_commit_wfd(struct msm_fb_data_type *mfd,
wfd = mdp5_data->wfd;
output_layer = commit->output_layer;
+ if (output_layer->buffer.plane_count > MAX_PLANES) {
+ pr_err("Output buffer plane_count exceeds MAX_PLANES limit:%d\n",
+ output_layer->buffer.plane_count);
+ return -EINVAL;
+ }
+
data = mdss_mdp_wfd_add_data(wfd, output_layer);
if (IS_ERR_OR_NULL(data))
return PTR_ERR(data);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_wfd.c b/drivers/video/fbdev/msm/mdss_mdp_wfd.c
index 71a07f6b7d39..7868dc0f1999 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_wfd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_wfd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -322,6 +322,12 @@ int mdss_mdp_wb_import_data(struct device *device,
if (wfd_data->layer.flags & MDP_LAYER_SECURE_SESSION)
flags = MDP_SECURE_OVERLAY_SESSION;
+ if (buffer->plane_count > MAX_PLANES) {
+ pr_err("buffer plane_count exceeds MAX_PLANES limit:%d",
+ buffer->plane_count);
+ return -EINVAL;
+ }
+
memset(planes, 0, sizeof(planes));
for (i = 0; i < buffer->plane_count; i++) {
diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c
index fdd1c0153ce0..399a12e3dcc8 100644
--- a/drivers/video/fbdev/msm/mdss_rotator.c
+++ b/drivers/video/fbdev/msm/mdss_rotator.c
@@ -501,6 +501,12 @@ static int mdss_rotator_import_buffer(struct mdp_layer_buffer *buffer,
memset(planes, 0, sizeof(planes));
+ if (buffer->plane_count > MAX_PLANES) {
+ pr_err("buffer plane_count exceeds MAX_PLANES limit:%d\n",
+ buffer->plane_count);
+ return -EINVAL;
+ }
+
for (i = 0; i < buffer->plane_count; i++) {
planes[i].memory_id = buffer->planes[i].fd;
planes[i].offset = buffer->planes[i].offset;
@@ -2104,6 +2110,20 @@ struct mdss_rot_entry_container *mdss_rotator_req_init(
struct mdss_rot_entry_container *req;
int size, i;
+ /*
+ * Check input and output plane_count from each given item
+ * are within the MAX_PLANES limit
+ */
+ for (i = 0 ; i < count; i++) {
+ if ((items[i].input.plane_count > MAX_PLANES) ||
+ (items[i].output.plane_count > MAX_PLANES)) {
+ pr_err("Input/Output plane_count exceeds MAX_PLANES limit, input:%d, output:%d\n",
+ items[i].input.plane_count,
+ items[i].output.plane_count);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
size = sizeof(struct mdss_rot_entry_container);
size += sizeof(struct mdss_rot_entry) * count;
req = devm_kzalloc(&mgr->pdev->dev, size, GFP_KERNEL);