Merge "ASoC: wcd9320: use hwdep nodes to get calibration"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index bbc9f08..541b50a 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -100,6 +100,12 @@
- qcom,efuse-temperature-map: Truth table of efuse value temperature value pair for
different parts. if qcom,default temp is defined, then it can
specify only pairs which deviate from default temperature.
+- qcom,therm-reset-temp: Degree above which the KTM will initiate a secure watchdog reset.
+ When this property is defined, KTM will monitor all the tsens from
+ boot time and will initiate a secure watchdog reset if any of the
+ tsens temperature reaches this threshold. This reset helps in
+ generating more informative crash dumps opposed to the crash dump
+ generated by the hardware reset.
Optional child nodes
- qti,pmic-opt-curr-temp: Threshold temperature for requesting optimum current (request
@@ -139,6 +145,7 @@
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
qcom,freq-control-mask = <0xf>
+ qcom,therm-reset-temp = <115>;
qcom,core-limit-temp = <90>;
qcom,core-temp-hysteresis = <10>;
qcom,core-control-mask = <7>;
diff --git a/Documentation/devicetree/bindings/platform/msm/avtimer.txt b/Documentation/devicetree/bindings/platform/msm/avtimer.txt
index 86c9b67..2d89262 100644
--- a/Documentation/devicetree/bindings/platform/msm/avtimer.txt
+++ b/Documentation/devicetree/bindings/platform/msm/avtimer.txt
@@ -12,10 +12,15 @@
"avtimer_msb_addr" : AVtimer msb physical address
- compatible : Must be "qcom,avtimer"
+Optional properties:
+- clk_div : For 8916 the clk is at 27MHz and hence ticks are to be
+ divided by 27 to achive the msec value.
+
Example:
qcom,avtimer {
compatible = "qcom,avtimer";
reg = <0xfe053008 0x4>,
<0xfe05300c 0x4>;
reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+ qcom,clk_div = <27>;
};
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index b7413cb..87fb3e9 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -360,6 +360,8 @@
[stack:1001] = the stack of the thread with tid 1001
[vdso] = the "virtual dynamic shared object",
the kernel system call handler
+ [anon:<name>] = an anonymous mapping that has been
+ named by userspace
or if empty, the mapping is anonymous.
@@ -409,6 +411,7 @@
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 374 kB
+Name: name from userspace
The first of these lines shows the same information as is displayed for the
mapping in /proc/PID/maps. The remaining lines show the size of the mapping
@@ -424,6 +427,9 @@
"Swap" shows how much would-be-anonymous memory is also used, but out on
swap.
+The "Name" field will only be present on a mapping that has been named by
+userspace, and will show the name passed in by userspace.
+
This file is only present if the CONFIG_MMU kernel configuration option is
enabled.
diff --git a/arch/arm/boot/compressed/libfdt_env.h b/arch/arm/boot/compressed/libfdt_env.h
index 1f4e718..799b575 100644
--- a/arch/arm/boot/compressed/libfdt_env.h
+++ b/arch/arm/boot/compressed/libfdt_env.h
@@ -1,6 +1,7 @@
#ifndef _ARM_LIBFDT_ENV_H
#define _ARM_LIBFDT_ENV_H
+#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <asm/byteorder.h>
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 495117f..f8c9b46 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1987,6 +1987,7 @@
gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>;
qcom,has-48mhz-xo;
qcom,has-pronto-hw;
+ qcom,wcnss-pm = <11 21 1200 1 1>;
};
qcom,ocmem@fdd00000 {
@@ -2263,6 +2264,7 @@
qcom,poll-ms = <250>;
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
+ qcom,therm-reset-temp = <115>;
qcom,freq-step = <2>;
qcom,freq-control-mask = <0xf>;
qcom,core-limit-temp = <80>;
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 525def5..ae3e19d 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -527,3 +527,4 @@
CONFIG_MOBICORE_API=m
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_MSM_RDBG=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 6874b28..b239bcb 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -504,3 +504,4 @@
CONFIG_MSM_RDBG=m
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 7c299d7..2711278 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -459,6 +459,7 @@
CONFIG_QPNP_CLKDIV=y
CONFIG_QPNP_REVID=y
CONFIG_QPNP_COINCELL=y
+CONFIG_MSM_AVTIMER=y
CONFIG_MSM_IOMMU_V1=y
CONFIG_IOMMU_PGTABLES_L2=y
CONFIG_MSM_IOMMU_VBIF_CHECK=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index e8a1cde..52f3598 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -483,6 +483,7 @@
CONFIG_QPNP_CLKDIV=y
CONFIG_QPNP_REVID=y
CONFIG_QPNP_COINCELL=y
+CONFIG_MSM_AVTIMER=y
CONFIG_MSM_IOMMU_V1=y
CONFIG_MSM_IOMMU_PMON=y
CONFIG_IOMMU_PGTABLES_L2=y
@@ -568,3 +569,4 @@
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
CONFIG_MSM_RDBG=m
CONFIG_MSM_AVTIMER=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 9f4acca..04eb5ee 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -168,4 +168,5 @@
int apr_set_q6_state(enum apr_subsys_state state);
void apr_set_subsys_state(void);
const char *apr_get_lpass_subsys_name(void);
+extern int is_modem_up;
#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 937eeda..d3119bc 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -41,6 +41,7 @@
static wait_queue_head_t dsp_wait;
static wait_queue_head_t modem_wait;
+int is_modem_up = 0;
/* Subsystem restart: QDSP6 data, functions */
static struct workqueue_struct *apr_reset_workqueue;
static void apr_reset_deregister(struct work_struct *work);
@@ -646,6 +647,7 @@
if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
APR_SUBSYS_DOWN)
wake_up(&modem_wait);
+ is_modem_up = 1;
pr_debug("M-Notify: Bootup Completed\n");
break;
default:
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v2.c b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
index fbb8713..c4d934e 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr_v2.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
@@ -53,7 +53,12 @@
pr_debug("%s: adsp Up\n", __func__);
} else if ((dest_id == APR_DEST_MODEM) &&
(apr_get_modem_state() == APR_SUBSYS_DOWN)) {
- pr_debug("%s: Wait for modem to bootup\n", __func__);
+ if (is_modem_up) {
+ pr_err("%s: modem shutdown \
+ due to SSR, return", __func__);
+ return NULL;
+ }
+ pr_debug("%s: Wait for modem to bootup\n", __func__);
rc = apr_wait_for_device_up(dest_id);
if (rc == 0) {
pr_err("%s: Modem is not Up\n", __func__);
diff --git a/drivers/base/sync.c b/drivers/base/sync.c
index 645a698..7e1ecf3 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -34,7 +34,6 @@
static void sync_fence_signal_pt(struct sync_pt *pt);
static int _sync_pt_has_signaled(struct sync_pt *pt);
static void sync_fence_free(struct kref *kref);
-static void sync_dump(struct sync_fence *fence);
static LIST_HEAD(sync_timeline_list_head);
static DEFINE_SPINLOCK(sync_timeline_list_lock);
@@ -586,6 +585,74 @@
return fence->status != 0;
}
+static const char *sync_status_str(int status)
+{
+ if (status > 0)
+ return "signaled";
+ else if (status == 0)
+ return "active";
+ else
+ return "error";
+}
+
+static void sync_pt_log(struct sync_pt *pt)
+{
+ int status = pt->status;
+ pr_cont(" %s_pt %s",
+ pt->parent->name,
+ sync_status_str(status));
+
+ if (pt->status) {
+ struct timeval tv = ktime_to_timeval(pt->timestamp);
+ pr_cont("@%ld.%06ld", tv.tv_sec, tv.tv_usec);
+ }
+
+ if (pt->parent->ops->timeline_value_str &&
+ pt->parent->ops->pt_value_str) {
+ char value[64];
+ pt->parent->ops->pt_value_str(pt, value, sizeof(value));
+ pr_cont(": %s", value);
+ pt->parent->ops->timeline_value_str(pt->parent, value,
+ sizeof(value));
+ pr_cont(" / %s", value);
+ }
+
+ pr_cont("\n");
+
+ /* Show additional details for active fences */
+ if (pt->status == 0 && pt->parent->ops->pt_log)
+ pt->parent->ops->pt_log(pt);
+}
+
+void sync_fence_log(struct sync_fence *fence)
+{
+ struct list_head *pos;
+ unsigned long flags;
+
+ pr_info("[%p] %s: %s\n", fence, fence->name,
+ sync_status_str(fence->status));
+
+ pr_info("waiters:\n");
+
+ spin_lock_irqsave(&fence->waiter_list_lock, flags);
+ list_for_each(pos, &fence->waiter_list_head) {
+ struct sync_fence_waiter *waiter =
+ container_of(pos, struct sync_fence_waiter,
+ waiter_list);
+
+ pr_info(" %pF\n", waiter->callback);
+ }
+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
+
+ pr_info("syncpoints:\n");
+ list_for_each(pos, &fence->pt_list_head) {
+ struct sync_pt *pt =
+ container_of(pos, struct sync_pt, pt_list);
+ sync_pt_log(pt);
+ }
+}
+EXPORT_SYMBOL(sync_fence_log);
+
int sync_fence_wait(struct sync_fence *fence, long timeout)
{
int err = 0;
@@ -611,7 +678,7 @@
if (fence->status < 0) {
pr_info("fence error %d on [%p]\n", fence->status, fence);
- sync_dump(fence);
+ sync_fence_log(fence);
return fence->status;
}
@@ -619,7 +686,7 @@
if (timeout > 0) {
pr_info("fence timeout on [%p] after %dms\n", fence,
jiffies_to_msecs(timeout));
- sync_dump(fence);
+ sync_fence_log(fence);
}
return -ETIME;
}
@@ -841,16 +908,6 @@
}
#ifdef CONFIG_DEBUG_FS
-static const char *sync_status_str(int status)
-{
- if (status > 0)
- return "signaled";
- else if (status == 0)
- return "active";
- else
- return "error";
-}
-
static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence)
{
int status = pt->status;
@@ -983,35 +1040,4 @@
return 0;
}
late_initcall(sync_debugfs_init);
-
-#define DUMP_CHUNK 256
-static char sync_dump_buf[64 * 1024];
-static void sync_dump(struct sync_fence *fence)
-{
- struct seq_file s = {
- .buf = sync_dump_buf,
- .size = sizeof(sync_dump_buf) - 1,
- };
- int i;
-
- seq_printf(&s, "fence:\n--------------\n");
- sync_print_fence(&s, fence);
- seq_printf(&s, "\n");
-
- for (i = 0; i < s.count; i += DUMP_CHUNK) {
- if ((s.count - i) > DUMP_CHUNK) {
- char c = s.buf[i + DUMP_CHUNK];
- s.buf[i + DUMP_CHUNK] = 0;
- pr_cont("%s", s.buf + i);
- s.buf[i + DUMP_CHUNK] = c;
- } else {
- s.buf[s.count] = 0;
- pr_cont("%s", s.buf + i);
- }
- }
-}
-#else
-static void sync_dump(struct sync_fence *fence)
-{
-}
#endif
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 009ab57..871864f 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -466,11 +466,15 @@
spin_unlock(&clst->hlock);
}
-static int get_page_list(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
- struct fastrpc_buf *ibuf, struct fastrpc_buf *obuf)
+static int get_page_list(uint32_t kernel, struct smq_invoke_ctx *ctx)
{
+ struct fastrpc_apps *me = &gfa;
struct smq_phy_page *pgstart, *pages;
struct smq_invoke_buf *list;
+ struct fastrpc_buf *ibuf = &ctx->dev->buf;
+ struct fastrpc_buf *obuf = &ctx->obuf;
+ remote_arg_t *pra = ctx->pra;
+ uint32_t sc = ctx->sc;
int i, rlen, err = 0;
int inbufs = REMOTE_SCALARS_INBUFS(sc);
int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
@@ -506,11 +510,21 @@
continue;
buf = pra[i].buf.pv;
num = buf_num_pages(buf, len);
- if (!kernel)
- list[i].num = buf_get_pages(buf, len, num,
- i >= inbufs, pages, rlen / sizeof(*pages));
- else
- list[i].num = 0;
+ if (!kernel) {
+ if (me->smmu.enabled) {
+ VERIFY(err, 0 != access_ok(i >= inbufs ?
+ VERIFY_WRITE : VERIFY_READ,
+ (void __user *)buf, len));
+ if (err)
+ goto bail;
+ if (ctx->fds && (ctx->fds[i] >= 0))
+ list[i].num = 1;
+ } else {
+ list[i].num = buf_get_pages(buf, len, num,
+ i >= inbufs, pages,
+ rlen / sizeof(*pages));
+ }
+ }
VERIFY(err, list[i].num >= 0);
if (err)
goto bail;
@@ -539,20 +553,25 @@
return err;
}
-static int get_args(uint32_t kernel, uint32_t sc, remote_arg_t *pra,
- remote_arg_t *rpra, remote_arg_t *upra,
- struct fastrpc_buf *ibuf, struct fastrpc_buf **abufs,
- int *nbufs, int *fds, struct ion_handle **handles)
+static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
+ remote_arg_t *upra)
{
struct fastrpc_apps *me = &gfa;
struct smq_invoke_buf *list;
- struct fastrpc_buf *pbuf = ibuf, *obufs = 0;
+ struct fastrpc_buf *pbuf = &ctx->obuf, *obufs = 0;
struct smq_phy_page *pages;
+ struct vm_area_struct *vma;
+ struct ion_handle **handles = ctx->handles;
void *args;
+ remote_arg_t *pra = ctx->pra;
+ remote_arg_t *rpra = ctx->rpra;
+ uint32_t sc = ctx->sc, start;
int i, rlen, size, used, inh, bufs = 0, err = 0;
int inbufs = REMOTE_SCALARS_INBUFS(sc);
int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
- unsigned long iova, len;
+ int *fds = ctx->fds, idx, num;
+ unsigned long len;
+ ion_phys_addr_t iova;
list = smq_invoke_buf_start(rpra, sc);
pages = smq_phy_page_start(sc, list);
@@ -565,7 +584,10 @@
if (!rpra[i].buf.len)
continue;
if (me->smmu.enabled && fds && (fds[i] >= 0)) {
+ start = buf_page_start(pra[i].buf.pv);
len = buf_page_size(pra[i].buf.len);
+ num = buf_num_pages(pra[i].buf.pv, pra[i].buf.len);
+ idx = list[i].pgidx;
handles[i] = ion_import_dma_buf(me->iclient, fds[i]);
VERIFY(err, 0 == IS_ERR_OR_NULL(handles[i]));
if (err)
@@ -575,10 +597,15 @@
&iova, &len, 0, 0));
if (err)
goto bail;
+ VERIFY(err, (num << PAGE_SHIFT) <= len);
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
+ if (err)
+ goto bail;
rpra[i].buf.pv = pra[i].buf.pv;
- list[i].num = 1;
- pages[list[i].pgidx].addr = iova;
- pages[list[i].pgidx].size = len;
+ pages[idx].addr = iova + (start - vma->vm_start);
+ pages[idx].size = num << PAGE_SHIFT;
continue;
} else if (list[i].num) {
rpra[i].buf.pv = pra[i].buf.pv;
@@ -642,8 +669,8 @@
}
dmac_flush_range(rpra, (char *)rpra + used);
bail:
- *abufs = obufs;
- *nbufs = bufs;
+ ctx->abufs = obufs;
+ ctx->nbufs = bufs;
return err;
}
@@ -950,14 +977,11 @@
VERIFY(err, 0 == get_dev(me, &ctx->dev));
if (err)
goto bail;
- VERIFY(err, 0 == get_page_list(kernel, ctx->sc, ctx->pra,
- &ctx->dev->buf, &ctx->obuf));
+ VERIFY(err, 0 == get_page_list(kernel, ctx));
if (err)
goto bail;
ctx->rpra = (remote_arg_t *)ctx->obuf.virt;
- VERIFY(err, 0 == get_args(kernel, ctx->sc, ctx->pra, ctx->rpra,
- invoke->pra, &ctx->obuf, &ctx->abufs,
- &ctx->nbufs, ctx->fds, ctx->handles));
+ VERIFY(err, 0 == get_args(kernel, ctx, invoke->pra));
if (err)
goto bail;
}
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 9c767c6..edf0216 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -473,12 +473,12 @@
*in_busy_ptr = 1;
err = diag_device_write(buf, smd_info->peripheral,
write_ptr_modem);
+ spin_unlock_irqrestore(&smd_info->in_busy_lock, flags);
if (err) {
pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
__func__, err);
goto err;
}
- spin_unlock_irqrestore(&smd_info->in_busy_lock, flags);
}
} else {
/* The data is raw and needs to be hdlc encoded */
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index a4bd163..5600c11 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -3547,6 +3547,7 @@
.drawctxt_create = adreno_drawctxt_create,
.drawctxt_detach = adreno_drawctxt_detach,
.drawctxt_destroy = adreno_drawctxt_destroy,
+ .drawctxt_dump = adreno_drawctxt_dump,
.setproperty = adreno_setproperty,
.postmortem_dump = adreno_dump,
.drawctxt_sched = adreno_drawctxt_sched,
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 5f80fcf..bcab791 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -157,7 +157,7 @@
struct kgsl_cmdbatch *cmdbatch = NULL;
int pending;
- mutex_lock(&drawctxt->mutex);
+ spin_lock(&drawctxt->lock);
if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head];
@@ -202,7 +202,7 @@
}
done:
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
return cmdbatch;
}
@@ -221,11 +221,11 @@
struct adreno_context *drawctxt, struct kgsl_cmdbatch *cmdbatch)
{
unsigned int prev;
- mutex_lock(&drawctxt->mutex);
+ spin_lock(&drawctxt->lock);
if (kgsl_context_detached(&drawctxt->base) ||
drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
/* get rid of this cmdbatch since the context is bad */
kgsl_cmdbatch_destroy(cmdbatch);
return -EINVAL;
@@ -247,7 +247,7 @@
/* Reset the command queue head to reflect the newly requeued change */
drawctxt->cmdqueue_head = prev;
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
return 0;
}
@@ -378,6 +378,7 @@
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
int count = 0;
int requeued = 0;
+ unsigned int timestamp;
/*
* Each context can send a specific number of command batches per cycle
@@ -417,6 +418,8 @@
continue;
}
+ timestamp = cmdbatch->timestamp;
+
ret = sendcmd(adreno_dev, cmdbatch);
/*
@@ -432,6 +435,8 @@
break;
}
+ drawctxt->submitted_timestamp = timestamp;
+
count++;
}
@@ -568,7 +573,7 @@
{
int ret;
- mutex_lock(&drawctxt->mutex);
+ spin_lock(&drawctxt->lock);
/*
* Wake up if there is room in the context or if the whole thing got
@@ -580,7 +585,7 @@
else
ret = drawctxt->queued < _context_cmdqueue_size ? 1 : 0;
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
return ret;
}
@@ -635,10 +640,10 @@
{
int ret;
- mutex_lock(&drawctxt->mutex);
+ spin_lock(&drawctxt->lock);
if (kgsl_context_detached(&drawctxt->base)) {
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
return -EINVAL;
}
@@ -679,17 +684,17 @@
while (drawctxt->queued >= _context_cmdqueue_size) {
trace_adreno_drawctxt_sleep(drawctxt);
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
ret = wait_event_interruptible_timeout(drawctxt->wq,
_check_context_queue(drawctxt),
msecs_to_jiffies(_context_queue_wait));
- mutex_lock(&drawctxt->mutex);
+ spin_lock(&drawctxt->lock);
trace_adreno_drawctxt_wake(drawctxt);
if (ret <= 0) {
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
return (ret == 0) ? -ETIMEDOUT : (int) ret;
}
}
@@ -699,22 +704,26 @@
*/
if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
return -EDEADLK;
}
if (kgsl_context_detached(&drawctxt->base)) {
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
return -EINVAL;
}
ret = get_timestamp(drawctxt, cmdbatch, timestamp);
if (ret) {
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
return ret;
}
cmdbatch->timestamp = *timestamp;
+ /* SYNC commands have timestamp 0 and will get optimized out anyway */
+ if (!(cmdbatch->flags & KGSL_CONTEXT_SYNC))
+ drawctxt->queued_timestamp = *timestamp;
+
/*
* Set the fault tolerance policy for the command batch - assuming the
* context hasn't disabled FT use the current device policy
@@ -734,7 +743,7 @@
trace_adreno_cmdbatch_queued(cmdbatch, drawctxt->queued);
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
/* Add the context to the dispatcher pending list */
dispatcher_queue_context(adreno_dev, drawctxt);
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 0778cac..df9d6ec 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -179,6 +179,56 @@
}
/**
+ * adreno_drawctxt_dump() - dump information about a draw context
+ * @device: KGSL device that owns the context
+ * @context: KGSL context to dump information about
+ *
+ * Dump specific information about the context to the kernel log. Used for
+ * fence timeout callbacks
+ */
+void adreno_drawctxt_dump(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+ unsigned int queue, start, retire;
+ struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
+
+ queue = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED);
+ start = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_CONSUMED);
+ retire = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
+
+ spin_lock(&drawctxt->lock);
+ dev_err(device->dev,
+ " context[%d]: queue=%d, submit=%d, start=%d, retire=%d\n",
+ context->id, queue, drawctxt->submitted_timestamp,
+ start, retire);
+
+ if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
+ struct kgsl_cmdbatch *cmdbatch =
+ drawctxt->cmdqueue[drawctxt->cmdqueue_head];
+
+ if (test_bit(CMDBATCH_FLAG_FENCE_LOG, &cmdbatch->priv)) {
+ dev_err(device->dev,
+ " possible deadlock. Context %d might be blocked for itself\n",
+ context->id);
+ goto done;
+ }
+
+ spin_lock(&cmdbatch->lock);
+
+ if (!list_empty(&cmdbatch->synclist)) {
+ dev_err(device->dev,
+ " context[%d] (ts=%d) Active sync points:\n",
+ context->id, cmdbatch->timestamp);
+
+ kgsl_dump_syncpoints(device, cmdbatch);
+ }
+ spin_unlock(&cmdbatch->lock);
+ }
+done:
+ spin_unlock(&drawctxt->lock);
+}
+
+/**
* adreno_drawctxt_wait() - sleep until a timestamp expires
* @adreno_dev: pointer to the adreno_device struct
* @drawctxt: Pointer to the draw context to sleep for
@@ -317,14 +367,10 @@
kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
if (timeout) {
- ret = (int) wait_event_timeout(drawctxt->waiting,
+ if (0 == (int) wait_event_timeout(drawctxt->waiting,
_check_global_timestamp(device, drawctxt, timestamp),
- msecs_to_jiffies(timeout));
-
- if (ret == 0)
+ msecs_to_jiffies(timeout)))
ret = -ETIMEDOUT;
- else if (ret > 0)
- ret = 0;
} else {
wait_event(drawctxt->waiting,
_check_global_timestamp(device, drawctxt, timestamp));
@@ -355,11 +401,9 @@
trace_adreno_drawctxt_invalidate(drawctxt);
+ spin_lock(&drawctxt->lock);
drawctxt->state = ADRENO_CONTEXT_STATE_INVALID;
- /* Clear the pending queue */
- mutex_lock(&drawctxt->mutex);
-
/*
* set the timestamp to the last value since the context is invalidated
* and we want the pending events for this context to go away
@@ -379,18 +423,13 @@
drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) %
ADRENO_CONTEXT_CMDQUEUE_SIZE;
- mutex_unlock(&drawctxt->mutex);
-
- kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
kgsl_cancel_events_timestamp(device, context,
cmdbatch->timestamp);
- kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
kgsl_cmdbatch_destroy(cmdbatch);
- mutex_lock(&drawctxt->mutex);
}
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
/* Give the bad news to everybody waiting around */
wake_up_all(&drawctxt->waiting);
@@ -439,7 +478,7 @@
drawctxt->base.flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
drawctxt->type = (drawctxt->base.flags & KGSL_CONTEXT_TYPE_MASK)
>> KGSL_CONTEXT_TYPE_SHIFT;
- mutex_init(&drawctxt->mutex);
+ spin_lock_init(&drawctxt->lock);
init_waitqueue_head(&drawctxt->wq);
init_waitqueue_head(&drawctxt->waiting);
@@ -518,7 +557,7 @@
if (adreno_dev->drawctxt_active == drawctxt)
adreno_drawctxt_switch(adreno_dev, NULL, 0);
- mutex_lock(&drawctxt->mutex);
+ spin_lock(&drawctxt->lock);
while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
struct kgsl_cmdbatch *cmdbatch =
@@ -527,7 +566,7 @@
drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) %
ADRENO_CONTEXT_CMDQUEUE_SIZE;
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
/*
* If the context is deteached while we are waiting for
@@ -543,10 +582,10 @@
*/
kgsl_cmdbatch_destroy(cmdbatch);
- mutex_lock(&drawctxt->mutex);
+ spin_lock(&drawctxt->lock);
}
- mutex_unlock(&drawctxt->mutex);
+ spin_unlock(&drawctxt->lock);
/*
* internal_timestamp is set in adreno_ringbuffer_addcmds,
* which holds the device mutex. The entire context destroy
@@ -555,9 +594,14 @@
*/
BUG_ON(!mutex_is_locked(&device->mutex));
- /* Wait for the last global timestamp to pass before continuing */
+ /* Wait for the last global timestamp to pass before continuing.
+ * The maxumum wait time is 30s, some large IB's can take longer
+ * than 10s and if hang happens then the time for the context's
+ * commands to retire will be greater than 10s. 30s should be sufficient
+ * time to wait for the commands even if a hang happens.
+ */
ret = adreno_drawctxt_wait_global(adreno_dev, context,
- drawctxt->internal_timestamp, 10 * 1000);
+ drawctxt->internal_timestamp, 30 * 1000);
/*
* If the wait for global fails then nothing after this point is likely
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 8543f39..e4de042 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -131,6 +131,8 @@
* @queued: Number of commands queued in the cmdqueue
* @ops: Context switch functions for this context.
* @fault_policy: GFT fault policy set in cmdbatch_skip_cmd();
+ * @queued_timestamp: The last timestamp that was queued on this context
+ * @submitted_timestamp: The last timestamp that was submitted for this context
*/
struct adreno_context {
struct kgsl_context base;
@@ -139,7 +141,7 @@
int state;
unsigned long priv;
unsigned int type;
- struct mutex mutex;
+ spinlock_t lock;
struct kgsl_memdesc gpustate;
unsigned int reg_restore[3];
unsigned int shader_save[3];
@@ -179,6 +181,8 @@
const struct adreno_context_ops *ops;
unsigned int fault_policy;
+ unsigned int queued_timestamp;
+ unsigned int submitted_timestamp;
};
/**
@@ -288,4 +292,7 @@
shadow->size = shadow->pitch * shadow->height * 4;
}
+void adreno_drawctxt_dump(struct kgsl_device *device,
+ struct kgsl_context *context);
+
#endif /* __ADRENO_DRAWCTXT_H */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5a33d9d..9adede8 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -471,6 +471,33 @@
}
/**
+ * kgsl_context_dump() - dump information about a draw context
+ * @device: KGSL device that owns the context
+ * @context: KGSL context to dump information about
+ *
+ * Dump specific information about the context to the kernel log. Used for
+ * fence timeout callbacks
+ */
+void kgsl_context_dump(struct kgsl_context *context)
+{
+ struct kgsl_device *device;
+
+ if (_kgsl_context_get(context) == 0)
+ return;
+
+ device = context->device;
+
+ if (kgsl_context_detached(context)) {
+ dev_err(device->dev, " context[%d]: context detached\n",
+ context->id);
+ } else if (device->ftbl->drawctxt_dump != NULL)
+ device->ftbl->drawctxt_dump(device, context);
+
+ kgsl_context_put(context);
+}
+EXPORT_SYMBOL(kgsl_context_dump);
+
+/**
* kgsl_context_init() - helper to initialize kgsl_context members
* @dev_priv: the owner of the context
* @context: the newly created context struct, should be allocated by
@@ -1554,22 +1581,11 @@
struct kref refcount;
};
-static void _kgsl_cmdbatch_timer(unsigned long data)
+void kgsl_dump_syncpoints(struct kgsl_device *device,
+ struct kgsl_cmdbatch *cmdbatch)
{
- struct kgsl_cmdbatch *cmdbatch = (struct kgsl_cmdbatch *) data;
struct kgsl_cmdbatch_sync_event *event;
- if (cmdbatch == NULL || cmdbatch->context == NULL)
- return;
-
- spin_lock(&cmdbatch->lock);
- if (list_empty(&cmdbatch->synclist))
- goto done;
-
- pr_err("kgsl: possible gpu syncpoint deadlock for context %d timestamp %d\n",
- cmdbatch->context->id, cmdbatch->timestamp);
- pr_err(" Active sync points:\n");
-
/* Print all the pending sync objects */
list_for_each_entry(event, &cmdbatch->synclist, node) {
@@ -1580,15 +1596,67 @@
retired = kgsl_readtimestamp(event->device,
event->context, KGSL_TIMESTAMP_RETIRED);
- pr_err(" [timestamp] context %d timestamp %d (retired %d)\n",
+ dev_err(device->dev,
+ " [timestamp] context %d timestamp %d (retired %d)\n",
event->context->id, event->timestamp,
retired);
break;
}
case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
- pr_err(" fence: [%p] %s\n", event->handle,
- (event->handle && event->handle->fence)
- ? event->handle->fence->name : "NULL");
+ if (event->handle)
+ dev_err(device->dev, " fence: [%p] %s\n",
+ event->handle->fence,
+ event->handle->name);
+ else
+ dev_err(device->dev, " fence: invalid\n");
+ break;
+ }
+ }
+}
+
+static void _kgsl_cmdbatch_timer(unsigned long data)
+{
+ struct kgsl_device *device;
+ struct kgsl_cmdbatch *cmdbatch = (struct kgsl_cmdbatch *) data;
+ struct kgsl_cmdbatch_sync_event *event;
+
+ if (cmdbatch == NULL || cmdbatch->context == NULL)
+ return;
+
+ spin_lock(&cmdbatch->lock);
+ if (list_empty(&cmdbatch->synclist))
+ goto done;
+
+ device = cmdbatch->context->device;
+
+ dev_err(device->dev,
+ "kgsl: possible gpu syncpoint deadlock for context %d timestamp %d\n",
+ cmdbatch->context->id, cmdbatch->timestamp);
+ dev_err(device->dev, " Active sync points:\n");
+
+ /* Print all the pending sync objects */
+ list_for_each_entry(event, &cmdbatch->synclist, node) {
+ switch (event->type) {
+ case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP: {
+ unsigned int retired;
+
+ retired = kgsl_readtimestamp(event->device,
+ event->context, KGSL_TIMESTAMP_RETIRED);
+
+ dev_err(device->dev,
+ " [timestamp] context %d timestamp %d (retired %d)\n",
+ event->context->id, event->timestamp, retired);
+ break;
+ }
+ case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
+ if (event->handle && event->handle->fence) {
+ set_bit(CMDBATCH_FLAG_FENCE_LOG,
+ &cmdbatch->priv);
+ kgsl_sync_fence_log(event->handle->fence);
+ clear_bit(CMDBATCH_FLAG_FENCE_LOG,
+ &cmdbatch->priv);
+ } else
+ dev_err(device->dev, " fence: invalid\n");
break;
}
}
@@ -1698,6 +1766,9 @@
{
struct kgsl_cmdbatch_sync_event *event = priv;
+ trace_syncpoint_timestamp_expire(event->cmdbatch,
+ event->context, event->timestamp);
+
kgsl_cmdbatch_sync_expire(device, event);
kgsl_context_put(event->context);
/* Put events that have signaled */
@@ -1736,13 +1807,16 @@
list_for_each_entry_safe(event, tmp, &cancel_synclist, node) {
if (event->type == KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP) {
+ struct kgsl_device *device = cmdbatch->device;
/*
* Timestamp events are guaranteed to signal
* when canceled
*/
- kgsl_cancel_event(cmdbatch->device, event->context,
+ kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
+ kgsl_cancel_event(device, event->context,
event->timestamp, kgsl_cmdbatch_sync_func,
event);
+ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
} else if (event->type == KGSL_CMD_SYNCPOINT_TYPE_FENCE) {
/* Put events that are successfully canceled */
if (kgsl_sync_fence_async_cancel(event->handle))
@@ -1765,6 +1839,9 @@
{
struct kgsl_cmdbatch_sync_event *event = priv;
+ trace_syncpoint_fence_expire(event->cmdbatch,
+ event->handle ? event->handle->name : "unknown");
+
kgsl_cmdbatch_sync_expire(event->device, event);
/* Put events that have signaled */
kgsl_cmdbatch_sync_event_put(event);
@@ -1823,10 +1900,11 @@
event->handle = kgsl_sync_fence_async_wait(sync->fd,
kgsl_cmdbatch_sync_fence_func, event);
-
if (IS_ERR_OR_NULL(event->handle)) {
int ret = PTR_ERR(event->handle);
+ event->handle = NULL;
+
/* Failed to add the event to the async callback */
kgsl_cmdbatch_sync_event_put(event);
@@ -1839,9 +1917,18 @@
/* Event no longer needed by this function */
kgsl_cmdbatch_sync_event_put(event);
+ /*
+ * If ret == 0 the fence was already signaled - print a trace
+ * message so we can track that
+ */
+ if (ret == 0)
+ trace_syncpoint_fence_expire(cmdbatch, "signaled");
+
return ret;
}
+ trace_syncpoint_fence(cmdbatch, event->handle->name);
+
/*
* Event was successfully added to the synclist, the async
* callback and handle to cancel event has been set.
@@ -1930,6 +2017,8 @@
kgsl_cmdbatch_put(cmdbatch);
kfree(event);
+ } else {
+ trace_syncpoint_timestamp(cmdbatch, context, sync->timestamp);
}
done:
@@ -3200,6 +3289,9 @@
return ret;
}
+/* The largest allowable alignment for a GPU object is 32MB */
+#define KGSL_MAX_ALIGN (32 * SZ_1M)
+
/*
* The common parts of kgsl_ioctl_gpumem_alloc and kgsl_ioctl_gpumem_alloc_id.
*/
@@ -3226,11 +3318,13 @@
/* Cap the alignment bits to the highest number we can handle */
align = (flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
- if (align >= 32) {
- KGSL_CORE_ERR("Alignment too big, restricting to 2^31\n");
+ if (align >= ilog2(KGSL_MAX_ALIGN)) {
+ KGSL_CORE_ERR("Alignment too large; restricting to %dK\n",
+ KGSL_MAX_ALIGN >> 10);
flags &= ~KGSL_MEMALIGN_MASK;
- flags |= (31 << KGSL_MEMALIGN_SHIFT) & KGSL_MEMALIGN_MASK;
+ flags |= (ilog2(KGSL_MAX_ALIGN) << KGSL_MEMALIGN_SHIFT) &
+ KGSL_MEMALIGN_MASK;
}
entry = kgsl_mem_entry_create();
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 6f17d56c..582af93 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -126,6 +126,8 @@
uint32_t *flags);
int (*drawctxt_detach) (struct kgsl_context *context);
void (*drawctxt_destroy) (struct kgsl_context *context);
+ void (*drawctxt_dump) (struct kgsl_device *device,
+ struct kgsl_context *context);
long (*ioctl) (struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
int (*setproperty) (struct kgsl_device_private *dev_priv,
@@ -202,12 +204,15 @@
* @CMDBATCH_FLAG_SKIP - skip the entire command batch
* @CMDBATCH_FLAG_FORCE_PREAMBLE - Force the preamble on for the cmdbatch
* @CMDBATCH_FLAG_WFI - Force wait-for-idle for the submission
+ * @CMDBATCH_FLAG_FENCE_LOG - Set if the cmdbatch is dumping fence logs via the
+ * cmdbatch timer - this is used to avoid recursion
*/
enum kgsl_cmdbatch_priv {
CMDBATCH_FLAG_SKIP = 0,
CMDBATCH_FLAG_FORCE_PREAMBLE,
CMDBATCH_FLAG_WFI,
+ CMDBATCH_FLAG_FENCE_LOG,
};
struct kgsl_device {
@@ -547,6 +552,8 @@
*context);
int kgsl_context_detach(struct kgsl_context *context);
+void kgsl_context_dump(struct kgsl_context *context);
+
int kgsl_memfree_find_entry(pid_t pid, unsigned long *gpuaddr,
unsigned long *size, unsigned int *flags);
@@ -693,6 +700,8 @@
{
kgsl_signal_event(device, context, timestamp, KGSL_EVENT_CANCELLED);
}
+void kgsl_dump_syncpoints(struct kgsl_device *device,
+ struct kgsl_cmdbatch *cmdbatch);
void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index e931a24..e26c09c 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1715,16 +1715,21 @@
int kgsl_active_count_wait(struct kgsl_device *device, int count)
{
int result = 0;
+ long wait_jiffies = HZ;
BUG_ON(!mutex_is_locked(&device->mutex));
- if (atomic_read(&device->active_cnt) > count) {
- int ret;
+ while (atomic_read(&device->active_cnt) > count) {
+ long ret;
kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
ret = wait_event_timeout(device->active_cnt_wq,
- _check_active_count(device, count), HZ);
+ _check_active_count(device, count), wait_jiffies);
kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
result = ret == 0 ? -ETIMEDOUT : 0;
+ if (!result)
+ wait_jiffies = ret;
+ else
+ break;
}
return result;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 896fb19..6b5a555 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -641,8 +641,12 @@
page_size = (align >= ilog2(SZ_64K) && size >= SZ_64K)
? SZ_64K : PAGE_SIZE;
- /* update align flags for what we actually use */
- if (page_size != PAGE_SIZE)
+ /*
+ * The alignment cannot be less than the intended page size - it can be
+ * larger however to accomodate hardware quirks
+ */
+
+ if (ilog2(align) < page_size)
kgsl_memdesc_set_align(memdesc, ilog2(page_size));
/*
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index cef052d..9b27722 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -22,12 +22,13 @@
#include "kgsl_sync.h"
struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
- unsigned int timestamp)
+ struct kgsl_context *context, unsigned int timestamp)
{
struct sync_pt *pt;
pt = sync_pt_create(timeline, (int) sizeof(struct kgsl_sync_pt));
if (pt) {
struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) pt;
+ kpt->context = context;
kpt->timestamp = timestamp;
}
return pt;
@@ -45,7 +46,7 @@
static struct sync_pt *kgsl_sync_pt_dup(struct sync_pt *pt)
{
struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) pt;
- return kgsl_sync_pt_create(pt->parent, kpt->timestamp);
+ return kgsl_sync_pt_create(pt->parent, kpt->context, kpt->timestamp);
}
static int kgsl_sync_pt_has_signaled(struct sync_pt *pt)
@@ -95,6 +96,38 @@
kfree(ev);
}
+static int _add_fence_event(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp)
+{
+ struct kgsl_fence_event_priv *event;
+ int ret;
+
+ event = kmalloc(sizeof(*event), GFP_KERNEL);
+ if (event == NULL)
+ return -ENOMEM;
+
+ /*
+ * Increase the refcount for the context to keep it through the
+ * callback
+ */
+
+ _kgsl_context_get(context);
+
+ event->context = context;
+ event->timestamp = timestamp;
+ event->context = context;
+
+ ret = kgsl_add_event(device, context->id, timestamp,
+ kgsl_fence_event_cb, event, context->dev_priv);
+
+ if (ret) {
+ kgsl_context_put(context);
+ kfree(event);
+ }
+
+ return ret;
+}
+
/**
* kgsl_add_fence_event - Create a new fence event
* @device - KGSL device to create the event on
@@ -112,23 +145,19 @@
u32 context_id, u32 timestamp, void __user *data, int len,
struct kgsl_device_private *owner)
{
- struct kgsl_fence_event_priv *event;
struct kgsl_timestamp_event_fence priv;
struct kgsl_context *context;
struct sync_pt *pt;
struct sync_fence *fence = NULL;
int ret = -EINVAL;
char fence_name[sizeof(fence->name)] = {};
+ unsigned int cur;
priv.fence_fd = -1;
if (len != sizeof(priv))
return -EINVAL;
- event = kzalloc(sizeof(*event), GFP_KERNEL);
- if (event == NULL)
- return -ENOMEM;
-
kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
context = kgsl_context_get_owner(owner, context_id);
@@ -136,10 +165,8 @@
if (context == NULL)
goto unlock;
- event->context = context;
- event->timestamp = timestamp;
+ pt = kgsl_sync_pt_create(context->timeline, context, timestamp);
- pt = kgsl_sync_pt_create(context->timeline, timestamp);
if (pt == NULL) {
KGSL_DRV_ERR(device, "kgsl_sync_pt_create failed\n");
ret = -ENOMEM;
@@ -169,6 +196,24 @@
}
sync_fence_install(fence, priv.fence_fd);
+ /*
+ * If the timestamp hasn't expired yet create an event to trigger it.
+ * Otherwise, just signal the fence - there is no reason to go through
+ * the effort of creating a fence we don't need.
+ */
+
+ cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
+
+ if (timestamp_cmp(cur, timestamp) >= 0)
+ kgsl_sync_timeline_signal(context->timeline, cur);
+ else {
+ ret = _add_fence_event(device, context, timestamp);
+ if (ret)
+ goto unlock;
+ }
+
+ kgsl_context_put(context);
+
/* Unlock the mutex before copying to user */
kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
@@ -177,21 +222,6 @@
goto out;
}
- /*
- * Hold the context ref-count for the event - it will get released in
- * the callback
- */
-
- kgsl_mutex_lock(&device->mutex, &device->mutex_owner);
-
- ret = kgsl_add_event(device, context_id, timestamp,
- kgsl_fence_event_cb, event, owner);
-
- kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
-
- if (ret)
- goto out;
-
return 0;
unlock:
@@ -205,7 +235,6 @@
sync_fence_put(fence);
kgsl_context_put(context);
- kfree(event);
return ret;
}
@@ -242,6 +271,14 @@
snprintf(str, size, "%u", kpt->timestamp);
}
+static void kgsl_sync_pt_log(struct sync_pt *sync_pt)
+{
+ struct kgsl_sync_pt *kpt = (struct kgsl_sync_pt *) sync_pt;
+ pr_info("-----\n");
+ kgsl_context_dump(kpt->context);
+ pr_info("-----\n");
+}
+
static void kgsl_sync_timeline_release_obj(struct sync_timeline *sync_timeline)
{
/*
@@ -259,6 +296,7 @@
.timeline_value_str = kgsl_sync_timeline_value_str,
.pt_value_str = kgsl_sync_pt_value_str,
.release_obj = kgsl_sync_timeline_release_obj,
+ .pt_log = kgsl_sync_pt_log,
};
int kgsl_sync_timeline_create(struct kgsl_context *context)
@@ -331,9 +369,13 @@
sync_fence_put(fence);
return ERR_PTR(-ENOMEM);
}
+
kwaiter->fence = fence;
kwaiter->priv = priv;
kwaiter->func = func;
+
+ strlcpy(kwaiter->name, fence->name, sizeof(kwaiter->name));
+
sync_fence_waiter_init((struct sync_fence_waiter *) kwaiter,
kgsl_sync_callback);
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index 275eaf0..d9d26ff 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -25,19 +25,21 @@
struct kgsl_sync_pt {
struct sync_pt pt;
+ struct kgsl_context *context;
unsigned int timestamp;
};
struct kgsl_sync_fence_waiter {
struct sync_fence_waiter waiter;
struct sync_fence *fence;
+ char name[32];
void (*func)(void *priv);
void *priv;
};
#if defined(CONFIG_SYNC)
struct sync_pt *kgsl_sync_pt_create(struct sync_timeline *timeline,
- unsigned int timestamp);
+ struct kgsl_context *context, unsigned int timestamp);
void kgsl_sync_pt_destroy(struct sync_pt *pt);
int kgsl_add_fence_event(struct kgsl_device *device,
u32 context_id, u32 timestamp, void __user *data, int len,
@@ -49,9 +51,14 @@
struct kgsl_sync_fence_waiter *kgsl_sync_fence_async_wait(int fd,
void (*func)(void *priv), void *priv);
int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter);
+static inline void kgsl_sync_fence_log(struct sync_fence *fence)
+{
+ sync_fence_log(fence);
+}
#else
static inline struct sync_pt
-*kgsl_sync_pt_create(struct sync_timeline *timeline, unsigned int timestamp)
+*kgsl_sync_pt_create(struct sync_timeline *timeline,
+ struct kgsl_context *context, unsigned int timestamp)
{
return NULL;
}
@@ -96,6 +103,10 @@
return 1;
}
+static inline void kgsl_sync_fence_log(struct sync_fence *fence)
+{
+}
+
#endif
#endif /* __KGSL_SYNC_H */
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index c737cc8..8830a9e 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -796,13 +796,11 @@
)
);
-
TRACE_EVENT(kgsl_pwrstats,
TP_PROTO(struct kgsl_device *device, s64 time,
struct kgsl_power_stats *pstats),
TP_ARGS(device, time, pstats),
-
TP_STRUCT__entry(
__string(device_name, device->name)
__field(s64, total_time)
@@ -826,6 +824,61 @@
)
);
+DECLARE_EVENT_CLASS(syncpoint_timestamp_template,
+ TP_PROTO(struct kgsl_cmdbatch *cmdbatch, struct kgsl_context *context,
+ unsigned int timestamp),
+ TP_ARGS(cmdbatch, context, timestamp),
+ TP_STRUCT__entry(
+ __field(unsigned int, cmdbatch_context_id)
+ __field(unsigned int, context_id)
+ __field(unsigned int, timestamp)
+ ),
+ TP_fast_assign(
+ __entry->cmdbatch_context_id = cmdbatch->context->id;
+ __entry->context_id = context->id;
+ __entry->timestamp = timestamp;
+ ),
+ TP_printk("ctx=%d sync ctx=%d ts=%d",
+ __entry->cmdbatch_context_id, __entry->context_id,
+ __entry->timestamp)
+);
+
+DEFINE_EVENT(syncpoint_timestamp_template, syncpoint_timestamp,
+ TP_PROTO(struct kgsl_cmdbatch *cmdbatch, struct kgsl_context *context,
+ unsigned int timestamp),
+ TP_ARGS(cmdbatch, context, timestamp)
+);
+
+DEFINE_EVENT(syncpoint_timestamp_template, syncpoint_timestamp_expire,
+ TP_PROTO(struct kgsl_cmdbatch *cmdbatch, struct kgsl_context *context,
+ unsigned int timestamp),
+ TP_ARGS(cmdbatch, context, timestamp)
+);
+
+DECLARE_EVENT_CLASS(syncpoint_fence_template,
+ TP_PROTO(struct kgsl_cmdbatch *cmdbatch, char *name),
+ TP_ARGS(cmdbatch, name),
+ TP_STRUCT__entry(
+ __string(fence_name, name)
+ __field(unsigned int, cmdbatch_context_id)
+ ),
+ TP_fast_assign(
+ __entry->cmdbatch_context_id = cmdbatch->context->id;
+ __assign_str(fence_name, name);
+ ),
+ TP_printk("ctx=%d fence=%s",
+ __entry->cmdbatch_context_id, __get_str(fence_name))
+);
+
+DEFINE_EVENT(syncpoint_fence_template, syncpoint_fence,
+ TP_PROTO(struct kgsl_cmdbatch *cmdbatch, char *name),
+ TP_ARGS(cmdbatch, name)
+);
+
+DEFINE_EVENT(syncpoint_fence_template, syncpoint_fence_expire,
+ TP_PROTO(struct kgsl_cmdbatch *cmdbatch, char *name),
+ TP_ARGS(cmdbatch, name)
+);
#endif /* _KGSL_TRACE_H */
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 545e68f..f77a4f6 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -789,7 +789,7 @@
(uint32_t)dev->base +
QUP_OUT_FIFO_BASE + (*idx), 0);
*idx += 2;
- } else if (next->flags == 0 && dev->pos == msg->len - 1
+ } else if ((dev->pos == msg->len - 1)
&& *idx < (dev->wr_sz*2) &&
(next->addr != msg->addr)) {
/* Last byte of an intermittent write */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index e8702e4..08cc00c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -19,7 +19,7 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/delay.h>
-#include <linux/avtimer.h>
+#include <linux/avtimer_kernel.h>
#include <media/v4l2-subdev.h>
#include <media/msmb_isp.h>
#include <mach/msm_bus.h>
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index ba1e58c..263d54d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -403,8 +403,8 @@
reset_type = ISP_RST_HARD;
}
rst_val = msm_vfe32_reset_values[reset_type];
- init_completion(&vfe_dev->reset_complete);
if (blocking) {
+ init_completion(&vfe_dev->reset_complete);
msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0x4);
rc = wait_for_completion_timeout(
&vfe_dev->reset_complete, msecs_to_jiffies(50));
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 2567657..12fd081 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -642,11 +642,11 @@
vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id;
if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id != *cfg_data
|| update_id == *cfg_data) {
- pr_err("hw update lock failed,acquire id %u\n",
+ ISP_DBG("hw update lock failed,acquire id %u\n",
*cfg_data);
- pr_err("hw update lock failed,current id %lu\n",
+ ISP_DBG("hw update lock failed,current id %lu\n",
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
- pr_err("hw update lock failed,last id %u\n",
+ ISP_DBG("hw update lock failed,last id %u\n",
update_id);
return -EINVAL;
}
@@ -655,13 +655,13 @@
case VFE_HW_UPDATE_UNLOCK: {
if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id
!= *cfg_data) {
- pr_err("hw update across frame boundary,begin id %u\n",
+ ISP_DBG("hw update across frame boundary,begin id %u\n",
*cfg_data);
- pr_err("hw update across frame boundary,end id %lu\n",
+ ISP_DBG("hw update across frame boundary,end id %lu\n",
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
- vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id =
- vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
}
+ vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id =
+ vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
break;
}
case VFE_READ: {
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 aa0d88b..c9e5159 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
@@ -166,7 +166,8 @@
} \
}
-static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev);
+static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
+ uint32_t buff_mgr_ops);
static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin);
static void cpp_timer_callback(unsigned long data);
@@ -638,13 +639,15 @@
/* delete CPP timer */
CPP_DBG("delete timer.\n");
msm_cpp_clear_timer(cpp_dev);
- msm_cpp_notify_frame_done(cpp_dev);
+ msm_cpp_notify_frame_done(cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_BUF_DONE);
} else if (msg_id ==
MSM_CPP_MSG_ID_FRAME_NACK) {
pr_err("NACK error from hw!!\n");
CPP_DBG("delete timer.\n");
msm_cpp_clear_timer(cpp_dev);
- msm_cpp_notify_frame_done(cpp_dev);
+ msm_cpp_notify_frame_done(cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_PUT_BUF);
}
i += cmd_len + 2;
}
@@ -1071,7 +1074,8 @@
return rc;
}
-static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
+static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
+ uint32_t buff_mgr_ops)
{
struct v4l2_event v4l2_evt;
struct msm_queue_cmd *frame_qcmd = NULL;
@@ -1107,7 +1111,7 @@
buff_mgr_info.index =
processed_frame->output_buffer_info[0].index;
rc = msm_cpp_buffer_ops(cpp_dev,
- VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+ buff_mgr_ops,
&buff_mgr_info);
if (rc < 0) {
pr_err("error putting buffer\n");
@@ -1129,8 +1133,8 @@
buff_mgr_info.index =
processed_frame->output_buffer_info[1].index;
rc = msm_cpp_buffer_ops(cpp_dev,
- VIDIOC_MSM_BUF_MNGR_BUF_DONE,
- &buff_mgr_info);
+ buff_mgr_ops,
+ &buff_mgr_info);
if (rc < 0) {
pr_err("error putting buffer\n");
rc = -EINVAL;
@@ -1197,7 +1201,8 @@
if (cpp_timer.data.cpp_dev->timeout_trial_cnt >=
MSM_CPP_MAX_TIMEOUT_TRIAL) {
pr_info("Max trial reached\n");
- msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev);
+ msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_PUT_BUF);
cpp_timer.data.cpp_dev->timeout_trial_cnt = 0;
return;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 270fb38..e5d82fd 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -211,13 +211,23 @@
pr_err("%s failed line %d\n", __func__, __LINE__);
return -EINVAL;
}
- /* assume total size within the max queue */
+
+ reg_addr = i2c_cmd->reg_addr;
while (cmd_size) {
- CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__,
+ CDBG("%s cmd_size %d addr 0x%x data 0x%x\n", __func__,
cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data);
delay = i2c_cmd->delay;
data[i++] = CCI_I2C_WRITE_CMD;
- reg_addr = i2c_cmd->reg_addr;
+
+ /* in case of multiple command
+ * MSM_CCI_I2C_WRITE : address is not continuous, so update
+ * address for a new packet.
+ * MSM_CCI_I2C_WRITE_SEQ : address is continuous, need to keep
+ * the incremented address for a
+ * new packet */
+ if (c_ctrl->cmd == MSM_CCI_I2C_WRITE)
+ reg_addr = i2c_cmd->reg_addr;
+
/* either byte or word addr */
if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
data[i++] = reg_addr;
@@ -226,21 +236,25 @@
data[i++] = reg_addr & 0x00FF;
}
/* max of 10 data bytes */
- if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) {
- data[i++] = i2c_cmd->reg_data;
- reg_addr++;
- } else {
- if ((i + 1) <= 10) {
- data[i++] = (i2c_cmd->reg_data &
- 0xFF00) >> 8; /* MSB */
- data[i++] = i2c_cmd->reg_data &
- 0x00FF; /* LSB */
- reg_addr += 2;
- } else
- break;
- }
- i2c_cmd++;
- --cmd_size;
+ do {
+ if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) {
+ data[i++] = i2c_cmd->reg_data;
+ reg_addr++;
+ } else {
+ if ((i + 1) <= 10) {
+ data[i++] = (i2c_cmd->reg_data &
+ 0xFF00) >> 8; /* MSB */
+ data[i++] = i2c_cmd->reg_data &
+ 0x00FF; /* LSB */
+ reg_addr += 2;
+ } else
+ break;
+ }
+ i2c_cmd++;
+ --cmd_size;
+ } while ((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) &&
+ (cmd_size > 0) && (i <= 10));
+
data[0] |= ((i-1) << 4);
len = ((i-1)/4) + 1;
rc = msm_cci_validate_queue(cci_dev, len, master, queue);
@@ -789,6 +803,7 @@
rc = msm_cci_i2c_read_bytes(sd, cci_ctrl);
break;
case MSM_CCI_I2C_WRITE:
+ case MSM_CCI_I2C_WRITE_SEQ:
rc = msm_cci_i2c_write(sd, cci_ctrl);
break;
case MSM_CCI_GPIO_WRITE:
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
index 44c134e..283bd28 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
@@ -53,6 +53,7 @@
MSM_CCI_SET_SYNC_CID,
MSM_CCI_I2C_READ,
MSM_CCI_I2C_WRITE,
+ MSM_CCI_I2C_WRITE_SEQ,
MSM_CCI_GPIO_WRITE,
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
index 8d9274b..6af0cea 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
@@ -158,7 +158,7 @@
reg_conf_tbl[i].reg_data = data[i];
reg_conf_tbl[i].delay = 0;
}
- cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+ cci_ctrl.cmd = MSM_CCI_I2C_WRITE_SEQ;
cci_ctrl.cci_info = client->cci_client;
cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl;
cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 0eee530..032cca4 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -215,6 +215,7 @@
cmd_done.device_id = device_id;
cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
session_id;
+ cmd_done.status = hfi_map_err_status(pkt->event_data1);
dprintk(VIDC_INFO, "Received : SESSION_ERROR with event id : %d\n",
pkt->event_data1);
switch (pkt->event_data1) {
@@ -222,6 +223,7 @@
case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
+ cmd_done.status = VIDC_ERR_NONE;
dprintk(VIDC_INFO, "Non Fatal : HFI_EVENT_SESSION_ERROR\n");
break;
default:
@@ -834,12 +836,9 @@
} else {
sess_close = (struct hal_session *)pkt->session_id;
if (sess_close) {
- dprintk(VIDC_INFO,
- "Sess init failed: Deleting session: 0x%x 0x%p",
+ dprintk(VIDC_WARN,
+ "Sess init failed: 0x%x, 0x%p",
sess_close->session_id, sess_close);
- list_del(&sess_close->list);
- kfree(sess_close);
- sess_close = NULL;
}
}
cmd_done.size = sizeof(struct vidc_hal_session_init_done);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 30ca194..7830db7 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1400,7 +1400,7 @@
case V4L2_DEC_QCOM_CMD_FLUSH:
if (core->state != VIDC_CORE_INVALID &&
inst->state == MSM_VIDC_CORE_INVALID) {
- rc = msm_comm_recover_from_session_error(inst);
+ rc = msm_comm_kill_session(inst);
if (rc)
dprintk(VIDC_ERR,
"Failed to recover from session_error: %d\n",
@@ -1415,7 +1415,7 @@
case V4L2_DEC_CMD_STOP:
if (core->state != VIDC_CORE_INVALID &&
inst->state == MSM_VIDC_CORE_INVALID) {
- rc = msm_comm_recover_from_session_error(inst);
+ rc = msm_comm_kill_session(inst);
if (rc)
dprintk(VIDC_ERR,
"Failed to recover from session_error: %d\n",
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index ba17820..794d116 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -46,6 +46,10 @@
u32 __mbs = (__h >> 4) * (__w >> 4);\
__mbs;\
})
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst);
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst);
+static void handle_session_error(enum command_response cmd, void *data);
+
static bool is_turbo_requested(struct msm_vidc_core *core,
enum session_type type)
{
@@ -398,7 +402,7 @@
dprintk(VIDC_ERR,
"%s: Wait interrupted or timeout[%u]: %d\n",
__func__, (u32)inst->session, SESSION_MSG_INDEX(cmd));
- msm_comm_recover_from_session_error(inst);
+ msm_comm_kill_session(inst);
rc = -EIO;
} else {
rc = 0;
@@ -432,32 +436,19 @@
wake_up(&inst->kernel_event_queue);
}
-static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
-{
- if (!inst) {
- dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
- return;
- }
- mutex_lock(&inst->lock);
- inst->session = NULL;
- inst->state = MSM_VIDC_CORE_INVALID;
- msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
- mutex_unlock(&inst->lock);
-}
-
static void msm_comm_generate_max_clients_error(struct msm_vidc_inst *inst)
{
+ enum command_response cmd = SESSION_ERROR;
+ struct msm_vidc_cb_cmd_done response = {0};
+
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
return;
}
- mutex_lock(&inst->sync_lock);
- inst->session = NULL;
- inst->state = MSM_VIDC_CORE_INVALID;
- msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_MAX_CLIENTS);
- dprintk(VIDC_WARN,
- "%s: Too many clients\n", __func__);
- mutex_unlock(&inst->sync_lock);
+ dprintk(VIDC_ERR, "%s: Too many clients\n", __func__);
+ response.session_id = (u32) inst;
+ response.status = VIDC_ERR_MAX_CLIENTS;
+ handle_session_error(cmd, (void *)&response);
}
static void handle_session_init_done(enum command_response cmd, void *data)
@@ -834,21 +825,50 @@
static void handle_session_error(enum command_response cmd, void *data)
{
struct msm_vidc_cb_cmd_done *response = data;
+ int rc;
+ struct hfi_device *hdev = NULL;
struct msm_vidc_inst *inst = NULL;
- if (response) {
- inst = (struct msm_vidc_inst *)response->session_id;
- if (inst) {
- dprintk(VIDC_WARN,
- "Session error receivd for session %p\n", inst);
- mutex_lock(&inst->sync_lock);
- inst->state = MSM_VIDC_CORE_INVALID;
- mutex_unlock(&inst->sync_lock);
- msm_vidc_queue_v4l2_event(inst,
- V4L2_EVENT_MSM_VIDC_SYS_ERROR);
- }
- } else {
+
+ if (!response) {
dprintk(VIDC_ERR,
"Failed to get valid response for session error\n");
+ return;
+ }
+
+ inst = (struct msm_vidc_inst *)response->session_id;
+
+ if (!inst || !inst->session || !inst->core->device) {
+ dprintk(VIDC_ERR,
+ "Session (%p) not in a stable enough state to handle session error\n",
+ inst);
+ return;
+ }
+
+ hdev = inst->core->device;
+ dprintk(VIDC_WARN, "Session error received for session %p\n", inst);
+ change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+
+ mutex_lock(&inst->lock);
+ dprintk(VIDC_DBG, "cleaning up inst: %p\n", inst);
+ rc = call_hfi_op(hdev, session_clean, inst->session);
+ if (rc)
+ dprintk(VIDC_ERR, "Session (%p) clean failed: %d\n", inst, rc);
+
+ inst->session = NULL;
+ mutex_unlock(&inst->lock);
+
+ if (response->status == VIDC_ERR_MAX_CLIENTS) {
+ dprintk(VIDC_WARN,
+ "send max clients reached error to client: %p\n",
+ inst);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_MAX_CLIENTS);
+ } else {
+ dprintk(VIDC_ERR,
+ "send session error to client: %p\n",
+ inst);
+ msm_vidc_queue_v4l2_event(inst,
+ V4L2_EVENT_MSM_VIDC_SYS_ERROR);
}
}
@@ -1249,10 +1269,10 @@
inst = (struct msm_vidc_inst *)response->session_id;
fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
buffer_type = msm_comm_get_hal_output_buffer(inst);
- if (fill_buf_done->buffer_type == buffer_type)
+ if (fill_buf_done->buffer_type == buffer_type) {
vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
(u32)fill_buf_done->packet_buffer1);
- else {
+ } else {
if (handle_multi_stream_buffers(inst,
(u32)fill_buf_done->packet_buffer1))
dprintk(VIDC_ERR,
@@ -1881,7 +1901,7 @@
num_mbs_per_sec, inst->core->resources.max_load);
msm_vidc_print_running_insts(inst->core);
inst->state = MSM_VIDC_CORE_INVALID;
- msm_comm_recover_from_session_error(inst);
+ msm_comm_kill_session(inst);
return -EBUSY;
}
@@ -2672,7 +2692,7 @@
__func__, (u32)inst->session,
SESSION_MSG_INDEX(SESSION_PROPERTY_INFO));
inst->state = MSM_VIDC_CORE_INVALID;
- msm_comm_recover_from_session_error(inst);
+ msm_comm_kill_session(inst);
rc = -EIO;
goto exit;
}
@@ -2790,11 +2810,9 @@
rc = wait_for_sess_signal_receipt(inst,
SESSION_RELEASE_BUFFER_DONE);
if (rc) {
- mutex_lock(&inst->sync_lock);
- inst->state = MSM_VIDC_CORE_INVALID;
- mutex_unlock(&inst->sync_lock);
- msm_comm_recover_from_session_error(
- inst);
+ change_inst_state(inst,
+ MSM_VIDC_CORE_INVALID);
+ msm_comm_kill_session(inst);
}
mutex_lock(&inst->lock);
}
@@ -2861,11 +2879,9 @@
rc = wait_for_sess_signal_receipt(inst,
SESSION_RELEASE_BUFFER_DONE);
if (rc) {
- mutex_lock(&inst->sync_lock);
- inst->state = MSM_VIDC_CORE_INVALID;
- mutex_unlock(&inst->sync_lock);
- msm_comm_recover_from_session_error(
- inst);
+ change_inst_state(inst,
+ MSM_VIDC_CORE_INVALID);
+ msm_comm_kill_session(inst);
}
mutex_lock(&inst->lock);
}
@@ -3472,9 +3488,7 @@
}
}
if (rc) {
- mutex_lock(&inst->sync_lock);
- inst->state = MSM_VIDC_CORE_INVALID;
- mutex_unlock(&inst->sync_lock);
+ change_inst_state(inst, MSM_VIDC_CORE_INVALID);
msm_vidc_queue_v4l2_event(inst,
V4L2_EVENT_MSM_VIDC_HW_OVERLOAD);
dprintk(VIDC_WARN,
@@ -3484,6 +3498,22 @@
return rc;
}
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
+{
+ enum command_response cmd = SESSION_ERROR;
+ struct msm_vidc_cb_cmd_done response = {0};
+
+ dprintk(VIDC_WARN, "msm_comm_generate_session_error\n");
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+ return;
+ }
+
+ response.session_id = (u32)inst;
+ response.status = VIDC_ERR_FAIL;
+ handle_session_error(cmd, (void *)&response);
+}
+
static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
{
struct msm_vidc_core *core;
@@ -3498,43 +3528,55 @@
handle_sys_error(cmd, (void *) &response);
}
-int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst)
+
+int msm_comm_kill_session(struct msm_vidc_inst *inst)
{
- struct hfi_device *hdev;
int rc = 0;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
return -EINVAL;
+ } else if (!inst->session) {
+ /* There's no hfi session to kill */
+ return 0;
}
- if (!inst->session || inst->state < MSM_VIDC_OPEN_DONE) {
- dprintk(VIDC_WARN,
- "No corresponding FW session. No need to send Abort");
- return rc;
- }
- hdev = inst->core->device;
- init_completion(&inst->completions[SESSION_MSG_INDEX
- (SESSION_ABORT_DONE)]);
-
- /* We have received session_error. Send session_abort to firmware
- * to clean up and release the session
+ /*
+ * We're internally forcibly killing the session, if fw is aware of
+ * the session send session_abort to firmware to clean up and release
+ * the session, else just kill the session inside the driver.
*/
- rc = call_hfi_op(hdev, session_abort, (void *) inst->session);
- if (rc) {
- dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
- return rc;
+ if (inst->state >= MSM_VIDC_OPEN_DONE &&
+ inst->state < MSM_VIDC_CLOSE_DONE) {
+ struct hfi_device *hdev = inst->core->device;
+ int abort_completion = SESSION_MSG_INDEX(SESSION_ABORT_DONE);
+
+ rc = call_hfi_op(hdev, session_abort, (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
+ return rc;
+ }
+
+ init_completion(&inst->completions[abort_completion]);
+ rc = wait_for_completion_timeout(
+ &inst->completions[abort_completion],
+ msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+ if (!rc) {
+ dprintk(VIDC_ERR,
+ "%s: Wait interrupted or timed out [%p]: %d\n",
+ __func__, inst, abort_completion);
+ msm_comm_generate_sys_error(inst);
+ } else {
+ change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
+ }
+ } else {
+ dprintk(VIDC_WARN,
+ "Inactive session %p, triggering an internal session error\n",
+ inst);
+ msm_comm_generate_session_error(inst);
+
}
- rc = wait_for_completion_timeout(
- &inst->completions[SESSION_MSG_INDEX(SESSION_ABORT_DONE)],
- msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
- if (!rc) {
- dprintk(VIDC_ERR, "%s: Wait interrupted or timeout[%u]: %d\n",
- __func__, (u32)inst->session,
- SESSION_MSG_INDEX(SESSION_ABORT_DONE));
- msm_comm_generate_sys_error(inst);
- } else
- change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
+
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index f4e2cd5..1e86278 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -52,7 +52,7 @@
V4L2_CTRL_DRIVER_PRIV(idx))
int msm_comm_check_scaling_supported(struct msm_vidc_inst *inst);
-int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
+int msm_comm_kill_session(struct msm_vidc_inst *inst);
enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index f5587fc..0de42ae 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1501,6 +1501,7 @@
void *pkt)
{
u32 rx_req_is_set = 0;
+ struct vidc_hal_cmd_pkt_hdr *cmd_packet;
struct vidc_iface_q_info *q_info;
int result = -EPERM;
@@ -1528,6 +1529,12 @@
goto err_q_null;
}
+ cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt;
+ if ((cmd_packet->packet_type != HFI_CMD_SYS_PC_PREP) &&
+ (cmd_packet->packet_type != HFI_CMD_SYS_RELEASE_RESOURCE)) {
+ device->pc_num_cmds++;
+ }
+
if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
WARN(!mutex_is_locked(&device->clk_pwr_lock),
"Clock/power lock must be acquired");
@@ -2865,15 +2872,24 @@
static void venus_hfi_pm_hndlr(struct work_struct *work)
{
int rc = 0;
+ u32 ctrl_status = 0;
struct venus_hfi_device *device = list_first_entry(
&hal_ctxt.dev_head, struct venus_hfi_device, list);
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
+ return;
+ }
+
mutex_lock(&device->clk_pwr_lock);
if (device->clk_state == ENABLED_PREPARED || !device->power_enabled) {
dprintk(VIDC_DBG,
"Clocks status: %d, Power status: %d, ignore power off\n",
device->clk_state, device->power_enabled);
- goto clks_enabled;
+ mutex_unlock(&device->clk_pwr_lock);
+ return;
}
+ device->pc_num_cmds = 0;
mutex_unlock(&device->clk_pwr_lock);
rc = __unset_free_ocmem(device);
@@ -2894,17 +2910,51 @@
}
mutex_lock(&device->clk_pwr_lock);
+ if (device->pc_num_cmds) {
+ dprintk(VIDC_DBG,
+ "ignore power off due to client sent commands = %d\n",
+ device->pc_num_cmds);
+ goto skip_power_off;
+ }
if (device->clk_state == ENABLED_PREPARED) {
dprintk(VIDC_ERR,
"Clocks are still enabled after PC_PREP_DONE, ignore power off");
- goto clks_enabled;
+ goto skip_power_off;
}
rc = venus_hfi_power_off(device);
- if (rc)
+ if (rc) {
dprintk(VIDC_ERR, "Failed venus power off");
-clks_enabled:
+ goto err_power_off;
+ }
+
mutex_unlock(&device->clk_pwr_lock);
+ return;
+
+err_power_off:
+skip_power_off:
+
+ /* Reset PC_READY bit as power_off is skipped, if set by Venus */
+ ctrl_status = venus_hfi_read_register(device, VIDC_CPU_CS_SCIACMDARG0);
+ if (ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY) {
+ ctrl_status &= ~(VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY);
+ venus_hfi_write_register(device, VIDC_CPU_CS_SCIACMDARG0,
+ ctrl_status, 0);
+ }
+
+ /* Cancel pending delayed works if any */
+ cancel_delayed_work(&venus_hfi_pm_work);
+ dprintk(VIDC_WARN, "Power off skipped (%d, %d)\n",
+ device->clk_state, device->pc_num_cmds);
+
+ mutex_unlock(&device->clk_pwr_lock);
+
+ rc = __alloc_set_ocmem(device, true);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to re-allocate OCMEM. Performance will be impacted\n");
+ }
+ return;
}
static int venus_hfi_try_clk_gating(struct venus_hfi_device *device)
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 05d7b6a..a1ed069 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -215,6 +215,7 @@
struct workqueue_struct *venus_pm_workq;
int spur_count;
int reg_count;
+ int pc_num_cmds;
u32 base_addr;
u32 register_base;
u32 register_size;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index b3c20b6..edd71f1 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -780,6 +780,11 @@
#define HFI_TEST_SSR_SW_DIV_BY_ZERO 0x2
#define HFI_TEST_SSR_HW_WDOG_IRQ 0x3
+struct vidc_hal_cmd_pkt_hdr {
+ u32 size;
+ u32 packet_type;
+};
+
struct vidc_hal_msg_pkt_hdr {
u32 size;
u32 packet;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 3a93469..399cea9 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -648,7 +648,7 @@
}
if (req_mode > HIGH) {
pr_err("Invalid bandwidth mode (%d)\n", req_mode);
- return ret;
+ return -EINVAL;
}
/*
@@ -1115,8 +1115,8 @@
bool found_dead_app = false;
if (!memcmp(data->client.app_name, "keymaste", strlen("keymaste"))) {
- pr_warn("Do not unload keymaster app from tz\n");
- return 0;
+ pr_debug("Do not unload keymaster app from tz\n");
+ goto unload_exit;
}
if (data->client.app_id > 0) {
@@ -1211,6 +1211,7 @@
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags1);
}
+unload_exit:
qseecom_unmap_ion_allocated_memory(data);
data->released = true;
return ret;
@@ -1392,6 +1393,74 @@
return ret;
}
+static int __validate_send_cmd_inputs(struct qseecom_dev_handle *data,
+ struct qseecom_send_cmd_req *req)
+{
+ if (!data || !data->client.ihandle) {
+ pr_err("Client or client handle is not initialized\n");
+ return -EINVAL;
+ }
+ if (((req->resp_buf == NULL) && (req->resp_len != 0)) ||
+ (req->cmd_req_buf == NULL)) {
+ pr_err("cmd buffer or response buffer is null\n");
+ return -EINVAL;
+ }
+ if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
+ ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
+ data->client.sb_length))) {
+ pr_err("cmd buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+ if (((uintptr_t)req->resp_buf <
+ data->client.user_virt_sb_base) ||
+ ((uintptr_t)req->resp_buf >=
+ (data->client.user_virt_sb_base + data->client.sb_length))) {
+ pr_err("response buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+ if ((req->cmd_req_len == 0) ||
+ (req->cmd_req_len > data->client.sb_length) ||
+ (req->resp_len > data->client.sb_length)) {
+ pr_err("cmd buf length or response buf length not valid\n");
+ return -EINVAL;
+ }
+ if (req->cmd_req_len > UINT_MAX - req->resp_len) {
+ pr_err("Integer overflow detected in req_len & rsp_len\n");
+ return -EINVAL;
+ }
+
+ if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
+ pr_debug("Not enough memory to fit cmd_buf.\n");
+ pr_debug("resp_buf. Required: %u, Available: %zu\n",
+ (req->cmd_req_len + req->resp_len),
+ data->client.sb_length);
+ return -ENOMEM;
+ }
+ if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
+ pr_err("Integer overflow in req_len & cmd_req_buf\n");
+ return -EINVAL;
+ }
+ if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
+ pr_err("Integer overflow in resp_len & resp_buf\n");
+ return -EINVAL;
+ }
+ if (data->client.user_virt_sb_base >
+ (ULONG_MAX - data->client.sb_length)) {
+ pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
+ return -EINVAL;
+ }
+ if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length)) ||
+ (((uintptr_t)req->resp_buf + req->resp_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length))) {
+ pr_err("cmd buf or resp buf is out of shared buffer region\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
struct qseecom_send_cmd_req *req)
{
@@ -1404,46 +1473,7 @@
bool found_app = false;
int name_len = 0;
- if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
- pr_err("cmd buffer or response buffer is null\n");
- return -EINVAL;
- }
- if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
- ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
- data->client.sb_length))) {
- pr_err("cmd buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
-
- if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
- ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
- data->client.sb_length))){
- pr_err("response buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
- if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
- req->cmd_req_len > data->client.sb_length ||
- req->resp_len > data->client.sb_length) {
- pr_err("cmd buffer length or "
- "response buffer length not valid\n");
- return -EINVAL;
- }
-
- if (req->cmd_req_len > UINT_MAX - req->resp_len) {
- pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
- return -EINVAL;
- }
-
reqd_len_sb_in = req->cmd_req_len + req->resp_len;
- if (reqd_len_sb_in > data->client.sb_length) {
- pr_debug("Not enough memory to fit cmd_buf and "
- "resp_buf. Required: %u, Available: %u\n",
- reqd_len_sb_in, data->client.sb_length);
- return -ENOMEM;
- }
-
/* find app_id & img_name from list */
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
@@ -1517,6 +1547,10 @@
pr_err("copy_from_user failed\n");
return ret;
}
+
+ if (__validate_send_cmd_inputs(data, &req))
+ return -EINVAL;
+
ret = __qseecom_send_cmd(data, &req);
if (ret)
@@ -1525,6 +1559,32 @@
return ret;
}
+int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *cmd_req,
+ struct qseecom_send_modfd_listener_resp *lstnr_resp,
+ struct qseecom_dev_handle *data, bool listener_svc,
+ int i) {
+
+ if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
+ if ((cmd_req->cmd_req_len < sizeof(uint32_t)) ||
+ (cmd_req->ifd_data[i].cmd_buf_offset >
+ cmd_req->cmd_req_len - sizeof(uint32_t))) {
+ pr_err("Invalid offset 0x%x\n",
+ cmd_req->ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
+ }
+ } else if ((listener_svc) && (lstnr_resp->ifd_data[i].fd > 0)) {
+ if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ lstnr_resp->resp_len - sizeof(uint32_t))) {
+ pr_err("Invalid offset 0x%x\n",
+ lstnr_resp->ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+#define SG_ENTRY_SZ sizeof(struct qseecom_sg_entry)
static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
struct qseecom_dev_handle *data,
bool listener_svc)
@@ -1598,6 +1658,10 @@
if (sg_ptr->nents == 1) {
uint32_t *update;
update = (uint32_t *) field;
+
+ if (__boundary_checks_offset(cmd_req, lstnr_resp, data,
+ listener_svc, i))
+ goto err;
if (cleanup)
*update = 0;
else
@@ -1607,6 +1671,31 @@
} else {
struct qseecom_sg_entry *update;
int j = 0;
+
+ if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
+ if ((cmd_req->cmd_req_len <
+ SG_ENTRY_SZ * sg_ptr->nents) ||
+ (cmd_req->ifd_data[i].cmd_buf_offset >
+ (cmd_req->cmd_req_len -
+ SG_ENTRY_SZ * sg_ptr->nents))) {
+ pr_err("Invalid offset = 0x%x\n",
+ cmd_req->ifd_data[i].
+ cmd_buf_offset);
+ goto err;
+ }
+ } else if ((listener_svc) &&
+ (lstnr_resp->ifd_data[i].fd > 0)) {
+ if ((lstnr_resp->resp_len <
+ SG_ENTRY_SZ * sg_ptr->nents) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ (lstnr_resp->resp_len -
+ SG_ENTRY_SZ * sg_ptr->nents))) {
+ pr_err("Invalid offset = 0x%x\n",
+ lstnr_resp->ifd_data[i].
+ cmd_buf_offset);
+ goto err;
+ }
+ }
update = (struct qseecom_sg_entry *) field;
for (j = 0; j < sg_ptr->nents; j++) {
if (cleanup) {
@@ -1655,35 +1744,14 @@
return ret;
}
- if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
- pr_err("cmd buffer or response buffer is null\n");
- return -EINVAL;
- }
- if (((uint32_t)req.cmd_req_buf < data->client.user_virt_sb_base) ||
- ((uint32_t)req.cmd_req_buf >= (data->client.user_virt_sb_base +
- data->client.sb_length))) {
- pr_err("cmd buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
- if (((uint32_t)req.resp_buf < data->client.user_virt_sb_base) ||
- ((uint32_t)req.resp_buf >= (data->client.user_virt_sb_base +
- data->client.sb_length))){
- pr_err("response buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
- if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
- req.resp_len > data->client.sb_length) {
- pr_err("cmd or response buffer length not valid\n");
- return -EINVAL;
- }
-
send_cmd_req.cmd_req_buf = req.cmd_req_buf;
send_cmd_req.cmd_req_len = req.cmd_req_len;
send_cmd_req.resp_buf = req.resp_buf;
send_cmd_req.resp_len = req.resp_len;
+ if (__validate_send_cmd_inputs(data, &send_cmd_req))
+ return -EINVAL;
+
/* validate offsets */
for (i = 0; i < MAX_ION_FD; i++) {
if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
@@ -2332,6 +2400,9 @@
req.cmd_req_buf = send_buf;
req.resp_buf = resp_buf;
+ if (__validate_send_cmd_inputs(data, &req))
+ return -EINVAL;
+
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
if (qseecom.support_bus_scaling) {
@@ -4525,8 +4596,7 @@
mutex_lock(&qsee_bw_mutex);
mutex_lock(&clk_access_lock);
- if (qseecom.cumulative_mode != INACTIVE &&
- qseecom.current_mode != INACTIVE) {
+ if (qseecom.current_mode != INACTIVE) {
ret = msm_bus_scale_client_update_request(
qseecom.qsee_perf_client, INACTIVE);
if (ret)
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index c066acd..9c65a63 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -236,6 +236,18 @@
cpu_relax();
iris_reg = readl_relaxed(iris_read_reg);
+ pr_info("wcnss: IRIS Reg: %08x\n", iris_reg);
+ if (iris_reg == PRONTO_IRIS_REG_CHIP_ID) {
+ pr_info("wcnss: IRIS Card not Preset\n");
+ auto_detect = WCNSS_XO_INVALID;
+ /* Reset iris read bit */
+ reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
+ /* Clear XO_MODE[b2:b1] bits.
+ Clear implies 19.2 MHz TCXO
+ */
+ reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
+ goto xo_configure;
+ }
auto_detect = xo_auto_detect(iris_reg);
/* Reset iris read bit */
@@ -258,6 +270,7 @@
*iris_xo_set = WCNSS_XO_48MHZ;
}
+xo_configure:
writel_relaxed(reg, pmu_conf_reg);
/* Reset IRIS */
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index ed6fa29..4a4a88c 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -215,7 +215,6 @@
#define WCNSS_BUILD_VER_REQ (WCNSS_CTRL_MSG_START + 9)
#define WCNSS_BUILD_VER_RSP (WCNSS_CTRL_MSG_START + 10)
#define WCNSS_PM_CONFIG_REQ (WCNSS_CTRL_MSG_START + 11)
-#define WCNSS_CBC_COMPLETE_IND (WCNSS_CTRL_MSG_START + 12)
/* max 20mhz channel count */
#define WCNSS_MAX_CH_NUM 45
@@ -408,7 +407,6 @@
void __iomem *alarms_tactl;
void __iomem *fiq_reg;
int nv_downloaded;
- int is_cbc_done;
unsigned char *fw_cal_data;
unsigned char *user_cal_data;
int fw_cal_rcvd;
@@ -1052,7 +1050,6 @@
pr_debug("wcnss: closing WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
penv->nv_downloaded = 0;
- penv->is_cbc_done = 0;
break;
default:
@@ -1261,15 +1258,6 @@
}
EXPORT_SYMBOL(wcnss_device_ready);
-int wcnss_cbc_complete(void)
-{
- if (penv && penv->pdev && penv->is_cbc_done &&
- !wcnss_device_is_shutdown())
- return 1;
- return 0;
-}
-EXPORT_SYMBOL(wcnss_cbc_complete);
-
int wcnss_device_is_shutdown(void)
{
if (penv && penv->is_shutdown)
@@ -1905,10 +1893,6 @@
pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
fw_status);
break;
- case WCNSS_CBC_COMPLETE_IND:
- penv->is_cbc_done = 1;
- pr_info("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n");
- break;
case WCNSS_CALDATA_UPLD_REQ:
extract_cal_data(len);
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index a9c093b..e51da7f 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -28,6 +28,7 @@
#include <linux/regulator/consumer.h>
#include "nfc-nci.h"
#include <mach/gpiomux.h>
+#include <linux/pm_runtime.h>
struct qca199x_platform_data {
unsigned int irq_gpio;
@@ -56,11 +57,14 @@
#define MAX_QCA_REG (116)
/* will timeout in approx. 100ms as 10us steps */
#define NFC_RF_CLK_FREQ (19200000)
-#define NTF_TIMEOUT (10)
+#define NTF_TIMEOUT (25)
#define CORE_RESET_RSP_GID (0x60)
#define CORE_RESET_OID (0x00)
#define CORE_RST_NTF_LENGTH (0x02)
#define WAKE_TIMEOUT (10)
+#define WAKE_REG (0x10)
+#define EFUSE_REG (0xA0)
+#define WAKEUP_SRC_TIMEOUT (2000)
static void clk_req_update(struct work_struct *work);
@@ -91,6 +95,7 @@
unsigned int clk_src_gpio;
const char *clk_src_name;
struct clk *s_clk;
+ unsigned int core_reset_ntf;
bool clk_run;
struct work_struct msm_clock_controll_work;
struct workqueue_struct *my_wq;
@@ -98,7 +103,8 @@
static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
static int nfcc_hw_check(struct i2c_client *client, unsigned short curr_addr);
-static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr);
+static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr,
+ struct qca199x_dev *qca199x_dev);
static int qca199x_clock_select(struct qca199x_dev *qca199x_dev);
static int qca199x_clock_deselect(struct qca199x_dev *qca199x_dev);
@@ -154,6 +160,20 @@
struct qca199x_dev *qca199x_dev = dev_id;
unsigned long flags;
+ if (device_may_wakeup(&qca199x_dev->client->dev) &&
+ (qca199x_dev->client->dev.power.is_suspended == true)) {
+ dev_dbg(&qca199x_dev->client->dev,
+ "NFC:Processor in suspend state device_may_wakeup\n");
+ /*
+ * Keep system awake long enough to allow userspace
+ * to process the packet.
+ */
+ pm_wakeup_event(&qca199x_dev->client->dev, WAKEUP_SRC_TIMEOUT);
+ } else {
+ dev_dbg(&qca199x_dev->client->dev,
+ "NFC:Processor not in suspend state\n");
+ }
+
spin_lock_irqsave(&qca199x_dev->irq_enabled_lock, flags);
qca199x_dev->count_irq++;
spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock, flags);
@@ -539,11 +559,13 @@
int nfcc_wake(int level, struct file *filp)
{
int r = 0;
+ int time_taken = 0;
unsigned char raw_nci_sleep[] = {0x2F, 0x03, 0x00};
/* Change slave address to 0xE */
unsigned char raw_nci_wake[] = {0x10, 0x0F};
unsigned short slave_addr = 0xE;
unsigned short curr_addr;
+ unsigned char wake_status = WAKE_REG;
struct qca199x_dev *qca199x_dev = filp->private_data;
dev_dbg(&qca199x_dev->client->dev, "nfcc_wake: %s: info: %p\n",
@@ -553,7 +575,6 @@
r = i2c_master_send(qca199x_dev->client, &raw_nci_sleep[0],
sizeof(raw_nci_sleep));
- r = sizeof(raw_nci_sleep);
if (r != sizeof(raw_nci_sleep))
return -EMSGSIZE;
qca199x_dev->state = NFCC_STATE_NORMAL_SLEEP;
@@ -562,11 +583,35 @@
qca199x_dev->client->addr = slave_addr;
r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
sizeof(raw_nci_wake));
+ do {
+ wake_status = WAKE_REG;
+ r = nfc_i2c_write(qca199x_dev->client, &wake_status, 1);
+ /*
+ * NFCC chip needs to be at least
+ * 10usec high before make it low
+ */
+ usleep_range(10, 15);
+ r = i2c_master_recv(qca199x_dev->client, &wake_status,
+ sizeof(wake_status));
+
+ time_taken++;
+ if ((wake_status & NCI_WAKE) != 0)
+ /* NFCC wakeup time is between 0.5 and .52 ms */
+ usleep_range(500, 520);
+
+ } while ((wake_status & NCI_WAKE)
+ && (time_taken < WAKE_TIMEOUT));
/* Restore original NFCC slave I2C address */
+
qca199x_dev->client->addr = curr_addr;
- r = sizeof(raw_nci_wake);
- if (r != sizeof(raw_nci_wake))
+ if (r != sizeof(wake_status))
return -EMSGSIZE;
+
+ if (time_taken >= WAKE_TIMEOUT) {
+ dev_err(&qca199x_dev->client->dev,
+ " %s : TIMED OUT to get WAKEUP bit\n", __func__);
+ r = -EIO;
+ }
qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
}
@@ -625,12 +670,13 @@
dev_dbg(&qca199x_dev->client->dev, "gpio_set_value enable: %s: info: %p\n",
__func__, qca199x_dev);
gpio_set_value(qca199x_dev->dis_gpio, 1);
- usleep(1000);
+ /*nfcc needs atleast 100ms for the chip to power cycle*/
+ msleep(100);
} else if (arg == 2) {
mutex_lock(&qca199x_dev->read_mutex);
dev_dbg(&qca199x_dev->client->dev, "before nfcc_initialise: %s: info: %p\n",
__func__, qca199x_dev);
- r = nfcc_initialise(qca199x_dev->client, 0xE);
+ r = nfcc_initialise(qca199x_dev->client, 0xE, qca199x_dev);
dev_dbg(&qca199x_dev->client->dev, "after nfcc_initialise: %s: info: %p\n",
__func__, qca199x_dev);
/* Also reset first NCI write */
@@ -645,12 +691,12 @@
msleep(20);
} else if (arg == 4) {
mutex_lock(&qca199x_dev->read_mutex);
- nfcc_wake(NFCC_WAKE, filp);
+ r = nfcc_wake(NFCC_WAKE, filp);
dev_dbg(&qca199x_dev->client->dev, "nfcc wake: %s: info: %p\n",
__func__, qca199x_dev);
mutex_unlock(&qca199x_dev->read_mutex);
} else if (arg == 5) {
- nfcc_wake(NFCC_SLEEP, filp);
+ r = nfcc_wake(NFCC_SLEEP, filp);
} else {
r = -ENOIOCTLCMD;
}
@@ -716,6 +762,60 @@
}
/*
+ * Inside nfc_ioctl_nfcc_efuse
+ *
+ * @brief nfc_ioctl_nfcc_efuse
+ *
+ */
+int nfc_ioctl_nfcc_efuse(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int r = 0;
+ unsigned short slave_addr = 0xE;
+ unsigned short curr_addr;
+ unsigned char efuse_addr = EFUSE_REG;
+ unsigned char efuse_value = 0xFF;
+
+ struct qca199x_dev *qca199x_dev = filp->private_data;
+
+ curr_addr = qca199x_dev->client->addr;
+ qca199x_dev->client->addr = slave_addr;
+
+ r = nfc_i2c_write(qca199x_dev->client,
+ &efuse_addr, 1);
+ if (r < 0) {
+ /* Restore original NFCC slave I2C address */
+ qca199x_dev->client->addr = curr_addr;
+ dev_err(&qca199x_dev->client->dev,
+ "ERROR_WRITE_FAIL : i2c write fail\n");
+ return -EIO;
+ }
+
+ /*
+ * NFCC chip needs to be at least
+ * 10usec high before make it low
+ */
+ usleep_range(10, 15);
+
+ r = i2c_master_recv(qca199x_dev->client, &efuse_value,
+ sizeof(efuse_value));
+ if (r < 0) {
+ /* Restore original NFCC slave I2C address */
+ qca199x_dev->client->addr = curr_addr;
+ dev_err(&qca199x_dev->client->dev,
+ "ERROR_I2C_RCV_FAIL : i2c recv fail\n");
+ return -EIO;
+ }
+
+ dev_dbg(&qca199x_dev->client->dev, "%s : EFUSE_VALUE %02x\n",
+ __func__, efuse_value);
+
+ /* Restore original NFCC slave I2C address */
+ qca199x_dev->client->addr = curr_addr;
+ return efuse_value;
+}
+
+/*
* Inside nfc_ioctl_nfcc_version
*
* @brief nfc_ioctl_nfcc_version
@@ -764,13 +864,24 @@
* been cleared.
*/
do {
+ raw_nci_read = 0x10;
+ r = nfc_i2c_write(qca199x_dev->client, &raw_nci_read, 1);
+ /*
+ * NFCC chip needs to be at least
+ * 10usec high before make it low
+ */
+ usleep_range(10, 15);
+
r = i2c_master_recv(qca199x_dev->client, &raw_nci_read,
sizeof(raw_nci_read));
+
if ((raw_nci_read & NCI_WAKE) != 0)
- usleep(1000);
+ /* NFCC wakeup time is between 0.5 and .52 ms */
+ usleep_range(500, 520);
time_taken++;
- } while ((r == 1) && (raw_nci_read & NCI_WAKE)
+
+ } while ((raw_nci_read & NCI_WAKE)
&& (time_taken < WAKE_TIMEOUT));
if (time_taken < WAKE_TIMEOUT)
@@ -854,14 +965,34 @@
return retval;
}
+/*
+ * Inside nfc_ioctl_core_reset_ntf
+ *
+ * @brief nfc_ioctl_core_reset_ntf
+ *
+ * Allows callers to determine if a CORE_RESET_NTF has arrived
+ *
+ * Returns the value of variable core_reset_ntf
+ *
+ */
+int nfc_ioctl_core_reset_ntf(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct qca199x_dev *qca199x_dev = filp->private_data;
+ dev_dbg(&qca199x_dev->client->dev,
+ "nfc_ioctl_core_reset_ntf: returning = %d\n",
+ qca199x_dev->core_reset_ntf);
+ return qca199x_dev->core_reset_ntf;
+}
+
static long nfc_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{
int r = 0;
-
+ struct qca199x_dev *qca199x_dev = pfile->private_data;
switch (cmd) {
case NFC_SET_PWR:
- nfc_ioctl_power_states(pfile, cmd, arg);
+ r = nfc_ioctl_power_states(pfile, cmd, arg);
break;
case NFCC_MODE:
nfc_ioctl_nfcc_mode(pfile, cmd, arg);
@@ -876,6 +1007,17 @@
break;
case SET_EMULATOR_TEST_POINT:
break;
+ case NFCC_INITIAL_CORE_RESET_NTF:
+ r = nfc_ioctl_core_reset_ntf(pfile, cmd, arg);
+ break;
+ case NFC_GET_EFUSE:
+ r = nfc_ioctl_nfcc_efuse(pfile, cmd, arg);
+ if (r < 0) {
+ r = 0xFF;
+ dev_err(&qca199x_dev->client->dev,
+ "nfc_ioctl : FAILED TO READ EFUSE TYPE\n");
+ }
+ break;
default:
r = -ENOIOCTLCMD;
}
@@ -960,7 +1102,8 @@
return r;
}
/* Initialise qca199x_ NFC controller hardware */
-static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
+static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr,
+ struct qca199x_dev *qca199x_dev)
{
int r = 0;
unsigned char raw_1p8_CONTROL_011[] = {0x11, XTAL_CLOCK};
@@ -979,6 +1122,7 @@
int ret = 0;
client->addr = curr_addr;
+ qca199x_dev->core_reset_ntf = DEFAULT_INITIAL_CORE_RESET_NTF;
r = i2c_master_send(client, &buf, 1);
if (r < 0)
goto err_init;
@@ -1102,6 +1246,11 @@
}
time_taken++;
} while (!core_reset_completed);
+ if (time_taken == NTF_TIMEOUT)
+ qca199x_dev->core_reset_ntf = TIMEDOUT_INITIAL_CORE_RESET_NTF;
+ else
+ qca199x_dev->core_reset_ntf = ARRIVED_INITIAL_CORE_RESET_NTF;
+
r = 0;
return r;
err_init:
@@ -1496,6 +1645,8 @@
INIT_WORK(&qca199x_dev->msm_clock_controll_work,
clk_req_update);
}
+ device_init_wakeup(&client->dev, true);
+ device_set_wakeup_capable(&client->dev, true);
i2c_set_clientdata(client, qca199x_dev);
gpio_set_value(platform_data->dis_gpio, 1);
@@ -1560,11 +1711,33 @@
return 0;
}
+static int qca199x_suspend(struct device *device)
+{
+ struct i2c_client *client = to_i2c_client(device);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+ return 0;
+}
+
+static int qca199x_resume(struct device *device)
+{
+ struct i2c_client *client = to_i2c_client(device);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+ return 0;
+}
+
static const struct i2c_device_id qca199x_id[] = {
{"qca199x-i2c", 0},
{}
};
+static const struct dev_pm_ops nfc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(qca199x_suspend, qca199x_resume)
+};
+
static struct i2c_driver qca199x = {
.id_table = qca199x_id,
.probe = qca199x_probe,
@@ -1573,6 +1746,7 @@
.owner = THIS_MODULE,
.name = "nfc-nci",
.of_match_table = msm_match_table,
+ .pm = &nfc_pm_ops,
},
};
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index 297c152..398fa3f 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -60,6 +60,8 @@
#define SET_RX_BLOCK _IOW(0xE9, 0x04, unsigned int)
#define SET_EMULATOR_TEST_POINT _IOW(0xE9, 0x05, unsigned int)
#define NFCC_VERSION _IOW(0xE9, 0x08, unsigned int)
+#define NFC_GET_EFUSE _IOW(0xE9, 0x09, unsigned int)
+#define NFCC_INITIAL_CORE_RESET_NTF _IOW(0xE9, 0x10, unsigned int)
#define NFC_MAX_I2C_TRANSFER (0x0400)
#define NFC_MSG_MAX_SIZE (0x21)
@@ -195,6 +197,11 @@
NFCC_INT,
};
+enum nfcc_initial_core_reset_ntf {
+ TIMEDOUT_INITIAL_CORE_RESET_NTF = 0, /* 0*/
+ ARRIVED_INITIAL_CORE_RESET_NTF, /* 1 */
+ DEFAULT_INITIAL_CORE_RESET_NTF, /*2*/
+};
struct nfc_info {
struct miscdevice miscdev;
diff --git a/drivers/platform/msm/avtimer.c b/drivers/platform/msm/avtimer.c
index d5fa885..bb9b2bf 100644
--- a/drivers/platform/msm/avtimer.c
+++ b/drivers/platform/msm/avtimer.c
@@ -25,11 +25,15 @@
#include <linux/wait.h>
#include <linux/sched.h>
#include <mach/qdsp6v2/apr.h>
+#include <sound/q6core.h>
#define DEVICE_NAME "avtimer"
#define TIMEOUT_MS 1000
#define CORE_CLIENT 1
#define TEMP_PORT ((CORE_CLIENT << 8) | 0x0001)
+#define SSR_WAKETIME 1000
+#define Q6_READY_RETRY 250
+#define Q6_READY_MAX_RETRIES 40
#define AVCS_CMD_REMOTE_AVTIMER_VOTE_REQUEST 0x00012914
#define AVCS_CMD_RSP_REMOTE_AVTIMER_VOTE_REQUEST 0x00012915
@@ -53,11 +57,15 @@
struct mutex avtimer_lock;
int avtimer_open_cnt;
struct dev_avtimer_data avtimer_pdata;
+ struct delayed_work ssr_dwork;
wait_queue_head_t adsp_resp_wait;
int enable_timer_resp_recieved;
int timer_handle;
void __iomem *p_avtimer_msw;
void __iomem *p_avtimer_lsw;
+ uint32_t clk_div;
+ atomic_t adsp_ready;
+ int num_retries;
};
static struct avtimer_t avtimer;
@@ -102,6 +110,10 @@
pr_debug("%s: Reset event received in AV timer\n", __func__);
apr_reset(avtimer.core_handle_q);
avtimer.core_handle_q = NULL;
+ avtimer.avtimer_open_cnt = 0;
+ atomic_set(&avtimer.adsp_ready, 0);
+ schedule_delayed_work(&avtimer.ssr_dwork,
+ msecs_to_jiffies(SSR_WAKETIME));
break;
}
@@ -239,8 +251,10 @@
goto done;
}
rc = avcs_core_enable_avtimer("timer");
- if (!rc)
+ if (!rc) {
avtimer.avtimer_open_cnt++;
+ atomic_set(&avtimer.adsp_ready, 1);
+ }
} else {
if (avtimer.avtimer_open_cnt > 0) {
avtimer.avtimer_open_cnt--;
@@ -257,6 +271,48 @@
}
EXPORT_SYMBOL(avcs_core_disable_power_collapse);
+static void reset_work(struct work_struct *work)
+{
+ if (q6core_is_adsp_ready()) {
+ avcs_core_disable_power_collapse(1);
+ avtimer.num_retries = Q6_READY_MAX_RETRIES;
+ return;
+ }
+ pr_debug("%s:Q6 not ready-retry after sometime\n", __func__);
+ if (--avtimer.num_retries > 0) {
+ schedule_delayed_work(&avtimer.ssr_dwork,
+ msecs_to_jiffies(Q6_READY_RETRY));
+ } else {
+ pr_err("%s: Q6 failed responding after multiple retries\n",
+ __func__);
+ avtimer.num_retries = Q6_READY_MAX_RETRIES;
+ }
+}
+
+int avcs_core_query_timer(uint64_t *avtimer_tick)
+{
+ uint32_t avtimer_msw = 0, avtimer_lsw = 0;
+ uint32_t res = 0;
+ uint64_t avtimer_tick_temp;
+
+ if (!atomic_read(&avtimer.adsp_ready)) {
+ pr_debug("%s:In SSR, return\n", __func__);
+ return -ENETRESET;
+ }
+ avtimer_lsw = ioread32(avtimer.p_avtimer_lsw);
+ avtimer_msw = ioread32(avtimer.p_avtimer_msw);
+
+ avtimer_tick_temp =
+ (uint64_t)((uint64_t)avtimer_msw << 32)
+ | avtimer_lsw;
+ res = do_div(avtimer_tick_temp, avtimer.clk_div);
+ *avtimer_tick = avtimer_tick_temp;
+ pr_debug("%s:Avtimer: msw: %u, lsw: %u, tick: %llu\n", __func__,
+ avtimer_msw, avtimer_lsw, *avtimer_tick);
+ return 0;
+}
+EXPORT_SYMBOL(avcs_core_query_timer);
+
static int avtimer_open(struct inode *inode, struct file *file)
{
return avcs_core_disable_power_collapse(1);
@@ -285,6 +341,7 @@
avtimer_msw_2nd = ioread32(avtimer.p_avtimer_msw);
} while (avtimer_msw_1st != avtimer_msw_2nd);
+ avtimer_lsw = avtimer_lsw/avtimer.clk_div;
avtimer_tick =
((uint64_t) avtimer_msw_1st << 32) | avtimer_lsw;
@@ -317,6 +374,7 @@
dev_t dev = MKDEV(major, 0);
struct device *device_handle;
struct resource *reg_lsb = NULL, *reg_msb = NULL;
+ uint32_t clk_div_val;
if (!pdev) {
pr_err("%s: Invalid params\n", __func__);
@@ -336,6 +394,8 @@
"avtimer_msb_addr", __func__);
return -EINVAL;
}
+ INIT_DELAYED_WORK(&avtimer.ssr_dwork, reset_work);
+
avtimer.p_avtimer_lsw = devm_ioremap_nocache(&pdev->dev,
reg_lsb->start, resource_size(reg_lsb));
if (!avtimer.p_avtimer_lsw) {
@@ -351,6 +411,7 @@
__func__);
goto unmap;
}
+ avtimer.num_retries = Q6_READY_MAX_RETRIES;
/* get the device number */
if (major)
result = register_chrdev_region(dev, 1, DEVICE_NAME);
@@ -360,14 +421,15 @@
}
if (result < 0) {
- pr_err("%s: Registering avtimer device failed\n", __func__);
+ dev_err(&pdev->dev, "%s: Registering avtimer device failed\n",
+ __func__);
goto unmap;
}
avtimer.avtimer_class = class_create(THIS_MODULE, "avtimer");
if (IS_ERR(avtimer.avtimer_class)) {
result = PTR_ERR(avtimer.avtimer_class);
- pr_err("%s: Error creating avtimer class: %d\n",
+ dev_err(&pdev->dev, "%s: Error creating avtimer class: %d\n",
__func__, result);
goto unregister_chrdev_region;
}
@@ -376,7 +438,8 @@
result = cdev_add(&avtimer.myc, dev, 1);
if (result < 0) {
- pr_err("%s: Registering file operations failed\n", __func__);
+ dev_err(&pdev->dev, "%s: Registering file operations failed\n",
+ __func__);
goto class_destroy;
}
@@ -394,6 +457,13 @@
pr_debug("%s: Device create done for avtimer major=%d\n",
__func__, major);
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,clk_div", &clk_div_val))
+ avtimer.clk_div = 1;
+ else
+ avtimer.clk_div = clk_div_val;
+
+ pr_debug("avtimer.clk_div = %d\n", avtimer.clk_div);
return 0;
class_destroy:
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 537dc1d..6752828 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -2209,7 +2209,6 @@
rc_new_uah = (params->fcc_uah * pc_new) / 100;
soc_new = (rc_new_uah - params->cc_uah - params->uuc_uah)*100
/ (params->fcc_uah - params->uuc_uah);
- soc_new = bound_soc(soc_new);
/*
* if soc_new is ZERO force it higher so that phone doesnt report soc=0
@@ -2467,6 +2466,8 @@
/* always clamp soc due to BMS hw/sw immaturities */
new_calculated_soc = clamp_soc_based_on_voltage(chip,
new_calculated_soc);
+
+ new_calculated_soc = bound_soc(new_calculated_soc);
/*
* If the battery is full, configure the cc threshold so the system
* wakes up after SoC changes
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a30b5bb..38bd666 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1736,11 +1736,8 @@
power_supply_changed(chip->usb_psy);
}
}
- if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
- chip->delta_vddmax_mv = 0;
- qpnp_chg_set_appropriate_vddmax(chip);
+ if (!qpnp_chg_is_dc_chg_plugged_in(chip))
chip->chg_done = false;
- }
if (!qpnp_is_dc_higher_prio(chip))
qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
@@ -1771,10 +1768,6 @@
}
}
- if (!qpnp_chg_is_dc_chg_plugged_in(chip)) {
- chip->delta_vddmax_mv = 0;
- qpnp_chg_set_appropriate_vddmax(chip);
- }
schedule_delayed_work(&chip->eoc_work,
msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
schedule_work(&chip->soc_check_work);
@@ -1952,14 +1945,8 @@
qpnp_chg_force_run_on_batt(chip, !dc_present ? 1 : 0);
if (!dc_present && (!qpnp_chg_is_usb_chg_plugged_in(chip) ||
qpnp_chg_is_otg_en_set(chip))) {
- chip->delta_vddmax_mv = 0;
- qpnp_chg_set_appropriate_vddmax(chip);
chip->chg_done = false;
} else {
- if (!qpnp_chg_is_usb_chg_plugged_in(chip)) {
- chip->delta_vddmax_mv = 0;
- qpnp_chg_set_appropriate_vddmax(chip);
- }
schedule_delayed_work(&chip->eoc_work,
msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
schedule_work(&chip->soc_check_work);
@@ -3808,8 +3795,6 @@
? "cool" : "warm",
qpnp_chg_vddmax_get(chip));
}
- chip->delta_vddmax_mv = 0;
- qpnp_chg_set_appropriate_vddmax(chip);
qpnp_chg_charge_en(chip, 0);
/* sleep for a second before enabling */
msleep(2000);
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 85e8842..299d3ee 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -1154,6 +1154,14 @@
struct slim_device *sbdev;
struct list_head *pos, *next;
int ret, i = 0;
+ ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
+ SLIMBUS_QMI_SVC_V1,
+ SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
+ if (ret) {
+ pr_err("Slimbus QMI service registration failed:%d", ret);
+ return ret;
+ }
+
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
wait_for_completion(&dev->qmi.slave_notify);
@@ -1426,14 +1434,6 @@
INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
dev->qmi.nb.notifier_call = ngd_qmi_available;
pm_runtime_get_noresume(dev->dev);
- ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
- SLIMBUS_QMI_SVC_V1,
- SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
- if (ret) {
- pr_err("Slimbus QMI service registration failed:%d", ret);
- goto qmi_register_failed;
- }
-
/* Fire up the Rx message queue thread */
dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
@@ -1458,10 +1458,6 @@
err_notify_thread_create_failed:
kthread_stop(dev->rx_msgq_thread);
err_rx_thread_create_failed:
- qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
- SLIMBUS_QMI_SVC_V1,
- SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
-qmi_register_failed:
free_irq(dev->irq, dev);
err_request_irq_failed:
slim_del_controller(&dev->ctrl);
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index e5eb9b2..f2fb09d 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -39,6 +39,8 @@
#include <mach/rpm-regulator-smd.h>
#include <linux/regulator/consumer.h>
#include <linux/msm_thermal_ioctl.h>
+#include <mach/rpm-smd.h>
+#include <mach/scm.h>
#define MAX_CURRENT_UA 1000000
#define MAX_RAILS 5
@@ -46,6 +48,7 @@
#define MONITOR_ALL_TSENS -1
#define BYTES_PER_FUSE_ROW 8
#define MAX_EFUSE_VALUE 16
+#define THERM_SECURE_BITE_CMD 8
static struct msm_thermal_data msm_thermal_info;
static struct delayed_work check_temp_work;
@@ -89,6 +92,7 @@
static bool ocr_probed;
static bool interrupt_mode_enable;
static bool msm_thermal_probed;
+static bool therm_reset_enabled;
static int *tsens_id_map;
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
@@ -169,6 +173,7 @@
};
enum msm_thresh_list {
+ MSM_THERM_RESET,
MSM_VDD_RESTRICTION,
MSM_LIST_MAX_NR,
};
@@ -929,6 +934,73 @@
return ret;
}
+static void msm_thermal_bite(int tsens_id, long temp)
+{
+ pr_err("TSENS:%d reached temperature:%ld. System reset\n",
+ tsens_id, temp);
+ scm_call_atomic1(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, 0);
+}
+
+static int do_therm_reset(void)
+{
+ int ret = 0, i;
+ long temp = 0;
+
+ if (!therm_reset_enabled)
+ return ret;
+
+ for (i = 0; i < thresh[MSM_THERM_RESET].thresh_ct; i++) {
+ ret = therm_get_temp(
+ thresh[MSM_THERM_RESET].thresh_list[i].sensor_id,
+ THERM_TSENS_ID,
+ &temp);
+ if (ret) {
+ pr_err("Unable to read TSENS sensor:%d. err:%d\n",
+ thresh[MSM_THERM_RESET].thresh_list[i].sensor_id,
+ ret);
+ continue;
+ }
+
+ if (temp >= msm_thermal_info.therm_reset_temp_degC)
+ msm_thermal_bite(
+ thresh[MSM_THERM_RESET].thresh_list[i].sensor_id, temp);
+ }
+
+ return ret;
+}
+
+static void therm_reset_notify(struct therm_threshold *thresh_data)
+{
+ long temp;
+ int ret = 0;
+
+ if (!therm_reset_enabled)
+ return;
+
+ if (!thresh_data) {
+ pr_err("Invalid input\n");
+ return;
+ }
+
+ switch (thresh_data->trip_triggered) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ ret = therm_get_temp(thresh_data->sensor_id,
+ THERM_TSENS_ID, &temp);
+ if (ret)
+ pr_err("Unable to read TSENS sensor:%d. err:%d\n",
+ thresh_data->sensor_id, ret);
+ msm_thermal_bite(tsens_id_map[thresh_data->sensor_id],
+ temp);
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ break;
+ default:
+ pr_err("Invalid trip type\n");
+ break;
+ }
+ set_threshold(thresh_data->sensor_id, thresh_data->threshold);
+}
+
#ifdef CONFIG_SMP
static void __ref do_core_control(long temp)
{
@@ -1266,6 +1338,8 @@
long temp = 0;
int ret = 0;
+ do_therm_reset();
+
ret = therm_get_temp(msm_thermal_info.sensor_id, THERM_TSENS_ID, &temp);
if (ret) {
pr_err("Unable to read TSENS sensor:%d. err:%d\n",
@@ -1740,6 +1814,9 @@
goto init_exit;
}
+ if (therm_reset_enabled)
+ therm_set_threshold(&thresh[MSM_THERM_RESET]);
+
if (vdd_rstr_enabled)
therm_set_threshold(&thresh[MSM_VDD_RESTRICTION]);
@@ -3047,6 +3124,38 @@
return ret;
}
+static int probe_therm_reset(struct device_node *node,
+ struct msm_thermal_data *data,
+ struct platform_device *pdev)
+{
+ char *key = NULL;
+ int ret = 0;
+
+ key = "qcom,therm-reset-temp";
+ ret = of_property_read_u32(node, key, &data->therm_reset_temp_degC);
+ if (ret)
+ goto PROBE_RESET_EXIT;
+
+ ret = init_threshold(MSM_THERM_RESET, MONITOR_ALL_TSENS,
+ data->therm_reset_temp_degC, data->therm_reset_temp_degC - 10,
+ therm_reset_notify);
+ if (ret) {
+ pr_err("Therm reset data structure init failed\n");
+ goto PROBE_RESET_EXIT;
+ }
+
+ therm_reset_enabled = true;
+
+PROBE_RESET_EXIT:
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s err=%d. KTM continues\n",
+ __func__, node->full_name, key, ret);
+ therm_reset_enabled = false;
+ }
+ return ret;
+}
+
static int probe_freq_mitigation(struct device_node *node,
struct msm_thermal_data *data,
struct platform_device *pdev)
@@ -3132,6 +3241,8 @@
ret = probe_cc(node, &data, pdev);
ret = probe_freq_mitigation(node, &data, pdev);
+ ret = probe_therm_reset(node, &data, pdev);
+
/*
* Probe optional properties below. Call probe_psm before
* probe_vdd_rstr because rpm_regulator_get has to be called
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index b13e8e5..fe0b20f 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1240,7 +1240,7 @@
* upon set config#1. Call set_alt for non-zero
* alternate setting.
*/
- if (!w_value && cdev->config) {
+ if (!w_value && cdev->config && !f->get_alt) {
value = 0;
break;
}
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 2dd66f8..4bf2ca7 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -763,7 +763,7 @@
MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_1);
spin_lock_irqsave(&dma->histo_lock, flag);
- init_completion(&dma->histo_comp);
+ INIT_COMPLETION(dma->histo_comp);
MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_START, 1);
wmb();
dma->histo_state = MDP3_DMA_HISTO_STATE_START;
@@ -781,7 +781,7 @@
spin_lock_irqsave(&dma->histo_lock, flag);
- init_completion(&dma->histo_comp);
+ INIT_COMPLETION(dma->histo_comp);
MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_START, 1);
wmb();
dma->histo_state = MDP3_DMA_HISTO_STATE_START;
@@ -800,7 +800,7 @@
spin_lock_irqsave(&dma->histo_lock, flag);
- init_completion(&dma->histo_comp);
+ INIT_COMPLETION(dma->histo_comp);
mdp3_dma_clk_auto_gating(dma, 0);
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
index a25c2c7..8c5d771 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_hwio.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -953,7 +953,7 @@
PPP_WRITEL(phase_step_y, MDP3_PPP_SCALE_PHASEY_STEP);
- if (dstW > src->roi.width || dstW > src->roi.height)
+ if (dstW > src->roi.width || dstH > src->roi.height)
ppp_load_up_lut();
if (mdp_blur)
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index bf91a29..edde3e3 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -44,6 +44,7 @@
#include <linux/file.h>
#include <linux/memory_alloc.h>
#include <linux/kthread.h>
+#include <linux/of_address.h>
#include <mach/board.h>
#include <mach/memory.h>
@@ -87,7 +88,10 @@
static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd);
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg);
-static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
+ struct vm_area_struct *vma);
+static int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd,
+ size_t size);
static void mdss_fb_release_fences(struct msm_fb_data_type *mfd);
static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
unsigned long val, void *data);
@@ -1070,31 +1074,258 @@
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
-/*
- * Custom Framebuffer mmap() function for MSM driver.
- * Differs from standard mmap() function by allowing for customized
- * page-protection.
+/* Set VM page protection */
+static inline void __mdss_fb_set_page_protection(struct vm_area_struct *vma,
+ struct msm_fb_data_type *mfd)
+{
+ if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
+ vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
+ vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
+ vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+
+}
+
+static inline int mdss_fb_create_ion_client(struct msm_fb_data_type *mfd)
+{
+ mfd->fb_ion_client = msm_ion_client_create(-1 , "mdss_fb_iclient");
+ if (IS_ERR_OR_NULL(mfd->fb_ion_client)) {
+ pr_err("Err:client not created, val %d\n",
+ PTR_RET(mfd->fb_ion_client));
+ mfd->fb_ion_client = NULL;
+ return PTR_RET(mfd->fb_ion_client);
+ }
+ return 0;
+}
+
+void mdss_fb_free_fb_ion_memory(struct msm_fb_data_type *mfd)
+{
+ if (!mfd) {
+ pr_err("no mfd\n");
+ return;
+ }
+
+ if (!mfd->fbi->screen_base)
+ return;
+
+ if (!mfd->fb_ion_client || !mfd->fb_ion_handle) {
+ pr_err("invalid input parameters for fb%d\n", mfd->index);
+ return;
+ }
+
+ mfd->fbi->screen_base = NULL;
+ mfd->fbi->fix.smem_start = 0;
+
+ ion_unmap_kernel(mfd->fb_ion_client, mfd->fb_ion_handle);
+
+ if (mfd->mdp.fb_mem_get_iommu_domain) {
+ ion_unmap_iommu(mfd->fb_ion_client, mfd->fb_ion_handle,
+ mfd->mdp.fb_mem_get_iommu_domain(), 0);
+ }
+
+ ion_free(mfd->fb_ion_client, mfd->fb_ion_handle);
+ mfd->fb_ion_handle = NULL;
+}
+
+int mdss_fb_alloc_fb_ion_memory(struct msm_fb_data_type *mfd, size_t fb_size)
+{
+ unsigned long buf_size;
+ int rc;
+ void *vaddr;
+
+ if (!mfd) {
+ pr_err("Invalid input param - no mfd");
+ return -EINVAL;
+ }
+
+ if (!mfd->fb_ion_client) {
+ rc = mdss_fb_create_ion_client(mfd);
+ if (rc < 0) {
+ pr_err("fb ion client couldn't be created - %d\n", rc);
+ return rc;
+ }
+ }
+
+ pr_debug("size for mmap = %zu", fb_size);
+ mfd->fb_ion_handle = ion_alloc(mfd->fb_ion_client, fb_size, SZ_4K,
+ ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(mfd->fb_ion_handle)) {
+ pr_err("unable to alloc fbmem from ion - %ld\n",
+ PTR_ERR(mfd->fb_ion_handle));
+ return PTR_ERR(mfd->fb_ion_handle);
+ }
+
+ if (mfd->mdp.fb_mem_get_iommu_domain) {
+ rc = ion_map_iommu(mfd->fb_ion_client, mfd->fb_ion_handle,
+ mfd->mdp.fb_mem_get_iommu_domain(), 0, SZ_4K, 0,
+ &mfd->iova, &buf_size, 0, 0);
+ if (rc) {
+ pr_err("Cannot map fb_mem to IOMMU. rc=%d\n", rc);
+ goto fb_mmap_failed;
+ }
+ } else {
+ pr_err("No IOMMU Domain");
+ goto fb_mmap_failed;
+
+ }
+
+ vaddr = ion_map_kernel(mfd->fb_ion_client, mfd->fb_ion_handle);
+ if (IS_ERR_OR_NULL(vaddr)) {
+ pr_err("ION memory mapping failed - %ld\n", PTR_ERR(vaddr));
+ rc = PTR_ERR(vaddr);
+ if (mfd->mdp.fb_mem_get_iommu_domain) {
+ ion_unmap_iommu(mfd->fb_ion_client, mfd->fb_ion_handle,
+ mfd->mdp.fb_mem_get_iommu_domain(), 0);
+ }
+ goto fb_mmap_failed;
+ }
+
+ pr_debug("alloc 0x%zuB vaddr = %p (%pa iova) for fb%d\n", fb_size,
+ vaddr, &mfd->iova, mfd->index);
+
+ mfd->fbi->screen_base = (char *) vaddr;
+ mfd->fbi->fix.smem_start = (unsigned int) mfd->iova;
+ mfd->fbi->fix.smem_len = fb_size;
+
+ return rc;
+
+fb_mmap_failed:
+ ion_free(mfd->fb_ion_client, mfd->fb_ion_handle);
+ return rc;
+}
+
+/**
+ * mdss_fb_fbmem_ion_mmap() - Custom fb mmap() function for MSM driver.
+ *
+ * @info - Framebuffer info.
+ * @vma - VM area which is part of the process virtual memory.
+ *
+ * This framebuffer mmap function differs from standard mmap() function by
+ * allowing for customized page-protection and dynamically allocate framebuffer
+ * memory from system heap and map to iommu virtual address.
+ *
+ * Return: virtual address is returned through vma
*/
-static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+static int mdss_fb_fbmem_ion_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
+{
+ int rc = 0;
+ size_t req_size, fb_size;
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct sg_table *table;
+ unsigned long addr = vma->vm_start;
+ unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+ struct scatterlist *sg;
+ unsigned int i;
+ struct page *page;
+
+ if (!mfd || !mfd->pdev || !mfd->pdev->dev.of_node) {
+ pr_err("Invalid device node\n");
+ return -ENODEV;
+ }
+
+ req_size = vma->vm_end - vma->vm_start;
+ fb_size = mfd->fbi->fix.smem_len;
+ if (req_size > fb_size) {
+ pr_warn("requested map is greater than framebuffer");
+ return -EOVERFLOW;
+ }
+
+ if (!mfd->fbi->screen_base) {
+ rc = mdss_fb_alloc_fb_ion_memory(mfd, fb_size);
+ if (rc < 0) {
+ pr_err("fb mmap failed!!!!");
+ return rc;
+ }
+ }
+
+ table = ion_sg_table(mfd->fb_ion_client, mfd->fb_ion_handle);
+ if (IS_ERR(table)) {
+ pr_err("Unable to get sg_table from ion:%ld\n", PTR_ERR(table));
+ mfd->fbi->screen_base = NULL;
+ return PTR_ERR(table);
+ } else if (!table) {
+ pr_err("sg_list is NULL\n");
+ mfd->fbi->screen_base = NULL;
+ return -EINVAL;
+ }
+
+ page = sg_page(table->sgl);
+ if (page) {
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ unsigned long remainder = vma->vm_end - addr;
+ unsigned long len = sg->length;
+
+ page = sg_page(sg);
+
+ if (offset >= sg->length) {
+ offset -= sg->length;
+ continue;
+ } else if (offset) {
+ page += offset / PAGE_SIZE;
+ len = sg->length - offset;
+ offset = 0;
+ }
+ len = min(len, remainder);
+
+ __mdss_fb_set_page_protection(vma, mfd);
+
+ pr_debug("vma=%p, addr=%x len=%ld",
+ vma, (unsigned int)addr, len);
+ pr_cont("vm_start=%x vm_end=%x vm_page_prot=%ld\n",
+ (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end,
+ (unsigned long int)vma->vm_page_prot);
+
+ io_remap_pfn_range(vma, addr, page_to_pfn(page), len,
+ vma->vm_page_prot);
+ addr += len;
+ if (addr >= vma->vm_end)
+ break;
+ }
+ } else {
+ pr_err("PAGE is null\n");
+ mdss_fb_free_fb_ion_memory(mfd);
+ return -ENOMEM;
+ }
+
+ return rc;
+}
+
+/*
+ * mdss_fb_physical_mmap() - Custom fb mmap() function for MSM driver.
+ *
+ * @info - Framebuffer info.
+ * @vma - VM area which is part of the process virtual memory.
+ *
+ * This framebuffer mmap function differs from standard mmap() function as
+ * map to framebuffer memory from the CMA memory which is allocated during
+ * bootup.
+ *
+ * Return: virtual address is returned through vma
+ */
+static int mdss_fb_physical_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
{
/* Get frame buffer memory range. */
unsigned long start = info->fix.smem_start;
u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- int ret = 0;
if (!start) {
- pr_warn("No framebuffer memory is allocated.\n");
+ pr_warn("No framebuffer memory is allocated\n");
return -ENOMEM;
}
- ret = mdss_fb_pan_idle(mfd);
- if (ret) {
- pr_err("Shutdown pending. Aborting operation\n");
- return ret;
- }
-
/* Set VM flags. */
start &= PAGE_MASK;
if ((vma->vm_end <= vma->vm_start) ||
@@ -1106,22 +1337,7 @@
return -EINVAL;
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
- vma->vm_flags |= VM_IO | VM_RESERVED;
-
- /* Set VM page protection */
- if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
- vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
- vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
- else if (mfd->mdp_fb_page_protection ==
- MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
- vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO;
/* Remap the frame buffer I/O range */
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
@@ -1132,6 +1348,22 @@
return 0;
}
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int rc = 0;
+
+ if (!info->fix.smem_start && !mfd->fb_ion_handle)
+ rc = mdss_fb_fbmem_ion_mmap(info, vma);
+ else
+ rc = mdss_fb_physical_mmap(info, vma);
+
+ if (rc < 0)
+ pr_err("fb mmap failed with rc = %d", rc);
+
+ return rc;
+}
+
static struct fb_ops mdss_fb_ops = {
.owner = THIS_MODULE,
.fb_open = mdss_fb_open,
@@ -1141,48 +1373,66 @@
.fb_blank = mdss_fb_blank, /* blank display */
.fb_pan_display = mdss_fb_pan_display, /* pan display */
.fb_ioctl = mdss_fb_ioctl, /* perform fb specific ioctl */
+#ifdef CONFIG_COMPAT
+ .fb_compat_ioctl = mdss_fb_compat_ioctl,
+#endif
.fb_mmap = mdss_fb_mmap,
};
static int mdss_fb_alloc_fbmem_iommu(struct msm_fb_data_type *mfd, int dom)
{
void *virt = NULL;
- unsigned long phys = 0;
+ phys_addr_t phys = 0;
size_t size = 0;
struct platform_device *pdev = mfd->pdev;
+ int rc = 0;
+ struct device_node *fbmem_pnode = NULL;
if (!pdev || !pdev->dev.of_node) {
pr_err("Invalid device node\n");
return -ENODEV;
}
- if (of_property_read_u32(pdev->dev.of_node,
- "qcom,memory-reservation-size",
- &size) || !size) {
+ fbmem_pnode = of_parse_phandle(pdev->dev.of_node,
+ "linux,contiguous-region", 0);
+ if (!fbmem_pnode) {
+ pr_debug("fbmem is not reserved for %s\n", pdev->name);
mfd->fbi->screen_base = NULL;
mfd->fbi->fix.smem_start = 0;
- mfd->fbi->fix.smem_len = 0;
return 0;
+ } else {
+ const u32 *addr;
+ u64 len;
+
+ addr = of_get_address(fbmem_pnode, 0, &len, NULL);
+ if (!addr) {
+ pr_err("fbmem size is not specified\n");
+ of_node_put(fbmem_pnode);
+ return -EINVAL;
+ }
+ size = (size_t)len;
+ of_node_put(fbmem_pnode);
}
- pr_info("%s frame buffer reserve_size=0x%x\n", __func__, size);
+ pr_debug("%s frame buffer reserve_size=0x%zx\n", __func__, size);
if (size < PAGE_ALIGN(mfd->fbi->fix.line_length *
mfd->fbi->var.yres_virtual))
pr_warn("reserve size is smaller than framebuffer size\n");
- virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+ virt = dma_alloc_coherent(&pdev->dev, size, &phys, GFP_KERNEL);
if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
+ pr_err("unable to alloc fbmem size=%zx\n", size);
return -ENOMEM;
}
- phys = memory_pool_node_paddr(virt);
-
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+ rc = msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
&mfd->iova);
- pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
- size, virt, phys, mfd->index);
+ if (rc)
+ pr_warn("Cannot map fb_mem %pa to IOMMU. rc=%d\n", &phys, rc);
+
+ pr_debug("alloc 0x%zxB @ (%pa phys) (0x%p virt) (%pa iova) for fb%d\n",
+ size, &phys, virt, &mfd->iova, mfd->index);
mfd->fbi->screen_base = virt;
mfd->fbi->fix.smem_start = phys;
@@ -1194,9 +1444,9 @@
static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
{
- if (mfd->mdp.fb_mem_alloc_fnc)
+ if (mfd->mdp.fb_mem_alloc_fnc) {
return mfd->mdp.fb_mem_alloc_fnc(mfd);
- else if (mfd->mdp.fb_mem_get_iommu_domain) {
+ } else if (mfd->mdp.fb_mem_get_iommu_domain) {
int dom = mfd->mdp.fb_mem_get_iommu_domain();
if (dom >= 0)
return mdss_fb_alloc_fbmem_iommu(mfd, dom);
@@ -1374,8 +1624,14 @@
var->hsync_len = panel_info->lcdc.h_pulse_width;
var->pixclock = panel_info->clk_rate / 1000;
- /* id field for fb app */
+ /*
+ * Populate smem length here for uspace to get the
+ * Framebuffer size when FBIO_FSCREENINFO ioctl is
+ * called.
+ */
+ fix->smem_len = PAGE_ALIGN(fix->line_length * var->yres) * mfd->fb_page;
+ /* id field for fb app */
id = (int *)&mfd->panel;
snprintf(fix->id, sizeof(fix->id), "mdssfb_%x", (u32) *id);
@@ -1390,10 +1646,8 @@
mdss_fb_parse_dt(mfd);
- if (mdss_fb_alloc_fbmem(mfd)) {
- pr_err("unable to allocate framebuffer memory\n");
- return -ENOMEM;
- }
+ if (mdss_fb_alloc_fbmem(mfd))
+ pr_warn("unable to allocate fb memory in fb register\n");
mfd->op_enable = true;
@@ -1430,9 +1684,8 @@
return -EPERM;
}
- pr_info("FrameBuffer[%d] %dx%d size=%d registered successfully!\n",
- mfd->index, fbi->var.xres, fbi->var.yres,
- fbi->fix.smem_len);
+ pr_info("FrameBuffer[%d] %dx%d registered successfully!\n", mfd->index,
+ fbi->var.xres, fbi->var.yres);
return 0;
}
@@ -1606,6 +1859,16 @@
mfd->disp_thread = NULL;
}
+ if (mfd->mdp.release_fnc) {
+ ret = mfd->mdp.release_fnc(mfd, true);
+ if (ret)
+ pr_err("error fb%d release process %s pid=%d\n",
+ mfd->index, task->comm, pid);
+ }
+
+ if (mfd->fb_ion_handle)
+ mdss_fb_free_fb_ion_memory(mfd);
+
ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
mfd->op_enable);
if (ret) {
@@ -2181,6 +2444,8 @@
else
mfd->fbi->fix.line_length = var->xres * var->bits_per_pixel / 8;
+ mfd->fbi->fix.smem_len = mfd->fbi->fix.line_length *
+ mfd->fbi->var.yres_virtual;
if (mfd->panel_reconfig || (mfd->fb_imgType != old_imgType)) {
mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 1ab0fb7..8e6be01 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -229,6 +229,8 @@
u32 dcm_state;
struct list_head proc_list;
u32 wait_for_kickoff;
+ struct ion_client *fb_ion_client;
+ struct ion_handle *fb_ion_handle;
};
static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index f7d02b2..08c0eac 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -615,6 +615,29 @@
return vbp_max;
}
+static bool mdss_mdp_video_mode_intf_connected(struct mdss_mdp_ctl *ctl)
+{
+ int i;
+ struct mdss_data_type *mdata;
+
+ if (!ctl || !ctl->mdata)
+ return 0;
+
+ mdata = ctl->mdata;
+ for (i = 0; i < mdata->nctl; i++) {
+ struct mdss_mdp_ctl *ctl = mdata->ctl_off + i;
+
+ if (ctl->is_video_mode && ctl->power_on) {
+ pr_debug("video interface connected ctl:%d\n",
+ ctl->num);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
static void __mdss_mdp_perf_calc_ctl_helper(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_perf_params *perf,
struct mdss_mdp_pipe **left_plist, int left_cnt,
@@ -710,13 +733,12 @@
left_plist, (left_plist ? MDSS_MDP_MAX_STAGE : 0),
right_plist, (right_plist ? MDSS_MDP_MAX_STAGE : 0));
- if (ctl->is_video_mode) {
- if (perf->bw_overlap > perf->bw_prefill)
- perf->bw_ctl = apply_fudge_factor(perf->bw_ctl,
- &mdss_res->ib_factor_overlap);
- else
- perf->bw_ctl = apply_fudge_factor(perf->bw_ctl,
- &mdss_res->ib_factor);
+ if (ctl->is_video_mode || mdss_mdp_video_mode_intf_connected(ctl)) {
+ perf->bw_ctl =
+ max(apply_fudge_factor(perf->bw_overlap,
+ &mdss_res->ib_factor_overlap),
+ apply_fudge_factor(perf->bw_prefill,
+ &mdss_res->ib_factor));
}
pr_debug("ctl=%d clk_rate=%u\n", ctl->num, perf->mdp_clk_rate);
pr_debug("bw_overlap=%llu bw_prefill=%llu prefill_bytes=%d\n",
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index f286de5..e5965e6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1731,7 +1731,7 @@
return;
if (!fbi->fix.smem_start || fbi->fix.smem_len == 0 ||
- mdp5_data->borderfill_enable) {
+ mdp5_data->borderfill_enable) {
mfd->mdp.kickoff_fnc(mfd, NULL);
return;
}
@@ -1747,11 +1747,6 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- ret = mdss_iommu_ctrl(1);
- if (IS_ERR_VALUE(ret)) {
- pr_err("IOMMU attach failed\n");
- goto pan_display_error;
- }
bpp = fbi->var.bits_per_pixel / 8;
offset = fbi->var.xoffset * bpp +
@@ -1769,6 +1764,12 @@
goto pan_display_error;
}
+ ret = mdss_iommu_ctrl(1);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("IOMMU attach failed\n");
+ goto pan_display_error;
+ }
+
ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
MDSS_MDP_MIXER_MUX_LEFT);
if (ret) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 4819456..b39c5a7 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -303,13 +303,7 @@
if (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
wb_mixer = 1;
- /*
- * Don't want to allow SMP changes for backend composition pipes
- * inorder to preserve SMPs as much as possible.
- * On the contrary for non backend composition pipes we should
- * allow SMP allocations to prevent composition failures.
- */
- force_alloc = !(pipe->flags & MDP_BACKEND_COMPOSITION);
+ force_alloc = pipe->flags & MDP_SMP_FORCE_ALLOC;
mutex_lock(&mdss_mdp_smp_lock);
for (i = (MAX_PLANES - 1); i >= ps.num_planes; i--) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index b50ba59..a87b0ab 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -406,11 +406,28 @@
int ret;
if (!list_empty(&wb->register_queue)) {
+ struct ion_client *iclient = mdss_get_ionclient();
+ struct ion_handle *ihdl;
+
+ if (!iclient) {
+ pr_err("iclient is NULL\n");
+ return NULL;
+ }
+
+ ihdl = ion_import_dma_buf(iclient, data->memory_id);
+ if (IS_ERR_OR_NULL(ihdl)) {
+ pr_err("unable to import fd %d\n", data->memory_id);
+ return NULL;
+ }
+ /* only interested in ptr address, so we can free handle */
+ ion_free(iclient, ihdl);
+
list_for_each_entry(node, &wb->register_queue, registered_entry)
- if ((node->buf_info.memory_id == data->memory_id) &&
+ if ((node->buf_data.p[0].srcp_ihdl == ihdl) &&
(node->buf_info.offset == data->offset)) {
- pr_debug("found node fd=%x off=%x addr=%x\n",
- data->memory_id, data->offset,
+ pr_debug("found fd=%d hdl=%p off=%x addr=%x\n",
+ data->memory_id, ihdl,
+ data->offset,
node->buf_data.p[0].addr);
return node;
}
@@ -465,8 +482,9 @@
if (node->user_alloc) {
buf = &node->buf_data.p[0];
- pr_debug("free user node mem_id=%d offset=%u addr=0x%x\n",
+ pr_debug("free user mem_id=%d ihdl=%p, offset=%u addr=0x%x\n",
node->buf_info.memory_id,
+ buf->srcp_ihdl,
node->buf_info.offset,
buf->addr);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 2fb663a..1874adb 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -82,6 +82,56 @@
return mm->total_vm;
}
+static void seq_print_vma_name(struct seq_file *m, struct vm_area_struct *vma)
+{
+ const char __user *name = vma_get_anon_name(vma);
+ struct mm_struct *mm = vma->vm_mm;
+
+ unsigned long page_start_vaddr;
+ unsigned long page_offset;
+ unsigned long num_pages;
+ unsigned long max_len = NAME_MAX;
+ int i;
+
+ page_start_vaddr = (unsigned long)name & PAGE_MASK;
+ page_offset = (unsigned long)name - page_start_vaddr;
+ num_pages = DIV_ROUND_UP(page_offset + max_len, PAGE_SIZE);
+
+ seq_puts(m, "[anon:");
+
+ for (i = 0; i < num_pages; i++) {
+ int len;
+ int write_len;
+ const char *kaddr;
+ long pages_pinned;
+ struct page *page;
+
+ pages_pinned = get_user_pages(current, mm, page_start_vaddr,
+ 1, 0, 0, &page, NULL);
+ if (pages_pinned < 1) {
+ seq_puts(m, "<fault>]");
+ return;
+ }
+
+ kaddr = (const char *)kmap(page);
+ len = min(max_len, PAGE_SIZE - page_offset);
+ write_len = strnlen(kaddr + page_offset, len);
+ seq_write(m, kaddr + page_offset, write_len);
+ kunmap(page);
+ put_page(page);
+
+ /* if strnlen hit a null terminator then we're done */
+ if (write_len != len)
+ break;
+
+ max_len -= len;
+ page_offset = 0;
+ page_start_vaddr += PAGE_SIZE;
+ }
+
+ seq_putc(m, ']');
+}
+
static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma)
{
if (vma && vma != priv->tail_vma) {
@@ -281,6 +331,12 @@
seq_pad(m, ' ');
seq_printf(m, "[stack:%d]", tid);
}
+ goto done;
+ }
+
+ if (vma_get_anon_name(vma)) {
+ seq_pad(m, ' ');
+ seq_print_vma_name(m, vma);
}
}
@@ -513,6 +569,12 @@
(vma->vm_flags & VM_LOCKED) ?
(unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0);
+ if (vma_get_anon_name(vma)) {
+ seq_puts(m, "Name: ");
+ seq_print_vma_name(m, vma);
+ seq_putc(m, '\n');
+ }
+
if (m->count < m->size) /* vma is copied successfully */
m->version = (vma != get_gate_vma(task->mm))
? vma->vm_start : 0;
diff --git a/include/linux/avtimer_kernel.h b/include/linux/avtimer_kernel.h
new file mode 100644
index 0000000..5eff8cc
--- /dev/null
+++ b/include/linux/avtimer_kernel.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014, 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.
+ *
+ */
+
+#ifndef _AVTIMER_H
+#define _AVTIMER_H
+
+#include <uapi/linux/avtimer.h>
+
+int avcs_core_open(void);
+int avcs_core_disable_power_collapse(int disable);/* true or flase */
+int avcs_core_query_timer(uint64_t *avtimer_tick);
+
+#endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 2218ac4..b574c60 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1394,7 +1394,7 @@
extern struct vm_area_struct *vma_merge(struct mm_struct *,
struct vm_area_struct *prev, unsigned long addr, unsigned long end,
unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
- struct mempolicy *);
+ struct mempolicy *, const char __user *);
extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *);
extern int split_vma(struct mm_struct *,
struct vm_area_struct *, unsigned long addr, int new_below);
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index b98b4b9..8535cc0 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -216,6 +216,10 @@
* linkage into the address_space->i_mmap prio tree, or
* linkage to the list of like vmas hanging off its node, or
* linkage of vma in the address_space->i_mmap_nonlinear list.
+ *
+ * For private anonymous mappings, a pointer to a null terminated string
+ * in the user process containing the name given to the vma, or NULL
+ * if unnamed.
*/
union {
struct {
@@ -225,6 +229,7 @@
} vm_set;
struct raw_prio_tree_node prio_tree_node;
+ const char __user *anon_name;
} shared;
/*
@@ -392,4 +397,14 @@
return mm->cpu_vm_mask_var;
}
+
+/* Return the name for an anonymous mapping or NULL for a file-backed mapping */
+static inline const char __user *vma_get_anon_name(struct vm_area_struct *vma)
+{
+ if (vma->vm_file)
+ return NULL;
+
+ return vma->shared.anon_name;
+}
+
#endif /* _LINUX_MM_TYPES_H */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index b295fcc..4be3260 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -221,6 +221,7 @@
#define MDP_MEMORY_ID_TYPE_FB 0x00001000
#define MDP_BWC_EN 0x00000400
#define MDP_DECIMATION_EN 0x00000800
+#define MDP_SMP_FORCE_ALLOC 0x00200000
#define MDP_TRANSP_NOP 0xffffffff
#define MDP_ALPHA_NOP 0xff
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 25b5363..2e3270d 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -36,6 +36,7 @@
int32_t psm_temp_hyst_degC;
int32_t ocr_temp_degC;
int32_t ocr_temp_hyst_degC;
+ int32_t therm_reset_temp_degC;
};
#ifdef CONFIG_THERMAL_MONITOR
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 0b95337..f712fba 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -2636,14 +2636,20 @@
* @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
* @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
* @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * (if @NL80211_BSS_PRESP_DATA is present then this is known to be
+ * from a probe response, otherwise it may be from the same beacon
+ * that the NL80211_BSS_BEACON_TSF will be from)
* @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
* @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
* @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
* raw information elements from the probe response/beacon (bin);
- * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
- * from a Probe Response frame; otherwise they are from a Beacon frame.
+ * if the %NL80211_BSS_BEACON_IES attribute is present and the data is
+ * different then the IEs here are from a Probe Response frame; otherwise
+ * they are from a Beacon frame.
* However, if the driver does not indicate the source of the IEs, these
* IEs may be from either frame subtype.
+ * If present, the @NL80211_BSS_PRESP_DATA attribute indicates that the
+ * data here is known to be from a probe response, without any heuristics.
* @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
* in mBm (100 * dBm) (s32)
* @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
@@ -2653,6 +2659,12 @@
* @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
* elements from a Beacon frame (bin); not present if no Beacon frame has
* yet been received
+ * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel
+ * (u32, enum nl80211_bss_scan_width)
+ * @NL80211_BSS_BEACON_TSF: TSF of the last received beacon (u64)
+ * (not present if no beacon frame has been received yet)
+ * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and
+ * @NL80211_BSS_TSF is known to be from a probe response (flag attribute)
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -2669,6 +2681,9 @@
NL80211_BSS_STATUS,
NL80211_BSS_SEEN_MS_AGO,
NL80211_BSS_BEACON_IES,
+ NL80211_BSS_CHAN_WIDTH,
+ NL80211_BSS_BEACON_TSF,
+ NL80211_BSS_PRESP_DATA,
/* keep last */
__NL80211_BSS_AFTER_LAST,
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index e0cfec2..23728f0 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -124,4 +124,13 @@
#define PR_SET_CHILD_SUBREAPER 36
#define PR_GET_CHILD_SUBREAPER 37
+/* Sets the timerslack for arbitrary threads
+ * arg2 slack value, 0 means "use default"
+ * arg3 pid of the thread whose timer slack needs to be set
+ */
+#define PR_SET_TIMERSLACK_PID 41
+
+#define PR_SET_VMA 0x53564d41
+# define PR_SET_VMA_ANON_NAME 0
+
#endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/sync.h b/include/linux/sync.h
index f4ac10e..7fdd6a7 100644
--- a/include/linux/sync.h
+++ b/include/linux/sync.h
@@ -84,6 +84,9 @@
/* optional */
void (*pt_value_str)(struct sync_pt *pt, char *str, int size);
+
+ /* optional */
+ void (*pt_log)(struct sync_pt *pt);
};
/**
@@ -342,6 +345,15 @@
*/
int sync_fence_wait(struct sync_fence *fence, long timeout);
+/**
+ * sync_fence_log() - log the details of the fence in the kernel log
+ * @fence: fence to log
+ *
+ * Log the details of the fence and the associated sync points in the kernel
+ * log.
+ */
+void sync_fence_log(struct sync_fence *fence);
+
#endif /* __KERNEL__ */
/**
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 56ba8ab..8bdcfd5 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -42,7 +42,6 @@
#define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
#define HAVE_WCNSS_RESET_INTR 1
#define HAVE_WCNSS_CAL_DOWNLOAD 1
-#define HAVE_CBC_DONE 1
#define HAVE_WCNSS_RX_BUFF_COUNT 1
#define WLAN_MAC_ADDR_SIZE (6)
@@ -82,7 +81,6 @@
void wcnss_pronto_log_debug_regs(void);
int wcnss_is_hw_pronto_ver3(void);
int wcnss_device_ready(void);
-int wcnss_cbc_complete(void);
int wcnss_device_is_shutdown(void);
void wcnss_riva_dump_pmic_regs(void);
int wcnss_xo_auto_detect_enabled(void);
diff --git a/include/net/tcp.h b/include/net/tcp.h
index dce56a6..4f093b4 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -254,6 +254,7 @@
extern int sysctl_tcp_cookie_size;
extern int sysctl_tcp_thin_linear_timeouts;
extern int sysctl_tcp_thin_dupack;
+extern int sysctl_tcp_default_init_rwnd;
/* sysctl variables for controlling various tcp parameters */
extern int sysctl_tcp_delack_seg;
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index ec3038b..059916e 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -183,6 +183,7 @@
/* audio cache operations fptr*/
int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
atomic_t unmap_cb_success;
+ atomic_t reset;
};
void q6asm_audio_client_free(struct audio_client *ac);
diff --git a/sound/soc/msm/qdsp6v2/q6core.h b/include/sound/q6core.h
similarity index 100%
rename from sound/soc/msm/qdsp6v2/q6core.h
rename to include/sound/q6core.h
diff --git a/include/uapi/linux/avtimer.h b/include/uapi/linux/avtimer.h
new file mode 100644
index 0000000..f688b38
--- /dev/null
+++ b/include/uapi/linux/avtimer.h
@@ -0,0 +1,19 @@
+#ifndef _UAPI_AVTIMER_H
+#define _UAPI_AVTIMER_H
+
+#include <linux/ioctl.h>
+
+#define MAJOR_NUM 100
+
+#define IOCTL_GET_AVTIMER_TICK _IOR(MAJOR_NUM, 0, char *)
+/*
+ * This IOCTL is used read the avtimer tick value.
+ * Avtimer is a 64 bit timer tick, hence the expected
+ * argument is of type uint64_t
+ */
+struct dev_avtimer_data {
+ uint32_t avtimer_msw_phy_addr;
+ uint32_t avtimer_lsw_phy_addr;
+};
+
+#endif
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 1e5bfd8..780ac9b 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1606,6 +1606,7 @@
{
unsigned long flags;
int cpu, src_cpu, success = 0;
+ int notify = 0;
smp_wmb();
raw_spin_lock_irqsave(&p->pi_lock, flags);
@@ -1663,10 +1664,13 @@
ttwu_queue(p, cpu);
stat:
ttwu_stat(p, cpu, wake_flags);
+
+ if (src_cpu != cpu && task_notify_on_migrate(p))
+ notify = 1;
out:
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
- if (src_cpu != cpu && task_notify_on_migrate(p))
+ if (notify)
atomic_notifier_call_chain(&migration_notifier_head,
cpu, (void *)src_cpu);
return success;
diff --git a/kernel/sys.c b/kernel/sys.c
index 39791be..2f95158 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -40,6 +40,9 @@
#include <linux/syscore_ops.h>
#include <linux/version.h>
#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/mempolicy.h>
+#include <linux/sched.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
@@ -1821,10 +1824,151 @@
}
#endif
+
+static int prctl_update_vma_anon_name(struct vm_area_struct *vma,
+ struct vm_area_struct **prev,
+ unsigned long start, unsigned long end,
+ const char __user *name_addr)
+{
+ struct mm_struct * mm = vma->vm_mm;
+ int error = 0;
+ pgoff_t pgoff;
+
+ if (name_addr == vma_get_anon_name(vma)) {
+ *prev = vma;
+ goto out;
+ }
+
+ pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+ *prev = vma_merge(mm, *prev, start, end, vma->vm_flags, vma->anon_vma,
+ vma->vm_file, pgoff, vma_policy(vma),
+ name_addr);
+ if (*prev) {
+ vma = *prev;
+ goto success;
+ }
+
+ *prev = vma;
+
+ if (start != vma->vm_start) {
+ error = split_vma(mm, vma, start, 1);
+ if (error)
+ goto out;
+ }
+
+ if (end != vma->vm_end) {
+ error = split_vma(mm, vma, end, 0);
+ if (error)
+ goto out;
+ }
+
+success:
+ if (!vma->vm_file)
+ vma->shared.anon_name = name_addr;
+
+out:
+ if (error == -ENOMEM)
+ error = -EAGAIN;
+ return error;
+}
+
+static int prctl_set_vma_anon_name(unsigned long start, unsigned long end,
+ unsigned long arg)
+{
+ unsigned long tmp;
+ struct vm_area_struct * vma, *prev;
+ int unmapped_error = 0;
+ int error = -EINVAL;
+
+ /*
+ * If the interval [start,end) covers some unmapped address
+ * ranges, just ignore them, but return -ENOMEM at the end.
+ * - this matches the handling in madvise.
+ */
+ vma = find_vma_prev(current->mm, start, &prev);
+ if (vma && start > vma->vm_start)
+ prev = vma;
+
+ for (;;) {
+ /* Still start < end. */
+ error = -ENOMEM;
+ if (!vma)
+ return error;
+
+ /* Here start < (end|vma->vm_end). */
+ if (start < vma->vm_start) {
+ unmapped_error = -ENOMEM;
+ start = vma->vm_start;
+ if (start >= end)
+ return error;
+ }
+
+ /* Here vma->vm_start <= start < (end|vma->vm_end) */
+ tmp = vma->vm_end;
+ if (end < tmp)
+ tmp = end;
+
+ /* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
+ error = prctl_update_vma_anon_name(vma, &prev, start, end,
+ (const char __user *)arg);
+ if (error)
+ return error;
+ start = tmp;
+ if (prev && start < prev->vm_end)
+ start = prev->vm_end;
+ error = unmapped_error;
+ if (start >= end)
+ return error;
+ if (prev)
+ vma = prev->vm_next;
+ else /* madvise_remove dropped mmap_sem */
+ vma = find_vma(current->mm, start);
+ }
+}
+
+static int prctl_set_vma(unsigned long opt, unsigned long start,
+ unsigned long len_in, unsigned long arg)
+{
+ struct mm_struct *mm = current->mm;
+ int error;
+ unsigned long len;
+ unsigned long end;
+
+ if (start & ~PAGE_MASK)
+ return -EINVAL;
+ len = (len_in + ~PAGE_MASK) & PAGE_MASK;
+
+ /* Check to see whether len was rounded up from small -ve to zero */
+ if (len_in && !len)
+ return -EINVAL;
+
+ end = start + len;
+ if (end < start)
+ return -EINVAL;
+
+ if (end == start)
+ return 0;
+
+ down_write(&mm->mmap_sem);
+
+ switch (opt) {
+ case PR_SET_VMA_ANON_NAME:
+ error = prctl_set_vma_anon_name(start, end, arg);
+ break;
+ default:
+ error = -EINVAL;
+ }
+
+ up_write(&mm->mmap_sem);
+
+ return error;
+}
+
SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5)
{
struct task_struct *me = current;
+ struct task_struct *tsk;
unsigned char comm[sizeof(me->comm)];
long error;
@@ -1981,6 +2125,29 @@
error = put_user(me->signal->is_child_subreaper,
(int __user *) arg2);
break;
+ case PR_SET_VMA:
+ error = prctl_set_vma(arg2, arg3, arg4, arg5);
+ break;
+ case PR_SET_TIMERSLACK_PID:
+ if (current->pid != (pid_t)arg3 &&
+ !capable(CAP_SYS_NICE))
+ return -EPERM;
+ rcu_read_lock();
+ tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns);
+ if (tsk == NULL) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ get_task_struct(tsk);
+ rcu_read_unlock();
+ if (arg2 <= 0)
+ tsk->timer_slack_ns =
+ tsk->default_timer_slack_ns;
+ else
+ tsk->timer_slack_ns = arg2;
+ put_task_struct(tsk);
+ error = 0;
+ break;
default:
error = -EINVAL;
break;
diff --git a/mm/madvise.c b/mm/madvise.c
index 55f645c..b075d1d 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -93,7 +93,8 @@
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
*prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma,
- vma->vm_file, pgoff, vma_policy(vma));
+ vma->vm_file, pgoff, vma_policy(vma),
+ vma_get_anon_name(vma));
if (*prev) {
vma = *prev;
goto success;
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index b195691..a786980 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -660,7 +660,7 @@
((vmstart - vma->vm_start) >> PAGE_SHIFT);
prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags,
vma->anon_vma, vma->vm_file, pgoff,
- new_pol);
+ new_pol, vma_get_anon_name(name));
if (prev) {
vma = prev;
next = vma->vm_next;
diff --git a/mm/mlock.c b/mm/mlock.c
index 38c77ab..029f234 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -333,7 +333,8 @@
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
*prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma,
- vma->vm_file, pgoff, vma_policy(vma));
+ vma->vm_file, pgoff, vma_policy(vma),
+ vma_get_anon_name(vma));
if (*prev) {
vma = *prev;
goto success;
diff --git a/mm/mmap.c b/mm/mmap.c
index 9932edb..964223d 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -649,7 +649,8 @@
* per-vma resources, so we don't attempt to merge those.
*/
static inline int is_mergeable_vma(struct vm_area_struct *vma,
- struct file *file, unsigned long vm_flags)
+ struct file *file, unsigned long vm_flags,
+ const char __user *anon_name)
{
/* VM_CAN_NONLINEAR may get set later by f_op->mmap() */
if ((vma->vm_flags ^ vm_flags) & ~VM_CAN_NONLINEAR)
@@ -658,6 +659,8 @@
return 0;
if (vma->vm_ops && vma->vm_ops->close)
return 0;
+ if (vma_get_anon_name(vma) != anon_name)
+ return 0;
return 1;
}
@@ -688,9 +691,10 @@
*/
static int
can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
- struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
+ struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff,
+ const char __user *anon_name)
{
- if (is_mergeable_vma(vma, file, vm_flags) &&
+ if (is_mergeable_vma(vma, file, vm_flags, anon_name) &&
is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
if (vma->vm_pgoff == vm_pgoff)
return 1;
@@ -707,9 +711,10 @@
*/
static int
can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
- struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
+ struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff,
+ const char __user *anon_name)
{
- if (is_mergeable_vma(vma, file, vm_flags) &&
+ if (is_mergeable_vma(vma, file, vm_flags, anon_name) &&
is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
pgoff_t vm_pglen;
vm_pglen = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
@@ -720,9 +725,9 @@
}
/*
- * Given a mapping request (addr,end,vm_flags,file,pgoff), figure out
- * whether that can be merged with its predecessor or its successor.
- * Or both (it neatly fills a hole).
+ * Given a mapping request (addr,end,vm_flags,file,pgoff,anon_name),
+ * figure out whether that can be merged with its predecessor or its
+ * successor. Or both (it neatly fills a hole).
*
* In most cases - when called for mmap, brk or mremap - [addr,end) is
* certain not to be mapped by the time vma_merge is called; but when
@@ -752,7 +757,8 @@
struct vm_area_struct *prev, unsigned long addr,
unsigned long end, unsigned long vm_flags,
struct anon_vma *anon_vma, struct file *file,
- pgoff_t pgoff, struct mempolicy *policy)
+ pgoff_t pgoff, struct mempolicy *policy,
+ const char __user *anon_name)
{
pgoff_t pglen = (end - addr) >> PAGE_SHIFT;
struct vm_area_struct *area, *next;
@@ -778,15 +784,15 @@
*/
if (prev && prev->vm_end == addr &&
mpol_equal(vma_policy(prev), policy) &&
- can_vma_merge_after(prev, vm_flags,
- anon_vma, file, pgoff)) {
+ can_vma_merge_after(prev, vm_flags, anon_vma,
+ file, pgoff, anon_name)) {
/*
* OK, it can. Can we now merge in the successor as well?
*/
if (next && end == next->vm_start &&
mpol_equal(policy, vma_policy(next)) &&
- can_vma_merge_before(next, vm_flags,
- anon_vma, file, pgoff+pglen) &&
+ can_vma_merge_before(next, vm_flags, anon_vma,
+ file, pgoff+pglen, anon_name) &&
is_mergeable_anon_vma(prev->anon_vma,
next->anon_vma, NULL)) {
/* cases 1, 6 */
@@ -806,8 +812,8 @@
*/
if (next && end == next->vm_start &&
mpol_equal(policy, vma_policy(next)) &&
- can_vma_merge_before(next, vm_flags,
- anon_vma, file, pgoff+pglen)) {
+ can_vma_merge_before(next, vm_flags, anon_vma,
+ file, pgoff+pglen, anon_name)) {
if (prev && addr < prev->vm_end) /* case 4 */
err = vma_adjust(prev, prev->vm_start,
addr, prev->vm_pgoff, NULL);
@@ -1282,7 +1288,8 @@
/*
* Can we just expand an old mapping?
*/
- vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, NULL);
+ vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff,
+ NULL, NULL);
if (vma)
goto out;
@@ -2232,7 +2239,7 @@
/* Can we just expand an old private anonymous mapping? */
vma = vma_merge(mm, prev, addr, addr + len, flags,
- NULL, NULL, pgoff, NULL);
+ NULL, NULL, pgoff, NULL, NULL);
if (vma)
goto out;
@@ -2382,7 +2389,8 @@
find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags,
- vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma));
+ vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
+ vma_get_anon_name(vma));
if (new_vma) {
/*
* Source vma may have been merged into new_vma
diff --git a/mm/mprotect.c b/mm/mprotect.c
index a409926..10add6b 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -179,7 +179,8 @@
*/
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
*pprev = vma_merge(mm, *pprev, start, end, newflags,
- vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma));
+ vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
+ vma_get_anon_name(vma));
if (*pprev) {
vma = *pprev;
goto success;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 7c81e3b..d615ac8 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -125,6 +125,21 @@
return ret;
}
+/* Validate changes from /proc interface. */
+static int proc_tcp_default_init_rwnd(ctl_table *ctl, int write,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ int old_value = *(int *)ctl->data;
+ int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+ int new_value = *(int *)ctl->data;
+
+ if (write && ret == 0 && (new_value < 3 || new_value > 100))
+ *(int *)ctl->data = old_value;
+
+ return ret;
+}
+
static int proc_tcp_congestion_control(ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
@@ -673,7 +688,7 @@
.mode = 0644,
.proc_handler = proc_dointvec
},
- {
+ {
.procname = "tcp_thin_dupack",
.data = &sysctl_tcp_thin_dupack,
.maxlen = sizeof(int),
@@ -681,6 +696,13 @@
.proc_handler = proc_dointvec
},
{
+ .procname = "tcp_default_init_rwnd",
+ .data = &sysctl_tcp_default_init_rwnd,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_tcp_default_init_rwnd
+ },
+ {
.procname = "udp_mem",
.data = &sysctl_udp_mem,
.maxlen = sizeof(sysctl_udp_mem),
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 7c3612b..3b9c021 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -99,6 +99,7 @@
int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
int sysctl_tcp_abc __read_mostly;
+int sysctl_tcp_default_init_rwnd __read_mostly = TCP_DEFAULT_INIT_RCVWND;
#define FLAG_DATA 0x01 /* Incoming frame contained data. */
#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */
@@ -348,14 +349,14 @@
static void tcp_fixup_rcvbuf(struct sock *sk)
{
u32 mss = tcp_sk(sk)->advmss;
- u32 icwnd = TCP_DEFAULT_INIT_RCVWND;
+ u32 icwnd = sysctl_tcp_default_init_rwnd;
int rcvmem;
/* Limit to 10 segments if mss <= 1460,
* or 14600/mss segments, with a minimum of two segments.
*/
if (mss > 1460)
- icwnd = max_t(u32, (1460 * TCP_DEFAULT_INIT_RCVWND) / mss, 2);
+ icwnd = max_t(u32, (1460 * icwnd) / mss, 2);
rcvmem = SKB_TRUESIZE(mss + MAX_TCP_HEADER);
while (tcp_win_from_space(rcvmem) < mss)
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 7ac6423..08b49f8 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -229,14 +229,13 @@
}
/* Set initial window to a value enough for senders starting with
- * initial congestion window of TCP_DEFAULT_INIT_RCVWND. Place
+ * initial congestion window of sysctl_tcp_default_init_rwnd. Place
* a limit on the initial window when mss is larger than 1460.
*/
if (mss > (1 << *rcv_wscale)) {
- int init_cwnd = TCP_DEFAULT_INIT_RCVWND;
+ int init_cwnd = sysctl_tcp_default_init_rwnd;
if (mss > 1460)
- init_cwnd =
- max_t(u32, (1460 * TCP_DEFAULT_INIT_RCVWND) / mss, 2);
+ init_cwnd = max_t(u32, (1460 * init_cwnd) / mss, 2);
/* when initializing use the value from init_rcv_wnd
* rather than the default from above
*/
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 1addd9f..efb0138 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1348,7 +1348,7 @@
int err;
if (level != SOL_PPPOL2TP)
- return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+ return -EINVAL;
if (optlen < sizeof(int))
return -EINVAL;
@@ -1474,7 +1474,7 @@
struct pppol2tp_session *ps;
if (level != SOL_PPPOL2TP)
- return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+ return -EINVAL;
if (get_user(len, (int __user *) optlen))
return -EFAULT;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index eb535cc..a3a7134 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -758,9 +758,10 @@
struct net *net = nf_ct_net(ct);
nf_ct_ext_destroy(ct);
- atomic_dec(&net->ct.count);
nf_ct_ext_free(ct);
kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
+ smp_mb__before_atomic_dec();
+ atomic_dec(&net->ct.count);
}
EXPORT_SYMBOL_GPL(nf_conntrack_free);
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index 5f8b5c2..7fa1975 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -18,16 +18,28 @@
country AE:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country AF: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
+country AI: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country AL:
(2402 - 2482 @ 40), (N/A, 20)
(5150 - 5250 @ 80), (N/A, 20)
(5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
+ (5470 - 5710 @ 80), (N/A, 27), DFS
country AM:
(2402 - 2482 @ 40), (N/A, 20)
@@ -42,17 +54,18 @@
country AR:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5590 @ 80), (6, 24), DFS
+ (5650 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country AS:
(2402 - 2472 @ 40), (N/A, 30)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5850 @ 80), (6, 30)
country AT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -64,16 +77,17 @@
country AU:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5590 @ 80), (6, 24), DFS
+ (5650 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country AW:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country AZ:
(2402 - 2482 @ 40), (N/A, 20)
@@ -96,7 +110,7 @@
country BD:
(2402 - 2482 @ 40), (N/A, 20)
- (5725 - 5850 @ 80), (N/A, 30)
+ (5735 - 5835 @ 80), (N/A, 30)
country BE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -106,11 +120,18 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country BF:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (3, 24)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
+
country BG: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (N/A, 23)
- (5250 - 5290 @ 80), (N/A, 23), DFS
- (5490 - 5710 @ 80), (N/A, 30), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -120,36 +141,49 @@
(5250 - 5330 @ 20), (N/A, 20), DFS
(5735 - 5835 @ 20), (N/A, 20)
+country BL:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
country BM:
(2402 - 2472 @ 40), (N/A, 30)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country BN:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
(5250 - 5330 @ 80), (N/A, 20), DFS
- (5735 - 5835 @ 80), (N/A, 30)
+ (5735 - 5835 @ 80), (N/A, 20)
country BO:
- (2402 - 2482 @ 40), (N/A, 30)
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 30), DFS
(5735 - 5835 @ 80), (N/A, 30)
country BR:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country BS:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country BT: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country BY:
(2402 - 2482 @ 40), (N/A, 20)
@@ -162,19 +196,32 @@
(5735 - 5835 @ 80), (N/A, 30)
country CA:
- (2402 - 2472 @ 40), (N/A, 27)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5590 @ 80), (6, 24), DFS
+ (5650 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
-country CH: DFS-ETSI
+country CF:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 40), (6, 24)
+ (5250 - 5330 @ 40), (6, 24), DFS
+ (5490 - 5730 @ 40), (6, 24), DFS
+ (5735 - 5835 @ 40), (6, 30)
+
+country CH:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
(5250 - 5330 @ 80), (N/A, 20), DFS
(5490 - 5710 @ 80), (N/A, 27), DFS
- # 60 gHz band channels 1-4, ref: Etsi En 302 567
- (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country CI:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country CL:
(2402 - 2482 @ 40), (N/A, 20)
@@ -184,10 +231,9 @@
country CN:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 23)
- (5250 - 5350 @ 80), (6, 23), DFS
- (5725 - 5850 @ 80), (6, 30)
- (5735 - 5835 @ 80), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 23)
+ (5250 - 5330 @ 80), (6, 23), DFS
+ (5735 - 5835 @ 80), (6, 30)
# 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm
# ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf
(57240 - 59400 @ 2160), (N/A, 28)
@@ -195,18 +241,25 @@
(63720 - 65880 @ 2160), (N/A, 28)
country CO:
- (2402 - 2472 @ 40), (N/A, 27)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country CR:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 20), (3, 24), DFS
- (5490 - 5730 @ 20), (3, 24), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (5170 - 5250 @ 20), (6, 24)
+ (5250 - 5330 @ 20), (6, 24), DFS
+ (5490 - 5730 @ 20), (6, 24), DFS
+ (5735 - 5835 @ 20), (6, 30)
+
+country CX:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country CY: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -221,10 +274,10 @@
# Power at 5250 - 5350 MHz and 5470 - 5725 MHz can be doubled if TPC is
# implemented.
country CZ: DFS-ETSI
- (2400 - 2483.5 @ 40), (N/A, 100 mW)
- (5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
- (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
- (5470 - 5725 @ 80), (N/A, 500 mW), DFS
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -242,13 +295,10 @@
country DE: DFS-ETSI
# entries 279004 and 280006
- (2400 - 2483.5 @ 40), (N/A, 100 mW)
- # entry 303005
- (5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
- # entries 304002 and 305002
- (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
- # entries 308002, 309001 and 310003
- (5470 - 5725 @ 80), (N/A, 500 mW), DFS
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -260,24 +310,30 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country DM:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 23), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
country DO:
- (2402 - 2472 @ 40), (N/A, 27)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 23), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 23), DFS
+ (5735 - 5835 @ 80), (6, 30)
country DZ:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 23)
- (5250 - 5350 @ 80), (N/A,23), DFS
- (5470 - 5670 @ 80), (N/A, 20), DFS
+ (5170 - 5250 @ 80), (N/A, 23)
+ (5250 - 5330 @ 80), (N/A, 23), DFS
+ (5490 - 5670 @ 80), (N/A, 23), DFS
country EC:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 20), (3, 24), DFS
- (5490 - 5730 @ 20), (3, 24), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (5170 - 5250 @ 20), (6, 24)
+ (5250 - 5330 @ 20), (6, 24), DFS
+ (5490 - 5730 @ 20), (6, 24), DFS
+ (5735 - 5835 @ 20), (6, 30)
country EE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -289,14 +345,14 @@
country EG:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (N/A, 20)
- (5250 - 5330 @ 20), (N/A, 20), DFS
+ (5170 - 5250 @ 40), (N/A, 20)
+ (5250 - 5330 @ 40), (N/A, 20), DFS
country ES: DFS-ETSI
- (2400 - 2483.5 @ 40), (N/A, 100 mW)
- (5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
- (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
- (5470 - 5725 @ 80), (N/A, 500 mW), DFS
+ (2402 - 2482 @ 40),(N/A, 20)
+ (5170 - 5250 @ 80),(N/A, 20)
+ (5250 - 5330 @ 80),(N/A, 20), DFS
+ (5490 - 5710 @ 80),(N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -314,6 +370,13 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country FM:
+ (2402 - 2472 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 24)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
+
country FR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
@@ -322,19 +385,6 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-country GF:
- (2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 20), DFS
-
-country GE:
- (2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (N/A, 18)
- (5250 - 5330 @ 80), (N/A, 18), DFS
- # 60 gHz band channels 1-4, ref: Etsi En 302 567
- (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-
country GB: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
@@ -345,16 +395,42 @@
country GD:
(2402 - 2472 @ 40), (3, 30)
- (5170 - 5250 @ 80), (6, 17)
+ (5170 - 5250 @ 80), (6, 24)
(5250 - 5330 @ 80), (6, 24), DFS
(5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
+country GE:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 18)
+ (5250 - 5330 @ 80), (N/A, 18), DFS
+ # 60 gHz band channels 1-4, ref: Etsi En 302 567
+ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+
+country GF:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
+country GH:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country GL: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 20), (N/A, 20)
+ (5250 - 5330 @ 20), (N/A, 20), DFS
+ (5490 - 5710 @ 20), (N/A, 27), DFS
+
country GP:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country GR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -364,35 +440,33 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-country GL: DFS-ETSI
- (2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (N/A, 20)
- (5250 - 5330 @ 20), (N/A, 20), DFS
- (5490 - 5710 @ 20), (N/A, 27), DFS
-
country GT:
- (2402 - 2472 @ 40), (3, 30)
- (5170 - 5250 @ 80), (6, 17)
- (5250 - 5330 @ 80), (6, 23), DFS
- (5735 - 5835 @ 80), (6, 30)
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country GU:
- (2402 - 2472 @ 40), (3, 30)
- (5170 - 5250 @ 20), (6, 17)
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 20), (6, 24)
(5250 - 5330 @ 20), (6, 24), DFS
(5490 - 5730 @ 20), (6, 24), DFS
(5735 - 5835 @ 20), (6, 30)
-country HN:
+country GY:
+ (2402 - 2482 @ 40), (N/A, 30)
+ (5735 - 5835 @ 80), (N/A, 30)
+
+country HK:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (6, 17)
+ (5170 - 5250 @ 80), (6, 24)
(5250 - 5330 @ 80), (6, 24), DFS
(5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
-country HK:
+country HN:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (6, 17)
+ (5170 - 5250 @ 80), (6, 24)
(5250 - 5330 @ 80), (6, 24), DFS
(5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
@@ -406,10 +480,11 @@
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country HT:
- (2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (N/A, 20)
- (5250 - 5330 @ 80), (N/A, 20), DFS
- (5490 - 5710 @ 80), (N/A, 27), DFS
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country HU: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -421,8 +496,8 @@
country ID:
# ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
- (2402 - 2482 @ 20), (N/A, 30)
- (5735 - 5815 @ 20), (N/A, 30)
+ (2402 - 2482 @ 40), (N/A, 30)
+ (5735 - 5815 @ 80), (N/A, 30)
country IE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -434,7 +509,7 @@
country IL:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
(5250 - 5330 @ 80), (N/A, 20), DFS
country IN:
@@ -443,6 +518,10 @@
(5250 - 5330 @ 80), (N/A, 20), DFS
(5735 - 5835 @ 80), (N/A, 20)
+country IR:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5735 - 5835 @ 80), (N/A, 30)
+
country IS: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
@@ -451,10 +530,6 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-country IR:
- (2402 - 2482 @ 40), (N/A, 20)
- (5735 - 5835 @ 80), (N/A, 30)
-
country IT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
@@ -465,30 +540,28 @@
country JM:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (6, 17)
+ (5170 - 5250 @ 80), (6, 24)
(5250 - 5330 @ 80), (6, 24), DFS
(5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
+country JO:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 23)
+ (5735 - 5835 @ 80), (N/A, 23)
+
country JP:
(2402 - 2482 @ 40), (N/A, 20)
(2474 - 2494 @ 20), (N/A, 20), NO-OFDM
- (4910 - 4990 @ 40), (N/A, 23)
- (5030 - 5090 @ 40), (N/A, 23)
(5170 - 5250 @ 80), (N/A, 20)
(5250 - 5330 @ 80), (N/A, 20), DFS
- (5490 - 5710 @ 160), (N/A, 23), DFS
-
-country JO:
- (2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 23)
- (5725 - 5850 @ 80), (N/A, 23)
+ (5490 - 5710 @ 80), (N/A, 20), DFS
country KE:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 23)
- (5470 - 5570 @ 80), (N/A, 30), DFS
- (5725 - 5775 @ 80), (N/A, 23)
+ (5170 - 5250 @ 80), (N/A, 23)
+ (5490 - 5570 @ 80), (N/A, 30), DFS
+ (5735 - 5775 @ 40), (N/A, 23)
country KH:
(2402 - 2482 @ 40), (N/A, 20)
@@ -496,41 +569,48 @@
(5250 - 5330 @ 80), (N/A, 20), DFS
(5490 - 5710 @ 80), (N/A, 27), DFS
-country KY:
- (2402 - 2472 @ 40), (N/A, 27)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
-
-country KP:
- (2402 - 2482 @ 20), (N/A, 20)
- (5170 - 5330 @ 20), (6, 20)
- (5160 - 5250 @ 20), (6, 20), DFS
- (5490 - 5630 @ 20), (6, 30), DFS
- (5735 - 5815 @ 20), (6, 30)
+country KN:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 20)
+ (5250 - 5330 @ 80), (6, 20), DFS
+ (5490 - 5710 @ 80), (6, 30), DFS
+ (5735 - 5815 @ 80), (6, 30)
country KR:
- (2402 - 2482 @ 20), (N/A, 20)
- (5150 - 5250 @ 80), (6, 20)
- (5250 - 5350 @ 80), (6, 20), DFS
- (5470 - 5725 @ 80), (6, 30), DFS
- (5725 - 5825 @ 80), (6, 30)
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 20)
+ (5250 - 5330 @ 80), (6, 20), DFS
+ (5490 - 5630 @ 80), (6, 30), DFS
+ (5735 - 5815 @ 80), (6, 30)
country KW:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
(5250 - 5330 @ 80), (N/A, 20), DFS
+country KY:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
country KZ:
(2402 - 2482 @ 40), (N/A, 20)
country LB:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country LC:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 20)
+ (5250 - 5330 @ 80), (6, 20), DFS
+ (5490 - 5710 @ 80), (6, 30), DFS
+ (5735 - 5815 @ 80), (6, 30)
country LI: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -540,10 +620,16 @@
country LK:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 20), (3, 20), DFS
- (5490 - 5730 @ 20), (3, 20), DFS
- (5735 - 5835 @ 20), (3, 30)
+ (5170 - 5250 @ 20), (6, 24)
+ (5250 - 5330 @ 20), (6, 24), DFS
+ (5490 - 5730 @ 20), (6, 24), DFS
+ (5735 - 5835 @ 20), (6, 30)
+
+country LS: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country LT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -569,101 +655,136 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-country MC: DFS-ETSI
- (2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
-
country MA:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
- (5735 - 5835 @ 80), (N/A, 20), DFS
+ (5250 - 5330 @ 80), (N/A, 20), DFS
-country MO:
+country MC: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 23)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
-country MP:
+country MD: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
+country ME: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
+country MF: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
+country MH: DFS-FCC
(2402 - 2472 @ 40), (N/A, 30)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country MK: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country MN:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country MO:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5735 - 5835 @ 80), (N/A, 30)
+
+country MP:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country MQ: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
+country MR: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country MT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (N/A, 20)
- (5250 - 5330 @ 40), (N/A, 20), DFS
- (5490 - 5710 @ 40), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-country MQ: DFS-ETSI
- (2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
-
country MU:
- (2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
-
-country MY:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (N/A, 17)
- (5250 - 5330 @ 80), (N/A, 23), DFS
- (5735 - 5835 @ 80), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
-country MX:
- (2402 - 2482 @ 40), (3, 20)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+country MV:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5735 - 5835 @ 80), (N/A, 20)
country MW:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
+country MX:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country MY:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 17)
+ (5250 - 5330 @ 80), (6, 23), DFS
+ (5735 - 5835 @ 80), (6, 30)
country NG:
(2402 - 2482 @ 40), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 30), DFS
- (5725 - 5850 @ 80), (N/A, 30)
+ (5250 - 5330 @ 80), (N/A, 30), DFS
+ (5735 - 5835 @ 80), (N/A, 30)
country NI:
(2402 - 2472 @ 40), (N/A, 30)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country NL: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (N/A, 20), NO-OUTDOOR
- (5250 - 5330 @ 80), (N/A, 20), NO-OUTDOOR, DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
(5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
@@ -678,22 +799,22 @@
country NP:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5725 - 5850 @ 80), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5735 - 5835 @ 80), (N/A, 20)
country NZ:
(2402 - 2482 @ 40), (N/A, 30)
- (5170 - 5250 @ 80), (6, 17)
+ (5170 - 5250 @ 80), (6, 24)
(5250 - 5330 @ 80), (6, 24), DFS
(5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country OM:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country PA:
(2402 - 2472 @ 40), (N/A, 30)
@@ -703,27 +824,27 @@
country PE:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (6, 20)
- (5250 - 5330 @ 80), (6, 20), DFS
- (5490 - 5730 @ 80), (6, 27), DFS
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country PF:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country PG:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country PH:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (6, 17)
+ (5170 - 5250 @ 80), (6, 24)
(5250 - 5330 @ 80), (6, 24), DFS
(5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
@@ -740,6 +861,26 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country PM: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
+country PR:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+# Public Safety FCCA, FCC4
+# 27dBm [4.9GHz 1/4 rate], 30dBm [1/2 rate], 33dBm [full rate], and 5GHz same as FCC1
+# db.txt cannot express the limitation on 5G so disable all 5G channels for FCC4
+country PS:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (4940 - 4990 @ 40), (6, 33)
+
country PT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
@@ -748,19 +889,19 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-country PR:
- (2402 - 2472 @ 40), (3, 30)
- (5170 - 5250 @ 80), (6, 17)
+country PW:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 24)
(5250 - 5330 @ 80), (6, 24), DFS
(5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country PY:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country QA:
(2402 - 2482 @ 40), (N/A, 20)
@@ -768,9 +909,9 @@
country RE:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country RO: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -780,37 +921,35 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-
# Source:
# http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf
country RS:
- (2400 - 2483.5 @ 40), (N/A, 100 mW)
- (5150 - 5250 @ 80), (N/A, 200 mW), NO-OUTDOOR
- (5250 - 5350 @ 80), (N/A, 200 mW), DFS
- (5470 - 5725 @ 80), (3, 1000 mW), DFS
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (3, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country RU:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 40), (N/A, 20)
- (5250 - 5350 @ 40), (N/A, 20), DFS
- (5650 - 5725 @ 40), (N/A, 30), DFS
- (5725 - 5825 @ 40), (N/A, 30)
+ (5170 - 5250 @ 40), (N/A, 20)
+ (5250 - 5330 @ 40), (N/A, 20), DFS
+ (5650 - 5710 @ 40), (N/A, 30), DFS
+ (5735 - 5835 @ 40), (N/A, 30)
country RW:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 17)
+ (5170 - 5250 @ 80), (6, 24)
(5250 - 5330 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5835 @ 80), (6, 30)
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country SA:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country SE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -822,7 +961,7 @@
country SG:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (6, 17)
+ (5170 - 5250 @ 80), (6, 24)
(5250 - 5330 @ 80), (6, 24), DFS
(5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
@@ -843,11 +982,18 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country SN:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
country SR: DFS-ETSI
- (2400 - 2483.5 @ 40), (N/A, 100 mW)
- (5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
- (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
- (5470 - 5725 @ 80), (N/A, 500 mW), DFS
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country SV:
(2402 - 2482 @ 40), (N/A, 20)
@@ -858,31 +1004,36 @@
country SY:
(2402 - 2482 @ 40), (N/A, 20)
-country TW:
- (2402 - 2472 @ 40), (3, 30)
- (5270 - 5330 @ 40), (6, 17)
- (5490 - 5590 @ 80), (6, 30), DFS
- (5650 - 5730 @ 80), (6, 30), DFS
- (5735 - 5815 @ 80), (6, 30)
+country TC:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country TD:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
+country TG: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 40), (N/A, 20)
+ (5250 - 5330 @ 40), (N/A, 20), DFS
+ (5490 - 5710 @ 40), (N/A, 27), DFS
country TH:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
-
-country TT:
- (2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5730 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country TN:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (N/A, 20)
- (5250 - 5330 @ 20), (N/A, 20), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
country TR: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
@@ -891,7 +1042,25 @@
(5490 - 5710 @ 80), (N/A, 27), DFS
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
-
+
+country TT:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country TW:
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5270 - 5330 @ 40), (6, 17)
+ (5490 - 5590 @ 80), (6, 17), DFS
+ (5650 - 5730 @ 80), (6, 30), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country TZ:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5735 - 5835 @ 80), (N/A, 30)
+
# Source:
# #914 / 06 Sep 2007: http://www.ucrf.gov.ua/uk/doc/nkrz/1196068874
# #1174 / 23 Oct 2008: http://www.nkrz.gov.ua/uk/activities/ruling/1225269361
@@ -900,102 +1069,108 @@
# rules in the referenced laws. Such a range is used because of
# disputable definitions there.
country UA:
- (2400 - 2483.5 @ 40), (N/A, 20), NO-OUTDOOR
- (5150 - 5250 @ 40), (N/A, 20), NO-OUTDOOR
- (5250 - 5350 @ 40), (N/A, 20), NO-OUTDOOR, DFS
- (5470 - 5670 @ 40), (N/A, 20), DFS
- (5725 - 5850 @ 40), (N/A, 20)
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 40), (N/A, 20)
+ (5250 - 5330 @ 40), (N/A, 20), DFS
+ (5490 - 5670 @ 40), (N/A, 30), DFS
+ (5735 - 5835 @ 40), (N/A, 30)
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country UG:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 20)
- (5250 - 5350 @ 80), (6, 20), DFS
- (5470 - 5725 @ 80), (6, 20), DFS
- (5725 - 5825 @ 80), (6, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country US: DFS-FCC
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5600 @ 80), (3, 24), DFS
- (5650 - 5730 @ 40), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (2402 - 2472 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
# 60g band
# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
# channels 1,2,3, EIRP=40dBm(43dBm peak)
(57240 - 63720 @ 2160), (N/A, 40)
-# Public Safety FCCA, FCC4
-# 27dBm [4.9GHz 1/4 rate], 30dBm [1/2 rate], 33dBm [full rate], and 5GHz same as FCC1
-# db.txt cannot express the limitation on 5G so disable all 5G channels for FCC4
-country PS:
- (2402 - 2472 @ 40), (N/A, 30)
- #(4940 - 4990 @ 40), (6, 27)
- #(5150 - 5250 @ 80), (6, 30)
- #(5250 - 5350 @ 80), (6, 30), DFS
- #(5725 - 5850 @ 80), (6, 33)
-
country UY:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5730 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country UZ:
- (2402 - 2472 @ 40), (3, 27)
- (5170 - 5250 @ 40), (3, 17)
- (5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5730 @ 40), (3, 20), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+
+country VC: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country VE:
- (2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 23), DFS
- (5725 - 5850 @ 80), (6, 30)
-
-
-country VN:
- (2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5730 @ 80), (3, 24), DFS
- (5735 - 5835 @ 80), (3, 30)
+ (2402 - 2482 @ 40), (N/A, 30)
+ (5170 - 5250 @ 80), (6, 23)
+ (5250 - 5330 @ 80), (6, 23), DFS
+ (5735 - 5835 @ 80), (6, 30)
country VI:
(2402 - 2472 @ 40), (N/A, 30)
- (5150 - 5250 @ 80), (6, 17)
- (5250 - 5350 @ 80), (6, 24), DFS
- (5470 - 5725 @ 80), (6, 24), DFS
- (5725 - 5850 @ 80), (6, 30)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country VN:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country VU:
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
+
+country WF: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country WS: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 20), (3, 17)
- (5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5170 - 5250 @ 40), (N/A, 20)
+ (5250 - 5330 @ 40), (N/A, 20), DFS
+ (5490 - 5710 @ 40), (N/A, 27), DFS
country YE:
(2402 - 2482 @ 40), (N/A, 20)
country YT: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
country ZA:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 80), (3, 20)
- (5250 - 5330 @ 80), (3, 20), DFS
- (5490 - 5710 @ 80), (3, 27), DFS
+ (5170 - 5250 @ 80), (6, 24)
+ (5250 - 5330 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
+ (5735 - 5835 @ 80), (6, 30)
country ZW:
(2402 - 2482 @ 40), (N/A, 20)
- (5150 - 5250 @ 80), (N/A, 20)
- (5250 - 5350 @ 80), (N/A, 20), DFS
- (5470 - 5725 @ 80), (N/A, 27), DFS
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index e56833a..e591c54 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -71,6 +71,20 @@
return -FDT_ERR_BADMAGIC;
}
+ if (fdt_off_dt_struct(fdt) > (UINT_MAX - fdt_size_dt_struct(fdt)))
+ return FDT_ERR_BADOFFSET;
+
+ if (fdt_off_dt_strings(fdt) > (UINT_MAX - fdt_size_dt_strings(fdt)))
+ return FDT_ERR_BADOFFSET;
+
+ if ((fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt))
+ > fdt_totalsize(fdt))
+ return FDT_ERR_BADOFFSET;
+
+ if ((fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))
+ > fdt_totalsize(fdt))
+ return FDT_ERR_BADOFFSET;
+
return 0;
}
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
index 24437df..d7d09fe 100644
--- a/scripts/dtc/libfdt/fdt_rw.c
+++ b/scripts/dtc/libfdt/fdt_rw.c
@@ -394,7 +394,7 @@
static void _fdt_packblocks(const char *old, char *new,
int mem_rsv_size, int struct_size)
{
- int mem_rsv_off, struct_off, strings_off;
+ uint32_t mem_rsv_off, struct_off, strings_off;
mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
struct_off = mem_rsv_off + mem_rsv_size;
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index f8e9d7a..240ce66 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -156,9 +156,12 @@
static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
struct snd_compr_tstamp *tstamp)
{
+ int err = 0;
if (!stream->ops->pointer)
return -ENOTSUPP;
- stream->ops->pointer(stream, tstamp);
+ err = stream->ops->pointer(stream, tstamp);
+ if (err)
+ return err;
pr_debug("dsp consumed till %d total %d bytes\n",
tstamp->byte_offset, tstamp->copied_total);
if (stream->direction == SND_COMPRESS_PLAYBACK)
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index f174685..58d377c 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1216,8 +1216,11 @@
list_del_init(&pcm->list);
for (cidx = 0; cidx < 2; cidx++)
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
- if (substream->runtime)
+ if (substream->runtime) {
substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
+ wake_up(&substream->runtime->sleep);
+ wake_up(&substream->runtime->tsleep);
+ }
list_for_each_entry(notify, &snd_pcm_notify_list, list) {
notify->n_disconnect(pcm);
}
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index bbe1ac7..a2f6811 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -35,10 +35,10 @@
#include <sound/tlv.h>
#include <mach/qdsp6v2/apr.h>
#include <mach/subsystem_notif.h>
+#include <sound/q6core.h>
#include "msm8x10-wcd.h"
#include "wcd9xxx-resmgr.h"
#include "msm8x10_wcd_registers.h"
-#include "../msm/qdsp6v2/q6core.h"
#include "wcd9xxx-common.h"
#define MSM8X10_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index b35f7fb..b29d81c 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -291,6 +291,9 @@
u32 anc_slot;
bool anc_func;
+ /*track adie loopback mode*/
+ bool lb_mode;
+
/*track tapan interface type*/
u8 intf_type;
@@ -306,6 +309,8 @@
u8 aux_l_gain;
u8 aux_r_gain;
+ bool dec_active[NUM_DECIMATORS];
+
bool spkr_pa_widget_on;
struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
@@ -512,6 +517,43 @@
return 0;
}
+static int tapan_loopback_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tapan->lb_mode;
+ dev_dbg(codec->dev, "%s: lb_mode = %d\n",
+ __func__, tapan->lb_mode);
+
+ return 0;
+}
+
+static int tapan_loopback_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ tapan->lb_mode = false;
+ break;
+ case 1:
+ tapan->lb_mode = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
static int tapan_pa_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1036,6 +1078,13 @@
return 0;
}
+static const char * const tapan_loopback_mode_ctrl_text[] = {
+ "DISABLE", "ENABLE"};
+static const struct soc_enum tapan_loopback_mode_ctl_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, tapan_loopback_mode_ctrl_text),
+};
+
+
static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_4P5_DB",
"POS_3_DB", "POS_1P5_DB",
"POS_0_DB", "NEG_2P5_DB",
@@ -1112,6 +1161,9 @@
SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
tapan_pa_gain_get, tapan_pa_gain_put),
+ SOC_ENUM_EXT("LOOPBACK Mode", tapan_loopback_mode_ctl_enum[0],
+ tapan_loopback_mode_get, tapan_loopback_mode_put),
+
SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 20, 1,
line_gain),
SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 20, 1,
@@ -1959,7 +2011,7 @@
1 << init_bit_shift);
break;
case SND_SOC_DAPM_POST_PMU:
-
+ usleep_range(2000, 2010);
snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
break;
@@ -2398,6 +2450,7 @@
dev_dbg(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
__func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+ snd_soc_update_bits(codec, TAPAN_A_TX_1_2_TXFE_CLKDIV, 0x55, 0x55);
snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
}
@@ -2411,10 +2464,11 @@
{
struct snd_soc_codec *codec = w->codec;
unsigned int decimator;
+ struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
char *dec_name = NULL;
char *widget_name = NULL;
char *temp;
- int ret = 0;
+ int ret = 0, i;
u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
u8 dec_hpf_cut_of_freq;
int offset;
@@ -2466,6 +2520,10 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ for (i = 0; i < NUM_DECIMATORS; i++) {
+ if (decimator == i + 1)
+ tapan_p->dec_active[i] = true;
+ }
/* Enableable TX digital mute */
snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
@@ -2490,13 +2548,17 @@
/* enable HPF */
snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
-
+ snd_soc_update_bits(codec, TAPAN_A_TX_1_2_TXFE_CLKDIV,
+ 0x55, 0x44);
break;
case SND_SOC_DAPM_POST_PMU:
- /* Disable TX digital mute */
- snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+ if (tapan_p->lb_mode) {
+ pr_debug("%s: loopback mode unmute the DEC\n",
+ __func__);
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+ }
if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
CF_MIN_3DB_150HZ) {
@@ -2525,7 +2587,10 @@
snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
(tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
-
+ for (i = 0; i < NUM_DECIMATORS; i++) {
+ if (decimator == i + 1)
+ tapan_p->dec_active[i] = false;
+ }
break;
}
out:
@@ -4026,6 +4091,53 @@
return 0;
}
+int tapan_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = NULL;
+ u16 tx_vol_ctl_reg = 0;
+ u8 decimator = 0, i;
+ struct tapan_priv *tapan_p;
+
+ pr_debug("%s: Digital Mute val = %d\n", __func__, mute);
+
+ if (!dai || !dai->codec) {
+ pr_err("%s: Invalid params\n", __func__);
+ return -EINVAL;
+ }
+ codec = dai->codec;
+ tapan_p = snd_soc_codec_get_drvdata(codec);
+
+ if (dai->id != AIF1_CAP) {
+ dev_dbg(codec->dev, "%s: Not capture use case skip\n",
+ __func__);
+ return 0;
+ }
+
+ mute = (mute) ? 1 : 0;
+ if (!mute) {
+ /*
+ * 5 ms is an emperical value for the mute time
+ * that was arrived by checking the pop level
+ * to be inaudible
+ */
+ usleep_range(5000, 5010);
+ }
+
+ for (i = 0; i < NUM_DECIMATORS; i++) {
+ if (tapan_p->dec_active[i])
+ decimator = i + 1;
+ if (decimator && decimator <= NUM_DECIMATORS) {
+ pr_debug("%s: Mute = %d Decimator = %d", __func__,
+ mute, decimator);
+ tx_vol_ctl_reg = TAPAN_A_CDC_TX1_VOL_CTL_CFG +
+ 8 * (decimator - 1);
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, mute);
+ }
+ decimator = 0;
+ }
+ return 0;
+}
+
static struct snd_soc_dai_ops tapan_dai_ops = {
.startup = tapan_startup,
.shutdown = tapan_shutdown,
@@ -4034,6 +4146,7 @@
.set_fmt = tapan_set_dai_fmt,
.set_channel_map = tapan_set_channel_map,
.get_channel_map = tapan_get_channel_map,
+ .digital_mute = tapan_digital_mute,
};
static struct snd_soc_dai_driver tapan9302_dai[] = {
@@ -6223,6 +6336,7 @@
tapan->aux_r_gain = 0x1F;
tapan->ldo_h_users = 0;
tapan->micb_2_users = 0;
+ tapan->lb_mode = false;
tapan_update_reg_defaults(codec);
tapan_update_reg_mclk_rate(wcd9xxx);
tapan_codec_init_reg(codec);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 4b8d5bd..1dfd72b 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -6946,6 +6946,18 @@
mutex_lock(&codec->mutex);
+ if (codec->reg_def_copy) {
+ pr_debug("%s: Update ASOC cache", __func__);
+ kfree(codec->reg_cache);
+ codec->reg_cache = kmemdup(codec->reg_def_copy,
+ codec->reg_size, GFP_KERNEL);
+ if (!codec->reg_cache) {
+ pr_err("%s: Cache update failed!\n", __func__);
+ mutex_unlock(&codec->mutex);
+ return -ENOMEM;
+ }
+ }
+
taiko_update_reg_defaults(codec);
if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ)
snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x0);
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
index 3a143aa..f997e44 100644
--- a/sound/soc/msm/apq8074.c
+++ b/sound/soc/msm/apq8074.c
@@ -26,13 +26,13 @@
#include <sound/pcm.h>
#include <sound/jack.h>
#include <sound/q6afe-v2.h>
+#include <sound/q6core.h>
#include <sound/pcm_params.h>
#include <asm/mach-types.h>
#include <mach/subsystem_notif.h>
#include <mach/socinfo.h>
#include "qdsp6v2/msm-pcm-routing-v2.h"
-#include "qdsp6v2/q6core.h"
#include "../codecs/wcd9xxx-common.h"
#include "../codecs/wcd9320.h"
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index cc27fc0..bf33208 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -27,8 +27,9 @@
#include <asm/mach-types.h>
#include <mach/socinfo.h>
#include <mach/subsystem_notif.h>
+#include <sound/q6core.h>
+
#include <qdsp6v2/msm-pcm-routing-v2.h>
-#include "qdsp6v2/q6core.h"
#include "../codecs/wcd9xxx-common.h"
#include "../codecs/wcd9306.h"
@@ -58,7 +59,7 @@
#define LO_1_SPK_AMP 0x1
#define LO_2_SPK_AMP 0x2
-#define ADSP_STATE_READY_TIMEOUT_MS 3000
+#define ADSP_STATE_READY_TIMEOUT_MS 50
static void *adsp_state_notifier;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 23ed60a..c74f8dc 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -26,11 +26,11 @@
#include <sound/pcm.h>
#include <sound/jack.h>
#include <sound/q6afe-v2.h>
+#include <sound/q6core.h>
#include <sound/pcm_params.h>
#include <asm/mach-types.h>
#include <mach/subsystem_notif.h>
#include "qdsp6v2/msm-pcm-routing-v2.h"
-#include "qdsp6v2/q6core.h"
#include "../codecs/wcd9xxx-common.h"
#include "../codecs/wcd9320.h"
@@ -80,7 +80,7 @@
static void *adsp_state_notifier;
-#define ADSP_STATE_READY_TIMEOUT_MS 3000
+#define ADSP_STATE_READY_TIMEOUT_MS 50
static inline int param_is_mask(int p)
{
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 5be880d..8432067 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -31,7 +31,7 @@
#include <mach/subsystem_restart.h>
#include <mach/msm_memtypes.h>
#include <mach/ramdump.h>
-#include "q6core.h"
+#include <sound/q6core.h>
#include "audio_ocmem.h"
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 3bc6abe..4ca5764 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -480,6 +480,7 @@
snd_compr_fragment_elapsed(cstream);
prtd->copied_total = prtd->bytes_received;
atomic_set(&prtd->error, 1);
+ wake_up(&prtd->drain_wait);
spin_unlock(&prtd->lock);
break;
default:
@@ -931,14 +932,19 @@
rc = wait_event_interruptible(prtd->drain_wait,
prtd->drain_ready ||
prtd->cmd_interrupt ||
- atomic_read(&prtd->xrun));
- pr_debug("%s: out of buffer drain wait\n", __func__);
+ atomic_read(&prtd->xrun) ||
+ atomic_read(&prtd->error));
+ pr_debug("%s: out of buffer drain wait with ret %d\n", __func__, rc);
spin_lock_irqsave(&prtd->lock, *flags);
if (prtd->cmd_interrupt) {
pr_debug("%s: buffer drain interrupted by flush)\n", __func__);
rc = -EINTR;
prtd->cmd_interrupt = 0;
}
+ if (atomic_read(&prtd->error)) {
+ pr_err("%s: Got RESET EVENTS notification, return\n", __func__);
+ rc = -ENETRESET;
+ }
return rc;
}
@@ -1404,13 +1410,12 @@
tstamp.byte_offset = prtd->byte_offset;
tstamp.copied_total = prtd->copied_total;
first_buffer = prtd->first_buffer;
-
if (atomic_read(&prtd->error)) {
pr_err("%s Got RESET EVENTS notification, return error", __func__);
tstamp.pcm_io_frames = 0;
memcpy(arg, &tstamp, sizeof(struct snd_compr_tstamp));
spin_unlock_irqrestore(&prtd->lock, flags);
- return -EINVAL;
+ return -ENETRESET;
}
spin_unlock_irqrestore(&prtd->lock, flags);
@@ -1424,7 +1429,10 @@
if (rc < 0) {
pr_err("%s: Get Session Time return value =%lld\n",
__func__, timestamp);
- return -EAGAIN;
+ if (atomic_read(&prtd->error))
+ return -ENETRESET;
+ else
+ return -EAGAIN;
}
} else {
timestamp = prtd->marker_timestamp;
@@ -1507,7 +1515,7 @@
if (atomic_read(&prtd->error)) {
pr_err("%s Got RESET EVENTS notification", __func__);
spin_unlock_irqrestore(&prtd->lock, flags);
- return -EINVAL;
+ return -ENETRESET;
}
spin_unlock_irqrestore(&prtd->lock, flags);
diff --git a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
index 39e6934..2fb2a00 100644
--- a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
@@ -28,6 +28,7 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
+#include <sound/timer.h>
#include "msm-pcm-q6-v2.h"
#include "msm-pcm-routing-v2.h"
@@ -199,6 +200,18 @@
}
}
break;
+ case RESET_EVENTS:
+ pr_debug("%s RESET_EVENTS\n", __func__);
+ atomic_inc(&prtd->out_count);
+ prtd->reset_event = true;
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ else if (substream->timer_running)
+ snd_timer_interrupt(substream->timer, 1);
+ wake_up(&the_locks.eos_wait);
+ wake_up(&the_locks.write_wait);
+ wake_up(&the_locks.read_wait);
+ break;
default:
pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
break;
@@ -453,12 +466,22 @@
fbytes = frames_to_bytes(runtime, frames);
pr_debug("%s: prtd->out_count = %d\n",
__func__, atomic_read(&prtd->out_count));
+ if (prtd->reset_event == true) {
+ pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
+ return -ENETRESET;
+ }
+
ret = wait_event_timeout(the_locks.write_wait,
(atomic_read(&prtd->out_count)), 5 * HZ);
if (!ret) {
pr_err("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
+ if (prtd->reset_event == true) {
+ pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
+ return -ENETRESET;
+ }
+
if (!atomic_read(&prtd->out_count)) {
pr_err("%s: pcm stopped out_count 0\n", __func__);
@@ -547,12 +570,22 @@
pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+ if (prtd->reset_event == true) {
+ pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
+ return -ENETRESET;
+ }
+
ret = wait_event_timeout(the_locks.read_wait,
(atomic_read(&prtd->in_count)), 5 * HZ);
if (!ret) {
pr_debug("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
+ if (prtd->reset_event == true) {
+ pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
+ return -ENETRESET;
+ }
+
if (!atomic_read(&prtd->in_count)) {
pr_debug("%s: pcm stopped in_count 0\n", __func__);
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index d80ca19..e2e488f 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -35,12 +35,12 @@
#define MIN_PLAYBACK_PERIOD_SIZE (128 * 2)
#define MAX_PLAYBACK_PERIOD_SIZE (128 * 2 * 2 * 6)
-#define MIN_PLAYBACK_NUM_PERIODS (64)
+#define MIN_PLAYBACK_NUM_PERIODS (4)
#define MAX_PLAYBACK_NUM_PERIODS (768)
#define MIN_CAPTURE_PERIOD_SIZE (128 * 2 * 4)
#define MAX_CAPTURE_PERIOD_SIZE (128 * 2 * 2 * 6 * 4)
-#define MIN_CAPTURE_NUM_PERIODS (32)
+#define MIN_CAPTURE_NUM_PERIODS (4)
#define MAX_CAPTURE_NUM_PERIODS (384)
static struct snd_pcm_hardware msm_afe_hardware_playback = {
@@ -58,7 +58,7 @@
.channels_min = 1,
.channels_max = 6,
.buffer_bytes_max = MAX_PLAYBACK_PERIOD_SIZE *
- MIN_PLAYBACK_NUM_PERIODS,
+ MAX_PLAYBACK_NUM_PERIODS,
.period_bytes_min = MIN_PLAYBACK_PERIOD_SIZE,
.period_bytes_max = MAX_PLAYBACK_PERIOD_SIZE,
.periods_min = MIN_PLAYBACK_NUM_PERIODS,
@@ -81,7 +81,7 @@
.channels_min = 1,
.channels_max = 6,
.buffer_bytes_max = MAX_CAPTURE_PERIOD_SIZE *
- MIN_CAPTURE_NUM_PERIODS,
+ MAX_CAPTURE_NUM_PERIODS,
.period_bytes_min = MIN_CAPTURE_PERIOD_SIZE,
.period_bytes_max = MAX_CAPTURE_PERIOD_SIZE,
.periods_min = MIN_CAPTURE_NUM_PERIODS,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index b49ce46..7d36fff 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -26,6 +26,7 @@
#include <sound/initval.h>
#include <sound/control.h>
#include <sound/q6audio-v2.h>
+#include <sound/timer.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/msm_audio_ion.h>
@@ -240,6 +241,18 @@
}
}
break;
+ case RESET_EVENTS:
+ pr_err("%s RESET_EVENTS\n", __func__);
+ prtd->pcm_irq_pos += prtd->pcm_count;
+ atomic_inc(&prtd->out_count);
+ atomic_inc(&prtd->in_count);
+ prtd->reset_event = true;
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ wake_up(&the_locks.eos_wait);
+ wake_up(&the_locks.write_wait);
+ wake_up(&the_locks.read_wait);
+ break;
default:
pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
break;
@@ -450,6 +463,7 @@
prtd->dsp_cnt = 0;
prtd->set_channel_map = false;
+ prtd->reset_event = false;
runtime->private_data = prtd;
return 0;
@@ -472,6 +486,12 @@
fbytes = frames_to_bytes(runtime, frames);
pr_debug("%s: prtd->out_count = %d\n",
__func__, atomic_read(&prtd->out_count));
+
+ if (prtd->reset_event) {
+ pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
+ return -ENETRESET;
+ }
+
ret = wait_event_timeout(the_locks.write_wait,
(atomic_read(&prtd->out_count)), 5 * HZ);
if (!ret) {
@@ -479,6 +499,11 @@
goto fail;
}
+ if (prtd->reset_event) {
+ pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
+ return -ENETRESET;
+ }
+
if (!atomic_read(&prtd->out_count)) {
pr_err("%s: pcm stopped out_count 0\n", __func__);
return 0;
@@ -569,12 +594,20 @@
pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+ if (prtd->reset_event) {
+ pr_err("%s: In SSR return ENETRESET before wait\n", __func__);
+ return -ENETRESET;
+ }
ret = wait_event_timeout(the_locks.read_wait,
(atomic_read(&prtd->in_count)), 5 * HZ);
if (!ret) {
pr_debug("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
+ if (prtd->reset_event) {
+ pr_err("%s: In SSR return ENETRESET after wait\n", __func__);
+ return -ENETRESET;
+ }
if (!atomic_read(&prtd->in_count)) {
pr_debug("%s: pcm stopped in_count 0\n", __func__);
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 5d5c995..da2a919 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -69,6 +69,7 @@
int abort; /* set when error, like sample rate mismatch */
+ bool reset_event;
int enabled;
int close_ack;
int cmd_ack;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index e973d10..c8ff41d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -30,12 +30,12 @@
#include <sound/tlv.h>
#include <sound/asound.h>
#include <sound/pcm_params.h>
+#include <sound/q6core.h>
#include <linux/slab.h>
#include "msm-pcm-routing-v2.h"
#include "msm-dolby-dap-config.h"
#include "q6voice.h"
-#include "q6core.h"
struct msm_pcm_routing_bdai_data {
u16 port_id; /* AFE port ID */
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 6b32064..4fe2459 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -144,6 +144,7 @@
spinlock_t dsp_lock;
spinlock_t dsp_ul_lock;
+ bool voip_reset;
uint32_t mode;
uint32_t rate_type;
uint32_t rate;
@@ -317,6 +318,34 @@
/* sample rate supported */
static unsigned int supported_sample_rates[] = {8000, 16000};
+static void voip_ssr_cb_fn(uint32_t opcode, void *private_data)
+{
+
+ /* Notify ASoC to send next playback/Capture to unblock write/read */
+ struct voip_drv_info *prtd = private_data;
+
+ if (opcode == 0xFFFFFFFF) {
+
+ prtd->voip_reset = true;
+ pr_debug("%s: Notify ASoC to send next playback/Capture\n",
+ __func__);
+
+ prtd->pcm_playback_irq_pos += prtd->pcm_count;
+ if (prtd->state == VOIP_STARTED)
+ snd_pcm_period_elapsed(prtd->playback_substream);
+ wake_up(&prtd->out_wait);
+
+ prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
+ if (prtd->state == VOIP_STARTED)
+ snd_pcm_period_elapsed(prtd->capture_substream);
+ wake_up(&prtd->in_wait);
+
+ } else {
+ pr_err("%s: Invalid opcode during reset : %d\n",
+ __func__, opcode);
+ }
+}
+
/* capture path */
static void voip_process_ul_pkt(uint8_t *voc_pkt,
uint32_t pkt_len,
@@ -754,10 +783,20 @@
int count = frames_to_bytes(runtime, frames);
pr_debug("%s: count = %d, frames=%d\n", __func__, count, (int)frames);
+ if (prtd->voip_reset) {
+ pr_debug("%s: RESET event happened during VoIP\n", __func__);
+ return -ENETRESET;
+ }
+
ret = wait_event_interruptible_timeout(prtd->in_wait,
(!list_empty(&prtd->free_in_queue) ||
prtd->state == VOIP_STOPPED),
1 * HZ);
+ if (prtd->voip_reset) {
+ pr_debug("%s: RESET event happened during VoIP\n", __func__);
+ return -ENETRESET;
+ }
+
if (ret > 0) {
if (count <= VOIP_MAX_VOC_PKT_SIZE) {
spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
@@ -807,11 +846,21 @@
pr_debug("%s: count = %d\n", __func__, count);
+ if (prtd->voip_reset) {
+ pr_debug("%s: RESET event happened during VoIP\n", __func__);
+ return -ENETRESET;
+ }
+
ret = wait_event_interruptible_timeout(prtd->out_wait,
(!list_empty(&prtd->out_queue) ||
prtd->state == VOIP_STOPPED),
1 * HZ);
+ if (prtd->voip_reset) {
+ pr_debug("%s: RESET event happened during VoIP\n", __func__);
+ return -ENETRESET;
+ }
+
if (ret > 0) {
if (count <= VOIP_MAX_VOC_PKT_SIZE) {
@@ -842,7 +891,6 @@
list_add_tail(&buf_node->list,
&prtd->free_out_queue);
spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
-
} else {
pr_err("%s: Read count %d > VOIP_MAX_VOC_PKT_SIZE\n",
__func__, count);
@@ -902,10 +950,11 @@
if (!prtd->playback_instance && !prtd->capture_instance) {
if (prtd->state == VOIP_STARTED) {
+ prtd->voip_reset = false;
prtd->state = VOIP_STOPPED;
voc_end_voice_call(
voc_get_session_id(VOIP_SESSION_NAME));
- voc_register_mvs_cb(NULL, NULL, prtd);
+ voc_register_mvs_cb(NULL, NULL, NULL, prtd);
}
/* release all buffer */
/* release in_queue and free_in_queue */
@@ -1131,8 +1180,10 @@
goto done;
}
+ /* Initialaizing cb variables */
voc_register_mvs_cb(voip_process_ul_pkt,
- voip_process_dl_pkt, prtd);
+ voip_process_dl_pkt,
+ voip_ssr_cb_fn, prtd);
ret = voc_start_voice_call(
voc_get_session_id(VOIP_SESSION_NAME));
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index a7a5d1e..f619b67 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -53,6 +53,7 @@
u16 dtmf_gen_rx_portid;
struct afe_spkr_prot_calib_get_resp calib_data;
int vi_tx_port;
+ int vi_rx_port;
uint32_t afe_sample_rates[AFE_MAX_PORTS];
struct aanc_data aanc_info;
};
@@ -500,7 +501,7 @@
return result;
}
-static int afe_spk_prot_prepare(int port, int param_id,
+static int afe_spk_prot_prepare(int src_port, int dst_port, int param_id,
union afe_spkr_prot_config *prot_config)
{
int ret = -EINVAL;
@@ -512,17 +513,28 @@
pr_err("%s Invalid params\n", __func__);
goto fail_cmd;
}
- if ((q6audio_validate_port(port) < 0)) {
- pr_err("%s invalid port %d", __func__, port);
+ ret = q6audio_validate_port(src_port);
+ if (ret < 0) {
+ pr_err("%s: Invalid src port 0x%x ret %d",
+ __func__, src_port, ret);
+ ret = -EINVAL;
goto fail_cmd;
}
- index = q6audio_get_port_index(port);
+ ret = q6audio_validate_port(dst_port);
+ if (ret < 0) {
+ pr_err("%s: Invalid dst port 0x%x ret %d", __func__,
+ dst_port, ret);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ index = q6audio_get_port_index(src_port);
switch (param_id) {
case AFE_PARAM_ID_FBSP_MODE_RX_CFG:
config.pdata.module_id = AFE_MODULE_FB_SPKR_PROT_RX;
break;
case AFE_PARAM_ID_FEEDBACK_PATH_CFG:
- this_afe.vi_tx_port = port;
+ this_afe.vi_tx_port = src_port;
+ this_afe.vi_rx_port = dst_port;
case AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG:
case AFE_PARAM_ID_MODE_VI_PROC_CFG:
config.pdata.module_id = AFE_MODULE_FB_SPKR_PROT_VI_PROC;
@@ -540,7 +552,7 @@
config.hdr.token = index;
config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
- config.param.port_id = q6audio_get_port_id(port);
+ config.param.port_id = q6audio_get_port_id(src_port);
config.param.payload_size = sizeof(config) - sizeof(config.hdr)
- sizeof(config.param);
config.pdata.param_id = param_id;
@@ -549,8 +561,8 @@
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
if (ret < 0) {
- pr_err("%s: Setting param for port %d param[0x%x]failed\n",
- __func__, port, param_id);
+ pr_err("%s: port = 0x%x param = 0x%x failed %d\n",
+ __func__, src_port, param_id, ret);
goto fail_cmd;
}
ret = wait_event_timeout(this_afe.wait[index],
@@ -568,8 +580,8 @@
}
ret = 0;
fail_cmd:
- pr_debug("%s config.pdata.param_id %x status %d\n",
- __func__, config.pdata.param_id, ret);
+ pr_debug("%s: config.pdata.param_id 0x%x status %d 0x%x\n",
+ __func__, config.pdata.param_id, ret, src_port);
return ret;
}
@@ -590,7 +602,7 @@
else
afe_spk_config.mode_rx_cfg.mode =
Q6AFE_MSM_SPKR_PROCESSING;
- if (afe_spk_prot_prepare(port_id,
+ if (afe_spk_prot_prepare(port_id, 0,
AFE_PARAM_ID_MODE_VI_PROC_CFG,
&afe_spk_config))
pr_err("%s TX VI_PROC_CFG failed\n", __func__);
@@ -600,7 +612,7 @@
(uint32_t) prot_cfg.r0;
afe_spk_config.vi_proc_cfg.t0_cali_q6 =
(uint32_t) prot_cfg.t0;
- if (afe_spk_prot_prepare(port_id,
+ if (afe_spk_prot_prepare(port_id, 0,
AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG,
&afe_spk_config))
pr_err("%s SPKR_CALIB_VI_PROC_CFG failed\n",
@@ -617,7 +629,8 @@
/*Get spkr protection cfg data*/
get_spk_protection_cfg(&prot_cfg);
- if (prot_cfg.mode != MSM_SPKR_PROT_DISABLED) {
+ if ((prot_cfg.mode != MSM_SPKR_PROT_DISABLED) &&
+ (this_afe.vi_rx_port == port_id)) {
if (prot_cfg.mode == MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS)
afe_spk_config.mode_rx_cfg.mode =
Q6AFE_MSM_SPKR_CALIBRATION;
@@ -625,7 +638,7 @@
afe_spk_config.mode_rx_cfg.mode =
Q6AFE_MSM_SPKR_PROCESSING;
afe_spk_config.mode_rx_cfg.minor_version = 1;
- if (afe_spk_prot_prepare(port_id,
+ if (afe_spk_prot_prepare(port_id, 0,
AFE_PARAM_ID_FBSP_MODE_RX_CFG,
&afe_spk_config))
pr_err("%s RX MODE_VI_PROC_CFG failed\n",
@@ -701,7 +714,7 @@
void afe_send_cal(u16 port_id)
{
- pr_debug("%s\n", __func__);
+ pr_debug("%s: port_id=0x%x\n", __func__, port_id);
if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) {
afe_send_cal_spkr_prot_tx(port_id);
@@ -1488,6 +1501,7 @@
case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
+ case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX;
case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -3220,6 +3234,7 @@
if (!enable) {
pr_debug("%s Disable Feedback tx path", __func__);
this_afe.vi_tx_port = -1;
+ this_afe.vi_rx_port = -1;
return 0;
}
@@ -3248,7 +3263,7 @@
}
prot_config.feedback_path_cfg.num_channels = index;
prot_config.feedback_path_cfg.minor_version = 1;
- ret = afe_spk_prot_prepare(src_port,
+ ret = afe_spk_prot_prepare(src_port, dst_port,
AFE_PARAM_ID_FEEDBACK_PATH_CFG, &prot_config);
fail_cmd:
return ret;
@@ -3264,6 +3279,7 @@
this_afe.dtmf_gen_rx_portid = -1;
this_afe.mmap_handle = 0;
this_afe.vi_tx_port = -1;
+ this_afe.vi_rx_port = -1;
for (i = 0; i < AFE_MAX_PORTS; i++)
init_waitqueue_head(&this_afe.wait[i]);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 9a3cb87..6796378 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -676,7 +676,7 @@
while (cnt >= 0) {
if (port->buf[cnt].data) {
- if (!rc)
+ if (!rc || atomic_read(&ac->reset))
msm_audio_ion_free(
port->buf[cnt].client,
port->buf[cnt].handle);
@@ -726,7 +726,7 @@
(void *)&port->buf[0].phys,
(void *)port->buf[0].client,
(void *)port->buf[0].handle);
- if (!rc)
+ if (!rc || atomic_read(&ac->reset))
msm_audio_ion_free(port->buf[0].client,
port->buf[0].handle);
port->buf[0].client = NULL;
@@ -886,6 +886,7 @@
init_waitqueue_head(&ac->time_wait);
init_waitqueue_head(&ac->mem_wait);
atomic_set(&ac->time_flag, 1);
+ atomic_set(&ac->reset, 0);
INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
pr_debug("%s: mem_map_handle list init'ed\n", __func__);
@@ -1124,11 +1125,7 @@
payload = data->payload;
if (data->opcode == RESET_EVENTS) {
- struct audio_client *ac_mmap = (struct audio_client *)priv;
- if (ac_mmap == NULL) {
- pr_err("%s ac or priv NULL\n", __func__);
- return -EINVAL;
- }
+
pr_debug("%s: Reset event is received: %d %d apr[%p]\n",
__func__,
data->reset_event,
@@ -1137,7 +1134,6 @@
atomic_set(&this_mmap.ref_cnt, 0);
apr_reset(this_mmap.apr);
this_mmap.apr = NULL;
- ac_mmap->mmap_apr = NULL;
for (; i <= OUT; i++) {
list_for_each_safe(ptr, next,
&common_client.port[i].mem_map_handle) {
@@ -1287,16 +1283,20 @@
}
if (data->opcode == RESET_EVENTS) {
- if(ac->apr == NULL) {
- ac->apr = ac->apr2;
- }
+ atomic_set(&ac->reset, 1);
+ if (ac->apr == NULL)
+ ac->apr = ac->apr2;
pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
data->reset_event, data->reset_proc, ac->apr);
- if (ac->cb)
- ac->cb(data->opcode, data->token,
- (uint32_t *)data->payload, ac->priv);
+ if (ac->cb)
+ ac->cb(data->opcode, data->token,
+ (uint32_t *)data->payload, ac->priv);
apr_reset(ac->apr);
ac->apr = NULL;
+ atomic_set(&ac->time_flag, 0);
+ atomic_set(&ac->cmd_state, 0);
+ wake_up(&ac->time_wait);
+ wake_up(&ac->cmd_wait);
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 496a5ef..ba237c1 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -20,10 +20,11 @@
#include <linux/slab.h>
#include <mach/msm_smd.h>
#include <mach/qdsp6v2/apr.h>
-#include "q6core.h"
#include <mach/ocmem.h>
+#include <sound/q6core.h>
#define TIMEOUT_MS 1000
+#define Q6_READY_TIMEOUT_MS 100
struct q6core_str {
struct apr_svc *core_handle_q;
@@ -237,7 +238,7 @@
rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
(q6core_lcl.bus_bw_resp_received == 1),
- msecs_to_jiffies(TIMEOUT_MS));
+ msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
/* ensure to read updated param by callback thread */
rmb();
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index 61222fe..051c4c2 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -26,12 +26,12 @@
#include <linux/atomic.h>
#include <sound/apr_audio-v2.h>
#include <sound/lsm_params.h>
+#include <sound/q6core.h>
#include <sound/q6lsm.h>
#include <asm/ioctls.h>
#include <mach/memory.h>
#include <mach/debug_mm.h>
#include "audio_acdb.h"
-#include "q6core.h"
#define APR_TIMEOUT (5 * HZ)
#define LSM_CAL_SIZE 4096
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 475a0eb..b165664 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -5206,10 +5206,12 @@
void voc_register_mvs_cb(ul_cb_fn ul_cb,
dl_cb_fn dl_cb,
+ voip_ssr_cb ssr_cb,
void *private_data)
{
common.mvs_info.ul_cb = ul_cb;
common.mvs_info.dl_cb = dl_cb;
+ common.mvs_info.ssr_cb = ssr_cb;
common.mvs_info.private_data = private_data;
}
@@ -5260,6 +5262,14 @@
} else {
pr_debug("%s: Reset event received in Voice service\n",
__func__);
+
+ if (common.mvs_info.ssr_cb) {
+ pr_debug("%s: Informing reset event to VoIP\n",
+ __func__);
+ common.mvs_info.ssr_cb(data->opcode,
+ common.mvs_info.private_data);
+ }
+
apr_reset(c->apr_q6_mvm);
c->apr_q6_mvm = NULL;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index c6f3482..58cdfc3 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1226,6 +1226,9 @@
char *session,
void *private_data);
+typedef void (*voip_ssr_cb) (uint32_t opcode,
+ void *private_data);
+
struct mvs_driver_info {
uint32_t media_type;
uint32_t rate;
@@ -1233,6 +1236,7 @@
uint32_t dtx_mode;
ul_cb_fn ul_cb;
dl_cb_fn dl_cb;
+ voip_ssr_cb ssr_cb;
void *private_data;
uint32_t evrc_min_rate;
uint32_t evrc_max_rate;
@@ -1365,6 +1369,7 @@
void voc_register_mvs_cb(ul_cb_fn ul_cb,
dl_cb_fn dl_cb,
+ voip_ssr_cb ssr_cb,
void *private_data);
void voc_register_dtmf_rx_detection_cb(dtmf_rx_det_cb_fn dtmf_rx_ul_cb,
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 4792719..fb4eed1 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -599,14 +599,15 @@
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_platform *platform = rtd->platform;
+ int ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
- platform->driver->compr_ops->pointer(cstream, tstamp);
+ ret = platform->driver->compr_ops->pointer(cstream, tstamp);
mutex_unlock(&rtd->pcm_mutex);
- return 0;
+ return ret;
}
static int soc_compr_copy(struct snd_compr_stream *cstream,
diff --git a/sound/usb/card.c b/sound/usb/card.c
index d419e2f..69c9ebc 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -48,7 +48,6 @@
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
#include <linux/module.h>
-#include <linux/switch.h>
#include <sound/control.h>
#include <sound/core.h>
@@ -87,7 +86,6 @@
static bool async_unlink = 1;
static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
static bool ignore_ctl_error;
-struct switch_dev *usbaudiosdev;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -277,7 +275,6 @@
break;
}
}
- switch_set_state(usbaudiosdev, 1);
return 0;
}
@@ -595,7 +592,6 @@
mutex_unlock(&chip->shutdown_mutex);
mutex_unlock(®ister_mutex);
}
- switch_set_state(usbaudiosdev, 0);
}
/*
@@ -728,32 +724,17 @@
static int __init snd_usb_audio_init(void)
{
- int err;
if (nrpacks < 1 || nrpacks > MAX_PACKS) {
printk(KERN_WARNING "invalid nrpacks value.\n");
return -EINVAL;
}
- usbaudiosdev = kzalloc(sizeof(*usbaudiosdev), GFP_KERNEL);
- if (!usbaudiosdev) {
- pr_err("Usb audio device memory allocation failed.\n");
- return -ENOMEM;
- }
-
- usbaudiosdev->name = "usb_audio";
-
- err = switch_dev_register(usbaudiosdev);
- if (err)
- pr_err("Usb-audio switch registration failed\n");
- else
- pr_debug("usb hs_detected\n");
return usb_register(&usb_audio_driver);
}
static void __exit snd_usb_audio_cleanup(void)
{
usb_deregister(&usb_audio_driver);
- kfree(usbaudiosdev);
}
module_init(snd_usb_audio_init);