i915: flush cached memory

git-svn-id: svn://kolibrios.org@4293 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2013-11-26 06:18:53 +00:00
parent a96a492233
commit 4b0faaf65f
16 changed files with 230 additions and 105 deletions

View File

@ -29,6 +29,7 @@
*/
#include <linux/export.h>
#include <linux/scatterlist.h>
#include <drm/drmP.h>
extern int x86_clflush_size;
@ -37,6 +38,7 @@ static inline void clflush(volatile void *__p)
{
asm volatile("clflush %0" : "+m" (*(volatile char*)__p));
}
#if 0
static void
drm_clflush_page(struct page *page)
@ -75,12 +77,12 @@ drm_clflush_ipi_handler(void *null)
void
drm_clflush_pages(struct page *pages[], unsigned long num_pages)
{
uint8_t *page_virtual;
uint8_t *pva;
unsigned int i, j;
page_virtual = AllocKernelSpace(4096);
pva = AllocKernelSpace(4096);
if(page_virtual != NULL)
if(pva != NULL)
{
dma_addr_t *src, *dst;
u32 count;
@ -88,44 +90,45 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
for (i = 0; i < num_pages; i++)
{
mb();
// asm volatile("mfence");
MapPage(page_virtual,*pages++, 0x001);
MapPage(pva, page_to_phys(pages[i]), 0x001);
for (j = 0; j < PAGE_SIZE; j += x86_clflush_size)
clflush(page_virtual + j);
mb();
clflush(pva + j);
}
FreeKernelSpace(page_virtual);
FreeKernelSpace(pva);
}
mb();
}
EXPORT_SYMBOL(drm_clflush_pages);
#if 0
void
drm_clflush_sg(struct sg_table *st)
{
#if defined(CONFIG_X86)
if (cpu_has_clflush) {
struct sg_page_iter sg_iter;
struct page *page;
uint8_t *pva;
unsigned int i;
pva = AllocKernelSpace(4096);
if( pva != NULL)
{
mb();
for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
drm_clflush_page(sg_page_iter_page(&sg_iter));
mb();
{
page = sg_page_iter_page(&sg_iter);
return;
}
MapPage(pva,page_to_phys(page), 0x001);
if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
printk(KERN_ERR "Timed out waiting for cache flush.\n");
#else
printk(KERN_ERR "Architecture has no drm_cache.c support\n");
WARN_ON_ONCE(1);
#endif
for (i = 0; i < PAGE_SIZE; i += x86_clflush_size)
clflush(pva + i);
};
FreeKernelSpace(pva);
};
mb();
}
EXPORT_SYMBOL(drm_clflush_sg);
#if 0
void
drm_clflush_virt_range(char *addr, unsigned long length)
{

View File

@ -84,6 +84,8 @@ int drm_irq_install(struct drm_device *dev)
unsigned long sh_flags = 0;
char *irqname;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
if (drm_dev_to_irq(dev) == 0)
return -EINVAL;
@ -202,6 +204,97 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc)
crtc->base.id, (int) dotclock/1000, (int) framedur_ns,
(int) linedur_ns, (int) pixeldur_ns);
}
EXPORT_SYMBOL(drm_calc_timestamping_constants);
/**
* drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms
* drivers. Implements calculation of exact vblank timestamps from
* given drm_display_mode timings and current video scanout position
* of a crtc. This can be called from within get_vblank_timestamp()
* implementation of a kms driver to implement the actual timestamping.
*
* Should return timestamps conforming to the OML_sync_control OpenML
* extension specification. The timestamp corresponds to the end of
* the vblank interval, aka start of scanout of topmost-leftmost display
* pixel in the following video frame.
*
* Requires support for optional dev->driver->get_scanout_position()
* in kms driver, plus a bit of setup code to provide a drm_display_mode
* that corresponds to the true scanout timing.
*
* The current implementation only handles standard video modes. It
* returns as no operation if a doublescan or interlaced video mode is
* active. Higher level code is expected to handle this.
*
* @dev: DRM device.
* @crtc: Which crtc's vblank timestamp to retrieve.
* @max_error: Desired maximum allowable error in timestamps (nanosecs).
* On return contains true maximum error of timestamp.
* @vblank_time: Pointer to struct timeval which should receive the timestamp.
* @flags: Flags to pass to driver:
* 0 = Default.
* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
* @refcrtc: drm_crtc* of crtc which defines scanout timing.
*
* Returns negative value on error, failure or if not supported in current
* video mode:
*
* -EINVAL - Invalid crtc.
* -EAGAIN - Temporary unavailable, e.g., called before initial modeset.
* -ENOTSUPP - Function not supported in current display mode.
* -EIO - Failed, e.g., due to failed scanout position query.
*
* Returns or'ed positive status flags on success:
*
* DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.
* DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
*
*/
int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
int *max_error,
struct timeval *vblank_time,
unsigned flags,
struct drm_crtc *refcrtc)
{
// ktime_t stime, etime, mono_time_offset;
struct timeval tv_etime;
struct drm_display_mode *mode;
int vbl_status, vtotal, vdisplay;
int vpos, hpos, i;
s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
bool invbl;
if (crtc < 0 || crtc >= dev->num_crtcs) {
DRM_ERROR("Invalid crtc %d\n", crtc);
return -EINVAL;
}
/* Scanout position query not supported? Should not happen. */
if (!dev->driver->get_scanout_position) {
DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
return -EIO;
}
mode = &refcrtc->hwmode;
vtotal = mode->crtc_vtotal;
vdisplay = mode->crtc_vdisplay;
/* Durations of frames, lines, pixels in nanoseconds. */
framedur_ns = refcrtc->framedur_ns;
linedur_ns = refcrtc->linedur_ns;
pixeldur_ns = refcrtc->pixeldur_ns;
/* If mode timing undefined, just return as no-op:
* Happens during initial modesetting of a crtc.
*/
if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {
DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
return -EAGAIN;
}
return -EIO;
}
EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
/**

View File

@ -81,6 +81,7 @@ NAME_SRC= main.c \
../hdmi.c \
Gtt/intel-agp.c \
Gtt/intel-gtt.c \
../drm_cache.c \
../drm_global.c \
../drm_drv.c \
../drm_vma_manager.c \

View File

@ -1215,6 +1215,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
cleanup_gem:
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_aliasing_ppgtt(dev);
cleanup_irq:
@ -1421,11 +1422,18 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (HAS_POWER_WELL(dev))
i915_init_power_well(dev);
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = i915_load_modeset_init(dev);
if (ret < 0) {
DRM_ERROR("failed to init modeset\n");
goto out_gem_unload;
}
} else {
/* Start out suspended in ums mode. */
dev_priv->ums.mm_suspended = 1;
}
if (INTEL_INFO(dev)->num_pipes) {
/* Must be done after probing outputs */

View File

@ -637,7 +637,8 @@ static int i915_drm_thaw(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
i915_gem_restore_gtt_mappings(dev);
mutex_unlock(&dev->struct_mutex);
}
} else if (drm_core_check_feature(dev, DRIVER_MODESET))
i915_check_and_clear_faults(dev);
__i915_drm_thaw(dev);
@ -949,14 +950,9 @@ int i915_init(void)
DRM_INFO("device %x:%x\n", device.pci_dev.vendor,
device.pci_dev.device);
/*
if (intel_info->gen != 3) {
} else if (init_agp() != 0) {
DRM_ERROR("drm/i915 can't work without intel_agp module!\n");
return -ENODEV;
}
*/
driver.driver_features |= DRIVER_MODESET;
err = drm_get_pci_dev(&device.pci_dev, ent, &driver);
return err;

