mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
drm/rockchip: vop2: Report POST_BUF_EMPTY event to userspace
Report ROCKCHIP_DRM_ERROR_EVENT_POST_BUF_EMPTY to userspace if a POST_BUF_EMPTY storm lasts more than 1 minute. The userspace should try to avoid use VOP for ovelay and scale down after receive such event. Change-Id: Ibd5be1cdb5a64708616e46e1729a16130e6afaf9 Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/fixp-arith.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
@@ -840,6 +841,11 @@ struct vop2_resource {
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
struct vop2_err_event {
|
||||
u64 count;
|
||||
unsigned long begin;
|
||||
};
|
||||
|
||||
struct vop2 {
|
||||
u32 version;
|
||||
struct device *dev;
|
||||
@@ -887,6 +893,11 @@ struct vop2 {
|
||||
*/
|
||||
bool report_iommu_fault;
|
||||
|
||||
/*
|
||||
* report post buf empty error event to userspace
|
||||
*/
|
||||
bool report_post_buf_empty;
|
||||
|
||||
bool loader_protect;
|
||||
|
||||
bool aclk_rate_reset;
|
||||
@@ -969,6 +980,8 @@ struct vop2 {
|
||||
#endif
|
||||
bool iommu_fault_in_progress;
|
||||
|
||||
struct vop2_err_event post_buf_empty;
|
||||
|
||||
/* aclk auto cs div */
|
||||
u32 csu_div;
|
||||
/* must put at the end of the struct */
|
||||
@@ -4273,6 +4286,62 @@ static int vop3_get_esmart_lb_mode(struct vop2 *vop2)
|
||||
return vop2->data->esmart_lb_mode_map[0].lb_map_value;
|
||||
}
|
||||
|
||||
/*
|
||||
* POST_BUF_EMPTY will cause hundreds thousands of interrupts strom per
|
||||
* second.
|
||||
*/
|
||||
|
||||
#define POST_BUF_EMPTY_COUNT_PER_MINUTE 100
|
||||
static DEFINE_RATELIMIT_STATE(post_buf_empty_handler_rate, 5 * HZ, 10);
|
||||
|
||||
static int vop2_post_buf_empty_handler_rate_limit(void)
|
||||
{
|
||||
return __ratelimit(&post_buf_empty_handler_rate);
|
||||
}
|
||||
|
||||
static void vop2_reset_post_buf_empty_handler_rate_limit(struct vop2 *vop2)
|
||||
{
|
||||
vop2->post_buf_empty.begin = 0;
|
||||
vop2->post_buf_empty.count = 0;
|
||||
}
|
||||
|
||||
static void vop2_handle_post_buf_empty(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
struct rockchip_drm_private *private = vop2->drm_dev->dev_private;
|
||||
struct vop2_err_event *event = &vop2->post_buf_empty;
|
||||
enum rockchip_drm_error_event_type type;
|
||||
|
||||
if (!vop2->report_post_buf_empty)
|
||||
return;
|
||||
|
||||
type = ROCKCHIP_DRM_ERROR_EVENT_POST_BUF_EMPTY;
|
||||
|
||||
/*
|
||||
* No need to handle POST_BUF_EMPTY if we are in iommu fault,
|
||||
* because we will try to recovery from the iommu fault handle
|
||||
*/
|
||||
if (vop2->iommu_fault_in_progress)
|
||||
return;
|
||||
|
||||
if (!event->begin)
|
||||
event->begin = jiffies;
|
||||
|
||||
if (vop2_post_buf_empty_handler_rate_limit())
|
||||
event->count++;
|
||||
|
||||
if (time_is_before_jiffies(event->begin + 60 * HZ)) {
|
||||
if (event->count >= POST_BUF_EMPTY_COUNT_PER_MINUTE)
|
||||
rockchip_drm_send_error_event(private, type);
|
||||
|
||||
DRM_DEV_ERROR(vop2->dev, "post_buf_err event count: %lld\n", event->count);
|
||||
|
||||
event->begin = 0;
|
||||
event->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void vop2_initial(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
@@ -4618,6 +4687,7 @@ static void vop2_disable(struct drm_crtc *crtc)
|
||||
* shortly after the recovery(Disable then enable) process done.
|
||||
*/
|
||||
rockchip_drm_reset_iommu_fault_handler_rate_limit();
|
||||
vop2_reset_post_buf_empty_handler_rate_limit(vop2);
|
||||
}
|
||||
if (vop2->version == VOP_VERSION_RK3588 || vop2->version == VOP_VERSION_RK3576)
|
||||
vop2_power_off_all_pd(vop2);
|
||||
@@ -12594,10 +12664,7 @@ static irqreturn_t vop2_isr(int irq, void *data)
|
||||
#define ERROR_HANDLER(x) \
|
||||
do { \
|
||||
if (active_irqs & x##_INTR) {\
|
||||
if (x##_INTR == POST_BUF_EMPTY_INTR) \
|
||||
DRM_DEV_ERROR_RATELIMITED(vop2->dev, #x " irq err at vp%d\n", vp->id); \
|
||||
else \
|
||||
DRM_DEV_ERROR_RATELIMITED(vop2->dev, #x " irq err\n"); \
|
||||
DRM_DEV_ERROR_RATELIMITED(vop2->dev, #x " irq err\n"); \
|
||||
active_irqs &= ~x##_INTR; \
|
||||
ret = IRQ_HANDLED; \
|
||||
} \
|
||||
@@ -12670,7 +12737,12 @@ static irqreturn_t vop2_isr(int irq, void *data)
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
ERROR_HANDLER(POST_BUF_EMPTY);
|
||||
if (active_irqs & POST_BUF_EMPTY_INTR) {
|
||||
vop2_handle_post_buf_empty(crtc);
|
||||
DRM_DEV_ERROR_RATELIMITED(vop2->dev, "POST_BUF_EMPTY irq err at vp%d\n", vp->id);
|
||||
active_irqs &= ~POST_BUF_EMPTY_INTR;
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Unhandled irqs are spurious. */
|
||||
if (active_irqs)
|
||||
@@ -14374,6 +14446,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
|
||||
vop2->disable_win_move = of_property_read_bool(dev->of_node, "disable-win-move");
|
||||
vop2->skip_ref_fb = of_property_read_bool(dev->of_node, "skip-ref-fb");
|
||||
vop2->report_iommu_fault = of_property_read_bool(dev->of_node, "rockchip,report-iommu-fault");
|
||||
vop2->report_post_buf_empty = of_property_read_bool(dev->of_node, "rockchip,report-post-buf-empty");
|
||||
if (!is_vop3(vop2) ||
|
||||
vop2->version == VOP_VERSION_RK3528 || vop2->version == VOP_VERSION_RK3562)
|
||||
vop2->merge_irq = true;
|
||||
|
||||
Reference in New Issue
Block a user