From 4c408c65cd3b837486d071f47675dab9e2d7acb5 Mon Sep 17 00:00:00 2001 From: Pengcheng Chen Date: Mon, 29 Apr 2019 16:51:19 +0800 Subject: [PATCH] osd: add osd sw_sync [1/1] PD#SWPL-9736 Problem: osd fence crash when play AIV H264 video Solution: add osd sw_sync Verify: Verified with raven,w400 Change-Id: I309af0e3718221e2309460a990ef0badb9e8bd39 Signed-off-by: Pengcheng Chen --- MAINTAINERS | 64 +++++++ drivers/amlogic/media/osd/Makefile | 2 +- drivers/amlogic/media/osd/osd_hw.c | 4 +- drivers/amlogic/media/osd/osd_sw_sync.c | 298 ++++++++++++++++++++++++++++++++ drivers/amlogic/media/osd/osd_sw_sync.h | 60 +++++++ drivers/dma-buf/sw_sync.c | 3 +- 6 files changed, 426 insertions(+), 5 deletions(-) create mode 100644 drivers/amlogic/media/osd/osd_sw_sync.c create mode 100644 drivers/amlogic/media/osd/osd_sw_sync.h diff --git a/MAINTAINERS b/MAINTAINERS index 7594ecb..156d98f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14971,3 +14971,67 @@ AMLOGIC GDC DRIVER M: Pengcheng Chen F: drivers/amlogic/media/gdc/app/gdc_wq.c F: drivers/amlogic/media/gdc/app/gdc_wq.h + +LAB126 PRIVACY +M: LAB126 +F: drivers/misc/amz_priv* + +LAB126 lifecycle and log +M: LAB126 +F: drivers/staging/amazon/* + +LAB126 tmp103 +M: LAB126 +F: drivers/hwmon/tmp103.c + +LAB126 RAVEN DTS +M: Yong Yu +F: arch/arm64/boot/dts/amlogic/raven.dts +F: arch/arm64/boot/dts/amlogic/raven_proto.dts +F: Documentation/devicetree/bindings/iio/light/tsl2540.txt + +LAB126 RAVEN DEFCONFIG +M: Yong Yu +F: arch/arm64/configs/raven_defconfig +F: arch/arm64/configs/raven_debug_defconfig + +LAB126 RAVEN THERMISTOR +M: Kevin Ow +F: Documentation/devicetree/bindings/thermal/ntc-bts-thermistor.txt +F: drivers/amlogic/iio/adc/saradc_ntc_bts.c +F: drivers/amlogic/iio/adc/Makefile +F: drivers/amlogic/iio/adc/Kconfig + +LAB126 RAVEN VIRTUAL THERMAL SENSOR +M: Kevin Ow +F: arch/arm64/boot/dts/amlogic/raven_thermal_zones.dtsi +F: Documentation/devicetree/bindings/thermal/virtual_sensor_thermal.txt +F: drivers/thermal/Kconfig +F: drivers/thermal/Makefile +F: drivers/thermal/trip_step_wise.c +F: drivers/thermal/virtual_sensor_thermal.c +F: include/linux/virtual_sensor_thermal.h + +LAB126 RAVEN WIFI_COOLING +M: Kevin Ow +F: Documentation/devicetree/bindings/thermal/wifi-temp-sensor.txt +F: drivers/thermal/wifi_cooling.c +F: drivers/amlogic/thermal/aml_thermal_cooling.c +F: drivers/amlogic/thermal/aml_thermal_hw.c +F: include/linux/amlogic/aml_thermal_cooling.h +F: include/linux/amlogic/aml_thermal_hw.h + +THIRD PARTY AUDIO CODEC TLV320DAC3203 +M: Xing Fang +F: sound/soc/codecs/tlv320dac3203.c +F: sound/soc/codecs/tlv320dac3203.h + +LAB126 PERFORMANCE BOOST DRIVER +M: Yong Yu +F: drivers/amlogic/cpufreq/cpufreq-boost.c +F: include/linux/cpufreq-boost.h + +ADD OSD SW_SYNC DRIVER +M: Pengcheng Chen +F: drivers/amlogic/media/osd/osd_sw_sync.c +F: drivers/amlogic/media/osd/osd_sw_sync.h diff --git a/drivers/amlogic/media/osd/Makefile b/drivers/amlogic/media/osd/Makefile index 2ead743..dbbef19 100644 --- a/drivers/amlogic/media/osd/Makefile +++ b/drivers/amlogic/media/osd/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_AMLOGIC_MEDIA_FB) += fb.o fb-objs = osd_hw.o osd_fb.o osd_debug.o osd_backup.o osd_logo.o osd_io.o fb-objs += osd_antiflicker.o osd_clone.o fb-objs += osd_drm.o -fb-objs += osd_rdma.o +fb-objs += osd_rdma.o osd_sw_sync.o obj-$(CONFIG_INSTABOOT) += osd_progressbar.o diff --git a/drivers/amlogic/media/osd/osd_hw.c b/drivers/amlogic/media/osd/osd_hw.c index 8c7b51d..f60a7d6 100644 --- a/drivers/amlogic/media/osd/osd_hw.c +++ b/drivers/amlogic/media/osd/osd_hw.c @@ -36,9 +36,6 @@ #include /* Android Headers */ -/* Amlogic sync headers */ -#include - /* Amlogic Headers */ #include #include @@ -74,6 +71,7 @@ #include "osd_hw.h" #include "osd_hw_def.h" #include "osd_fb.h" +#include "osd_sw_sync.h" #ifdef CONFIG_AMLOGIC_VSYNC_FIQ_ENABLE #define FIQ_VSYNC diff --git a/drivers/amlogic/media/osd/osd_sw_sync.c b/drivers/amlogic/media/osd/osd_sw_sync.c new file mode 100644 index 0000000..3e11669 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_sw_sync.c @@ -0,0 +1,298 @@ +/* + * drivers/amlogic/media/osd/osd_sw_sync.c + * + * Copyright (C) 2017 Amlogic, Inc. 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 as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include + +#include "osd_sw_sync.h" + +static const struct fence_ops timeline_fence_ops; +static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) +{ + if (fence->ops != &timeline_fence_ops) + return NULL; + return container_of(fence, struct sync_pt, base); +} + +/** + * sync_timeline_create() - creates a sync object + * @name: sync_timeline name + * + * Creates a new sync_timeline. Returns the sync_timeline object or NULL in + * case of error. + */ +static struct sync_timeline *sync_timeline_create(const char *name) +{ + struct sync_timeline *obj; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) + return NULL; + + kref_init(&obj->kref); + obj->context = fence_context_alloc(1); + strlcpy(obj->name, name, sizeof(obj->name)); + INIT_LIST_HEAD(&obj->active_list_head); + INIT_LIST_HEAD(&obj->pt_list); + spin_lock_init(&obj->lock); + + return obj; +} + +static void sync_timeline_free(struct kref *kref) +{ + struct sync_timeline *obj = + container_of(kref, struct sync_timeline, kref); + + kfree(obj); +} + +static void sync_timeline_get(struct sync_timeline *obj) +{ + kref_get(&obj->kref); +} + +static void sync_timeline_put(struct sync_timeline *obj) +{ + kref_put(&obj->kref, sync_timeline_free); +} + +static const char *timeline_fence_get_driver_name(struct fence *fence) +{ + return "sw_sync"; +} + +static const char *timeline_fence_get_timeline_name(struct fence *fence) +{ + struct sync_timeline *parent = fence_parent(fence); + + return parent->name; +} + +static void timeline_fence_release(struct fence *fence) +{ + struct sync_pt *pt = fence_to_sync_pt(fence); + struct sync_timeline *parent = fence_parent(fence); + unsigned long flags; + + spin_lock_irqsave(fence->lock, flags); + list_del(&pt->link); + if (!list_empty(&pt->active_list)) + list_del(&pt->active_list); + spin_unlock_irqrestore(fence->lock, flags); + sync_timeline_put(parent); + fence_free(fence); +} + +static bool timeline_fence_signaled(struct fence *fence) +{ + struct sync_timeline *parent = fence_parent(fence); + + return !__fence_is_later(fence->seqno, parent->value); +} + +static bool timeline_fence_enable_signaling(struct fence *fence) +{ + struct sync_pt *pt = container_of(fence, struct sync_pt, base); + struct sync_timeline *parent = fence_parent(fence); + + if (timeline_fence_signaled(fence)) + return false; + + list_add_tail(&pt->active_list, &parent->active_list_head); + return true; +} + +static void timeline_fence_disable_signaling(struct fence *fence) +{ + struct sync_pt *pt = container_of(fence, struct sync_pt, base); + + list_del_init(&pt->active_list); +} + +static void timeline_fence_value_str(struct fence *fence, + char *str, int size) +{ + snprintf(str, size, "%d", fence->seqno); +} + +static void timeline_fence_timeline_value_str(struct fence *fence, + char *str, int size) +{ + struct sync_timeline *parent = fence_parent(fence); + + snprintf(str, size, "%d", parent->value); +} + +static const struct fence_ops timeline_fence_ops = { + .get_driver_name = timeline_fence_get_driver_name, + .get_timeline_name = timeline_fence_get_timeline_name, + .enable_signaling = timeline_fence_enable_signaling, + .disable_signaling = timeline_fence_disable_signaling, + .signaled = timeline_fence_signaled, + .wait = fence_default_wait, + .release = timeline_fence_release, + .fence_value_str = timeline_fence_value_str, + .timeline_value_str = timeline_fence_timeline_value_str, +}; + +/** + * sync_timeline_signal() - signal a status change on a sync_timeline + * @obj: sync_timeline to signal + * @inc: num to increment on timeline->value + * + * A sync implementation should call this any time one of it's fences + * has signaled or has an error condition. + */ +static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) +{ + struct sync_pt *pt, *next; + unsigned long flags; + + spin_lock_irqsave(&obj->lock, flags); + obj->value += inc; + list_for_each_entry_safe(pt, next, &obj->active_list_head, + active_list) { + if (fence_is_signaled_locked(&pt->base)) + list_del_init(&pt->active_list); + } + spin_unlock_irqrestore(&obj->lock, flags); +} + +/** + * sync_pt_create() - creates a sync pt + * @parent: fence's parent sync_timeline + * @inc: value of the fence + * + * Creates a new sync_pt as a child of @parent. @size bytes will be + * allocated allowing for implementation specific data to be kept after + * the generic sync_timeline struct. Returns the sync_pt object or + * NULL in case of error. + */ +static struct sync_pt *sync_pt_create(struct sync_timeline *obj, + unsigned int value) +{ + struct sync_pt *pt; + unsigned long flags; + + pt = kzalloc(sizeof(*pt), GFP_KERNEL); + if (!pt) + return NULL; + spin_lock_irqsave(&obj->lock, flags); + sync_timeline_get(obj); + fence_init(&pt->base, &timeline_fence_ops, &obj->lock, + obj->context, value); + list_add_tail(&pt->link, &obj->pt_list); + INIT_LIST_HEAD(&pt->active_list); + spin_unlock_irqrestore(&obj->lock, flags); + + return pt; +} + +static void sync_pt_free(struct sync_timeline *obj, + struct sync_pt *pt) +{ + unsigned long flags; + + spin_lock_irqsave(&obj->lock, flags); + list_del(&pt->link); + sync_timeline_put(obj); + spin_unlock_irqrestore(&obj->lock, flags); + kfree(pt); + pt = NULL; +} + +void *aml_sync_create_timeline(const char *tname) +{ + struct sync_timeline *timeline; + + timeline = sync_timeline_create(tname); + return (void *)timeline; +} + +int aml_sync_create_fence(void *timeline, unsigned int value) +{ + struct sync_timeline *tl = (struct sync_timeline *)timeline; + int fd; + int err; + struct sync_pt *pt; + struct sync_file *sync_file; + + if (tl == NULL) + return -EPERM; + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) + return -EBADF; + + pt = sync_pt_create(tl, value); + if (!pt) { + err = -ENOMEM; + goto err; + } + + sync_file = sync_file_create(&pt->base); + fence_put(&pt->base); + if (!sync_file) { + err = -ENOMEM; + goto err; + } + + fd_install(fd, sync_file->file); + return fd; + +err: + put_unused_fd(fd); + if (pt) + sync_pt_free(tl, pt); + return err; +} + +void aml_sync_inc_timeline(void *timeline, unsigned int value) +{ + struct sync_timeline *tl = (struct sync_timeline *)timeline; + + if (tl == NULL) + return; + while (value > INT_MAX) { + sync_timeline_signal(tl, INT_MAX); + value -= INT_MAX; + } + + sync_timeline_signal(tl, value); +} + +struct fence *aml_sync_get_fence(int syncfile_fd) +{ + return sync_file_get_fence(syncfile_fd); +} + +int aml_sync_wait_fence(struct fence *fence, long timeout) +{ + long ret; + + ret = fence_wait_timeout(fence, false, timeout); + return ret; +} + +void aml_sync_put_fence(struct fence *fence) +{ + fence_put(fence); +} diff --git a/drivers/amlogic/media/osd/osd_sw_sync.h b/drivers/amlogic/media/osd/osd_sw_sync.h new file mode 100644 index 0000000..a9b958a --- /dev/null +++ b/drivers/amlogic/media/osd/osd_sw_sync.h @@ -0,0 +1,60 @@ +/* + * drivers/amlogic/media/osd/osd_sw_sync.h + * + * Copyright (C) 2017 Amlogic, Inc. 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 as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 _OSD_SW_SYNC_H +#define _OSD_SW_SYNC_H + +#include +#include +#include +#include + +#include +#include + + +struct sync_timeline { + struct kref kref; + char name[32]; + + /* protected by lock */ + u64 context; + int value; + + struct list_head active_list_head; + struct list_head pt_list; + spinlock_t lock; +}; + +static inline struct sync_timeline *fence_parent(struct fence *fence) +{ + return container_of(fence->lock, struct sync_timeline, lock); +} + +struct sync_pt { + struct fence base; + struct list_head link; + struct list_head active_list; +}; + +void *aml_sync_create_timeline(const char *tname); +int aml_sync_create_fence(void *timeline, unsigned int value); +void aml_sync_inc_timeline(void *timeline, unsigned int value); +struct fence *aml_sync_get_fence(int syncfile_fd); +int aml_sync_wait_fence(struct fence *fence, long timeout); +void aml_sync_put_fence(struct fence *fence); +#endif /* _OSD_SW_SYNC_H */ diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 862a37c..59f89f26 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -431,7 +431,7 @@ const struct file_operations sw_sync_debugfs_fops = { .compat_ioctl = sw_sync_ioctl, }; - +#if 0 /*api for amlogic use.*/ void *aml_sync_create_timeline(const char *tname) { @@ -509,3 +509,4 @@ void aml_sync_put_fence(struct fence *fence) fence_put(fence); } EXPORT_SYMBOL(aml_sync_put_fence); +#endif -- 2.7.4