View File

@ -1292,10 +1292,42 @@ unlock:
return ret;
}
/**
* Called when user space has done writes to this buffer
*/
int
i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct drm_i915_gem_sw_finish *args = data;
struct drm_i915_gem_object *obj;
int ret = 0;
if(args->handle == -2)
{
printf("%s handle %d\n", __FUNCTION__, args->handle);
return 0;
}
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (&obj->base == NULL) {
ret = -ENOENT;
goto unlock;
}
/* Pinned buffers may be scanout, so flush the cache */
if (obj->pin_display)
i915_gem_object_flush_cpu_write_domain(obj, true);
drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
}
/**
* Maps the contents of an object, returning the address it is mapped
@ -3115,54 +3147,9 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj,
*/
if (!force && cpu_cache_is_coherent(obj->base.dev, obj->cache_level))
return false;
#if 0
if(obj->mapped != NULL)
{
uint8_t *page_virtual;
unsigned int i;
page_virtual = obj->mapped;
asm volatile("mfence");
for (i = 0; i < obj->base.size; i += x86_clflush_size)
clflush(page_virtual + i);
asm volatile("mfence");
}
else
{
uint8_t *page_virtual;
unsigned int i;
page_virtual = AllocKernelSpace(obj->base.size);
if(page_virtual != NULL)
{
dma_addr_t *src, *dst;
u32 count;
#define page_tabs 0xFDC00000 /* really dirty hack */
src = obj->pages.page;
dst = &((dma_addr_t*)page_tabs)[(u32_t)page_virtual >> 12];
count = obj->base.size/4096;
while(count--)
{
*dst++ = (0xFFFFF000 & *src++) | 0x001 ;
};
asm volatile("mfence");
for (i = 0; i < obj->base.size; i += x86_clflush_size)
clflush(page_virtual + i);
asm volatile("mfence");
FreeKernelSpace(page_virtual);
}
else
{
asm volatile (
"mfence \n"
"wbinvd \n" /* this is really ugly */
"mfence");
}
}
#endif
trace_i915_gem_object_clflush(obj);
drm_clflush_sg(obj->pages);
return true;
}

