#include "fp_trig.h"
#include "drm_flip.h"
+#include "ossync.h"
+#include "mutex.h"
+#include "lock.h"
enum {
OVL_DIRTY_REGS = 0x1,
struct mfld_overlay_regs regs;
bool vblank_ref;
unsigned int dirty;
+ atomic_t refcnt;
+ struct psb_pending_values pending_values;
+ struct pvr_pending_sync pending_sync;
};
static void ovl_prepare(struct drm_flip *flip)
return (OVL_REG_READ(ovl, OVL_DOVSTA) & OVL_DOVSTA_OVR_UPDT) != 0;
}
+static void free_flip(struct mfld_overlay_flip *oflip)
+{
+ if (atomic_dec_and_test(&oflip->refcnt))
+ kfree(oflip);
+}
+
+static void ovl_sync_callback(struct pvr_pending_sync *sync,
+ bool call_from_work)
+{
+ struct mfld_overlay_flip *oflip =
+ container_of(sync, struct mfld_overlay_flip, pending_sync);
+
+ if (psb_fb_increase_read_ops_completed(oflip->old_mem_info,
+ &oflip->pending_values, sync)) {
+ WARN(true, "Sync callback called without completing operation");
+ return;
+ }
+
+ free_flip(oflip);
+
+ if (call_from_work)
+ mutex_lock(&gPVRSRVLock);
+
+ PVRSRVScheduleDeviceCallbacks();
+
+ if (call_from_work)
+ mutex_unlock(&gPVRSRVLock);
+}
+
static void ovl_flip_complete(struct drm_flip *pending_flip)
{
struct mfld_overlay_flip *oflip =
if (oflip->vblank_ref)
drm_vblank_put(dev, pipe);
- psb_fb_increase_read_ops_completed(oflip->old_mem_info);
+ atomic_inc(&oflip->refcnt);
+ oflip->pending_sync.callback = ovl_sync_callback;
+ if (psb_fb_increase_read_ops_completed(oflip->old_mem_info,
+ &oflip->pending_values, &oflip->pending_sync))
+ return;
+
+ free_flip(oflip);
PVRSRVScheduleDeviceCallbacks();
}
psb_fb_gtt_unref(dev, oflip->mem_info, oflip->tgid);
mutex_unlock(&dev->mode_config.mutex);
- kfree(oflip);
+ free_flip(oflip);
}
static const struct drm_flip_helper_funcs ovl_flip_funcs = {
drm_flip_init(&oflip->base, &ovl->flip_helper);
+ atomic_set(&oflip->refcnt, 1);
oflip->mem_info = ovl->mem_info;
/* reference ownership moved to the flip */
ovl->mem_info = NULL;
oflip->vblank_ref = false;
- psb_fb_increase_read_ops_pending(oflip->old_mem_info);
+ psb_fb_increase_read_ops_pending(oflip->old_mem_info,
+ &oflip->pending_values);
psb_fb_flip_trace(oflip->old_mem_info, oflip->mem_info);
/* we must pipeline the register changes */
#include "mdfld_output.h"
#include "pvr_trace_cmd.h"
+#include "ossync.h"
+
extern struct mutex gPVRSRVLock;
extern int MRSTLFBHandleChangeFB(struct drm_device* dev, struct psb_framebuffer *psbfb);
}
void
-psb_fb_increase_read_ops_pending(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo)
+psb_fb_increase_read_ops_pending(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo,
+ struct psb_pending_values *pending)
{
- if (psKernelMemInfo && psKernelMemInfo->psKernelSyncInfo)
- psKernelMemInfo->psKernelSyncInfo
- ->psSyncData->ui32ReadOpsPending++;
+ PVRSRV_SYNC_DATA *sync_data;
+ if (!psKernelMemInfo || !psKernelMemInfo->psKernelSyncInfo)
+ return;
+
+ sync_data = psKernelMemInfo->psKernelSyncInfo->psSyncData;
+ pending->write = sync_data->ui32WriteOpsPending;
+ pending->read = sync_data->ui32ReadOpsPending++;
}
-void
-psb_fb_increase_read_ops_completed(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo)
+int
+psb_fb_increase_read_ops_completed(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo,
+ struct psb_pending_values *pending,
+ struct pvr_pending_sync *pending_sync)
{
- if (psKernelMemInfo && psKernelMemInfo->psKernelSyncInfo)
- psKernelMemInfo->psKernelSyncInfo
- ->psSyncData->ui32ReadOpsComplete++;
+ PVRSRV_SYNC_DATA *sync_data;
+ if (!psKernelMemInfo || !psKernelMemInfo->psKernelSyncInfo)
+ return 0;
+ sync_data = psKernelMemInfo->psKernelSyncInfo->psSyncData;
+ if (unlikely(
+ pvr_ops_after(pending->write, sync_data->ui32WriteOpsComplete) ||
+ pvr_ops_after(pending->read, sync_data->ui32ReadOpsComplete))) {
+ /* Has to wait SGX micorkernel to complete parallel reads to
+ * avoid deadlock.
+ */
+
+ pending_sync->sync_info = psKernelMemInfo->psKernelSyncInfo;
+ pending_sync->pending_read_ops = pending->read;
+ pending_sync->pending_write_ops = pending->write;
+ pending_sync->flags = PVRSRV_SYNC_WRITE | PVRSRV_SYNC_READ;
+
+ PVRSRVCallbackOnSync2(pending_sync);
+
+ return -EBUSY;
+ }
+ sync_data->ui32ReadOpsComplete++;
pvr_trcmd_check_syn_completions(PVR_TRCMD_FLPCOMP);
+ return 0;
}
void
struct psb_framebuffer * pfb;
};
+struct psb_pending_values {
+ uint32_t read;
+ uint32_t write;
+};
+
#define to_psb_fb(x) container_of(x, struct psb_framebuffer, base)
PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo,
uint32_t tgid);
-void psb_fb_increase_read_ops_pending(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo);
-void psb_fb_increase_read_ops_completed(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo);
+struct pvr_pending_sync;
+
+void psb_fb_increase_read_ops_pending(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo,
+ struct psb_pending_values *pending);
+int psb_fb_increase_read_ops_completed(PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo,
+ struct psb_pending_values *pending,
+ struct pvr_pending_sync *pending_sync);
void psb_fb_flip_trace(PVRSRV_KERNEL_MEM_INFO *old,
PVRSRV_KERNEL_MEM_INFO *new);
#endif
#include "drm_flip.h"
+#include "mutex.h"
+#include "lock.h"
struct pending_flip {
struct drm_crtc *crtc;
struct list_head companions;
u32 tgid;
bool vblank_ref;
+ atomic_t refcnt;
+ struct psb_pending_values pending_values;
};
static const u32 dspsurf_reg[] = {
(void)ioread32(dev_priv->vdc_reg + PIPEASTAT);
}
+static void free_flip(struct pending_flip *crtc_flip)
+{
+ if (atomic_dec_and_test(&crtc_flip->refcnt))
+ kfree(crtc_flip);
+}
+
+static void psb_flip_complete_sync_callback(struct pvr_pending_sync *sync,
+ bool call_from_work)
+{
+ struct pending_flip *crtc_flip =
+ container_of(sync, struct pending_flip, pending_sync);
+
+ if (psb_fb_increase_read_ops_completed(crtc_flip->old_mem_info,
+ &crtc_flip->pending_values, sync)) {
+ WARN(true, "Sync callback called without completing operation");
+ return;
+ }
+
+ free_flip(crtc_flip);
+
+ if (call_from_work)
+ mutex_lock(&gPVRSRVLock);
+
+ PVRSRVScheduleDeviceCallbacks();
+
+ if (call_from_work)
+ mutex_unlock(&gPVRSRVLock);
+}
+
static void crtc_flip_complete(struct drm_flip *flip)
{
struct pending_flip *crtc_flip =
if (crtc_flip->vblank_ref)
drm_vblank_put(dev, pipe);
- psb_fb_increase_read_ops_completed(crtc_flip->old_mem_info);
+ atomic_inc(&crtc_flip->refcnt);
+ crtc_flip->pending_sync.callback = psb_flip_complete_sync_callback;
+ if (psb_fb_increase_read_ops_completed(crtc_flip->old_mem_info,
+ &crtc_flip->pending_values,
+ &crtc_flip->pending_sync))
+ return;
+
+ free_flip(crtc_flip);
PVRSRVScheduleDeviceCallbacks();
}
drm_flip_init(&new_pending_flip->base, &to_psb_intel_crtc(crtc)->flip_helper);
+ atomic_set(&new_pending_flip->refcnt, 1);
new_pending_flip->crtc = crtc;
new_pending_flip->event = event;
new_pending_flip->offset = psbfb->offset;
new_pending_flip->mem_info = psbfb->pvrBO;
new_pending_flip->old_mem_info = current_fb_mem_info;
- psb_fb_increase_read_ops_pending(current_fb_mem_info);
+ psb_fb_increase_read_ops_pending(current_fb_mem_info,
+ &new_pending_flip->pending_values);
psb_fb_flip_trace(current_fb_mem_info, psbfb->pvrBO);
new_pending_flip->tgid = tgid;