From 1ffc8ba3f701d72eecfb0044eaa3cd35ec538e99 Mon Sep 17 00:00:00 2001 From: Antti Koskipaa Date: Wed, 28 Mar 2012 14:25:53 +0300 Subject: [PATCH] gfx: drv: DPST 3.0 kernel side support This patch removes the dead UMG workqueue implementation and adds support for sending signals to userspace on DPST interrupts. The DRM fasync infrastructure is used for this. SIGIO/POLL_IN is sent on histogram interrupts and SIGIO/POLL_OUT on phase-in interrupts. Issue: ANDROID-2333 Signed-off-by: Antti Koskipaa Signed-off-by: Yong-Joon.Park Reviewed-by: Jani Nikula (with a claim he does not know DPST) Signed-off-by: Artem Bityutskiy --- drivers/staging/mrst/Makefile | 1 - drivers/staging/mrst/drv/psb_dpst.c | 253 ------------------------------- drivers/staging/mrst/drv/psb_dpst.h | 98 ------------ drivers/staging/mrst/drv/psb_drv.c | 32 +--- drivers/staging/mrst/drv/psb_drv.h | 2 - drivers/staging/mrst/drv/psb_irq.c | 35 ++--- drivers/staging/mrst/imgv/psb_ttm_glue.c | 3 + 7 files changed, 14 insertions(+), 410 deletions(-) delete mode 100644 drivers/staging/mrst/drv/psb_dpst.c delete mode 100644 drivers/staging/mrst/drv/psb_dpst.h diff --git a/drivers/staging/mrst/Makefile b/drivers/staging/mrst/Makefile index 66c76f2..530a340 100644 --- a/drivers/staging/mrst/Makefile +++ b/drivers/staging/mrst/Makefile @@ -171,7 +171,6 @@ medfield_gfx-y += \ $(DRMDRVDIR)/mdfld_output.o \ $(DRMDRVDIR)/mdfld_overlay.o \ $(DRMDRVDIR)/psb_bl.o \ - $(DRMDRVDIR)/psb_dpst.o \ $(DRMDRVDIR)/psb_drv.o \ $(DRMDRVDIR)/psb_fb.o \ $(DRMDRVDIR)/psb_gtt.o \ diff --git a/drivers/staging/mrst/drv/psb_dpst.c b/drivers/staging/mrst/drv/psb_dpst.c deleted file mode 100644 index 7499b39..0000000 --- a/drivers/staging/mrst/drv/psb_dpst.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright © 2009 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Authors: - * James C. Gualario - * - */ - -#include "psb_umevents.h" -#include "psb_dpst.h" -/** - * inform the kernel of the work to be performed and related function. - * - */ -static DECLARE_WORK(dpst_dev_change_work, &psb_dpst_dev_change_wq); -/** - * psb_dpst_notify_change_um - notify user mode of hotplug changes - * - * @name: name of event to notify user mode of change to - * @state: dpst state struct to get workqueue from - * - */ -int psb_dpst_notify_change_um(enum dpst_event_enum event, - struct dpst_state *state) -{ - if (state == NULL) - return IRQ_HANDLED; - - state->dpst_change_wq_data.dev_name_arry_rw_status - [state->dpst_change_wq_data.dev_name_write] = - DRM_DPST_READY_TO_READ; - state->dpst_change_wq_data.dpst_events - [state->dpst_change_wq_data.dev_name_write] = - event; - if (state->dpst_change_wq_data.dev_name_read_write_wrap_ack == 1) - state->dpst_change_wq_data.dev_name_read_write_wrap_ack = 0; - state->dpst_change_wq_data.dev_name_write++; - if (state->dpst_change_wq_data.dev_name_write == - state->dpst_change_wq_data.dev_name_read) { - state->dpst_change_wq_data.dev_name_write--; - return IRQ_NONE; - } - if (state->dpst_change_wq_data.dev_name_write > - DRM_DPST_RING_DEPTH_MAX) { - state->dpst_change_wq_data.dev_name_write = 0; - state->dpst_change_wq_data.dev_name_write_wrap = 1; - } - state->dpst_change_wq_data.hotplug_dev_list = state->list; - queue_work(state->dpst_wq, &(state->dpst_change_wq_data.work)); - return IRQ_HANDLED; -} -/*EXPORT_SYMBOL(psb_dpst_notify_change_um); */ -/** - * - * psb_dpst_create_and_notify_um - create and notify user mode of new dev - * - * @name: name to give for new event / device - * @state: dpst state instaces to associate event with - * - */ -struct umevent_obj *psb_dpst_create_and_notify_um(const char *name, - struct dpst_state *state) -{ - return psb_create_umevent_obj(name, state->list); - -} -/*EXPORT_SYMBOL(psb_dpst_create_and_notify_um); */ -/** - * psb_dpst_device_pool_create_and_init - make new hotplug device pool - * - * @parent_kobj - parent kobject to associate dpst kset with - * @state - dpst state instance to associate list with - * - */ -struct umevent_list *psb_dpst_device_pool_create_and_init( - struct kobject *parent_kobj, - struct dpst_state *state) -{ - struct umevent_list *new_hotplug_dev_list = NULL; - new_hotplug_dev_list = psb_umevent_create_list(); - if (new_hotplug_dev_list) - psb_umevent_init(parent_kobj, new_hotplug_dev_list, - "psb_dpst"); - - state->dpst_wq = create_singlethread_workqueue("dpst-wq"); - - if (!state->dpst_wq) - return NULL; - - INIT_WORK(&state->dpst_change_wq_data.work, psb_dpst_dev_change_wq); - - state->dpst_change_wq_data.dev_name_read = 0; - state->dpst_change_wq_data.dev_name_write = 0; - state->dpst_change_wq_data.dev_name_write_wrap = 0; - state->dpst_change_wq_data.dev_name_read_write_wrap_ack = 0; - - memset(&(state->dpst_change_wq_data.dev_name_arry_rw_status[0]), - 0, sizeof(int)*DRM_DPST_RING_DEPTH); - - return new_hotplug_dev_list; -} -/*EXPORT_SYMBOL(psb_dpst_device_pool_create_and_init); */ -/** - * psb_dpst_init - init dpst subsystem - * @parent_kobj - parent kobject to associate dpst state with - * - */ -struct dpst_state *psb_dpst_init(struct kobject *parent_kobj) -{ - struct dpst_state *state; - struct umevent_obj *working_umevent; - - state = kzalloc(sizeof(struct dpst_state), GFP_KERNEL); - state->list = NULL; - state->list = psb_dpst_device_pool_create_and_init( - parent_kobj, - state); - working_umevent = - psb_dpst_create_and_notify_um("init", - state); - state->dpst_change_wq_data.dev_umevent_arry - [DPST_EVENT_INIT_COMPLETE] = &(working_umevent->head); - working_umevent = - psb_dpst_create_and_notify_um("hist_int", - state); - state->dpst_change_wq_data.dev_umevent_arry - [DPST_EVENT_HIST_INTERRUPT] = &(working_umevent->head); - working_umevent = - psb_dpst_create_and_notify_um("term", - state); - state->dpst_change_wq_data.dev_umevent_arry - [DPST_EVENT_TERMINATE] = &(working_umevent->head); - working_umevent = - psb_dpst_create_and_notify_um("phase_done", - state); - state->dpst_change_wq_data.dev_umevent_arry - [DPST_EVENT_PHASE_COMPLETE] = &(working_umevent->head); - - return state; -} -/*EXPORT_SYMBOL(psb_dpst_init); */ -/** - * psb_dpst_device_pool_destroy - destroy all dpst related resources - * - * @state: dpst state instance to destroy - * - */ -void psb_dpst_device_pool_destroy(struct dpst_state *state) -{ - int i; - struct umevent_list *list; - struct umevent_obj *umevent_test; - list = state->list; - flush_workqueue(state->dpst_wq); - destroy_workqueue(state->dpst_wq); - for (i = 0; i < DRM_DPST_MAX_NUM_EVENTS; i++) { - umevent_test = list_entry( - (state->dpst_change_wq_data.dev_umevent_arry[i]), - struct umevent_obj, head); - state->dpst_change_wq_data.dev_umevent_arry[i] = NULL; - } - psb_umevent_cleanup(list); - kfree(state); -} -/*EXPORT_SYMBOL(psb_dpst_device_pool_destroy); */ -/** - * psb_dpst_dev_change_wq - change workqueue implementation - * - * @work: work struct to use for kernel scheduling - * - */ -void psb_dpst_dev_change_wq(struct work_struct *work) -{ - struct dpst_disp_workqueue_data *wq_data; - int curr_event_index; - wq_data = to_dpst_disp_workqueue_data(work); - if (wq_data->dev_name_write_wrap == 1) { - wq_data->dev_name_read_write_wrap_ack = 1; - wq_data->dev_name_write_wrap = 0; - while (wq_data->dev_name_read != DRM_DPST_RING_DEPTH_MAX) { - if (wq_data->dev_name_arry_rw_status - [wq_data->dev_name_read] == - DRM_DPST_READY_TO_READ) { - wq_data->dev_name_arry_rw_status - [wq_data->dev_name_read] = - DRM_DPST_READ_COMPLETE; - curr_event_index = wq_data->dpst_events - [wq_data->dev_name_read]; - psb_umevent_notify_change_gfxsock - (list_entry( - (wq_data->dev_umevent_arry - [curr_event_index]), - struct umevent_obj, head), - DRM_DPST_SOCKET_GROUP_ID); - } - wq_data->dev_name_read++; - } - wq_data->dev_name_read = 0; - while (wq_data->dev_name_read < wq_data->dev_name_write-1) { - if (wq_data->dev_name_arry_rw_status - [wq_data->dev_name_read] == - DRM_DPST_READY_TO_READ) { - wq_data->dev_name_arry_rw_status - [wq_data->dev_name_read] = - DRM_DPST_READ_COMPLETE; - curr_event_index = wq_data->dpst_events - [wq_data->dev_name_read]; - psb_umevent_notify_change_gfxsock - (list_entry( - (wq_data->dev_umevent_arry - [curr_event_index]), - struct umevent_obj, head), - DRM_DPST_SOCKET_GROUP_ID); - } - wq_data->dev_name_read++; - } - } else { - while (wq_data->dev_name_read < wq_data->dev_name_write) { - if (wq_data->dev_name_arry_rw_status - [wq_data->dev_name_read] == - DRM_DPST_READY_TO_READ) { - wq_data->dev_name_arry_rw_status - [wq_data->dev_name_read] = - DRM_DPST_READ_COMPLETE; - curr_event_index = wq_data->dpst_events - [wq_data->dev_name_read]; - psb_umevent_notify_change_gfxsock - (list_entry( - (wq_data->dev_umevent_arry - [curr_event_index]), - struct umevent_obj, head), - DRM_DPST_SOCKET_GROUP_ID); - } - wq_data->dev_name_read++; - } - } - if (wq_data->dev_name_read > DRM_DPST_RING_DEPTH_MAX) - wq_data->dev_name_read = 0; -} -/*EXPORT_SYMBOL(psb_dpst_dev_change_wq); */ diff --git a/drivers/staging/mrst/drv/psb_dpst.h b/drivers/staging/mrst/drv/psb_dpst.h deleted file mode 100644 index 6f24a05..0000000 --- a/drivers/staging/mrst/drv/psb_dpst.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright © 2009 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Authors: - * James C. Gualario - * - */ - -#ifndef _PSB_DPST_H_ -#define _PSB_DPST_H_ -/** - * required includes - * - */ -#include "psb_umevents.h" -/** - * dpst event enumeration - * - */ -enum dpst_event_enum { - DPST_EVENT_INIT_COMPLETE, - DPST_EVENT_HIST_INTERRUPT, - DPST_EVENT_TERMINATE, - DPST_EVENT_PHASE_COMPLETE, - DPST_MAX_EVENT -}; -/** - * dpst specific defines - * - */ -#define DRM_DPST_RING_DEPTH 256 -#define DRM_DPST_RING_DEPTH_MAX (DRM_DPST_RING_DEPTH-1) -#define DRM_DPST_READY_TO_READ 1 -#define DRM_DPST_READ_COMPLETE 2 -#define DRM_DPST_MAX_NUM_EVENTS (DPST_MAX_EVENT) -/** - * dpst workqueue data struct. - */ -struct dpst_disp_workqueue_data { - struct work_struct work; - const char *dev_name; - int dev_name_write; - int dev_name_read; - int dev_name_write_wrap; - int dev_name_read_write_wrap_ack; - enum dpst_event_enum dpst_events[DRM_DPST_RING_DEPTH]; - int dev_name_arry_rw_status[DRM_DPST_RING_DEPTH]; - struct umevent_list *hotplug_dev_list; - struct list_head *dev_umevent_arry[DRM_DPST_MAX_NUM_EVENTS]; -}; -/** - * dpst state structure - * - */ -struct dpst_state { - struct workqueue_struct *dpst_wq; - struct dpst_disp_workqueue_data dpst_change_wq_data; - struct umevent_list *list; -}; -/** - * main interface function prototytpes for dpst support. - * - */ -extern struct dpst_state *psb_dpst_init(struct kobject *parent_kobj); -extern int psb_dpst_notify_change_um(enum dpst_event_enum event, - struct dpst_state *state); -extern struct umevent_obj *psb_dpst_create_and_notify_um(const char *name, - struct dpst_state *state); -extern struct umevent_list *psb_dpst_device_pool_create_and_init( - struct kobject *parent_kobj, - struct dpst_state *state); -extern void psb_dpst_device_pool_destroy(struct dpst_state *state); -/** - * to go back and forth between work struct and workqueue data - * - */ -#define to_dpst_disp_workqueue_data(x) \ - container_of(x, struct dpst_disp_workqueue_data, work) - -/** - * function prototypes for workqueue implementation - * - */ -extern void psb_dpst_dev_change_wq(struct work_struct *work); -#endif diff --git a/drivers/staging/mrst/drv/psb_drv.c b/drivers/staging/mrst/drv/psb_drv.c index e349b11..a65ff77 100644 --- a/drivers/staging/mrst/drv/psb_drv.c +++ b/drivers/staging/mrst/drv/psb_drv.c @@ -1063,8 +1063,6 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->num_pipe = 3; - /*init DPST umcomm to NULL*/ - dev_priv->psb_dpst_state = NULL; dev_priv->psb_hotplug_state = NULL; dev_priv->hdmi_done_reading_edid = false; dev_priv->xserver_start = false; @@ -1600,36 +1598,10 @@ static int psb_hist_status_ioctl(struct drm_device *dev, void *data, static int psb_init_comm_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_psb_private *dev_priv = psb_priv(dev); - struct pci_dev *pdev = NULL; - struct device *ddev = NULL; - struct kobject *kobj = NULL; - uint32_t *arg = data; - - if (*arg == 1) { - /*find handle to drm kboject*/ - pdev = dev->pdev; - ddev = &pdev->dev; - kobj = &ddev->kobj; - - if (dev_priv->psb_dpst_state == NULL) { - /*init dpst kmum comms*/ - dev_priv->psb_dpst_state = psb_dpst_init(kobj); - } else { - printk(KERN_ALERT "DPST already initialized\n"); - } - + if (*(int *)data == 1) psb_irq_enable_dpst(dev); - psb_dpst_notify_change_um(DPST_EVENT_INIT_COMPLETE, - dev_priv->psb_dpst_state); - } else { - /*hotplug and dpst destroy examples*/ + else psb_irq_disable_dpst(dev); - psb_dpst_notify_change_um(DPST_EVENT_TERMINATE, - dev_priv->psb_dpst_state); - psb_dpst_device_pool_destroy(dev_priv->psb_dpst_state); - dev_priv->psb_dpst_state = NULL; - } return 0; } diff --git a/drivers/staging/mrst/drv/psb_drv.h b/drivers/staging/mrst/drv/psb_drv.h index 8c9259b..328f8bf 100644 --- a/drivers/staging/mrst/drv/psb_drv.h +++ b/drivers/staging/mrst/drv/psb_drv.h @@ -30,7 +30,6 @@ #include "psb_schedule.h" #include "psb_intel_drv.h" #include "psb_hotplug.h" -#include "psb_dpst.h" #include "psb_gtt.h" #include "psb_powermgmt.h" #include "ttm/ttm_object.h" @@ -898,7 +897,6 @@ struct drm_psb_private { * DPST and Hotplug state */ - struct dpst_state *psb_dpst_state; struct hotplug_state *psb_hotplug_state; pfn_vsync_handler psb_vsync_handler; diff --git a/drivers/staging/mrst/drv/psb_irq.c b/drivers/staging/mrst/drv/psb_irq.c index 284f6f1..ee21cc2 100644 --- a/drivers/staging/mrst/drv/psb_irq.c +++ b/drivers/staging/mrst/drv/psb_irq.c @@ -265,6 +265,7 @@ static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) (struct drm_psb_private *) dev->dev_private; uint32_t pipe_stat_val = 0; + uint32_t pipe_stat_val_b = 0; uint32_t pipe_stat_reg = psb_pipestat(pipe); uint32_t pipe_enable = dev_priv->pipestat[pipe]; uint32_t pipe_status = dev_priv->pipestat[pipe] >> 16; @@ -277,6 +278,8 @@ static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) pipe_stat_val &= pipe_enable | pipe_status; pipe_stat_val &= pipe_stat_val >> 16; + pipe_stat_val_b = PSB_RVDC32(PSB_PIPESTAT(PSB_PIPE_B)); + spin_unlock_irqrestore(&dev_priv->irqmask_lock, irq_flags); /* clear the 2nd level interrupt status bits */ @@ -297,48 +300,28 @@ static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) DRM_ERROR("%s, can't clear the status bits in pipe_stat_reg, its value = 0x%x. \n", __FUNCTION__, PSB_RVDC32(pipe_stat_reg)); - if ((pipe_stat_val & PIPE_DPST_EVENT_STATUS) && - (dev_priv->psb_dpst_state != NULL)) { + if (pipe_stat_val_b & PIPE_DPST_EVENT_STATUS) { uint32_t pwm_reg = 0; uint32_t hist_reg = 0; - u32 irqCtrl = 0; struct dpst_guardband guardband_reg; - struct dpst_ie_histogram_control ie_hist_cont_reg; - hist_reg = PSB_RVDC32(HISTOGRAM_INT_CONTROL); /* Determine if this is histogram or pwm interrupt */ if (hist_reg & HISTOGRAM_INT_CTRL_CLEAR) { - /* Notify UM of histogram interrupt */ - psb_dpst_notify_change_um(DPST_EVENT_HIST_INTERRUPT, - dev_priv->psb_dpst_state); + /* Send a SIGIO with a band of POLL_IN on hist irq */ + kill_fasync(&dev->buf_async, SIGIO, POLL_IN); /* disable dpst interrupts */ guardband_reg.data = PSB_RVDC32(HISTOGRAM_INT_CONTROL); guardband_reg.interrupt_enable = 0; guardband_reg.interrupt_status = 1; PSB_WVDC32(guardband_reg.data, HISTOGRAM_INT_CONTROL); - - ie_hist_cont_reg.data = PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL); - ie_hist_cont_reg.ie_histogram_enable = 0; - PSB_WVDC32(ie_hist_cont_reg.data, HISTOGRAM_LOGIC_CONTROL); - - irqCtrl = PSB_RVDC32(PSB_PIPESTAT(PSB_PIPE_A)); - irqCtrl &= ~PIPE_DPST_EVENT_ENABLE; - PSB_WVDC32(irqCtrl, PSB_PIPESTAT(PSB_PIPE_A)); } + /* Send a SIGIO with a band of POLL_OUT on phase irq */ pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC); if ((pwm_reg & PWM_PHASEIN_INT_ENABLE) && !(pwm_reg & PWM_PHASEIN_ENABLE)) { - /* Notify UM of the phase complete */ - psb_dpst_notify_change_um(DPST_EVENT_PHASE_COMPLETE, - dev_priv->psb_dpst_state); - - /* Temporarily get phase mngr ready to generate - * another interrupt until this can be moved to - * user mode */ - /* PSB_WVDC32(pwm_reg | 0x80010100 | PWM_PHASEIN_ENABLE, - PWM_CONTROL_LOGIC); */ + kill_fasync(&dev->buf_async, SIGIO, POLL_OUT); } } @@ -681,7 +664,7 @@ void psb_irq_turn_on_dpst(struct drm_device *dev) u32 hist_reg; u32 pwm_reg; - if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, false)) { + if (ospm_power_using_hw_begin_atomic(OSPM_DISPLAY_ISLAND)) { PSB_WVDC32(BIT(31), HISTOGRAM_LOGIC_CONTROL); hist_reg = PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL); PSB_WVDC32(BIT(31), HISTOGRAM_INT_CONTROL); diff --git a/drivers/staging/mrst/imgv/psb_ttm_glue.c b/drivers/staging/mrst/imgv/psb_ttm_glue.c index e598b21..bc9c6f2 100644 --- a/drivers/staging/mrst/imgv/psb_ttm_glue.c +++ b/drivers/staging/mrst/imgv/psb_ttm_glue.c @@ -107,6 +107,9 @@ int psb_release(struct inode *inode, struct file *filp) psb_cleanup_pending_events(dev, psb_fp); + /* Disable asynchronous notifications for the DRM file descriptor. */ + drm_fasync(-1, filp, 0); + /*cleanup for msvdx*/ if (msvdx_priv->tfile == psb_fpriv(file_priv)->tfile) { msvdx_priv->fw_status = 0; -- 2.7.4