View File

@ -2385,6 +2385,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
if (!dev_priv)
return;
del_timer_sync(&dev_priv->hotplug_reenable_timer);
for_each_pipe(pipe)
I915_WRITE(PIPESTAT(pipe), 0xffff);
@ -2406,6 +2408,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
if (!dev_priv)
return;
del_timer_sync(&dev_priv->hotplug_reenable_timer);
I915_WRITE(HWSTAM, 0xffffffff);
I915_WRITE(DEIMR, 0xffffffff);
@ -2788,6 +2792,8 @@ static void i915_irq_uninstall(struct drm_device * dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int pipe;
del_timer_sync(&dev_priv->hotplug_reenable_timer);
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@ -3036,6 +3042,8 @@ static void i965_irq_uninstall(struct drm_device * dev)
if (!dev_priv)
return;
del_timer_sync(&dev_priv->hotplug_reenable_timer);
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@ -3098,32 +3106,52 @@ void intel_irq_init(struct drm_device *dev)
setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func,
(unsigned long) dev_priv);
dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
}
// dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
if (drm_core_check_feature(dev, DRIVER_MODESET))
dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
else
dev->driver->get_vblank_timestamp = NULL;
dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
if (IS_VALLEYVIEW(dev)) {
dev->driver->irq_handler = valleyview_irq_handler;
dev->driver->irq_preinstall = valleyview_irq_preinstall;
dev->driver->irq_postinstall = valleyview_irq_postinstall;
dev->driver->irq_uninstall = valleyview_irq_uninstall;
dev->driver->enable_vblank = valleyview_enable_vblank;
dev->driver->disable_vblank = valleyview_disable_vblank;
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
} else if (HAS_PCH_SPLIT(dev)) {
dev->driver->irq_handler = ironlake_irq_handler;
dev->driver->irq_preinstall = ironlake_irq_preinstall;
dev->driver->irq_postinstall = ironlake_irq_postinstall;
dev->driver->irq_uninstall = ironlake_irq_uninstall;
dev->driver->enable_vblank = ironlake_enable_vblank;
dev->driver->disable_vblank = ironlake_disable_vblank;
dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
} else {
if (INTEL_INFO(dev)->gen == 2) {
} else if (INTEL_INFO(dev)->gen == 3) {
dev->driver->irq_preinstall = i915_irq_preinstall;
dev->driver->irq_postinstall = i915_irq_postinstall;
dev->driver->irq_uninstall = i915_irq_uninstall;
dev->driver->irq_handler = i915_irq_handler;
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
} else {
dev->driver->irq_preinstall = i965_irq_preinstall;
dev->driver->irq_postinstall = i965_irq_postinstall;
dev->driver->irq_uninstall = i965_irq_uninstall;
dev->driver->irq_handler = i965_irq_handler;
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
}
dev->driver->enable_vblank = i915_enable_vblank;
dev->driver->disable_vblank = i915_disable_vblank;
}
}

View File

@ -3,9 +3,7 @@
//#include <linux/stringify.h>
#include <linux/types.h>
//#include <linux/tracepoint.h>
//#define WARN_ON(x)
#define trace_i915_gem_object_create(x)
#define trace_i915_gem_object_destroy(x)
@ -27,5 +25,7 @@
#define trace_i915_gem_ring_dispatch(a, b, c)
#define trace_i915_vma_bind(a, b)
#define trace_i915_vma_unbind(a)
#define trace_i915_gem_object_clflush(a)
#define trace_i915_reg_rw(a, b, c, d, e)
#endif

View File

@ -6161,7 +6161,7 @@ static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv)
if (dev_priv->pc8.disable_count != 1)
return;
// cancel_delayed_work_sync(&dev_priv->pc8.enable_work);
cancel_delayed_work_sync(&dev_priv->pc8.enable_work);
if (!dev_priv->pc8.enabled)
return;
@ -7566,7 +7566,7 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
spin_unlock_irqrestore(&dev->event_lock, flags);
if (work) {
// cancel_work_sync(&work->work);
cancel_work_sync(&work->work);
kfree(work);
}

View File

