Merge branch 'partner/android-exynos-r11-4.19-rvc-jr3' into android-exynos-r11-4.19 JUL 2023.1 Bug: 280774281 Change-Id: I2b5558abf36662bf0a5bcdd9e02f113027b16012
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 337e177..252d13b 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c
@@ -468,9 +468,19 @@ struct binder_priority { * (protected by binder_deferred_lock) * @deferred_work: bitmap of deferred work to perform * (protected by binder_deferred_lock) + * @outstanding_txns: number of transactions to be transmitted before + * processes in freeze_wait are woken up + * (protected by @inner_lock) * @is_dead: process is dead and awaiting free * when outstanding transactions are cleaned up * (protected by @inner_lock) + * @sync_recv: process received sync transactions since last frozen + * (protected by @inner_lock) + * @async_recv: process received async transactions since last frozen + * (protected by @inner_lock) + * @freeze_wait: waitqueue of processes waiting for all outstanding + * transactions to be processed + * (protected by @inner_lock) * @todo: list of work for this process * (protected by @inner_lock) * @stats: per-process binder statistics @@ -514,7 +524,12 @@ struct binder_proc { const struct cred *cred; struct hlist_node deferred_work_node; int deferred_work; + int outstanding_txns; bool is_dead; + bool is_frozen; + bool sync_recv; + bool async_recv; + wait_queue_head_t freeze_wait; struct list_head todo; struct binder_stats stats; @@ -2087,6 +2102,10 @@ static void binder_free_transaction(struct binder_transaction *t) if (target_proc) { binder_inner_proc_lock(target_proc); + target_proc->outstanding_txns--; + BUG_ON(target_proc->outstanding_txns < 0); + if (!target_proc->outstanding_txns && target_proc->is_frozen) + wake_up_interruptible_all(&target_proc->freeze_wait); if (t->buffer) t->buffer->transaction = NULL; binder_inner_proc_unlock(target_proc); @@ -2837,10 +2856,11 @@ static int binder_fixup_parent(struct binder_transaction *t, * If the @thread parameter is not NULL, the transaction is always queued * to the waitlist of that specific thread. * - * Return: true if the transactions was successfully queued - * false if the target process or thread is dead + * Return: 0 if the transaction was successfully queued + * BR_DEAD_REPLY if the target process or thread is dead + * BR_FROZEN_REPLY if the target process or thread is frozen */ -static bool binder_proc_transaction(struct binder_transaction *t, +static int binder_proc_transaction(struct binder_transaction *t, struct binder_proc *proc, struct binder_thread *thread) { @@ -2864,11 +2884,18 @@ static bool binder_proc_transaction(struct binder_transaction *t, } binder_inner_proc_lock(proc); + if (proc->is_frozen) { + proc->sync_recv |= !oneway; + proc->async_recv |= oneway; + } - if (proc->is_dead || (thread && thread->is_dead)) { + if ((proc->is_frozen && !oneway) || proc->is_dead || + (thread && thread->is_dead)) { + bool proc_is_dead = proc->is_dead + || (thread && thread->is_dead); binder_inner_proc_unlock(proc); binder_node_unlock(node); - return false; + return proc_is_dead ? BR_DEAD_REPLY : BR_FROZEN_REPLY; } if (!thread && !pending_async) @@ -2887,10 +2914,11 @@ static bool binder_proc_transaction(struct binder_transaction *t, if (!pending_async) binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); + proc->outstanding_txns++; binder_inner_proc_unlock(proc); binder_node_unlock(node); - return true; + return 0; } /** @@ -3508,13 +3536,16 @@ static void binder_transaction(struct binder_proc *proc, if (reply) { binder_enqueue_thread_work(thread, tcomplete); binder_inner_proc_lock(target_proc); - if (target_thread->is_dead) { + if (target_thread->is_dead || target_proc->is_frozen) { + return_error = target_thread->is_dead ? + BR_DEAD_REPLY : BR_FROZEN_REPLY; binder_inner_proc_unlock(target_proc); goto err_dead_proc_or_thread; } BUG_ON(t->buffer->async_transaction != 0); binder_pop_transaction_ilocked(target_thread, in_reply_to); binder_enqueue_thread_work_ilocked(target_thread, &t->work); + target_proc->outstanding_txns++; binder_inner_proc_unlock(target_proc); wake_up_interruptible_sync(&target_thread->wait); binder_restore_priority(current, in_reply_to->saved_priority); @@ -3534,7 +3565,9 @@ static void binder_transaction(struct binder_proc *proc, t->from_parent = thread->transaction_stack; thread->transaction_stack = t; binder_inner_proc_unlock(proc); - if (!binder_proc_transaction(t, target_proc, target_thread)) { + return_error = binder_proc_transaction(t, + target_proc, target_thread); + if (return_error) { binder_inner_proc_lock(proc); binder_pop_transaction_ilocked(thread, t); binder_inner_proc_unlock(proc); @@ -3544,7 +3577,8 @@ static void binder_transaction(struct binder_proc *proc, BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); binder_enqueue_thread_work(thread, tcomplete); - if (!binder_proc_transaction(t, target_proc, NULL)) + return_error = binder_proc_transaction(t, target_proc, NULL); + if (return_error) goto err_dead_proc_or_thread; } if (target_thread) @@ -3561,7 +3595,6 @@ static void binder_transaction(struct binder_proc *proc, return; err_dead_proc_or_thread: - return_error = BR_DEAD_REPLY; return_error_line = __LINE__; binder_dequeue_work(proc, tcomplete); err_translate_failed: @@ -4167,7 +4200,7 @@ static int binder_wait_for_work(struct binder_thread *thread, binder_inner_proc_lock(proc); list_del_init(&thread->waiting_thread_node); if (signal_pending(current)) { - ret = -ERESTARTSYS; + ret = -EINTR; break; } } @@ -4671,6 +4704,7 @@ static void binder_free_proc(struct binder_proc *proc) BUG_ON(!list_empty(&proc->todo)); BUG_ON(!list_empty(&proc->delivered_death)); + WARN_ON(proc->outstanding_txns); device = container_of(proc->context, struct binder_device, context); if (refcount_dec_and_test(&device->ref)) { kfree(proc->context->name); @@ -4732,6 +4766,7 @@ static int binder_thread_release(struct binder_proc *proc, (t->to_thread == thread) ? "in" : "out"); if (t->to_thread == thread) { + t->to_proc->outstanding_txns--; t->to_proc = NULL; t->to_thread = NULL; if (t->buffer) { @@ -4975,6 +5010,76 @@ static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, return 0; } +static int binder_ioctl_freeze(struct binder_freeze_info *info, + struct binder_proc *target_proc) +{ + int ret = 0; + + if (!info->enable) { + binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + return 0; + } + + /* + * Freezing the target. Prevent new transactions by + * setting frozen state. If timeout specified, wait + * for transactions to drain. + */ + binder_inner_proc_lock(target_proc); + target_proc->sync_recv = false; + target_proc->async_recv = false; + target_proc->is_frozen = true; + binder_inner_proc_unlock(target_proc); + + if (info->timeout_ms > 0) + ret = wait_event_interruptible_timeout( + target_proc->freeze_wait, + (!target_proc->outstanding_txns), + msecs_to_jiffies(info->timeout_ms)); + + if (!ret && target_proc->outstanding_txns) + ret = -EAGAIN; + + if (ret < 0) { + binder_inner_proc_lock(target_proc); + target_proc->is_frozen = false; + binder_inner_proc_unlock(target_proc); + } + + return ret; +} + +static int binder_ioctl_get_freezer_info( + struct binder_frozen_status_info *info) +{ + struct binder_proc *target_proc; + bool found = false; + + info->sync_recv = 0; + info->async_recv = 0; + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info->pid) { + found = true; + binder_inner_proc_lock(target_proc); + info->sync_recv |= target_proc->sync_recv; + info->async_recv |= target_proc->async_recv; + binder_inner_proc_unlock(target_proc); + } + } + mutex_unlock(&binder_procs_lock); + + if (!found) + return -EINVAL; + + return 0; +} + static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; @@ -5093,6 +5198,84 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; } + case BINDER_FREEZE: { + struct binder_freeze_info info; + struct binder_proc **target_procs = NULL, *target_proc; + int target_procs_count = 0, i = 0; + + ret = 0; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid == info.pid) + target_procs_count++; + } + + if (target_procs_count == 0) { + mutex_unlock(&binder_procs_lock); + ret = -EINVAL; + goto err; + } + + target_procs = kmalloc(sizeof(struct binder_proc *) * + target_procs_count, + GFP_KERNEL); + + if (!target_procs) { + mutex_unlock(&binder_procs_lock); + ret = -ENOMEM; + goto err; + } + + hlist_for_each_entry(target_proc, &binder_procs, proc_node) { + if (target_proc->pid != info.pid) + continue; + + binder_inner_proc_lock(target_proc); + target_proc->tmp_ref++; + binder_inner_proc_unlock(target_proc); + + target_procs[i++] = target_proc; + } + mutex_unlock(&binder_procs_lock); + + for (i = 0; i < target_procs_count; i++) { + if (ret >= 0) + ret = binder_ioctl_freeze(&info, + target_procs[i]); + + binder_proc_dec_tmpref(target_procs[i]); + } + + kfree(target_procs); + + if (ret < 0) + goto err; + break; + } + case BINDER_GET_FROZEN_INFO: { + struct binder_frozen_status_info info; + + if (copy_from_user(&info, ubuf, sizeof(info))) { + ret = -EFAULT; + goto err; + } + + ret = binder_ioctl_get_freezer_info(&info); + if (ret < 0) + goto err; + + if (copy_to_user(ubuf, &info, sizeof(info))) { + ret = -EFAULT; + goto err; + } + break; + } default: ret = -EINVAL; goto err; @@ -5102,7 +5285,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (thread) thread->looper_need_return = false; wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); - if (ret && ret != -ERESTARTSYS) + if (ret && ret != -EINTR) pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); err_unlocked: trace_binder_ioctl_done(ret); @@ -5207,6 +5390,7 @@ static int binder_open(struct inode *nodp, struct file *filp) mutex_init(&proc->files_lock); proc->cred = get_cred(filp->f_cred); INIT_LIST_HEAD(&proc->todo); + init_waitqueue_head(&proc->freeze_wait); if (binder_supported_policy(current->policy)) { proc->default_priority.sched_policy = current->policy; proc->default_priority.prio = current->normal_prio; @@ -5428,6 +5612,9 @@ static void binder_deferred_release(struct binder_proc *proc) proc->tmp_ref++; proc->is_dead = true; + proc->is_frozen = false; + proc->sync_recv = false; + proc->async_recv = false; threads = 0; active_transactions = 0; while ((n = rb_first(&proc->threads))) {
diff --git a/drivers/video/fbdev/exynos/dpu30/panels/panel-boe-wf012fbm.c b/drivers/video/fbdev/exynos/dpu30/panels/panel-boe-wf012fbm.c index 2e60e6f..1f7a1d1 100644 --- a/drivers/video/fbdev/exynos/dpu30/panels/panel-boe-wf012fbm.c +++ b/drivers/video/fbdev/exynos/dpu30/panels/panel-boe-wf012fbm.c
@@ -19,6 +19,28 @@ #define PANEL_MAX_TRIES 3 +// Look up table to convert between AOD and Interactive DBV that would +// yield the same display nits, defined in go/rh-eos-dbv-lut +const static u8 InteractiveToAodDbvLUT[] = { + 0, 3, 5, 5, 8, 15, 16, 21, 25, 30, 33, 38, 43, + 47, 51, 56, 59, 69, 69, 72, 77, 79, 81, 83, 86, 88, + 90, 92, 94, 96, 98, 101, 103, 106, 110, 112, 114, 116, 120, + 122, 125, 128, 130, 134, 136, 140, 143, 146, 149, 152, 155, 158, + 162, 166, 169, 174, 178, 182, 186, 188, 192, 196, 201, 205, 211, + 215, 220, 225, 228, 232, 237, 241, 246, 251 +}; + +static u8 interactive_to_aod_brightness(u8 interactive_brightness) +{ + if (interactive_brightness >= sizeof(InteractiveToAodDbvLUT)) { + // This means Interactive brightness (nits) is already saturated + // if converted to Doze brightness (i.e. > max AOD 150 nits). + // Let's return the maximum DBV here, which is 255. + return 255; + } + return InteractiveToAodDbvLUT[interactive_brightness]; +} + static int wf012fbm_suspend(struct exynos_panel_device *panel) { struct dsim_device *dsim = get_dsim_drvdata(0); @@ -81,6 +103,19 @@ int wf012fbm_panel_init(struct dsim_device *dsim) dsim_write_data_seq(dsim, false, 0x57, 0x30); dsim_write_data_seq(dsim, false, 0xff, 0x10); + /* Disable master DBV control mode */ + dsim_write_data_seq(dsim, false, 0xff, 0x21); + dsim_write_data_seq(dsim, false, 0xfb, 0x01); + dsim_write_data_seq(dsim, false, 0x5d, 0x00); + dsim_write_data_seq(dsim, false, 0xff, 0x10); + + /* No gradual DBV change during the mode transition */ + dsim_write_data_seq(dsim, false, 0xff, 0x25); + dsim_write_data_seq(dsim, false, 0xfb, 0x01); + dsim_write_data_seq(dsim, false, 0x74, 0xa1); + dsim_write_data_seq(dsim, false, 0x76, 0x51); + dsim_write_data_seq(dsim, false, 0xff, 0x10); + /* Write sequence for setting the PWM frequency if necessary*/ ret = dsim_read_data(dsim, MIPI_DSI_DCS_READ, 0xDA, sizeof(buf), buf); @@ -350,50 +385,13 @@ static int wf012fbm_displayon(struct exynos_panel_device *panel) static int wf012fbm_doze(struct exynos_panel_device *panel) { struct dsim_device *dsim = get_dsim_drvdata(0); - u8 aod_brightness = 0; - u8 interactive_brightness = 0; - u16 brightness_u16 = 0; DPU_INFO_PANEL("%s +\n", __func__); mutex_lock(&panel->ops_lock); /* Page select */ dsim_write_data_seq(dsim, false, 0xff, 0x10); - /* Calculate normalized brightness */ - interactive_brightness = panel->bl->props.brightness; - if (interactive_brightness > 0) { - brightness_u16 = - DIV_ROUND_CLOSEST(interactive_brightness * 650, 150); - /* If normalized brightness is set late after mode-change - frame finish, it could cause a dip when interactive brightness - gets scaled down (150/650) and rises back up to the normalized - level. To cover for this case, let's scale down the normalized - brightness by 90% so that it doesn't rise back up. This should - only apply to brighter level (i.e. > 20/255) where the dip - could be seen easily. */ - if (interactive_brightness > 20) { - brightness_u16 = brightness_u16 * 90 / 100; - } - aod_brightness = brightness_u16 > 255 ? 255 : brightness_u16; - } - /* Idle Mode */ dsim_write_data_seq(dsim, false, MIPI_DCS_ENTER_IDLE_MODE); - /* Set normalized brightness */ - if (!panel->doze_brightness_normalized && aod_brightness != 0) { - /* Delay until mode-change frame. - This requires an exact delay of 1 frame after exit-doze cmd */ - usleep_range(16667, 16667); - /* Disable brightness dimming */ - dsim_write_data_seq(dsim, false, 0x53, 0x20); - /* Set normalized brightness */ - dsim_write_data_seq(dsim, false, 0x51, aod_brightness); - /* Delay until mode-change frame ends */ - usleep_range(16667, 16667); - /* Enable brightness dimming */ - dsim_write_data_seq(dsim, false, 0x53, 0x28); - panel->doze_brightness_normalized = true; - } - /* Exit HBM in case it's on */ dsim_write_data_seq(dsim, false, 0x66, 0x00); @@ -409,7 +407,8 @@ static int wf012fbm_doze_suspend(struct exynos_panel_device *panel) static int wf012fbm_set_light(struct exynos_panel_device *panel, u32 br_val) { - u8 data; + u8 interactive_brightness; + u8 aod_brightness; struct dsim_device *dsim = get_dsim_drvdata(0); /* * Only set brightness if it's not currently in doze mode as AP @@ -424,9 +423,14 @@ static int wf012fbm_set_light(struct exynos_panel_device *panel, u32 br_val) if (dsim->state != DSIM_STATE_DOZE) { mutex_lock(&panel->ops_lock); /* WRDISBV(8bit): 1st DBV[7:0] */ - data = br_val & 0xFF; - dsim_write_data_seq(dsim, false, 0x51, data); + interactive_brightness = br_val & 0xFF; + aod_brightness = + interactive_to_aod_brightness(interactive_brightness); + dsim_write_data_seq(dsim, false, 0x51, interactive_brightness); + dsim_write_data_seq(dsim, false, 0x61, aod_brightness); mutex_unlock(&panel->ops_lock); + DPU_INFO_PANEL("%s: set brightness (i=%d, aod=%d)\n", __func__, + interactive_brightness, aod_brightness); } else { DPU_INFO_PANEL("%s: skip doze br=%d\n", __func__, br_val); } @@ -466,50 +470,22 @@ static int wf012fbm_exit_hbm(struct exynos_panel_device *panel) static int wf012fbm_exit_doze(struct exynos_panel_device *panel) { struct dsim_device *dsim = get_dsim_drvdata(0); - unsigned char buf[1] = {0}; - u8 normalized_brightness = 0; + u8 brightness = 0; DPU_INFO_PANEL("%s +\n", __func__); mutex_lock(&panel->ops_lock); + /* page select 0x10 */ dsim_write_data_seq(dsim, false, 0xff, 0x10); - /* Read brightness */ - dsim_read_data(dsim, MIPI_DSI_DCS_READ, - MIPI_DCS_GET_DISPLAY_BRIGHTNESS, sizeof(buf), buf); - if (buf[0] != 0) { - panel->bl->props.brightness = buf[0]; - /* Calculate interactive DBV that would yield the same - brightness nits to the current AOD DBV. - As both interactive and AOD DBV-nits conversion are linear, - this can be done by scaling with the max brightness nits - (150 nits for AOD and 650 nits for interactive at DBV255) */ - normalized_brightness = DIV_ROUND_CLOSEST(buf[0] * 150, 650); - /* If normalized brightness is set late after mode-change - frame finish, it could cause a spike when AOD brightness gets - scaled up (650/150) and dip back down to the normalized level. - To cover for this case, let's scale up the normalized - brightness by 120% so that it doesn't dip back down */ - normalized_brightness = normalized_brightness * 120 / 100; + /* Read interactive brightness */ + dsim_read_data(dsim, MIPI_DSI_DCS_READ, 0x51, + sizeof(brightness), &brightness); + if (brightness != 0) { + panel->bl->props.brightness = brightness; } /* Exit Idle Mode */ dsim_write_data_seq(dsim, false, MIPI_DCS_EXIT_IDLE_MODE); - /* Flatten mode-change brightness ramp */ - if (normalized_brightness != 0) { - panel->bl->props.brightness = normalized_brightness; - /* Delay until mode-change frame. - This requires an exact delay of 1 frame after exit-doze cmd */ - usleep_range(16667, 16667); - /* Disable brightness dimming */ - dsim_write_data_seq(dsim, false, 0x53, 0x20); - /* Set normalized brightness */ - dsim_write_data_seq(dsim, false, 0x51, normalized_brightness); - /* Delay until mode-change frame ends */ - usleep_range(16667, 16667); - /* Enable brightness dimming */ - dsim_write_data_seq(dsim, false, 0x53, 0x28); - } - panel->doze_brightness_normalized = false; mutex_unlock(&panel->ops_lock); - DPU_INFO_PANEL("%s -\n", __func__); + DPU_INFO_PANEL("%s - read br=%d\n", __func__, brightness); return 0; }
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index f02aef1..4ad24d0 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c
@@ -517,7 +517,8 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent, if (unlikely(!inode)) return failed_creating(dentry); - inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; + /* Do not set bits for OTH */ + inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP; inode->i_op = ops; inode->i_fop = &simple_dir_operations; inode->i_uid = d_inode(dentry->d_parent)->i_uid;
diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 36a53fd..d5bcba6 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h
@@ -264,6 +264,18 @@ struct binder_node_info_for_ref { __u32 reserved3; }; +struct binder_freeze_info { + __u32 pid; + __u32 enable; + __u32 timeout_ms; +}; + +struct binder_frozen_status_info { + __u32 pid; + __u32 sync_recv; + __u32 async_recv; +}; + #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) @@ -274,6 +286,8 @@ struct binder_node_info_for_ref { #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) #define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref) #define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) +#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info) +#define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info) /* * NOTE: Two special error codes you should check for when calling @@ -454,6 +468,12 @@ enum binder_driver_return_protocol { * The the last transaction (either a bcTRANSACTION or * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters. */ + + BR_FROZEN_REPLY = _IO('r', 18), + /* + * The target of the last transaction (either a bcTRANSACTION or + * a bcATTEMPT_ACQUIRE) is frozen. No parameters. + */ }; enum binder_driver_command_protocol {