drm/msm/dpu: use kthread_destroy_worker to release msm workers
PATCH v4 1/5 drm/msm/dpu: use kthread_destroy_worker to release msm workers
use kthread_destroy_worker to destroy workers and
release their associated kthreads.
changes in v3:
- introduced in the series
changes in v4:
- none
--- drivers/gpu/drm/msm/msm_drv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/gpu/drm/msm/msm_drv.c +2 -4
@@ -290,14 +290,12 @@ static int msm_drm_uninit(struct device *dev)/* clean up display commit/event worker threads */ for (i =0 ; i < priv->num_crtcs; i++) {if (priv->disp_thread[i].thread) { -kthread_flush_worker (&priv->disp_thread[i].worker); -kthread_stop (priv->disp_thread[i].thread); +kthread_destroy_worker (&priv->disp_thread[i].worker); priv->disp_thread[i].thread =NULL ; }if (priv->event_thread[i].thread) { -kthread_flush_worker (&priv->event_thread[i].worker); -kthread_stop (priv->event_thread[i].thread); +kthread_destroy_worker (&priv->event_thread[i].worker); priv->event_thread[i].thread =NULL ; } }
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project _______________________________________________ Freedreno mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/freedreno
PATCH v4 2/5 drm/msm/dpu: use msm wq for vblank events
DPU was using one thread per display to dispatch async commits and vblank requests. Since clean up already happened in msm to use the common thread for all the display commits, display threads are only used to cater vblank requests. Since a single thread is sufficient to do the job without any performance hits, use msm workqueue to queue requests. A separate patch is submitted later in this series to remove the display threads altogether.
changes in v2:
- switch to system wq before removing disp threads (Sean Paul)
changes in v3:
- none
changes in v4:
- use msm wq for vblank events
--- drivers/gpu/drm/msm/msm_drv.c | 9 ++++----- drivers/gpu/drm/msm/msm_drv.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-)
drivers/gpu/drm/msm/msm_drv.c +4 -5
@@ -212,7 +212,7 @@ struct vblank_event {bool enable; }; -static void vblank_ctrl_worker (struct kthread_work *work) +static void vblank_ctrl_worker (struct work_struct *work) {struct msm_vblank_ctrl *vbl_ctrl =container_of (work, struct msm_vblank_ctrl, work);
@@ -260,8 +260,7 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv,list_add_tail (&vbl_ev->node, &vbl_ctrl->event_list);spin_unlock_irqrestore (&vbl_ctrl->lock, flags); -kthread_queue_work (&priv->disp_thread[crtc_id].worker, - &vbl_ctrl->work); +queue_work (priv->wq, &vbl_ctrl->work);return 0 ; }
@@ -281,7 +280,7 @@ static int msm_drm_uninit(struct device *dev)* work before drm_irq_uninstall() to avoid work re-enabling an * irq after uninstall has disabled it. */ -kthread_flush_work (&vbl_ctrl->work); +flush_work (&vbl_ctrl->work);list_for_each_entry_safe (vbl_ev, tmp, &vbl_ctrl->event_list, node) {list_del (&vbl_ev->node);kfree (vbl_ev);
@@ -479,7 +478,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)INIT_LIST_HEAD (&priv->inactive_list);INIT_LIST_HEAD (&priv->vblank_ctrl.event_list); -kthread_init_work (&priv->vblank_ctrl.work, vblank_ctrl_worker); +INIT_WORK (&priv->vblank_ctrl.work, vblank_ctrl_worker);spin_lock_init (&priv->vblank_ctrl.lock);drm_mode_config_init (ddev);
drivers/gpu/drm/msm/msm_drv.h +1 -1
@@ -78,7 +78,7 @@ enum msm_mdp_plane_property { };struct msm_vblank_ctrl { -struct kthread_work work; +struct work_struct work;struct list_head event_list;spinlock_t lock; };
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
A message that is not in the archive (sent off-list or not yet received): 1544150504-19630-1-git-send-email-jsanka-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
PATCH v4 3/5 drm/msm/dpu: use msm wq for idle power collapse
msm is using msm wq for dispatching commit and vblank events. Switch idle power collapse feature also to use msm wq to handle delayed work handlers so that msm can get rid of redundant display threads.
changes in v2:
- patch introduced in v2
changes in v3:
- none
changes in v4:
- use msm wq for delayed works
--- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-)
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +7 -18
@@ -205,7 +205,7 @@ struct dpu_encoder_virt {bool idle_pc_supported;struct mutex rc_lock;enum dpu_enc_rc_states rc_state; -struct kthread_delayed_work delayed_off_work; +struct delayed_work delayed_off_work;struct kthread_work vsync_event_work;struct msm_display_topology topology;bool mode_set_complete;
@@ -742,7 +742,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, {struct dpu_encoder_virt *dpu_enc;struct msm_drm_private *priv; -struct msm_drm_thread *disp_thread;bool is_vid_mode = false; if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private ||
@@ -755,12 +754,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, is_vid_mode = dpu_enc->disp_info.capabilities &MSM_DISPLAY_CAP_VID_MODE ; -if (drm_enc->crtc->index >=ARRAY_SIZE (priv->disp_thread)) { -DPU_ERROR ("invalid crtc index\n" ); -return -EINVAL ; - } - disp_thread = &priv->disp_thread[drm_enc->crtc->index]; -/* * when idle_pc is not supported, process only KICKOFF, STOP and MODESET * events and return early for other events (ie wb display).
@@ -777,8 +770,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,switch (sw_event) {case DPU_ENC_RC_EVENT_KICKOFF :/* cancel delayed off work, if any */ -if (kthread_cancel_delayed_work_sync ( - &dpu_enc->delayed_off_work)) +if (cancel_delayed_work_sync (&dpu_enc->delayed_off_work))DPU_DEBUG_ENC (dpu_enc,"sw_event:%d, work cancelled\n" , sw_event);
@@ -837,10 +829,8 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,return 0 ; } -kthread_queue_delayed_work ( - &disp_thread->worker, - &dpu_enc->delayed_off_work, -msecs_to_jiffies (dpu_enc->idle_timeout)); +queue_delayed_work (priv->wq, &dpu_enc->delayed_off_work, +msecs_to_jiffies (dpu_enc->idle_timeout)); trace_dpu_enc_rc(DRMID(drm_enc), sw_event, dpu_enc->idle_pc_supported, dpu_enc->rc_state,
@@ -849,8 +839,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,case DPU_ENC_RC_EVENT_PRE_STOP :/* cancel delayed off work, if any */ -if (kthread_cancel_delayed_work_sync ( - &dpu_enc->delayed_off_work)) +if (cancel_delayed_work_sync (&dpu_enc->delayed_off_work))DPU_DEBUG_ENC (dpu_enc,"sw_event:%d, work cancelled\n" , sw_event);
@@ -1368,7 +1357,7 @@ static void dpu_encoder_frame_done_callback( } } -static void dpu_encoder_off_work (struct kthread_work *work) +static void dpu_encoder_off_work (struct work_struct *work) {struct dpu_encoder_virt *dpu_enc =container_of (work, struct dpu_encoder_virt, delayed_off_work.work);
@@ -2193,7 +2182,7 @@ int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc,mutex_init (&dpu_enc->rc_lock); -kthread_init_delayed_work (&dpu_enc->delayed_off_work, +INIT_DELAYED_WORK (&dpu_enc->delayed_off_work, dpu_encoder_off_work); dpu_enc->idle_timeout =IDLE_TIMEOUT ;
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project _______________________________________________ Freedreno mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/freedreno
PATCH v4 4/5 drm/msm: clean up display thread
In reply to a message not in the archiveSince there are no clients using these threads,
cleaning it up.
changes in v2:
- switch all the dependent clients to use system wq before removing the disp_threads (Sean Paul)
changes in v3:
- none
changes in v4:
- none
--- drivers/gpu/drm/msm/msm_drv.c | 35 +---------------------------------- drivers/gpu/drm/msm/msm_drv.h | 1 - 2 files changed, 1 insertion(+), 35 deletions(-)
drivers/gpu/drm/msm/msm_drv.c +1 -34
@@ -286,13 +286,8 @@ static int msm_drm_uninit(struct device *dev)kfree (vbl_ev); } -/* clean up display commit/event worker threads */ +/* clean up event worker threads */ for (i =0 ; i < priv->num_crtcs; i++) { -if (priv->disp_thread[i].thread) { -kthread_destroy_worker (&priv->disp_thread[i].worker); - priv->disp_thread[i].thread =NULL ; - } -if (priv->event_thread[i].thread) {kthread_destroy_worker (&priv->event_thread[i].worker); priv->event_thread[i].thread =NULL ;
@@ -545,27 +540,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)*/ param.sched_priority =16 ;for (i =0 ; i < priv->num_crtcs; i++) { - -/* initialize display thread */ - priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; -kthread_init_worker (&priv->disp_thread[i].worker); - priv->disp_thread[i].dev = ddev; - priv->disp_thread[i].thread = -kthread_run (kthread_worker_fn, - &priv->disp_thread[i].worker, -"crtc_commit:%d" , priv->disp_thread[i].crtc_id); -if (IS_ERR (priv->disp_thread[i].thread)) { -DRM_DEV_ERROR (dev,"failed to create crtc_commit kthread\n" ); - priv->disp_thread[i].thread =NULL ; - goto err_msm_uninit; - } - - ret =sched_setscheduler (priv->disp_thread[i].thread, -SCHED_FIFO , ¶m); -if (ret) -dev_warn (dev,"disp_thread set priority failed: %d\n" , - ret); -/* initialize event thread */ priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id;kthread_init_worker (&priv->event_thread[i].worker);
@@ -580,13 +554,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) goto err_msm_uninit; } -/** -* event thread should also run at same priority as disp_thread -* because it is handling frame_done events. A lower priority -* event thread and higher priority disp_thread can causes -* frame_pending counters beyond 2. This can lead to commit -* failure at crtc commit level. -*/ ret =sched_setscheduler (priv->event_thread[i].thread,SCHED_FIFO , ¶m);if (ret)
drivers/gpu/drm/msm/msm_drv.h +0 -1
@@ -197,7 +197,6 @@ struct msm_drm_private {unsigned int num_crtcs;struct drm_crtc *crtcs[MAX_CRTCS ]; -struct msm_drm_thread disp_thread[MAX_CRTCS ];struct msm_drm_thread event_thread[MAX_CRTCS ];unsigned int num_encoders;
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project _______________________________________________ Freedreno mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/freedreno
A message that is not in the archive (sent off-list or not yet received): 1544150504-19630-4-git-send-email-jsanka-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org
Re: [PATCH v4 4/5] drm/msm: clean up display thread
Quoted 51 lines · Jeykumar Sankaran
Since there are no clients using these threads,
cleaning it up.changes in v2:
- switch all the dependent clients to use system wq before removing thedisp_threads(Sean Paul)
changes in v3:
- none
changes in v4:
- noneSigned-off-by Jeykumar Sankaran <[email protected]>--- drivers/gpu/drm/msm/msm_drv.c | 35 +---------------------------------- drivers/gpu/drm/msm/msm_drv.h | 1 - 2 files changed, 1 insertion(+), 35 deletions(-)drivers/gpu/drm/msm/msm_drv.c +1
-17@@ -286,13 +286,8 @@ static int msm_drm_uninit(struct device *dev)kfree (vbl_ev); } -/* clean up display commit/event worker threads */ +/* clean up event worker threads */ for (i =0 ; i < priv->num_crtcs; i++) { -if (priv->disp_thread[i].thread) { -kthread_destroy_worker (&priv->disp_thread[i].worker); - priv->disp_thread[i].thread =NULL ; - } -if (priv->event_thread[i].thread) {kthread_destroy_worker (&priv->event_thread[i].worker); priv->event_thread[i].thread =NULL ;@@ -545,27 +540,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)*/ param.sched_priority =16 ;for (i =0 ; i < priv->num_crtcs; i++) { - -/* initialize display thread */ - priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; -kthread_init_worker (&priv->disp_thread[i].worker); - priv->disp_thread[i].dev = ddev; - priv->disp_thread[i].thread = -kthread_run (kthread_worker_fn, - &priv->disp_thread[i].worker, -"crtc_commit:%d" , priv->disp_thread[i].crtc_id); -if (IS_ERR (priv->disp_thread[i].thread)) { -DRM_DEV_ERROR (dev,"failed to create crtc_commit kthread\n" );
drivers/gpu/drm/msm/msm_drv.c static int msm_drm_init(struct device *dev, struct drm_driver *drv) · line 568
Quoted 10 lines
drivers/gpu/drm/msm/msm_drv.c +0
-10- priv->disp_thread[i].thread =NULL ; - goto err_msm_uninit; - } - - ret =sched_setscheduler (priv->disp_thread[i].thread, -SCHED_FIFO , ¶m); -if (ret) -dev_warn (dev,"disp_thread set priority failed: %d\n" , - ret); -
I'm getting the following compilation errors with this patch applied to dpu-staging/for-next:
../drivers/gpu/drm/msm/msm_drv.c: In function ‘msm_drm_init’:../drivers/gpu/drm/msm/msm_drv.c:569:15: error: ‘struct msm_drm_private’ has no member named ‘disp_thread’; did you mean ‘event_thread’?
if ((!priv->disp_thread[i].thread) ||
^~~~~~~~~~~
event_thread
../drivers/gpu/drm/msm/msm_drv.c:573:15: error: ‘struct msm_drm_private’ has no member named ‘disp_thread’; did you mean ‘event_thread’?
if (priv->disp_thread[i].thread) {
^~~~~~~~~~~
event_thread
../drivers/gpu/drm/msm/msm_drv.c:575:13: error: ‘struct msm_drm_private’ has no member named ‘disp_thread’; did you mean ‘event_thread’?
priv->disp_thread[i].thread);
^~~~~~~~~~~
event_thread
../drivers/gpu/drm/msm/msm_drv.c:576:12: error: ‘struct msm_drm_private’ has no member named ‘disp_thread’; did you mean ‘event_thread’?
priv->disp_thread[i].thread = NULL;
^~~~~~~~~~~
event_threadI think you also need:
@@ -598,16 +566,9 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
priv->event_thread[i].thread = NULL;
}- if ((!priv->disp_thread[i].thread) ||
- !priv->event_thread[i].thread) {
+ if (!priv->event_thread[i].thread) {
/* clean up previously created threads if any */
for ( ; i >= 0; i--) {- if (priv->disp_thread[i].thread) {
- kthread_stop(
- priv->disp_thread[i].thread);
- priv->disp_thread[i].thread = NULL;
- }
-
if (priv->event_thread[i].thread) {
kthread_stop(
priv->event_thread[i].thread);Quoted 37 lines
drivers/gpu/drm/msm/msm_drv.c +0
-7/* initialize event thread */ priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id;kthread_init_worker (&priv->event_thread[i].worker);@@ -580,13 +554,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) goto err_msm_uninit; } -/** -* event thread should also run at same priority as disp_thread -* because it is handling frame_done events. A lower priority -* event thread and higher priority disp_thread can causes -* frame_pending counters beyond 2. This can lead to commit -* failure at crtc commit level. -*/ ret =sched_setscheduler (priv->event_thread[i].thread,SCHED_FIFO , ¶m);if (ret)drivers/gpu/drm/msm/msm_drv.h +0
-1@@ -197,7 +197,6 @@ struct msm_drm_private {unsigned int num_crtcs;struct drm_crtc *crtcs[MAX_CRTCS ]; -struct msm_drm_thread disp_thread[MAX_CRTCS ];struct msm_drm_thread event_thread[MAX_CRTCS ];unsigned int num_encoders;Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project _______________________________________________ Freedreno mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/freedreno
Signature · 5 lines
Sean Paul, Software Engineer, Google / Chromium OS _______________________________________________ Freedreno mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/freedreno
PATCH v4 5/5 drm/msm: subclass work object for vblank events
In reply to a message not in the archivemsm maintains a separate structure to define vblank work definitions and a list to track events submitted to the workqueue. We can avoid this redundant list and its protection mechanism, if we subclass the work object to encapsulate vblank event parameters.
changes in v2:
- subclass optimization on system wq (Sean Paul)
changes in v3:
- none
changes in v4:
- move flush_workqueue before irq uninstall
--- drivers/gpu/drm/msm/msm_drv.c | 71 ++++++++++++++----------------------------- drivers/gpu/drm/msm/msm_drv.h | 7 ----- 2 files changed, 22 insertions(+), 56 deletions(-)
drivers/gpu/drm/msm/msm_drv.c +22 -49
@@ -206,61 +206,44 @@ u32 msm_readl(const void __iomem *addr)return val; } -struct vblank_event { -struct list_head node; +struct msm_vblank_work { +struct work_struct work;int crtc_id;bool enable; +struct msm_drm_private *priv; };static void vblank_ctrl_worker (struct work_struct *work) { -struct msm_vblank_ctrl *vbl_ctrl =container_of (work, - struct msm_vblank_ctrl, work); -struct msm_drm_private *priv =container_of (vbl_ctrl, - struct msm_drm_private, vblank_ctrl); +struct msm_vblank_work *vbl_work =container_of (work, + struct msm_vblank_work, work); +struct msm_drm_private *priv = vbl_work->priv;struct msm_kms *kms = priv->kms; -struct vblank_event *vbl_ev, *tmp; -unsigned long flags; - -spin_lock_irqsave (&vbl_ctrl->lock, flags); -list_for_each_entry_safe (vbl_ev, tmp, &vbl_ctrl->event_list, node) { -list_del (&vbl_ev->node); -spin_unlock_irqrestore (&vbl_ctrl->lock, flags); - -if (vbl_ev->enable) - kms->funcs->enable_vblank (kms, - priv->crtcs[vbl_ev->crtc_id]); -else - kms->funcs->disable_vblank (kms, - priv->crtcs[vbl_ev->crtc_id]); - -kfree (vbl_ev); -spin_lock_irqsave (&vbl_ctrl->lock, flags); - } +if (vbl_work->enable) + kms->funcs->enable_vblank (kms, priv->crtcs[vbl_work->crtc_id]); +else + kms->funcs->disable_vblank (kms, priv->crtcs[vbl_work->crtc_id]); -spin_unlock_irqrestore (&vbl_ctrl->lock, flags); +kfree (vbl_work); }static int vblank_ctrl_queue_work (struct msm_drm_private *priv,int crtc_id,bool enable) { -struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl; -struct vblank_event *vbl_ev; -unsigned long flags; +struct msm_vblank_work *vbl_work; - vbl_ev =kzalloc (sizeof (*vbl_ev),GFP_ATOMIC ); -if (!vbl_ev) + vbl_work =kzalloc (sizeof (*vbl_work),GFP_ATOMIC ); +if (!vbl_work)return -ENOMEM ; - vbl_ev->crtc_id = crtc_id; - vbl_ev->enable = enable; +INIT_WORK (&vbl_work->work, vblank_ctrl_worker); -spin_lock_irqsave (&vbl_ctrl->lock, flags); -list_add_tail (&vbl_ev->node, &vbl_ctrl->event_list); -spin_unlock_irqrestore (&vbl_ctrl->lock, flags); + vbl_work->crtc_id = crtc_id; + vbl_work->enable = enable; + vbl_work->priv = priv; -queue_work (priv->wq, &vbl_ctrl->work); +queue_work (priv->wq, &vbl_work->work);return 0 ; }
@@ -272,19 +255,15 @@ static int msm_drm_uninit(struct device *dev)struct msm_drm_private *priv = ddev->dev_private;struct msm_kms *kms = priv->kms;struct msm_mdss *mdss = priv->mdss; -struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl; -struct vblank_event *vbl_ev, *tmp;int i;/* We must cancel and cleanup any pending vblank enable/disable * work before drm_irq_uninstall() to avoid work re-enabling an * irq after uninstall has disabled it. */ -flush_work (&vbl_ctrl->work); -list_for_each_entry_safe (vbl_ev, tmp, &vbl_ctrl->event_list, node) { -list_del (&vbl_ev->node); -kfree (vbl_ev); - } + +flush_workqueue (priv->wq); +destroy_workqueue (priv->wq);/* clean up event worker threads */ for (i =0 ; i < priv->num_crtcs; i++) {
@@ -313,9 +292,6 @@ static int msm_drm_uninit(struct device *dev)drm_irq_uninstall (ddev);pm_runtime_put_sync (dev); -flush_workqueue (priv->wq); -destroy_workqueue (priv->wq); -if (kms && kms->funcs) kms->funcs->destroy (kms);
@@ -472,9 +448,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) priv->wq =alloc_ordered_workqueue ("msm" ,0 );INIT_LIST_HEAD (&priv->inactive_list); -INIT_LIST_HEAD (&priv->vblank_ctrl.event_list); -INIT_WORK (&priv->vblank_ctrl.work, vblank_ctrl_worker); -spin_lock_init (&priv->vblank_ctrl.lock);drm_mode_config_init (ddev);
drivers/gpu/drm/msm/msm_drv.h +0 -7
@@ -77,12 +77,6 @@ enum msm_mdp_plane_property { PLANE_PROP_MAX_NUM }; -struct msm_vblank_ctrl { -struct work_struct work; -struct list_head event_list; -spinlock_t lock; -}; -#define MSM_GPU_MAX_RINGS 4#define MAX_H_TILES_PER_DISPLAY 2
@@ -225,7 +219,6 @@ struct msm_drm_private {struct notifier_block vmap_notifier;struct shrinker shrinker; -struct msm_vblank_ctrl vblank_ctrl;struct drm_atomic_state *pm_state; };
Signature · 7 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project _______________________________________________ Freedreno mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/freedreno