@ -3053,7 +3053,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
i2c_del_adapter(&intel_dp->adapter);
drm_encoder_cleanup(encoder);
if (is_edp(intel_dp)) {
// cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
mutex_lock(&dev->mode_config.mutex);
ironlake_panel_vdd_off_sync(intel_dp);
mutex_unlock(&dev->mode_config.mutex);
@ -3493,7 +3493,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
if (!intel_edp_init_connector(intel_dp, intel_connector)) {
i2c_del_adapter(&intel_dp->adapter);
if (is_edp(intel_dp)) {
// cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
mutex_lock(&dev->mode_config.mutex);
ironlake_panel_vdd_off_sync(intel_dp);
mutex_unlock(&dev->mode_config.mutex);

View File

@ -490,6 +490,17 @@ void intel_panel_disable_backlight(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long flags;
/*
* Do not disable backlight on the vgaswitcheroo path. When switching
* away from i915, the other client may depend on i915 to handle the
* backlight. This will leave the backlight on unnecessarily when
* another client is not activated.
*/
if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
return;
}
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
dev_priv->backlight.enabled = false;

View File

@ -363,9 +363,9 @@ static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
* dev_priv->fbc.fbc_work, so we can perform the cancellation
* entirely asynchronously.
*/
// if (cancel_delayed_work(&dev_priv->fbc_work->work))
if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
/* tasklet was killed before being run, clean up */
// kfree(dev_priv->fbc_work);
kfree(dev_priv->fbc.fbc_work);
/* Mark the work as no longer wanted so that if it does
* wake-up (because the work was already running and waiting
@ -4608,8 +4608,11 @@ void intel_disable_gt_powersave(struct drm_device *dev)
if (IS_IRONLAKE_M(dev)) {
ironlake_disable_drps(dev);
ironlake_disable_rc6(dev);
} else if (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) {
// cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
} else if (INTEL_INFO(dev)->gen >= 6) {
cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
cancel_work_sync(&dev_priv->rps.work);
if (IS_VALLEYVIEW(dev))
cancel_delayed_work_sync(&dev_priv->rps.vlv_work);
mutex_lock(&dev_priv->rps.hw_lock);
if (IS_VALLEYVIEW(dev))
valleyview_disable_rps(dev);

View File

@ -1247,8 +1247,8 @@ static int intel_init_ring_buffer(struct drm_device *dev,
}
obj = NULL;
if (!HAS_LLC(dev))
obj = i915_gem_object_create_stolen(dev, ring->size);
// if (!HAS_LLC(dev))
// obj = i915_gem_object_create_stolen(dev, ring->size);
if (obj == NULL)
obj = i915_gem_alloc_object(dev, ring->size);
if (obj == NULL) {

View File

@ -364,6 +364,7 @@ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg, bool trace) { \
val = __raw_i915_read##x(dev_priv, reg); \
} \
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
return val; \
}
@ -377,6 +378,7 @@ __i915_read(64)
void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val, bool trace) { \
unsigned long irqflags; \
u32 __fifo_ret = 0; \
trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); \
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \

View File

@ -197,7 +197,6 @@ do_set:
{
os_display->width = fb->width;
os_display->height = fb->height;
os_display->pitch = fb->pitches[0];
os_display->vrefresh = drm_mode_vrefresh(mode);
sysSetScreen(fb->width, fb->height, fb->pitches[0]);
@ -209,7 +208,6 @@ do_set:
DRM_ERROR("failed to set mode %d_%d on crtc %p\n",
fb->width, fb->height, crtc);
return ret;
}
@ -381,12 +379,9 @@ int init_display_kms(struct drm_device *dev, videomode_t *usermode)
{
struct drm_display_mode *mode;
// connector->funcs->fill_modes(connector, dev->mode_config.max_width,
// dev->mode_config.max_height);
list_for_each_entry(mode, &connector->modes, head)
{
printf("check mode w:%d h:%d %dHz\n",
dbgprintf("check mode w:%d h:%d %dHz\n",
drm_mode_width(mode), drm_mode_height(mode),
drm_mode_vrefresh(mode));

View File

@ -184,15 +184,10 @@ u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline)
if( cmdline && *cmdline )
parse_cmdline(cmdline, cmdtable, log, &usermode);
if(!dbg_open(log))
{
strcpy(log, "/tmp1/1/i915.log");
if(!dbg_open(log))
if( *log && !dbg_open(log))
{
printf("Can't open %s\nExit\n", log);
return 0;
};
}
cpu_detect();
@ -622,7 +617,9 @@ static char* parse_path(char *p, char *log)
while( (c = *p++) == ' ');
p--;
while( (c = *log++ = *p++) && (c != ' '));
while((c = *p++) && (c != ' '))
*log++ = c;
*log = 0;
return p;
@ -643,7 +640,6 @@ void parse_cmdline(char *cmdline, struct cmdtable *table, char *log, videomode_t
{
p1+= table->size;
*table->val = my_atoi(&p1);
// printf("%s %d\n", table->key, *table->val);
}
table++;
}
@ -696,3 +692,5 @@ __asm__ __volatile__(
: "dx", "di");
return __res;
}