*
******************************************************************************/
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
#ifndef AUTOCONF_INCLUDED
#include <linux/config.h>
#endif
+#endif
-#include <linux/version.h>
#include <asm/atomic.h>
if (psDSSDrv->get_update_mode == NULL)
{
- DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Can't get update mode\n", __FUNCTION__, psDevInfo->uiFBDevID));
+// DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Can't get update mode\n", __FUNCTION__, psDevInfo->uiFBDevID));
return OMAPLFB_UPDATE_MODE_AUTO;
// return OMAPLFB_UPDATE_MODE_UNDEFINED;
}
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
- console_lock();
+ console_lock();
#else
acquire_console_sem();
#endif
ret = fb_blank(psDevInfo->psLINFBInfo, iFBMode);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
- console_unlock();
+ console_unlock();
#else
release_console_sem();
#endif
unsigned long ulLCM;
unsigned uiFBDevID = psDevInfo->uiFBDevID;
- acquire_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_lock();
+#else
+ acquire_console_sem();
+#endif
psLINFBInfo = registered_fb[uiFBDevID];
if (psLINFBInfo == NULL)
ErrorModPut:
module_put(psLINFBOwner);
ErrorRelSem:
- release_console_sem();
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_unlock();
+#else
+ release_console_sem();
+#endif
return eError;
}
struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo;
struct module *psLINFBOwner;
- acquire_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_lock();
+#else
+ acquire_console_sem();
+#endif
psLINFBOwner = psLINFBInfo->fbops->owner;
}
module_put(psLINFBOwner);
-
- release_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_unlock();
+#else
+ release_console_sem();
+#endif
}
static OMAPLFB_DEVINFO *OMAPLFBInitDev(unsigned uiFBDevID)
*
******************************************************************************/
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
#ifndef AUTOCONF_INCLUDED
#include <linux/config.h>
#endif
+#endif
-#include <linux/version.h>
#include <asm/atomic.h>
int res;
unsigned long ulYResVirtual;
- acquire_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_lock();
+#else
+ acquire_console_sem();
+#endif
sFBVar = psDevInfo->psLINFBInfo->var;
printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: fb_pan_display failed (Y Offset: %lu, Error: %d)\n", __FUNCTION__, psDevInfo->uiFBDevID, psBuffer->ulYOffset, res);
}
}
-
- release_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_unlock();
+#else
+ release_console_sem();
+#endif
}
OMAPLFB_UPDATE_MODE OMAPLFBGetUpdateMode(OMAPLFB_DEVINFO *psDevInfo)
{
int res;
#ifdef FBDEV_PRESENT
- acquire_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_lock();
+#else
+ acquire_console_sem();
+#endif
res = fb_blank(psDevInfo->psLINFBInfo, 0);
- release_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_unlock();
+#else
+ release_console_sem();
+#endif
if (res != 0 && res != -EINVAL)
{
printk(KERN_WARNING DRIVER_PREFIX
static void OMAPLFBBlankDisplay(OMAPLFB_DEVINFO *psDevInfo)
{
- acquire_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_lock();
+#else
+ acquire_console_sem();
+#endif
fb_blank(psDevInfo->psLINFBInfo, 1);
- release_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_unlock();
+#else
+ release_console_sem();
+#endif
}
static void OMAPLFBEarlySuspendHandler(struct early_suspend *h)
{
flush_workqueue(psDevInfo->psSwapChain->psWorkQueue);
}
-
- acquire_console_sem();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_lock();
+#else
+ acquire_console_sem();
+#endif
ret = fb_blank(psDevInfo->psLINFBInfo, iFBMode);
- release_console_sem();
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+ console_unlock();
+#else
+ release_console_sem();
+#endif
OMAPLFBCreateSwapChainUnLock(psDevInfo);
break;
}
EXPORT_SYMBOL(drm_agp_bind_pages);
+void drm_agp_chipset_flush(struct drm_device *dev)
+{
+ agp_flush_chipset(dev->agp->bridge);
+}
+EXPORT_SYMBOL(drm_agp_chipset_flush);
+
#endif /* __OS_HAS_AGP */
list_for_each_entry(entry, &dev->maplist, head) {
/*
* Because the kernel-userspace ABI is fixed at a 32-bit offset
- * while PCI resources may live above that, we only compare the
- * lower 32 bits of the map offset for maps of type
- * _DRM_FRAMEBUFFER or _DRM_REGISTERS.
- * It is assumed that if a driver have more than one resource
- * of each type, the lower 32 bits are different.
+ * while PCI resources may live above that, we ignore the map
+ * offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS.
+ * It is assumed that each driver will have only one resource of
+ * each type.
*/
if (!entry->map ||
map->type != entry->map->type ||
case _DRM_SHM:
if (map->flags != _DRM_CONTAINS_LOCK)
break;
- return entry;
case _DRM_REGISTERS:
case _DRM_FRAME_BUFFER:
- if ((entry->map->offset & 0xffffffff) ==
- (map->offset & 0xffffffff))
- return entry;
+ return entry;
default: /* Make gcc happy */
;
}
kfree(map);
return -EINVAL;
}
+#endif
+#ifdef __alpha__
+ map->offset += dev->hose->mem_space->start;
#endif
/* Some drivers preinitialize some maps, without the X Server
* needing to be aware of it. Therefore, we just return success
mutex_lock(&dev->mode_config.mutex);
drm_mode_object_put(dev, &connector->base);
list_del(&connector->head);
- dev->mode_config.num_connector--;
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_connector_cleanup);
mutex_lock(&dev->mode_config.mutex);
drm_mode_object_put(dev, &encoder->base);
list_del(&encoder->head);
- dev->mode_config.num_encoder--;
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_encoder_cleanup);
total_objects += dev->mode_config.num_connector;
total_objects += dev->mode_config.num_encoder;
+ if (total_objects == 0)
+ return -EINVAL;
+
group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
if (!group->id_list)
return -ENOMEM;
uint32_t __user *encoder_id;
struct drm_mode_group *mode_group;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
/*
if (card_res->count_fbs >= fb_count) {
copied = 0;
fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
- list_for_each_entry(fb, &file_priv->fbs, filp_head) {
+ list_for_each_entry(fb, &file_priv->fbs, head) {
if (put_user(fb->base.id, fb_id + copied)) {
ret = -EFAULT;
goto out;
struct drm_mode_object *obj;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
uint64_t __user *prop_values;
uint32_t __user *encoder_ptr;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
struct drm_encoder *encoder;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, enc_resp->encoder_id,
DRM_MODE_OBJECT_ENCODER);
int ret = 0;
int i;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, crtc_req->crtc_id,
DRM_MODE_OBJECT_CRTC);
struct drm_crtc *crtc;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
if (!req->flags) {
DRM_ERROR("no operation set\n");
return -EINVAL;
struct drm_framebuffer *fb;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
if ((config->min_width > r->width) || (r->width > config->max_width)) {
DRM_ERROR("mode new framebuffer width not within limits\n");
return -EINVAL;
mutex_lock(&dev->mode_config.mutex);
- /* TODO check buffer is sufficiently large */
+ /* TODO check buffer is sufficently large */
/* TODO setup destructor callback */
fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
int ret = 0;
int found = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
- /* TODO check that we really get a framebuffer back. */
+ /* TODO check that we realy get a framebuffer back. */
if (!obj) {
DRM_ERROR("mode invalid framebuffer id\n");
ret = -EINVAL;
struct drm_framebuffer *fb;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
if (!obj) {
int num_clips;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
if (!obj) {
struct drm_mode_modeinfo *umode = &mode_cmd->mode;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
struct drm_mode_modeinfo *umode = &mode_cmd->mode;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
uint64_t __user *values_ptr;
uint32_t __user *blob_length_ptr;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
if (!obj) {
int ret = 0;
void *blob_ptr;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
if (!obj) {
int ret = -EINVAL;
int i;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR);
int size;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
int size;
int ret = 0;
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- return -EINVAL;
-
mutex_lock(&dev->mode_config.mutex);
obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
mutex_unlock(&dev->mode_config.mutex);
return ret;
}
-
-void drm_mode_config_reset(struct drm_device *dev)
-{
- struct drm_crtc *crtc;
- struct drm_encoder *encoder;
- struct drm_connector *connector;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
- if (crtc->funcs->reset)
- crtc->funcs->reset(crtc);
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
- if (encoder->funcs->reset)
- encoder->funcs->reset(encoder);
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head)
- if (connector->funcs->reset)
- connector->funcs->reset(connector);
-}
-EXPORT_SYMBOL(drm_mode_config_reset);
-
-int drm_mode_create_dumb_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file_priv)
-{
- struct drm_mode_create_dumb *args = data;
-
- if (!dev->driver->dumb_create)
- return -ENOSYS;
- return dev->driver->dumb_create(file_priv, dev, args);
-}
-
-int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file_priv)
-{
- struct drm_mode_map_dumb *args = data;
-
- /* call driver ioctl to get mmap offset */
- if (!dev->driver->dumb_map_offset)
- return -ENOSYS;
-
- return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
-}
-
-int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file_priv)
-{
- struct drm_mode_destroy_dumb *args = data;
-
- if (!dev->driver->dumb_destroy)
- return -ENOSYS;
-
- return dev->driver->dumb_destroy(file_priv, dev, args->handle);
-}
struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
- struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
+ struct drm_display_mode *adjusted_mode, saved_mode;
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
struct drm_encoder_helper_funcs *encoder_funcs;
int saved_x, saved_y;
struct drm_encoder *encoder;
bool ret = true;
+ adjusted_mode = drm_mode_duplicate(dev, mode);
+
crtc->enabled = drm_helper_crtc_in_use(crtc);
+
if (!crtc->enabled)
return true;
- adjusted_mode = drm_mode_duplicate(dev, mode);
-
- saved_hwmode = crtc->hwmode;
saved_mode = crtc->mode;
saved_x = crtc->x;
saved_y = crtc->y;
}
- /* Store real post-adjustment hardware mode. */
- crtc->hwmode = *adjusted_mode;
-
- /* Calculate and store various constants which
- * are later needed by vblank and swap-completion
- * timestamping. They are derived from true hwmode.
- */
- drm_calc_timestamping_constants(crtc);
-
+ /* XXX free adjustedmode */
+ drm_mode_destroy(dev, adjusted_mode);
/* FIXME: add subpixel order */
done:
- drm_mode_destroy(dev, adjusted_mode);
if (!ret) {
- crtc->hwmode = saved_hwmode;
crtc->mode = saved_mode;
crtc->x = saved_x;
crtc->y = saved_y;
crtc_funcs = set->crtc->helper_private;
- if (!set->mode)
- set->fb = NULL;
-
if (set->fb) {
DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
set->crtc->base.id, set->fb->base.id,
(int)set->num_connectors, set->x, set->y);
} else {
- DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
- set->mode = NULL;
- set->num_connectors = 0;
+ DRM_DEBUG_KMS("[CRTC:%d] [NOFB] #connectors=%d (x y) (%i %i)\n",
+ set->crtc->base.id, (int)set->num_connectors,
+ set->x, set->y);
}
dev = set->crtc->dev;
mode_changed = true;
} else if (set->fb == NULL) {
mode_changed = true;
- } else if (set->fb->depth != set->crtc->fb->depth) {
- mode_changed = true;
- } else if (set->fb->bits_per_pixel !=
- set->crtc->fb->bits_per_pixel) {
- mode_changed = true;
} else
fb_changed = true;
}
mode_changed = true;
if (mode_changed) {
- set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
- if (set->crtc->enabled) {
+ set->crtc->enabled = (set->mode != NULL);
+ if (set->mode != NULL) {
DRM_DEBUG_KMS("attempting to set mode from"
" userspace\n");
drm_mode_debug_printmodeline(set->mode);
old_fb)) {
DRM_ERROR("failed to set mode on [CRTC:%d]\n",
set->crtc->base.id);
- set->crtc->fb = old_fb;
ret = -EINVAL;
goto fail;
}
- DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
- for (i = 0; i < set->num_connectors; i++) {
- DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
- drm_get_connector_name(set->connectors[i]));
- set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
- }
}
drm_helper_disable_unused_functions(dev);
} else if (fb_changed) {
set->crtc->fb = set->fb;
ret = crtc_funcs->mode_set_base(set->crtc,
set->x, set->y, old_fb);
- if (ret != 0) {
- set->crtc->fb = old_fb;
+ if (ret != 0)
goto fail;
- }
+ }
+ DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+ for (i = 0; i < set->num_connectors; i++) {
+ DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+ drm_get_connector_name(set->connectors[i]));
+ set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
}
kfree(save_connectors);
struct drm_device *dev = minor->dev;
struct dentry *ent;
struct drm_info_node *tmp;
+ char name[64];
int i, ret;
for (i = 0; i < count; i++) {
ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
root, tmp, &drm_debugfs_fops);
if (!ent) {
- char name[64];
- strncpy(name, root->d_name.name,
- min(root->d_name.len, 64U));
DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n",
name, files[i].name);
kfree(tmp);
DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
- DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, 0),
DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
return 0;
}
+/**
+ * Module initialization. Called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported).
+ *
+ * \return zero on success or a negative number on failure.
+ *
+ * Initializes an array of drm_device structures, and attempts to
+ * initialize all available devices, using consecutive minors, registering the
+ * stubs and initializing the device.
+ *
+ * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
+ * after the initialization for driver customization.
+ */
+int drm_init(struct drm_driver *driver)
+{
+ DRM_DEBUG("\n");
+ INIT_LIST_HEAD(&driver->device_list);
+
+ if (driver->driver_features & DRIVER_USE_PLATFORM_DEVICE)
+ return drm_platform_init(driver);
+ else
+ return drm_pci_init(driver);
+}
+
+EXPORT_SYMBOL(drm_init);
+
+void drm_exit(struct drm_driver *driver)
+{
+ struct drm_device *dev, *tmp;
+ DRM_DEBUG("\n");
+
+ if (driver->driver_features & DRIVER_MODESET) {
+ pci_unregister_driver(&driver->pci_driver);
+ } else {
+ list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
+ drm_put_dev(dev);
+ }
+
+ DRM_INFO("Module unloaded\n");
+}
+
+EXPORT_SYMBOL(drm_exit);
+
/** File operations structure */
static const struct file_operations drm_stub_fops = {
.owner = THIS_MODULE,
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
};
- /*
- * Sanity check the header of the base EDID block. Return 8 if the header
- * is perfect, down to 0 if it's totally wrong.
- */
-int drm_edid_header_is_valid(const u8 *raw_edid)
-{
- int i, score = 0;
-
- for (i = 0; i < sizeof(edid_header); i++)
- if (raw_edid[i] == edid_header[i])
- score++;
-
- return score;
-}
-EXPORT_SYMBOL(drm_edid_header_is_valid);
-
-
/*
* Sanity check the EDID block (base or extension). Return 0 if the block
* doesn't check out, or 1 if it's valid.
struct edid *edid = (struct edid *)raw_edid;
if (raw_edid[0] == 0x00) {
- int score = drm_edid_header_is_valid(raw_edid);
+ int score = 0;
+
+ for (i = 0; i < sizeof(edid_header); i++)
+ if (raw_edid[i] == edid_header[i])
+ score++;
+
if (score == 8) ;
else if (score >= 6) {
DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
bad:
if (raw_edid) {
- printk(KERN_ERR "Raw EDID:\n");
- print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1,
- raw_edid, EDID_LENGTH, false);
+ DRM_ERROR("Raw EDID:\n");
+ print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH);
+ printk("\n");
}
return 0;
}
int block, int len)
{
unsigned char start = block * EDID_LENGTH;
- int ret, retries = 5;
-
- /* The core i2c driver will automatically retry the transfer if the
- * adapter reports EAGAIN. However, we find that bit-banging transfers
- * are susceptible to errors under a heavily loaded machine and
- * generate spurious NAKs and timeouts. Retrying the transfer
- * of the individual block a few times seems to overcome this.
- */
- do {
- struct i2c_msg msgs[] = {
- {
- .addr = DDC_ADDR,
- .flags = 0,
- .len = 1,
- .buf = &start,
- }, {
- .addr = DDC_ADDR,
- .flags = I2C_M_RD,
- .len = len,
- .buf = buf,
- }
- };
- ret = i2c_transfer(adapter, msgs, 2);
- } while (ret != 2 && --retries);
-
- return ret == 2 ? 0 : -1;
-}
+ struct i2c_msg msgs[] = {
+ {
+ .addr = DDC_ADDR,
+ .flags = 0,
+ .len = 1,
+ .buf = &start,
+ }, {
+ .addr = DDC_ADDR,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = buf,
+ }
+ };
-static bool drm_edid_is_zero(u8 *in_edid, int length)
-{
- int i;
- u32 *raw_edid = (u32 *)in_edid;
+ if (i2c_transfer(adapter, msgs, 2) == 2)
+ return 0;
- for (i = 0; i < length / 4; i++)
- if (*(raw_edid + i) != 0)
- return false;
- return true;
+ return -1;
}
static u8 *
goto out;
if (drm_edid_block_valid(block))
break;
- if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
- connector->null_edid_counter++;
- goto carp;
- }
}
if (i == 4)
goto carp;
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
int hsize, int vsize, int fresh)
{
- struct drm_display_mode *mode = NULL;
int i;
+ struct drm_display_mode *ptr, *mode;
+ mode = NULL;
for (i = 0; i < drm_num_dmt_modes; i++) {
- const struct drm_display_mode *ptr = &drm_dmt_modes[i];
+ ptr = &drm_dmt_modes[i];
if (hsize == ptr->hdisplay &&
vsize == ptr->vdisplay &&
fresh == drm_mode_vrefresh(ptr)) {
}
static bool
-mode_is_rb(const struct drm_display_mode *mode)
+mode_is_rb(struct drm_display_mode *mode)
{
return (mode->htotal - mode->hdisplay == 160) &&
(mode->hsync_end - mode->hdisplay == 80) &&
}
static bool
-mode_in_hsync_range(const struct drm_display_mode *mode,
- struct edid *edid, u8 *t)
+mode_in_hsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t)
{
int hsync, hmin, hmax;
}
static bool
-mode_in_vsync_range(const struct drm_display_mode *mode,
- struct edid *edid, u8 *t)
+mode_in_vsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t)
{
int vsync, vmin, vmax;
}
static bool
-mode_in_range(const struct drm_display_mode *mode, struct edid *edid,
+mode_in_range(struct drm_display_mode *mode, struct edid *edid,
struct detailed_timing *timing)
{
u32 max_clock;
/**
* Search EDID for CEA extension block.
*/
-u8 *drm_find_cea_extension(struct edid *edid)
+static u8 *drm_find_cea_extension(struct edid *edid)
{
u8 *edid_ext = NULL;
int i;
return edid_ext;
}
-EXPORT_SYMBOL(drm_find_cea_extension);
/**
* drm_detect_hdmi_monitor - detect whether monitor is hdmi.
}
EXPORT_SYMBOL(drm_detect_monitor_audio);
-/**
- * drm_add_display_info - pull display info out if present
- * @edid: EDID data
- * @info: display info (attached to connector)
- *
- * Grab any available display info and stuff it into the drm_display_info
- * structure that's part of the connector. Useful for tracking bpp and
- * color spaces.
- */
-static void drm_add_display_info(struct edid *edid,
- struct drm_display_info *info)
-{
- u8 *edid_ext;
-
- info->width_mm = edid->width_cm * 10;
- info->height_mm = edid->height_cm * 10;
-
- /* driver figures it out in this case */
- info->bpc = 0;
- info->color_formats = 0;
-
- /* Only defined for 1.4 with digital displays */
- if (edid->revision < 4)
- return;
-
- if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
- return;
-
- switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
- case DRM_EDID_DIGITAL_DEPTH_6:
- info->bpc = 6;
- break;
- case DRM_EDID_DIGITAL_DEPTH_8:
- info->bpc = 8;
- break;
- case DRM_EDID_DIGITAL_DEPTH_10:
- info->bpc = 10;
- break;
- case DRM_EDID_DIGITAL_DEPTH_12:
- info->bpc = 12;
- break;
- case DRM_EDID_DIGITAL_DEPTH_14:
- info->bpc = 14;
- break;
- case DRM_EDID_DIGITAL_DEPTH_16:
- info->bpc = 16;
- break;
- case DRM_EDID_DIGITAL_DEPTH_UNDEF:
- default:
- info->bpc = 0;
- break;
- }
-
- info->color_formats = DRM_COLOR_FORMAT_RGB444;
- if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444)
- info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
- if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
- info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
-
- /* Get data from CEA blocks if present */
- edid_ext = drm_find_cea_extension(edid);
- if (!edid_ext)
- return;
-
- info->cea_rev = edid_ext[1];
-}
-
/**
* drm_add_edid_modes - add modes from EDID data, if available
* @connector: connector we're probing
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
edid_fixup_preferred(connector, quirks);
- drm_add_display_info(edid, &connector->display_info);
+ connector->display_info.width_mm = edid->width_cm * 10;
+ connector->display_info.height_mm = edid->height_cm * 10;
return num_modes;
}
int hdisplay, int vdisplay)
{
int i, count, num_modes = 0;
- struct drm_display_mode *mode;
+ struct drm_display_mode *mode, *ptr;
struct drm_device *dev = connector->dev;
count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
vdisplay = 0;
for (i = 0; i < count; i++) {
- const struct drm_display_mode *ptr = &drm_dmt_modes[i];
+ ptr = &drm_dmt_modes[i];
if (hdisplay && vdisplay) {
/*
* Only when two are valid, they will be used to check
}
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
+/**
+ * drm_fb_helper_connector_parse_command_line - parse command line for connector
+ * @connector - connector to parse line for
+ * @mode_option - per connector mode option
+ *
+ * This parses the connector specific then generic command lines for
+ * modes and options to configure the connector.
+ *
+ * This uses the same parameters as the fb modedb.c, except for extra
+ * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
+ *
+ * enable/enable Digital/disable bit at the end
+ */
+static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
+ const char *mode_option)
+{
+ const char *name;
+ unsigned int namelen;
+ int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
+ unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
+ int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
+ int i;
+ enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
+ struct drm_fb_helper_cmdline_mode *cmdline_mode;
+ struct drm_connector *connector;
+
+ if (!fb_helper_conn)
+ return false;
+ connector = fb_helper_conn->connector;
+
+ cmdline_mode = &fb_helper_conn->cmdline_mode;
+ if (!mode_option)
+ mode_option = fb_mode_option;
+
+ if (!mode_option) {
+ cmdline_mode->specified = false;
+ return false;
+ }
+
+ name = mode_option;
+ namelen = strlen(name);
+ for (i = namelen-1; i >= 0; i--) {
+ switch (name[i]) {
+ case '@':
+ namelen = i;
+ if (!refresh_specified && !bpp_specified &&
+ !yres_specified) {
+ refresh = simple_strtol(&name[i+1], NULL, 10);
+ refresh_specified = 1;
+ if (cvt || rb)
+ cvt = 0;
+ } else
+ goto done;
+ break;
+ case '-':
+ namelen = i;
+ if (!bpp_specified && !yres_specified) {
+ bpp = simple_strtol(&name[i+1], NULL, 10);
+ bpp_specified = 1;
+ if (cvt || rb)
+ cvt = 0;
+ } else
+ goto done;
+ break;
+ case 'x':
+ if (!yres_specified) {
+ yres = simple_strtol(&name[i+1], NULL, 10);
+ yres_specified = 1;
+ } else
+ goto done;
+ case '0' ... '9':
+ break;
+ case 'M':
+ if (!yres_specified)
+ cvt = 1;
+ break;
+ case 'R':
+ if (cvt)
+ rb = 1;
+ break;
+ case 'm':
+ if (!cvt)
+ margins = 1;
+ break;
+ case 'i':
+ if (!cvt)
+ interlace = 1;
+ break;
+ case 'e':
+ force = DRM_FORCE_ON;
+ break;
+ case 'D':
+ if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
+ (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+ force = DRM_FORCE_ON;
+ else
+ force = DRM_FORCE_ON_DIGITAL;
+ break;
+ case 'd':
+ force = DRM_FORCE_OFF;
+ break;
+ default:
+ goto done;
+ }
+ }
+ if (i < 0 && yres_specified) {
+ xres = simple_strtol(name, NULL, 10);
+ res_specified = 1;
+ }
+done:
+
+ DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+ drm_get_connector_name(connector), xres, yres,
+ (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
+ "", (margins) ? " with margins" : "", (interlace) ?
+ " interlaced" : "");
+
+ if (force) {
+ const char *s;
+ switch (force) {
+ case DRM_FORCE_OFF: s = "OFF"; break;
+ case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
+ default:
+ case DRM_FORCE_ON: s = "ON"; break;
+ }
+
+ DRM_INFO("forcing %s connector %s\n",
+ drm_get_connector_name(connector), s);
+ connector->force = force;
+ }
+
+ if (res_specified) {
+ cmdline_mode->specified = true;
+ cmdline_mode->xres = xres;
+ cmdline_mode->yres = yres;
+ }
+
+ if (refresh_specified) {
+ cmdline_mode->refresh_specified = true;
+ cmdline_mode->refresh = refresh;
+ }
+
+ if (bpp_specified) {
+ cmdline_mode->bpp_specified = true;
+ cmdline_mode->bpp = bpp;
+ }
+ cmdline_mode->rb = rb ? true : false;
+ cmdline_mode->cvt = cvt ? true : false;
+ cmdline_mode->interlace = interlace ? true : false;
+
+ return true;
+}
+
static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
{
struct drm_fb_helper_connector *fb_helper_conn;
int i;
for (i = 0; i < fb_helper->connector_count; i++) {
- struct drm_cmdline_mode *mode;
- struct drm_connector *connector;
char *option = NULL;
fb_helper_conn = fb_helper->connector_info[i];
- connector = fb_helper_conn->connector;
- mode = &fb_helper_conn->cmdline_mode;
/* do something on return - turn off connector maybe */
- if (fb_get_options(drm_get_connector_name(connector), &option))
+ if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
continue;
- if (drm_mode_parse_command_line_for_connector(option,
- connector,
- mode)) {
- if (mode->force) {
- const char *s;
- switch (mode->force) {
- case DRM_FORCE_OFF: s = "OFF"; break;
- case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
- default:
- case DRM_FORCE_ON: s = "ON"; break;
- }
-
- DRM_INFO("forcing %s connector %s\n",
- drm_get_connector_name(connector), s);
- connector->force = mode->force;
- }
-
- DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
- drm_get_connector_name(connector),
- mode->xres, mode->yres,
- mode->refresh_specified ? mode->refresh : 60,
- mode->rb ? " reduced blanking" : "",
- mode->margins ? " with margins" : "",
- mode->interlace ? " interlaced" : "");
- }
-
+ drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
}
return 0;
}
}
EXPORT_SYMBOL(drm_fb_helper_debug_leave);
-bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
-{
- bool error = false;
- int i, ret;
- for (i = 0; i < fb_helper->crtc_count; i++) {
- struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
- ret = drm_crtc_helper_set_config(mode_set);
- if (ret)
- error = true;
- }
- return error;
-}
-EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
-
bool drm_fb_helper_force_kernel_mode(void)
{
+ int i = 0;
bool ret, error = false;
struct drm_fb_helper *helper;
return false;
list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
- if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
- continue;
-
- ret = drm_fb_helper_restore_fbdev_mode(helper);
- if (ret)
- error = true;
+ for (i = 0; i < helper->crtc_count; i++) {
+ struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
+ ret = drm_crtc_helper_set_config(mode_set);
+ if (ret)
+ error = true;
+ }
}
return error;
}
{
printk(KERN_ERR "panic occurred, switching back to text console\n");
return drm_fb_helper_force_kernel_mode();
+ return 0;
}
EXPORT_SYMBOL(drm_fb_helper_panic);
value = (red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
- if (info->var.transp.length > 0) {
- u32 mask = (1 << info->var.transp.length) - 1;
- mask <<= info->var.transp.offset;
- value |= mask;
- }
palette[regno] = value;
return 0;
}
struct drm_crtc_helper_funcs *crtc_funcs;
u16 *red, *green, *blue, *transp;
struct drm_crtc *crtc;
- int i, j, rc = 0;
+ int i, rc = 0;
int start;
for (i = 0; i < fb_helper->crtc_count; i++) {
transp = cmap->transp;
start = cmap->start;
- for (j = 0; j < cmap->len; j++) {
+ for (i = 0; i < cmap->len; i++) {
u16 hred, hgreen, hblue, htransp = 0xffff;
hred = *red++;
/* first up get a count of crtcs now in use and new min/maxes width/heights */
for (i = 0; i < fb_helper->connector_count; i++) {
struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
- struct drm_cmdline_mode *cmdline_mode;
+ struct drm_fb_helper_cmdline_mode *cmdline_mode;
cmdline_mode = &fb_helper_conn->cmdline_mode;
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
FB_VISUAL_TRUECOLOR;
- info->fix.mmio_start = 0;
- info->fix.mmio_len = 0;
info->fix.type_aux = 0;
info->fix.xpanstep = 1; /* doing it in hw */
info->fix.ypanstep = 1; /* doing it in hw */
info->var.xres_virtual = fb->width;
info->var.yres_virtual = fb->height;
info->var.bits_per_pixel = fb->bits_per_pixel;
- info->var.accel_flags = FB_ACCELF_TEXT;
info->var.xoffset = 0;
info->var.yoffset = 0;
info->var.activate = FB_ACTIVATE_NOW;
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
{
- struct drm_cmdline_mode *cmdline_mode;
+ struct drm_fb_helper_cmdline_mode *cmdline_mode;
cmdline_mode = &fb_connector->cmdline_mode;
return cmdline_mode->specified;
}
static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
int width, int height)
{
- struct drm_cmdline_mode *cmdline_mode;
+ struct drm_fb_helper_cmdline_mode *cmdline_mode;
struct drm_display_mode *mode = NULL;
cmdline_mode = &fb_helper_conn->cmdline_mode;
}
create_mode:
- mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
- cmdline_mode);
+ if (cmdline_mode->cvt)
+ mode = drm_cvt_mode(fb_helper_conn->connector->dev,
+ cmdline_mode->xres, cmdline_mode->yres,
+ cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
+ cmdline_mode->rb, cmdline_mode->interlace,
+ cmdline_mode->margins);
+ else
+ mode = drm_gtf_mode(fb_helper_conn->connector->dev,
+ cmdline_mode->xres, cmdline_mode->yres,
+ cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
+ cmdline_mode->interlace,
+ cmdline_mode->margins);
+ drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
list_add(&mode->head, &fb_helper_conn->connector->modes);
return mode;
}
}
EXPORT_SYMBOL(drm_fb_helper_initial_config);
-/**
- * drm_fb_helper_hotplug_event - respond to a hotplug notification by
- * probing all the outputs attached to the fb.
- * @fb_helper: the drm_fb_helper
- *
- * LOCKING:
- * Called at runtime, must take mode config lock.
- *
- * Scan the connectors attached to the fb_helper and try to put together a
- * setup after *notification of a change in output configuration.
- *
- * RETURNS:
- * 0 on success and a non-zero error code otherwise.
- */
-int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
+bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
{
- struct drm_device *dev = fb_helper->dev;
int count = 0;
u32 max_width, max_height, bpp_sel;
bool bound = false, crtcs_bound = false;
struct drm_crtc *crtc;
if (!fb_helper->fb)
- return 0;
+ return false;
- mutex_lock(&dev->mode_config.mutex);
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
if (crtc->fb)
crtcs_bound = true;
if (crtc->fb == fb_helper->fb)
if (!bound && crtcs_bound) {
fb_helper->delayed_hotplug = true;
- mutex_unlock(&dev->mode_config.mutex);
- return 0;
+ return false;
}
DRM_DEBUG_KMS("\n");
count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
max_height);
drm_setup_crtcs(fb_helper);
- mutex_unlock(&dev->mode_config.mutex);
return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
}
EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
-/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
- * but the module doesn't depend on any fb console symbols. At least
- * attempt to load fbcon to avoid leaving the system without a usable console.
- */
-#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
-static int __init drm_fb_helper_modinit(void)
-{
- const char *name = "fbcon";
- struct module *fbcon;
-
- mutex_lock(&module_mutex);
- fbcon = find_module(name);
- mutex_unlock(&module_mutex);
-
- if (!fbcon)
- request_module_nowait(name);
- return 0;
-}
-
-module_init(drm_fb_helper_modinit);
-#endif
return -EBUSY; /* No exclusive opens */
if (!drm_cpu_valid())
return -EINVAL;
- if (dev->switch_power_state != DRM_SWITCH_POWER_ON)
- return -EINVAL;
DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id);
#include <linux/module.h>
#include <linux/mman.h>
#include <linux/pagemap.h>
-#include <linux/shmem_fs.h>
#include "drmP.h"
/** @file drm_gem.c
dev->mm_private = mm;
- if (drm_ht_create(&mm->offset_hash, 12)) {
+ if (drm_ht_create(&mm->offset_hash, 19)) {
kfree(mm);
return -ENOMEM;
}
}
/**
- * Initialize an already allocated GEM object of the specified size with
+ * Initialize an already allocate GEM object of the specified size with
* shmfs backing store.
*/
int drm_gem_object_init(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_gem_object_init);
-/**
- * Initialize an already allocated GEM object of the specified size with
- * no GEM provided backing store. Instead the caller is responsible for
- * backing the object and handling it.
- */
-int drm_gem_private_object_init(struct drm_device *dev,
- struct drm_gem_object *obj, size_t size)
-{
- BUG_ON((size & (PAGE_SIZE - 1)) != 0);
-
- obj->dev = dev;
- obj->filp = NULL;
-
- kref_init(&obj->refcount);
- atomic_set(&obj->handle_count, 0);
- obj->size = size;
-
- return 0;
-}
-EXPORT_SYMBOL(drm_gem_private_object_init);
-
/**
* Allocate a GEM object of the specified size with shmfs backing store
*/
/**
* Removes the mapping from handle to filp for this object.
*/
-int
+static int
drm_gem_handle_delete(struct drm_file *filp, u32 handle)
{
struct drm_device *dev;
idr_remove(&filp->object_idr, handle);
spin_unlock(&filp->table_lock);
- if (dev->driver->gem_close_object)
- dev->driver->gem_close_object(obj, filp);
drm_gem_object_handle_unreference_unlocked(obj);
return 0;
}
-EXPORT_SYMBOL(drm_gem_handle_delete);
/**
* Create a handle for this object. This adds a handle reference
struct drm_gem_object *obj,
u32 *handlep)
{
- struct drm_device *dev = obj->dev;
- int ret;
+ int ret;
/*
* Get the user-visible handle using idr.
return ret;
drm_gem_object_handle_reference(obj);
-
- if (dev->driver->gem_open_object) {
- ret = dev->driver->gem_open_object(obj, file_priv);
- if (ret) {
- drm_gem_handle_delete(file_priv, *handlep);
- return ret;
- }
- }
-
return 0;
}
EXPORT_SYMBOL(drm_gem_handle_create);
static int
drm_gem_object_release_handle(int id, void *ptr, void *data)
{
- struct drm_file *file_priv = data;
struct drm_gem_object *obj = ptr;
- struct drm_device *dev = obj->dev;
-
- if (dev->driver->gem_close_object)
- dev->driver->gem_close_object(obj, file_priv);
drm_gem_object_handle_unreference_unlocked(obj);
drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
{
idr_for_each(&file_private->object_idr,
- &drm_gem_object_release_handle, file_private);
+ &drm_gem_object_release_handle, NULL);
idr_remove_all(&file_private->object_idr);
idr_destroy(&file_private->object_idr);
void
drm_gem_object_release(struct drm_gem_object *obj)
{
- if (obj->filp)
- fput(obj->filp);
+ fput(obj->filp);
}
EXPORT_SYMBOL(drm_gem_object_release);
void drm_gem_vm_close(struct vm_area_struct *vma)
{
struct drm_gem_object *obj = vma->vm_private_data;
- struct drm_device *dev = obj->dev;
- mutex_lock(&dev->struct_mutex);
+ mutex_lock(&obj->dev->struct_mutex);
drm_vm_close_locked(vma);
drm_gem_object_unreference(obj);
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&obj->dev->struct_mutex);
}
EXPORT_SYMBOL(drm_gem_vm_close);
int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
{
- unsigned int size = 1 << order;
+ unsigned int i;
+ ht->size = 1 << order;
ht->order = order;
+ ht->fill = 0;
ht->table = NULL;
- if (size <= PAGE_SIZE / sizeof(*ht->table))
- ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL);
- else
- ht->table = vzalloc(size*sizeof(*ht->table));
+ ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE);
+ if (!ht->use_vmalloc) {
+ ht->table = kcalloc(ht->size, sizeof(*ht->table), GFP_KERNEL);
+ }
+ if (!ht->table) {
+ ht->use_vmalloc = 1;
+ ht->table = vmalloc(ht->size*sizeof(*ht->table));
+ }
if (!ht->table) {
DRM_ERROR("Out of memory for hash table\n");
return -ENOMEM;
}
+ for (i=0; i< ht->size; ++i) {
+ INIT_HLIST_HEAD(&ht->table[i]);
+ }
return 0;
}
EXPORT_SYMBOL(drm_ht_create);
list = drm_ht_find_key(ht, key);
if (list) {
hlist_del_init(list);
+ ht->fill--;
return 0;
}
return -EINVAL;
int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item)
{
hlist_del_init(&item->head);
+ ht->fill--;
return 0;
}
EXPORT_SYMBOL(drm_ht_remove_item);
void drm_ht_remove(struct drm_open_hash *ht)
{
if (ht->table) {
- if ((PAGE_SIZE / sizeof(*ht->table)) >> ht->order)
- kfree(ht->table);
- else
+ if (ht->use_vmalloc)
vfree(ht->table);
+ else
+ kfree(ht->table);
ht->table = NULL;
}
}
struct drm_minor *minor = node->minor;
struct drm_device *dev = minor->dev;
struct drm_master *master = minor->master;
- const char *bus_name;
+
if (!master)
return 0;
- bus_name = dev->driver->bus->get_name(dev);
- if (master->unique) {
- seq_printf(m, "%s %s %s\n",
- bus_name,
- dev_name(dev->dev), master->unique);
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
+ if (master->unique) {
+ seq_printf(m, "%s %s %s\n",
+ dev->driver->platform_device->name,
+ dev_name(dev->dev), master->unique);
+ } else {
+ seq_printf(m, "%s\n",
+ dev->driver->platform_device->name);
+ }
} else {
- seq_printf(m, "%s %s\n",
- bus_name, dev_name(dev->dev));
+ if (master->unique) {
+ seq_printf(m, "%s %s %s\n",
+ dev->driver->pci_driver.name,
+ dev_name(dev->dev), master->unique);
+ } else {
+ seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
+ dev_name(dev->dev));
+ }
}
+
return 0;
}
#endif
mutex_lock(&dev->struct_mutex);
- seq_printf(m, "vma use count: %d, high_memory = %pK, 0x%pK\n",
+ seq_printf(m, "vma use count: %d, high_memory = %p, 0x%08llx\n",
atomic_read(&dev->vma_count),
- high_memory, (void *)virt_to_phys(high_memory));
+ high_memory, (u64)virt_to_phys(high_memory));
list_for_each_entry(pt, &dev->vmalist, head) {
vma = pt->vma;
if (!vma)
continue;
seq_printf(m,
- "\n%5d 0x%pK-0x%pK %c%c%c%c%c%c 0x%08lx000",
- pt->pid,
- (void *)vma->vm_start, (void *)vma->vm_end,
+ "\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
+ pt->pid, vma->vm_start, vma->vm_end,
vma->vm_flags & VM_READ ? 'r' : '-',
vma->vm_flags & VM_WRITE ? 'w' : '-',
vma->vm_flags & VM_EXEC ? 'x' : '-',
* IN THE SOFTWARE.
*/
#include <linux/compat.h>
-#include <linux/ratelimit.h>
#include "drmP.h"
#include "drm_core.h"
return -EFAULT;
m32.handle = (unsigned long)handle;
- if (m32.handle != (unsigned long)handle)
- printk_ratelimited(KERN_ERR "compat_drm_addmap truncated handle"
- " %p for type %d offset %x\n",
- handle, m32.type, m32.offset);
+ if (m32.handle != (unsigned long)handle && printk_ratelimit())
+ printk(KERN_ERR "compat_drm_addmap truncated handle"
+ " %p for type %d offset %x\n",
+ handle, m32.type, m32.offset);
if (copy_to_user(argp, &m32, sizeof(m32)))
return -EFAULT;
{
struct drm_unique *u = data;
struct drm_master *master = file_priv->master;
- int ret;
+ int domain, bus, slot, func, ret;
if (master->unique_len || master->unique)
return -EBUSY;
if (!u->unique_len || u->unique_len > 1024)
return -EINVAL;
- if (!dev->driver->bus->set_unique)
- return -EINVAL;
+ master->unique_len = u->unique_len;
+ master->unique_size = u->unique_len + 1;
+ master->unique = kmalloc(master->unique_size, GFP_KERNEL);
+ if (!master->unique) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (copy_from_user(master->unique, u->unique, master->unique_len)) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ master->unique[master->unique_len] = '\0';
- ret = dev->driver->bus->set_unique(dev, master, u);
- if (ret)
+ dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
+ strlen(master->unique) + 2, GFP_KERNEL);
+ if (!dev->devname) {
+ ret = -ENOMEM;
goto err;
+ }
+
+ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
+ master->unique);
+
+ /* Return error if the busid submitted doesn't match the device's actual
+ * busid.
+ */
+ ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+ if (ret != 3) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ domain = bus >> 8;
+ bus &= 0xff;
+
+ if ((domain != drm_get_pci_domain(dev)) ||
+ (bus != dev->pdev->bus->number) ||
+ (slot != PCI_SLOT(dev->pdev->devfn)) ||
+ (func != PCI_FUNC(dev->pdev->devfn))) {
+ ret = -EINVAL;
+ goto err;
+ }
return 0;
static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_master *master = file_priv->master;
- int ret;
+ int len, ret;
if (master->unique != NULL)
drm_unset_busid(dev, master);
- ret = dev->driver->bus->set_busid(dev, master);
- if (ret)
- goto err;
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
+ master->unique_len = 10 + strlen(dev->platformdev->name);
+ master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
+
+ if (master->unique == NULL)
+ return -ENOMEM;
+
+ len = snprintf(master->unique, master->unique_len,
+ "platform:%s", dev->platformdev->name);
+
+ if (len > master->unique_len) {
+ DRM_ERROR("Unique buffer overflowed\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dev->devname =
+ kmalloc(strlen(dev->platformdev->name) +
+ master->unique_len + 2, GFP_KERNEL);
+
+ if (dev->devname == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ sprintf(dev->devname, "%s@%s", dev->platformdev->name,
+ master->unique);
+
+ } else {
+ master->unique_len = 40;
+ master->unique_size = master->unique_len;
+ master->unique = kmalloc(master->unique_size, GFP_KERNEL);
+ if (master->unique == NULL)
+ return -ENOMEM;
+
+ len = snprintf(master->unique, master->unique_len,
+ "pci:%04x:%02x:%02x.%d",
+ drm_get_pci_domain(dev),
+ dev->pdev->bus->number,
+ PCI_SLOT(dev->pdev->devfn),
+ PCI_FUNC(dev->pdev->devfn));
+ if (len >= master->unique_len) {
+ DRM_ERROR("buffer overflow");
+ ret = -EINVAL;
+ goto err;
+ } else
+ master->unique_len = len;
+
+ dev->devname =
+ kmalloc(strlen(dev->driver->pci_driver.name) +
+ master->unique_len + 2, GFP_KERNEL);
+
+ if (dev->devname == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
+ master->unique);
+ }
+
return 0;
+
err:
drm_unset_busid(dev, master);
return ret;
return 0;
}
-/**
- * Get device/driver capabilities
- */
-int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- struct drm_get_cap *req = data;
-
- req->value = 0;
- switch (req->capability) {
- case DRM_CAP_DUMB_BUFFER:
- if (dev->driver->dumb_create)
- req->value = 1;
- break;
- case DRM_CAP_VBLANK_HIGH_CRTC:
- req->value = 1;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
/**
* Setversion ioctl.
*
#include <linux/slab.h>
#include <linux/vgaarb.h>
-
-/* Access macro for slots in vblank timestamp ringbuffer. */
-#define vblanktimestamp(dev, crtc, count) ( \
- (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \
- ((count) % DRM_VBLANKTIME_RBSIZE)])
-
-/* Retry timestamp calculation up to 3 times to satisfy
- * drm_timestamp_precision before giving up.
- */
-#define DRM_TIMESTAMP_MAXRETRIES 3
-
-/* Threshold in nanoseconds for detection of redundant
- * vblank irq in drm_handle_vblank(). 1 msec should be ok.
- */
-#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
-
/**
* Get interrupt from bus id.
*
{
struct drm_irq_busid *p = data;
- if (!dev->driver->bus->irq_by_busid)
+ if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
return -EINVAL;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
- return dev->driver->bus->irq_by_busid(dev, p);
-}
-
-/*
- * Clear vblank timestamp buffer for a crtc.
- */
-static void clear_vblank_timestamps(struct drm_device *dev, int crtc)
-{
- memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0,
- DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval));
-}
-
-/*
- * Disable vblank irq's on crtc, make sure that last vblank count
- * of hardware and corresponding consistent software vblank counter
- * are preserved, even if there are any spurious vblank irq's after
- * disable.
- */
-static void vblank_disable_and_save(struct drm_device *dev, int crtc)
-{
- unsigned long irqflags;
- u32 vblcount;
- s64 diff_ns;
- int vblrc;
- struct timeval tvblank;
-
- /* Prevent vblank irq processing while disabling vblank irqs,
- * so no updates of timestamps or count can happen after we've
- * disabled. Needed to prevent races in case of delayed irq's.
- * Disable preemption, so vblank_time_lock is held as short as
- * possible, even under a kernel with PREEMPT_RT patches.
- */
- preempt_disable();
- spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
-
- dev->driver->disable_vblank(dev, crtc);
- dev->vblank_enabled[crtc] = 0;
-
- /* No further vblank irq's will be processed after
- * this point. Get current hardware vblank count and
- * vblank timestamp, repeat until they are consistent.
- *
- * FIXME: There is still a race condition here and in
- * drm_update_vblank_count() which can cause off-by-one
- * reinitialization of software vblank counter. If gpu
- * vblank counter doesn't increment exactly at the leading
- * edge of a vblank interval, then we can lose 1 count if
- * we happen to execute between start of vblank and the
- * delayed gpu counter increment.
- */
- do {
- dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
- vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0);
- } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc));
+ if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
+ (p->busnum & 0xff) != dev->pdev->bus->number ||
+ p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
+ return -EINVAL;
- /* Compute time difference to stored timestamp of last vblank
- * as updated by last invocation of drm_handle_vblank() in vblank irq.
- */
- vblcount = atomic_read(&dev->_vblank_count[crtc]);
- diff_ns = timeval_to_ns(&tvblank) -
- timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
-
- /* If there is at least 1 msec difference between the last stored
- * timestamp and tvblank, then we are currently executing our
- * disable inside a new vblank interval, the tvblank timestamp
- * corresponds to this new vblank interval and the irq handler
- * for this vblank didn't run yet and won't run due to our disable.
- * Therefore we need to do the job of drm_handle_vblank() and
- * increment the vblank counter by one to account for this vblank.
- *
- * Skip this step if there isn't any high precision timestamp
- * available. In that case we can't account for this and just
- * hope for the best.
- */
- if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {
- atomic_inc(&dev->_vblank_count[crtc]);
- smp_mb__after_atomic_inc();
- }
+ p->irq = dev->pdev->irq;
- /* Invalidate all timestamps while vblank irq's are off. */
- clear_vblank_timestamps(dev, crtc);
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
+ p->irq);
- spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
- preempt_enable();
+ return 0;
}
static void vblank_disable_fn(unsigned long arg)
if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
dev->vblank_enabled[i]) {
DRM_DEBUG("disabling vblank on crtc %d\n", i);
- vblank_disable_and_save(dev, i);
+ dev->last_vblank[i] =
+ dev->driver->get_vblank_counter(dev, i);
+ dev->driver->disable_vblank(dev, i);
+ dev->vblank_enabled[i] = 0;
}
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
kfree(dev->last_vblank);
kfree(dev->last_vblank_wait);
kfree(dev->vblank_inmodeset);
- kfree(dev->_vblank_time);
dev->num_crtcs = 0;
}
setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
(unsigned long)dev);
spin_lock_init(&dev->vbl_lock);
- spin_lock_init(&dev->vblank_time_lock);
-
dev->num_crtcs = num_crtcs;
dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs,
if (!dev->vblank_inmodeset)
goto err;
- dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE,
- sizeof(struct timeval), GFP_KERNEL);
- if (!dev->_vblank_time)
- goto err;
-
- DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n");
-
- /* Driver specific high-precision vblank timestamping supported? */
- if (dev->driver->get_vblank_timestamp)
- DRM_INFO("Driver supports precise vblank timestamp query.\n");
- else
- DRM_INFO("No driver support for vblank timestamp query.\n");
-
/* Zero per-crtc vblank stuff */
for (i = 0; i < num_crtcs; i++) {
init_waitqueue_head(&dev->vbl_queue[i]);
if (!dev->irq_enabled)
return;
- if (state) {
- if (dev->driver->irq_uninstall)
- dev->driver->irq_uninstall(dev);
- } else {
- if (dev->driver->irq_preinstall)
- dev->driver->irq_preinstall(dev);
- if (dev->driver->irq_postinstall)
- dev->driver->irq_postinstall(dev);
+ if (state)
+ dev->driver->irq_uninstall(dev);
+ else {
+ dev->driver->irq_preinstall(dev);
+ dev->driver->irq_postinstall(dev);
}
}
DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
/* Before installing handler */
- if (dev->driver->irq_preinstall)
- dev->driver->irq_preinstall(dev);
+ dev->driver->irq_preinstall(dev);
/* Install handler */
if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
/* After installing handler */
- if (dev->driver->irq_postinstall)
- ret = dev->driver->irq_postinstall(dev);
-
+ ret = dev->driver->irq_postinstall(dev);
if (ret < 0) {
mutex_lock(&dev->struct_mutex);
dev->irq_enabled = 0;
mutex_unlock(&dev->struct_mutex);
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- vga_client_register(dev->pdev, NULL, NULL, NULL);
- free_irq(drm_dev_to_irq(dev), dev);
}
return ret;
*
* Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.
*/
-int drm_irq_uninstall(struct drm_device *dev)
+int drm_irq_uninstall(struct drm_device * dev)
{
unsigned long irqflags;
int irq_enabled, i;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
vga_client_register(dev->pdev, NULL, NULL, NULL);
- if (dev->driver->irq_uninstall)
- dev->driver->irq_uninstall(dev);
+ dev->driver->irq_uninstall(dev);
free_irq(drm_dev_to_irq(dev), dev);
{
struct drm_control *ctl = data;
- /* if we haven't irq we fallback for compatibility reasons -
- * this used to be a separate function in drm_dma.h
- */
+ /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */
switch (ctl->func) {
}
}
-/**
- * drm_calc_timestamping_constants - Calculate and
- * store various constants which are later needed by
- * vblank and swap-completion timestamping, e.g, by
- * drm_calc_vbltimestamp_from_scanoutpos().
- * They are derived from crtc's true scanout timing,
- * so they take things like panel scaling or other
- * adjustments into account.
- *
- * @crtc drm_crtc whose timestamp constants should be updated.
- *
- */
-void drm_calc_timestamping_constants(struct drm_crtc *crtc)
-{
- s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
- u64 dotclock;
-
- /* Dot clock in Hz: */
- dotclock = (u64) crtc->hwmode.clock * 1000;
-
- /* Fields of interlaced scanout modes are only halve a frame duration.
- * Double the dotclock to get halve the frame-/line-/pixelduration.
- */
- if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)
- dotclock *= 2;
-
- /* Valid dotclock? */
- if (dotclock > 0) {
- /* Convert scanline length in pixels and video dot clock to
- * line duration, frame duration and pixel duration in
- * nanoseconds:
- */
- pixeldur_ns = (s64) div64_u64(1000000000, dotclock);
- linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal *
- 1000000000), dotclock);
- framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns;
- } else
- DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
- crtc->base.id);
-
- crtc->pixeldur_ns = pixeldur_ns;
- crtc->linedur_ns = linedur_ns;
- crtc->framedur_ns = framedur_ns;
-
- DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
- crtc->base.id, crtc->hwmode.crtc_htotal,
- crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay);
- DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
- 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)
-{
- struct timeval stime, raw_time;
- 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;
- }
-
- /* Get current scanout position with system timestamp.
- * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times
- * if single query takes longer than max_error nanoseconds.
- *
- * This guarantees a tight bound on maximum error if
- * code gets preempted or delayed for some reason.
- */
- for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) {
- /* Disable preemption to make it very likely to
- * succeed in the first iteration even on PREEMPT_RT kernel.
- */
- preempt_disable();
-
- /* Get system timestamp before query. */
- do_gettimeofday(&stime);
-
- /* Get vertical and horizontal scanout pos. vpos, hpos. */
- vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos);
-
- /* Get system timestamp after query. */
- do_gettimeofday(&raw_time);
-
- preempt_enable();
-
- /* Return as no-op if scanout query unsupported or failed. */
- if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
- DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n",
- crtc, vbl_status);
- return -EIO;
- }
-
- duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime);
-
- /* Accept result with < max_error nsecs timing uncertainty. */
- if (duration_ns <= (s64) *max_error)
- break;
- }
-
- /* Noisy system timing? */
- if (i == DRM_TIMESTAMP_MAXRETRIES) {
- DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n",
- crtc, (int) duration_ns/1000, *max_error/1000, i);
- }
-
- /* Return upper bound of timestamp precision error. */
- *max_error = (int) duration_ns;
-
- /* Check if in vblank area:
- * vpos is >=0 in video scanout area, but negative
- * within vblank area, counting down the number of lines until
- * start of scanout.
- */
- invbl = vbl_status & DRM_SCANOUTPOS_INVBL;
-
- /* Convert scanout position into elapsed time at raw_time query
- * since start of scanout at first display scanline. delta_ns
- * can be negative if start of scanout hasn't happened yet.
- */
- delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns;
-
- /* Is vpos outside nominal vblank area, but less than
- * 1/100 of a frame height away from start of vblank?
- * If so, assume this isn't a massively delayed vblank
- * interrupt, but a vblank interrupt that fired a few
- * microseconds before true start of vblank. Compensate
- * by adding a full frame duration to the final timestamp.
- * Happens, e.g., on ATI R500, R600.
- *
- * We only do this if DRM_CALLED_FROM_VBLIRQ.
- */
- if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl &&
- ((vdisplay - vpos) < vtotal / 100)) {
- delta_ns = delta_ns - framedur_ns;
-
- /* Signal this correction as "applied". */
- vbl_status |= 0x8;
- }
-
- /* Subtract time delta from raw timestamp to get final
- * vblank_time timestamp for end of vblank.
- */
- *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);
-
- DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
- crtc, (int)vbl_status, hpos, vpos,
- (long)raw_time.tv_sec, (long)raw_time.tv_usec,
- (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
- (int)duration_ns/1000, i);
-
- vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
- if (invbl)
- vbl_status |= DRM_VBLANKTIME_INVBL;
-
- return vbl_status;
-}
-EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
-
-/**
- * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
- * vblank interval.
- *
- * @dev: DRM device
- * @crtc: which crtc's vblank timestamp to retrieve
- * @tvblank: Pointer to target 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.
- *
- * Fetches the system timestamp corresponding to the time of the most recent
- * vblank interval on specified crtc. May call into kms-driver to
- * compute the timestamp with a high-precision GPU specific method.
- *
- * Returns zero if timestamp originates from uncorrected do_gettimeofday()
- * call, i.e., it isn't very precisely locked to the true vblank.
- *
- * Returns non-zero if timestamp is considered to be very precise.
- */
-u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
- struct timeval *tvblank, unsigned flags)
-{
- int ret = 0;
-
- /* Define requested maximum error on timestamps (nanoseconds). */
- int max_error = (int) drm_timestamp_precision * 1000;
-
- /* Query driver if possible and precision timestamping enabled. */
- if (dev->driver->get_vblank_timestamp && (max_error > 0)) {
- ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error,
- tvblank, flags);
- if (ret > 0)
- return (u32) ret;
- }
-
- /* GPU high precision timestamp query unsupported or failed.
- * Return gettimeofday timestamp as best estimate.
- */
- do_gettimeofday(tvblank);
-
- return 0;
-}
-EXPORT_SYMBOL(drm_get_last_vbltimestamp);
-
/**
* drm_vblank_count - retrieve "cooked" vblank counter value
* @dev: DRM device
}
EXPORT_SYMBOL(drm_vblank_count);
-/**
- * drm_vblank_count_and_time - retrieve "cooked" vblank counter value
- * and the system timestamp corresponding to that vblank counter value.
- *
- * @dev: DRM device
- * @crtc: which counter to retrieve
- * @vblanktime: Pointer to struct timeval to receive the vblank timestamp.
- *
- * Fetches the "cooked" vblank count value that represents the number of
- * vblank events since the system was booted, including lost events due to
- * modesetting activity. Returns corresponding system timestamp of the time
- * of the vblank interval that corresponds to the current value vblank counter
- * value.
- */
-u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
- struct timeval *vblanktime)
-{
- u32 cur_vblank;
-
- /* Read timestamp from slot of _vblank_time ringbuffer
- * that corresponds to current vblank count. Retry if
- * count has incremented during readout. This works like
- * a seqlock.
- */
- do {
- cur_vblank = atomic_read(&dev->_vblank_count[crtc]);
- *vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
- smp_rmb();
- } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc]));
-
- return cur_vblank;
-}
-EXPORT_SYMBOL(drm_vblank_count_and_time);
-
/**
* drm_update_vblank_count - update the master vblank counter
* @dev: DRM device
*/
static void drm_update_vblank_count(struct drm_device *dev, int crtc)
{
- u32 cur_vblank, diff, tslot, rc;
- struct timeval t_vblank;
+ u32 cur_vblank, diff;
/*
* Interrupts were disabled prior to this call, so deal with counter
* NOTE! It's possible we lost a full dev->max_vblank_count events
* here if the register is small or we had vblank interrupts off for
* a long time.
- *
- * We repeat the hardware vblank counter & timestamp query until
- * we get consistent results. This to prevent races between gpu
- * updating its hardware counter while we are retrieving the
- * corresponding vblank timestamp.
*/
- do {
- cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
- rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0);
- } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));
-
- /* Deal with counter wrap */
+ cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
diff = cur_vblank - dev->last_vblank[crtc];
if (cur_vblank < dev->last_vblank[crtc]) {
diff += dev->max_vblank_count;
DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
crtc, diff);
- /* Reinitialize corresponding vblank timestamp if high-precision query
- * available. Skip this step if query unsupported or failed. Will
- * reinitialize delayed at next vblank interrupt in that case.
- */
- if (rc) {
- tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;
- vblanktimestamp(dev, crtc, tslot) = t_vblank;
- }
-
- smp_mb__before_atomic_inc();
atomic_add(diff, &dev->_vblank_count[crtc]);
- smp_mb__after_atomic_inc();
}
/**
*/
int drm_vblank_get(struct drm_device *dev, int crtc)
{
- unsigned long irqflags, irqflags2;
+ unsigned long irqflags;
int ret = 0;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Going from 0->1 means we have to enable interrupts again */
if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
- /* Disable preemption while holding vblank_time_lock. Do
- * it explicitely to guard against PREEMPT_RT kernel.
- */
- preempt_disable();
- spin_lock_irqsave(&dev->vblank_time_lock, irqflags2);
if (!dev->vblank_enabled[crtc]) {
- /* Enable vblank irqs under vblank_time_lock protection.
- * All vblank count & timestamp updates are held off
- * until we are done reinitializing master counter and
- * timestamps. Filtercode in drm_handle_vblank() will
- * prevent double-accounting of same vblank interval.
- */
ret = dev->driver->enable_vblank(dev, crtc);
- DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n",
- crtc, ret);
+ DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
if (ret)
atomic_dec(&dev->vblank_refcount[crtc]);
else {
drm_update_vblank_count(dev, crtc);
}
}
- spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2);
- preempt_enable();
} else {
if (!dev->vblank_enabled[crtc]) {
atomic_dec(&dev->vblank_refcount[crtc]);
* @crtc: which counter to give up
*
* Release ownership of a given vblank counter, turning off interrupts
- * if possible. Disable interrupts after drm_vblank_offdelay milliseconds.
+ * if possible.
*/
void drm_vblank_put(struct drm_device *dev, int crtc)
{
- BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0);
+ BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0);
/* Last user schedules interrupt disable */
- if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) &&
- (drm_vblank_offdelay > 0))
- mod_timer(&dev->vblank_disable_timer,
- jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000));
+ if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
+ mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
}
EXPORT_SYMBOL(drm_vblank_put);
void drm_vblank_off(struct drm_device *dev, int crtc)
{
- struct drm_pending_vblank_event *e, *t;
- struct timeval now;
unsigned long irqflags;
- unsigned int seq;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
- vblank_disable_and_save(dev, crtc);
+ dev->driver->disable_vblank(dev, crtc);
DRM_WAKEUP(&dev->vbl_queue[crtc]);
-
- /* Send any queued vblank events, lest the natives grow disquiet */
- seq = drm_vblank_count_and_time(dev, crtc, &now);
- list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
- if (e->pipe != crtc)
- continue;
- DRM_DEBUG("Sending premature vblank event on disable: \
- wanted %d, current %d\n",
- e->event.sequence, seq);
-
- e->event.sequence = seq;
- e->event.tv_sec = now.tv_sec;
- e->event.tv_usec = now.tv_usec;
- drm_vblank_put(dev, e->pipe);
- list_move_tail(&e->base.link, &e->base.file_priv->event_list);
- wake_up_interruptible(&e->base.file_priv->event_wait);
- trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
- e->event.sequence);
- }
-
+ dev->vblank_enabled[crtc] = 0;
+ dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
EXPORT_SYMBOL(drm_vblank_off);
struct drm_file *file_priv)
{
struct drm_modeset_ctl *modeset = data;
- int ret = 0;
- unsigned int crtc;
+ int crtc, ret = 0;
/* If drm_vblank_init() hasn't been called yet, just no-op */
if (!dev->num_crtcs)
e->base.file_priv = file_priv;
e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+ do_gettimeofday(&now);
spin_lock_irqsave(&dev->event_lock, flags);
if (file_priv->event_space < sizeof e->event) {
}
file_priv->event_space -= sizeof e->event;
- seq = drm_vblank_count_and_time(dev, pipe, &now);
-
+ seq = drm_vblank_count(dev, pipe);
if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
(seq - vblwait->request.sequence) <= (1 << 23)) {
vblwait->request.sequence = seq + 1;
e->event.sequence = vblwait->request.sequence;
if ((seq - vblwait->request.sequence) <= (1 << 23)) {
- e->event.sequence = seq;
e->event.tv_sec = now.tv_sec;
e->event.tv_usec = now.tv_usec;
drm_vblank_put(dev, pipe);
list_add_tail(&e->base.link, &e->base.file_priv->event_list);
wake_up_interruptible(&e->base.file_priv->event_wait);
- vblwait->reply.sequence = seq;
trace_drm_vblank_event_delivered(current->pid, pipe,
vblwait->request.sequence);
} else {
list_add_tail(&e->base.link, &dev->vblank_event_list);
- vblwait->reply.sequence = vblwait->request.sequence;
}
spin_unlock_irqrestore(&dev->event_lock, flags);
{
union drm_wait_vblank *vblwait = data;
int ret = 0;
- unsigned int flags, seq, crtc, high_crtc;
+ unsigned int flags, seq, crtc;
if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
return -EINVAL;
return -EINVAL;
if (vblwait->request.type &
- ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
- _DRM_VBLANK_HIGH_CRTC_MASK)) {
+ ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
vblwait->request.type,
- (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
- _DRM_VBLANK_HIGH_CRTC_MASK));
+ (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
return -EINVAL;
}
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
- high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);
- if (high_crtc)
- crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
- else
- crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
+ crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
+
if (crtc >= dev->num_crtcs)
return -EINVAL;
if (ret != -EINTR) {
struct timeval now;
- vblwait->reply.sequence = drm_vblank_count_and_time(dev, crtc, &now);
+ do_gettimeofday(&now);
+
vblwait->reply.tval_sec = now.tv_sec;
vblwait->reply.tval_usec = now.tv_usec;
-
+ vblwait->reply.sequence = drm_vblank_count(dev, crtc);
DRM_DEBUG("returning %d to client\n",
vblwait->reply.sequence);
} else {
unsigned long flags;
unsigned int seq;
- seq = drm_vblank_count_and_time(dev, crtc, &now);
+ do_gettimeofday(&now);
+ seq = drm_vblank_count(dev, crtc);
spin_lock_irqsave(&dev->event_lock, flags);
* Drivers should call this routine in their vblank interrupt handlers to
* update the vblank counter and send any signals that may be pending.
*/
-bool drm_handle_vblank(struct drm_device *dev, int crtc)
+void drm_handle_vblank(struct drm_device *dev, int crtc)
{
- u32 vblcount;
- s64 diff_ns;
- struct timeval tvblank;
- unsigned long irqflags;
-
if (!dev->num_crtcs)
- return false;
-
- /* Need timestamp lock to prevent concurrent execution with
- * vblank enable/disable, as this would cause inconsistent
- * or corrupted timestamps and vblank counts.
- */
- spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
-
- /* Vblank irq handling disabled. Nothing to do. */
- if (!dev->vblank_enabled[crtc]) {
- spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
- return false;
- }
-
- /* Fetch corresponding timestamp for this vblank interval from
- * driver and store it in proper slot of timestamp ringbuffer.
- */
-
- /* Get current timestamp and count. */
- vblcount = atomic_read(&dev->_vblank_count[crtc]);
- drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
-
- /* Compute time difference to timestamp of last vblank */
- diff_ns = timeval_to_ns(&tvblank) -
- timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
-
- /* Update vblank timestamp and count if at least
- * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds
- * difference between last stored timestamp and current
- * timestamp. A smaller difference means basically
- * identical timestamps. Happens if this vblank has
- * been already processed and this is a redundant call,
- * e.g., due to spurious vblank interrupts. We need to
- * ignore those for accounting.
- */
- if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) {
- /* Store new timestamp in ringbuffer. */
- vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;
-
- /* Increment cooked vblank count. This also atomically commits
- * the timestamp computed above.
- */
- smp_mb__before_atomic_inc();
- atomic_inc(&dev->_vblank_count[crtc]);
- smp_mb__after_atomic_inc();
- } else {
- DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
- crtc, (int) diff_ns);
- }
+ return;
+ atomic_inc(&dev->_vblank_count[crtc]);
DRM_WAKEUP(&dev->vbl_queue[crtc]);
drm_handle_vblank_events(dev, crtc);
-
- spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
- return true;
}
EXPORT_SYMBOL(drm_handle_vblank);
else {
child =
list_entry(mm->unused_nodes.next,
- struct drm_mm_node, node_list);
- list_del(&child->node_list);
+ struct drm_mm_node, free_stack);
+ list_del(&child->free_stack);
--mm->num_unused;
}
spin_unlock(&mm->unused_lock);
return ret;
}
++mm->num_unused;
- list_add_tail(&node->node_list, &mm->unused_nodes);
+ list_add_tail(&node->free_stack, &mm->unused_nodes);
}
spin_unlock(&mm->unused_lock);
return 0;
}
EXPORT_SYMBOL(drm_mm_pre_get);
-static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
+static int drm_mm_create_tail_node(struct drm_mm *mm,
+ unsigned long start,
+ unsigned long size, int atomic)
{
- return hole_node->start + hole_node->size;
-}
+ struct drm_mm_node *child;
-static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
-{
- struct drm_mm_node *next_node =
- list_entry(hole_node->node_list.next, struct drm_mm_node,
- node_list);
+ child = drm_mm_kmalloc(mm, atomic);
+ if (unlikely(child == NULL))
+ return -ENOMEM;
- return next_node->start;
-}
+ child->free = 1;
+ child->size = size;
+ child->start = start;
+ child->mm = mm;
-static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
- struct drm_mm_node *node,
- unsigned long size, unsigned alignment)
-{
- struct drm_mm *mm = hole_node->mm;
- unsigned long tmp = 0, wasted = 0;
- unsigned long hole_start = drm_mm_hole_node_start(hole_node);
- unsigned long hole_end = drm_mm_hole_node_end(hole_node);
+ list_add_tail(&child->node_list, &mm->node_list);
+ list_add_tail(&child->free_stack, &mm->free_stack);
- BUG_ON(!hole_node->hole_follows || node->allocated);
+ return 0;
+}
- if (alignment)
- tmp = hole_start % alignment;
+static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
+ unsigned long size,
+ int atomic)
+{
+ struct drm_mm_node *child;
- if (!tmp) {
- hole_node->hole_follows = 0;
- list_del_init(&hole_node->hole_stack);
- } else
- wasted = alignment - tmp;
+ child = drm_mm_kmalloc(parent->mm, atomic);
+ if (unlikely(child == NULL))
+ return NULL;
- node->start = hole_start + wasted;
- node->size = size;
- node->mm = mm;
- node->allocated = 1;
+ INIT_LIST_HEAD(&child->free_stack);
- INIT_LIST_HEAD(&node->hole_stack);
- list_add(&node->node_list, &hole_node->node_list);
+ child->size = size;
+ child->start = parent->start;
+ child->mm = parent->mm;
- BUG_ON(node->start + node->size > hole_end);
+ list_add_tail(&child->node_list, &parent->node_list);
+ INIT_LIST_HEAD(&child->free_stack);
- if (node->start + node->size < hole_end) {
- list_add(&node->hole_stack, &mm->hole_stack);
- node->hole_follows = 1;
- } else {
- node->hole_follows = 0;
- }
+ parent->size -= size;
+ parent->start += size;
+ return child;
}
-struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node,
+
+struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
unsigned long size,
unsigned alignment,
int atomic)
{
- struct drm_mm_node *node;
-
- node = drm_mm_kmalloc(hole_node->mm, atomic);
- if (unlikely(node == NULL))
- return NULL;
- drm_mm_insert_helper(hole_node, node, size, alignment);
+ struct drm_mm_node *align_splitoff = NULL;
+ unsigned tmp = 0;
- return node;
-}
-EXPORT_SYMBOL(drm_mm_get_block_generic);
+ if (alignment)
+ tmp = node->start % alignment;
-/**
- * Search for free space and insert a preallocated memory node. Returns
- * -ENOSPC if no suitable free area is available. The preallocated memory node
- * must be cleared.
- */
-int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
- unsigned long size, unsigned alignment)
-{
- struct drm_mm_node *hole_node;
+ if (tmp) {
+ align_splitoff =
+ drm_mm_split_at_start(node, alignment - tmp, atomic);
+ if (unlikely(align_splitoff == NULL))
+ return NULL;
+ }
- hole_node = drm_mm_search_free(mm, size, alignment, 0);
- if (!hole_node)
- return -ENOSPC;
+ if (node->size == size) {
+ list_del_init(&node->free_stack);
+ node->free = 0;
+ } else {
+ node = drm_mm_split_at_start(node, size, atomic);
+ }
- drm_mm_insert_helper(hole_node, node, size, alignment);
+ if (align_splitoff)
+ drm_mm_put_block(align_splitoff);
- return 0;
+ return node;
}
-EXPORT_SYMBOL(drm_mm_insert_node);
+EXPORT_SYMBOL(drm_mm_get_block_generic);
-static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
- struct drm_mm_node *node,
- unsigned long size, unsigned alignment,
- unsigned long start, unsigned long end)
+struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *node,
+ unsigned long size,
+ unsigned alignment,
+ unsigned long start,
+ unsigned long end,
+ int atomic)
{
- struct drm_mm *mm = hole_node->mm;
- unsigned long tmp = 0, wasted = 0;
- unsigned long hole_start = drm_mm_hole_node_start(hole_node);
- unsigned long hole_end = drm_mm_hole_node_end(hole_node);
-
- BUG_ON(!hole_node->hole_follows || node->allocated);
+ struct drm_mm_node *align_splitoff = NULL;
+ unsigned tmp = 0;
+ unsigned wasted = 0;
- if (hole_start < start)
- wasted += start - hole_start;
+ if (node->start < start)
+ wasted += start - node->start;
if (alignment)
- tmp = (hole_start + wasted) % alignment;
+ tmp = ((node->start + wasted) % alignment);
if (tmp)
wasted += alignment - tmp;
-
- if (!wasted) {
- hole_node->hole_follows = 0;
- list_del_init(&hole_node->hole_stack);
+ if (wasted) {
+ align_splitoff = drm_mm_split_at_start(node, wasted, atomic);
+ if (unlikely(align_splitoff == NULL))
+ return NULL;
}
- node->start = hole_start + wasted;
- node->size = size;
- node->mm = mm;
- node->allocated = 1;
-
- INIT_LIST_HEAD(&node->hole_stack);
- list_add(&node->node_list, &hole_node->node_list);
-
- BUG_ON(node->start + node->size > hole_end);
- BUG_ON(node->start + node->size > end);
-
- if (node->start + node->size < hole_end) {
- list_add(&node->hole_stack, &mm->hole_stack);
- node->hole_follows = 1;
+ if (node->size == size) {
+ list_del_init(&node->free_stack);
+ node->free = 0;
} else {
- node->hole_follows = 0;
+ node = drm_mm_split_at_start(node, size, atomic);
}
-}
-
-struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *hole_node,
- unsigned long size,
- unsigned alignment,
- unsigned long start,
- unsigned long end,
- int atomic)
-{
- struct drm_mm_node *node;
- node = drm_mm_kmalloc(hole_node->mm, atomic);
- if (unlikely(node == NULL))
- return NULL;
-
- drm_mm_insert_helper_range(hole_node, node, size, alignment,
- start, end);
+ if (align_splitoff)
+ drm_mm_put_block(align_splitoff);
return node;
}
EXPORT_SYMBOL(drm_mm_get_block_range_generic);
-/**
- * Search for free space and insert a preallocated memory node. Returns
- * -ENOSPC if no suitable free area is available. This is for range
- * restricted allocations. The preallocated memory node must be cleared.
+/*
+ * Put a block. Merge with the previous and / or next block if they are free.
+ * Otherwise add to the free stack.
*/
-int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node,
- unsigned long size, unsigned alignment,
- unsigned long start, unsigned long end)
-{
- struct drm_mm_node *hole_node;
- hole_node = drm_mm_search_free_in_range(mm, size, alignment,
- start, end, 0);
- if (!hole_node)
- return -ENOSPC;
-
- drm_mm_insert_helper_range(hole_node, node, size, alignment,
- start, end);
-
- return 0;
-}
-EXPORT_SYMBOL(drm_mm_insert_node_in_range);
-
-/**
- * Remove a memory node from the allocator.
- */
-void drm_mm_remove_node(struct drm_mm_node *node)
+void drm_mm_put_block(struct drm_mm_node *cur)
{
- struct drm_mm *mm = node->mm;
- struct drm_mm_node *prev_node;
-
- BUG_ON(node->scanned_block || node->scanned_prev_free
- || node->scanned_next_free);
-
- prev_node =
- list_entry(node->node_list.prev, struct drm_mm_node, node_list);
-
- if (node->hole_follows) {
- BUG_ON(drm_mm_hole_node_start(node)
- == drm_mm_hole_node_end(node));
- list_del(&node->hole_stack);
- } else
- BUG_ON(drm_mm_hole_node_start(node)
- != drm_mm_hole_node_end(node));
-
- if (!prev_node->hole_follows) {
- prev_node->hole_follows = 1;
- list_add(&prev_node->hole_stack, &mm->hole_stack);
- } else
- list_move(&prev_node->hole_stack, &mm->hole_stack);
-
- list_del(&node->node_list);
- node->allocated = 0;
-}
-EXPORT_SYMBOL(drm_mm_remove_node);
-/*
- * Remove a memory node from the allocator and free the allocated struct
- * drm_mm_node. Only to be used on a struct drm_mm_node obtained by one of the
- * drm_mm_get_block functions.
- */
-void drm_mm_put_block(struct drm_mm_node *node)
-{
+ struct drm_mm *mm = cur->mm;
+ struct list_head *cur_head = &cur->node_list;
+ struct list_head *root_head = &mm->node_list;
+ struct drm_mm_node *prev_node = NULL;
+ struct drm_mm_node *next_node;
- struct drm_mm *mm = node->mm;
+ int merged = 0;
- drm_mm_remove_node(node);
+ BUG_ON(cur->scanned_block || cur->scanned_prev_free
+ || cur->scanned_next_free);
- spin_lock(&mm->unused_lock);
- if (mm->num_unused < MM_UNUSED_TARGET) {
- list_add(&node->node_list, &mm->unused_nodes);
- ++mm->num_unused;
- } else
- kfree(node);
- spin_unlock(&mm->unused_lock);
+ if (cur_head->prev != root_head) {
+ prev_node =
+ list_entry(cur_head->prev, struct drm_mm_node, node_list);
+ if (prev_node->free) {
+ prev_node->size += cur->size;
+ merged = 1;
+ }
+ }
+ if (cur_head->next != root_head) {
+ next_node =
+ list_entry(cur_head->next, struct drm_mm_node, node_list);
+ if (next_node->free) {
+ if (merged) {
+ prev_node->size += next_node->size;
+ list_del(&next_node->node_list);
+ list_del(&next_node->free_stack);
+ spin_lock(&mm->unused_lock);
+ if (mm->num_unused < MM_UNUSED_TARGET) {
+ list_add(&next_node->free_stack,
+ &mm->unused_nodes);
+ ++mm->num_unused;
+ } else
+ kfree(next_node);
+ spin_unlock(&mm->unused_lock);
+ } else {
+ next_node->size += cur->size;
+ next_node->start = cur->start;
+ merged = 1;
+ }
+ }
+ }
+ if (!merged) {
+ cur->free = 1;
+ list_add(&cur->free_stack, &mm->free_stack);
+ } else {
+ list_del(&cur->node_list);
+ spin_lock(&mm->unused_lock);
+ if (mm->num_unused < MM_UNUSED_TARGET) {
+ list_add(&cur->free_stack, &mm->unused_nodes);
+ ++mm->num_unused;
+ } else
+ kfree(cur);
+ spin_unlock(&mm->unused_lock);
+ }
}
+
EXPORT_SYMBOL(drm_mm_put_block);
static int check_free_hole(unsigned long start, unsigned long end,
best = NULL;
best_size = ~0UL;
- list_for_each_entry(entry, &mm->hole_stack, hole_stack) {
- BUG_ON(!entry->hole_follows);
- if (!check_free_hole(drm_mm_hole_node_start(entry),
- drm_mm_hole_node_end(entry),
+ list_for_each_entry(entry, &mm->free_stack, free_stack) {
+ if (!check_free_hole(entry->start, entry->start + entry->size,
size, alignment))
continue;
best = NULL;
best_size = ~0UL;
- list_for_each_entry(entry, &mm->hole_stack, hole_stack) {
- unsigned long adj_start = drm_mm_hole_node_start(entry) < start ?
- start : drm_mm_hole_node_start(entry);
- unsigned long adj_end = drm_mm_hole_node_end(entry) > end ?
- end : drm_mm_hole_node_end(entry);
+ list_for_each_entry(entry, &mm->free_stack, free_stack) {
+ unsigned long adj_start = entry->start < start ?
+ start : entry->start;
+ unsigned long adj_end = entry->start + entry->size > end ?
+ end : entry->start + entry->size;
- BUG_ON(!entry->hole_follows);
if (!check_free_hole(adj_start, adj_end, size, alignment))
continue;
}
EXPORT_SYMBOL(drm_mm_search_free_in_range);
-/**
- * Moves an allocation. To be used with embedded struct drm_mm_node.
- */
-void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
-{
- list_replace(&old->node_list, &new->node_list);
- list_replace(&old->hole_stack, &new->hole_stack);
- new->hole_follows = old->hole_follows;
- new->mm = old->mm;
- new->start = old->start;
- new->size = old->size;
-
- old->allocated = 0;
- new->allocated = 1;
-}
-EXPORT_SYMBOL(drm_mm_replace_node);
-
/**
* Initializa lru scanning.
*
mm->scanned_blocks = 0;
mm->scan_hit_start = 0;
mm->scan_hit_size = 0;
- mm->scan_check_range = 0;
- mm->prev_scanned_node = NULL;
}
EXPORT_SYMBOL(drm_mm_init_scan);
-/**
- * Initializa lru scanning.
- *
- * This simply sets up the scanning routines with the parameters for the desired
- * hole. This version is for range-restricted scans.
- *
- * Warning: As long as the scan list is non-empty, no other operations than
- * adding/removing nodes to/from the scan list are allowed.
- */
-void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size,
- unsigned alignment,
- unsigned long start,
- unsigned long end)
-{
- mm->scan_alignment = alignment;
- mm->scan_size = size;
- mm->scanned_blocks = 0;
- mm->scan_hit_start = 0;
- mm->scan_hit_size = 0;
- mm->scan_start = start;
- mm->scan_end = end;
- mm->scan_check_range = 1;
- mm->prev_scanned_node = NULL;
-}
-EXPORT_SYMBOL(drm_mm_init_scan_with_range);
-
/**
* Add a node to the scan list that might be freed to make space for the desired
* hole.
int drm_mm_scan_add_block(struct drm_mm_node *node)
{
struct drm_mm *mm = node->mm;
- struct drm_mm_node *prev_node;
- unsigned long hole_start, hole_end;
- unsigned long adj_start;
- unsigned long adj_end;
+ struct list_head *prev_free, *next_free;
+ struct drm_mm_node *prev_node, *next_node;
mm->scanned_blocks++;
- BUG_ON(node->scanned_block);
+ prev_free = next_free = NULL;
+
+ BUG_ON(node->free);
node->scanned_block = 1;
+ node->free = 1;
- prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
- node_list);
-
- node->scanned_preceeds_hole = prev_node->hole_follows;
- prev_node->hole_follows = 1;
- list_del(&node->node_list);
- node->node_list.prev = &prev_node->node_list;
- node->node_list.next = &mm->prev_scanned_node->node_list;
- mm->prev_scanned_node = node;
-
- hole_start = drm_mm_hole_node_start(prev_node);
- hole_end = drm_mm_hole_node_end(prev_node);
- if (mm->scan_check_range) {
- adj_start = hole_start < mm->scan_start ?
- mm->scan_start : hole_start;
- adj_end = hole_end > mm->scan_end ?
- mm->scan_end : hole_end;
- } else {
- adj_start = hole_start;
- adj_end = hole_end;
+ if (node->node_list.prev != &mm->node_list) {
+ prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
+ node_list);
+
+ if (prev_node->free) {
+ list_del(&prev_node->node_list);
+
+ node->start = prev_node->start;
+ node->size += prev_node->size;
+
+ prev_node->scanned_prev_free = 1;
+
+ prev_free = &prev_node->free_stack;
+ }
}
- if (check_free_hole(adj_start , adj_end,
+ if (node->node_list.next != &mm->node_list) {
+ next_node = list_entry(node->node_list.next, struct drm_mm_node,
+ node_list);
+
+ if (next_node->free) {
+ list_del(&next_node->node_list);
+
+ node->size += next_node->size;
+
+ next_node->scanned_next_free = 1;
+
+ next_free = &next_node->free_stack;
+ }
+ }
+
+ /* The free_stack list is not used for allocated objects, so these two
+ * pointers can be abused (as long as no allocations in this memory
+ * manager happens). */
+ node->free_stack.prev = prev_free;
+ node->free_stack.next = next_free;
+
+ if (check_free_hole(node->start, node->start + node->size,
mm->scan_size, mm->scan_alignment)) {
- mm->scan_hit_start = hole_start;
- mm->scan_hit_size = hole_end;
+ mm->scan_hit_start = node->start;
+ mm->scan_hit_size = node->size;
return 1;
}
* corrupted.
*
* When the scan list is empty, the selected memory nodes can be freed. An
- * immediately following drm_mm_search_free with best_match = 0 will then return
+ * immediatly following drm_mm_search_free with best_match = 0 will then return
* the just freed block (because its at the top of the free_stack list).
*
* Returns one if this block should be evicted, zero otherwise. Will always
int drm_mm_scan_remove_block(struct drm_mm_node *node)
{
struct drm_mm *mm = node->mm;
- struct drm_mm_node *prev_node;
+ struct drm_mm_node *prev_node, *next_node;
mm->scanned_blocks--;
BUG_ON(!node->scanned_block);
node->scanned_block = 0;
+ node->free = 0;
- prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
- node_list);
+ prev_node = list_entry(node->free_stack.prev, struct drm_mm_node,
+ free_stack);
+ next_node = list_entry(node->free_stack.next, struct drm_mm_node,
+ free_stack);
- prev_node->hole_follows = node->scanned_preceeds_hole;
- INIT_LIST_HEAD(&node->node_list);
- list_add(&node->node_list, &prev_node->node_list);
+ if (prev_node) {
+ BUG_ON(!prev_node->scanned_prev_free);
+ prev_node->scanned_prev_free = 0;
+
+ list_add_tail(&prev_node->node_list, &node->node_list);
+
+ node->start = prev_node->start + prev_node->size;
+ node->size -= prev_node->size;
+ }
+
+ if (next_node) {
+ BUG_ON(!next_node->scanned_next_free);
+ next_node->scanned_next_free = 0;
+
+ list_add(&next_node->node_list, &node->node_list);
+
+ node->size -= next_node->size;
+ }
+
+ INIT_LIST_HEAD(&node->free_stack);
/* Only need to check for containement because start&size for the
* complete resulting free block (not just the desired part) is
int drm_mm_clean(struct drm_mm * mm)
{
- struct list_head *head = &mm->head_node.node_list;
+ struct list_head *head = &mm->node_list;
return (head->next->next == head);
}
int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
{
- INIT_LIST_HEAD(&mm->hole_stack);
+ INIT_LIST_HEAD(&mm->node_list);
+ INIT_LIST_HEAD(&mm->free_stack);
INIT_LIST_HEAD(&mm->unused_nodes);
mm->num_unused = 0;
mm->scanned_blocks = 0;
spin_lock_init(&mm->unused_lock);
- /* Clever trick to avoid a special case in the free hole tracking. */
- INIT_LIST_HEAD(&mm->head_node.node_list);
- INIT_LIST_HEAD(&mm->head_node.hole_stack);
- mm->head_node.hole_follows = 1;
- mm->head_node.scanned_block = 0;
- mm->head_node.scanned_prev_free = 0;
- mm->head_node.scanned_next_free = 0;
- mm->head_node.mm = mm;
- mm->head_node.start = start + size;
- mm->head_node.size = start - mm->head_node.start;
- list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack);
-
- return 0;
+ return drm_mm_create_tail_node(mm, start, size, 0);
}
EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(struct drm_mm * mm)
{
- struct drm_mm_node *entry, *next;
+ struct list_head *bnode = mm->free_stack.next;
+ struct drm_mm_node *entry;
+ struct drm_mm_node *next;
+
+ entry = list_entry(bnode, struct drm_mm_node, free_stack);
- if (!list_empty(&mm->head_node.node_list)) {
+ if (entry->node_list.next != &mm->node_list ||
+ entry->free_stack.next != &mm->free_stack) {
DRM_ERROR("Memory manager not clean. Delaying takedown\n");
return;
}
+ list_del(&entry->free_stack);
+ list_del(&entry->node_list);
+ kfree(entry);
+
spin_lock(&mm->unused_lock);
- list_for_each_entry_safe(entry, next, &mm->unused_nodes, node_list) {
- list_del(&entry->node_list);
+ list_for_each_entry_safe(entry, next, &mm->unused_nodes, free_stack) {
+ list_del(&entry->free_stack);
kfree(entry);
--mm->num_unused;
}
void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
{
struct drm_mm_node *entry;
- unsigned long total_used = 0, total_free = 0, total = 0;
- unsigned long hole_start, hole_end, hole_size;
-
- hole_start = drm_mm_hole_node_start(&mm->head_node);
- hole_end = drm_mm_hole_node_end(&mm->head_node);
- hole_size = hole_end - hole_start;
- if (hole_size)
- printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
- prefix, hole_start, hole_end,
- hole_size);
- total_free += hole_size;
-
- drm_mm_for_each_node(entry, mm) {
- printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
+ int total_used = 0, total_free = 0, total = 0;
+
+ list_for_each_entry(entry, &mm->node_list, node_list) {
+ printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8ld: %s\n",
prefix, entry->start, entry->start + entry->size,
- entry->size);
- total_used += entry->size;
-
- if (entry->hole_follows) {
- hole_start = drm_mm_hole_node_start(entry);
- hole_end = drm_mm_hole_node_end(entry);
- hole_size = hole_end - hole_start;
- printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
- prefix, hole_start, hole_end,
- hole_size);
- total_free += hole_size;
- }
+ entry->size, entry->free ? "free" : "used");
+ total += entry->size;
+ if (entry->free)
+ total_free += entry->size;
+ else
+ total_used += entry->size;
}
- total = total_free + total_used;
-
- printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total,
+ printk(KERN_DEBUG "%s total: %d, used %d free %d\n", prefix, total,
total_used, total_free);
}
EXPORT_SYMBOL(drm_mm_debug_table);
int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
{
struct drm_mm_node *entry;
- unsigned long total_used = 0, total_free = 0, total = 0;
- unsigned long hole_start, hole_end, hole_size;
-
- hole_start = drm_mm_hole_node_start(&mm->head_node);
- hole_end = drm_mm_hole_node_end(&mm->head_node);
- hole_size = hole_end - hole_start;
- if (hole_size)
- seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
- hole_start, hole_end, hole_size);
- total_free += hole_size;
-
- drm_mm_for_each_node(entry, mm) {
- seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n",
- entry->start, entry->start + entry->size,
- entry->size);
- total_used += entry->size;
- if (entry->hole_follows) {
- hole_start = drm_mm_hole_node_start(entry);
- hole_end = drm_mm_hole_node_end(entry);
- hole_size = hole_end - hole_start;
- seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
- hole_start, hole_end, hole_size);
- total_free += hole_size;
- }
+ int total_used = 0, total_free = 0, total = 0;
+
+ list_for_each_entry(entry, &mm->node_list, node_list) {
+ seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: %s\n", entry->start, entry->start + entry->size, entry->size, entry->free ? "free" : "used");
+ total += entry->size;
+ if (entry->free)
+ total_free += entry->size;
+ else
+ total_used += entry->size;
}
- total = total_free + total_used;
-
- seq_printf(m, "total: %lu, used %lu free %lu\n", total, total_used, total_free);
+ seq_printf(m, "total: %d, used %d free %d\n", total, total_used, total_free);
return 0;
}
EXPORT_SYMBOL(drm_mm_dump_table);
*
* Return @modes's hsync rate in kHz, rounded to the nearest int.
*/
-int drm_mode_hsync(const struct drm_display_mode *mode)
+int drm_mode_hsync(struct drm_display_mode *mode)
{
unsigned int calc_val;
* If it is 70.288, it will return 70Hz.
* If it is 59.6, it will return 60Hz.
*/
-int drm_mode_vrefresh(const struct drm_display_mode *mode)
+int drm_mode_vrefresh(struct drm_display_mode *mode)
{
int refresh = 0;
unsigned int calc_val;
* a pointer to it. Used to create new instances of established modes.
*/
struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
- const struct drm_display_mode *mode)
+ struct drm_display_mode *mode)
{
struct drm_display_mode *nmode;
int new_id;
}
}
EXPORT_SYMBOL(drm_mode_connector_list_update);
-
-/**
- * drm_mode_parse_command_line_for_connector - parse command line for connector
- * @mode_option - per connector mode option
- * @connector - connector to parse line for
- *
- * This parses the connector specific then generic command lines for
- * modes and options to configure the connector.
- *
- * This uses the same parameters as the fb modedb.c, except for extra
- * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
- *
- * enable/enable Digital/disable bit at the end
- */
-bool drm_mode_parse_command_line_for_connector(const char *mode_option,
- struct drm_connector *connector,
- struct drm_cmdline_mode *mode)
-{
- const char *name;
- unsigned int namelen;
- bool res_specified = false, bpp_specified = false, refresh_specified = false;
- unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
- bool yres_specified = false, cvt = false, rb = false;
- bool interlace = false, margins = false, was_digit = false;
- int i;
- enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
-
-#ifdef CONFIG_FB
- if (!mode_option)
- mode_option = fb_mode_option;
-#endif
-
- if (!mode_option) {
- mode->specified = false;
- return false;
- }
-
- name = mode_option;
- namelen = strlen(name);
- for (i = namelen-1; i >= 0; i--) {
- switch (name[i]) {
- case '@':
- if (!refresh_specified && !bpp_specified &&
- !yres_specified && !cvt && !rb && was_digit) {
- refresh = simple_strtol(&name[i+1], NULL, 10);
- refresh_specified = true;
- was_digit = false;
- } else
- goto done;
- break;
- case '-':
- if (!bpp_specified && !yres_specified && !cvt &&
- !rb && was_digit) {
- bpp = simple_strtol(&name[i+1], NULL, 10);
- bpp_specified = true;
- was_digit = false;
- } else
- goto done;
- break;
- case 'x':
- if (!yres_specified && was_digit) {
- yres = simple_strtol(&name[i+1], NULL, 10);
- yres_specified = true;
- was_digit = false;
- } else
- goto done;
- case '0' ... '9':
- was_digit = true;
- break;
- case 'M':
- if (yres_specified || cvt || was_digit)
- goto done;
- cvt = true;
- break;
- case 'R':
- if (yres_specified || cvt || rb || was_digit)
- goto done;
- rb = true;
- break;
- case 'm':
- if (cvt || yres_specified || was_digit)
- goto done;
- margins = true;
- break;
- case 'i':
- if (cvt || yres_specified || was_digit)
- goto done;
- interlace = true;
- break;
- case 'e':
- if (yres_specified || bpp_specified || refresh_specified ||
- was_digit || (force != DRM_FORCE_UNSPECIFIED))
- goto done;
-
- force = DRM_FORCE_ON;
- break;
- case 'D':
- if (yres_specified || bpp_specified || refresh_specified ||
- was_digit || (force != DRM_FORCE_UNSPECIFIED))
- goto done;
-
- if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
- (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
- force = DRM_FORCE_ON;
- else
- force = DRM_FORCE_ON_DIGITAL;
- break;
- case 'd':
- if (yres_specified || bpp_specified || refresh_specified ||
- was_digit || (force != DRM_FORCE_UNSPECIFIED))
- goto done;
-
- force = DRM_FORCE_OFF;
- break;
- default:
- goto done;
- }
- }
-
- if (i < 0 && yres_specified) {
- char *ch;
- xres = simple_strtol(name, &ch, 10);
- if ((ch != NULL) && (*ch == 'x'))
- res_specified = true;
- else
- i = ch - name;
- } else if (!yres_specified && was_digit) {
- /* catch mode that begins with digits but has no 'x' */
- i = 0;
- }
-done:
- if (i >= 0) {
- printk(KERN_WARNING
- "parse error at position %i in video mode '%s'\n",
- i, name);
- mode->specified = false;
- return false;
- }
-
- if (res_specified) {
- mode->specified = true;
- mode->xres = xres;
- mode->yres = yres;
- }
-
- if (refresh_specified) {
- mode->refresh_specified = true;
- mode->refresh = refresh;
- }
-
- if (bpp_specified) {
- mode->bpp_specified = true;
- mode->bpp = bpp;
- }
- mode->rb = rb;
- mode->cvt = cvt;
- mode->interlace = interlace;
- mode->margins = margins;
- mode->force = force;
-
- return true;
-}
-EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
-
-struct drm_display_mode *
-drm_mode_create_from_cmdline_mode(struct drm_device *dev,
- struct drm_cmdline_mode *cmd)
-{
- struct drm_display_mode *mode;
-
- if (cmd->cvt)
- mode = drm_cvt_mode(dev,
- cmd->xres, cmd->yres,
- cmd->refresh_specified ? cmd->refresh : 60,
- cmd->rb, cmd->interlace,
- cmd->margins);
- else
- mode = drm_gtf_mode(dev,
- cmd->xres, cmd->yres,
- cmd->refresh_specified ? cmd->refresh : 60,
- cmd->interlace,
- cmd->margins);
- if (!mode)
- return NULL;
-
- drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
- return mode;
-}
-EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
EXPORT_SYMBOL(drm_pci_free);
#ifdef CONFIG_PCI
-
-static int drm_get_pci_domain(struct drm_device *dev)
-{
-#ifndef __alpha__
- /* For historical reasons, drm_get_pci_domain() is busticated
- * on most archs and has to remain so for userspace interface
- * < 1.4, except on alpha which was right from the beginning
- */
- if (dev->if_version < 0x10004)
- return 0;
-#endif /* __alpha__ */
-
- return pci_domain_nr(dev->pdev->bus);
-}
-
-static int drm_pci_get_irq(struct drm_device *dev)
-{
- return dev->pdev->irq;
-}
-
-static const char *drm_pci_get_name(struct drm_device *dev)
-{
- struct pci_driver *pdriver = dev->driver->kdriver.pci;
- return pdriver->name;
-}
-
-int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
-{
- int len, ret;
- struct pci_driver *pdriver = dev->driver->kdriver.pci;
- master->unique_len = 40;
- master->unique_size = master->unique_len;
- master->unique = kmalloc(master->unique_size, GFP_KERNEL);
- if (master->unique == NULL)
- return -ENOMEM;
-
-
- len = snprintf(master->unique, master->unique_len,
- "pci:%04x:%02x:%02x.%d",
- drm_get_pci_domain(dev),
- dev->pdev->bus->number,
- PCI_SLOT(dev->pdev->devfn),
- PCI_FUNC(dev->pdev->devfn));
-
- if (len >= master->unique_len) {
- DRM_ERROR("buffer overflow");
- ret = -EINVAL;
- goto err;
- } else
- master->unique_len = len;
-
- dev->devname =
- kmalloc(strlen(pdriver->name) +
- master->unique_len + 2, GFP_KERNEL);
-
- if (dev->devname == NULL) {
- ret = -ENOMEM;
- goto err;
- }
-
- sprintf(dev->devname, "%s@%s", pdriver->name,
- master->unique);
-
- return 0;
-err:
- return ret;
-}
-
-int drm_pci_set_unique(struct drm_device *dev,
- struct drm_master *master,
- struct drm_unique *u)
-{
- int domain, bus, slot, func, ret;
- const char *bus_name;
-
- master->unique_len = u->unique_len;
- master->unique_size = u->unique_len + 1;
- master->unique = kmalloc(master->unique_size, GFP_KERNEL);
- if (!master->unique) {
- ret = -ENOMEM;
- goto err;
- }
-
- if (copy_from_user(master->unique, u->unique, master->unique_len)) {
- ret = -EFAULT;
- goto err;
- }
-
- master->unique[master->unique_len] = '\0';
-
- bus_name = dev->driver->bus->get_name(dev);
- dev->devname = kmalloc(strlen(bus_name) +
- strlen(master->unique) + 2, GFP_KERNEL);
- if (!dev->devname) {
- ret = -ENOMEM;
- goto err;
- }
-
- sprintf(dev->devname, "%s@%s", bus_name,
- master->unique);
-
- /* Return error if the busid submitted doesn't match the device's actual
- * busid.
- */
- ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
- if (ret != 3) {
- ret = -EINVAL;
- goto err;
- }
-
- domain = bus >> 8;
- bus &= 0xff;
-
- if ((domain != drm_get_pci_domain(dev)) ||
- (bus != dev->pdev->bus->number) ||
- (slot != PCI_SLOT(dev->pdev->devfn)) ||
- (func != PCI_FUNC(dev->pdev->devfn))) {
- ret = -EINVAL;
- goto err;
- }
- return 0;
-err:
- return ret;
-}
-
-
-static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
-{
- if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
- (p->busnum & 0xff) != dev->pdev->bus->number ||
- p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
- return -EINVAL;
-
- p->irq = dev->pdev->irq;
-
- DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
- p->irq);
- return 0;
-}
-
-int drm_pci_agp_init(struct drm_device *dev)
-{
- if (drm_core_has_AGP(dev)) {
- if (drm_pci_device_is_agp(dev))
- dev->agp = drm_agp_init(dev);
- if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
- && (dev->agp == NULL)) {
- DRM_ERROR("Cannot initialize the agpgart module.\n");
- return -EINVAL;
- }
- if (drm_core_has_MTRR(dev)) {
- if (dev->agp)
- dev->agp->agp_mtrr =
- mtrr_add(dev->agp->agp_info.aper_base,
- dev->agp->agp_info.aper_size *
- 1024 * 1024, MTRR_TYPE_WRCOMB, 1);
- }
- }
- return 0;
-}
-
-static struct drm_bus drm_pci_bus = {
- .bus_type = DRIVER_BUS_PCI,
- .get_irq = drm_pci_get_irq,
- .get_name = drm_pci_get_name,
- .set_busid = drm_pci_set_busid,
- .set_unique = drm_pci_set_unique,
- .irq_by_busid = drm_pci_irq_by_busid,
- .agp_init = drm_pci_agp_init,
-};
-
/**
* Register.
*
EXPORT_SYMBOL(drm_get_pci_dev);
/**
- * PCI device initialization. Called direct from modules at load time.
+ * PCI device initialization. Called via drm_init at module load time,
*
* \return zero on success or a negative number on failure.
*
* Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
* after the initialization for driver customization.
*/
-int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
+int drm_pci_init(struct drm_driver *driver)
{
struct pci_dev *pdev = NULL;
const struct pci_device_id *pid;
int i;
- DRM_DEBUG("\n");
-
- INIT_LIST_HEAD(&driver->device_list);
- driver->kdriver.pci = pdriver;
- driver->bus = &drm_pci_bus;
-
if (driver->driver_features & DRIVER_MODESET)
- return pci_register_driver(pdriver);
+ return pci_register_driver(&driver->pci_driver);
/* If not using KMS, fall back to stealth mode manual scanning. */
- for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
- pid = &pdriver->id_table[i];
+ for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
+ pid = &driver->pci_driver.id_table[i];
/* Loop around setting up a DRM device for each PCI device
* matching our ID and device class. If we had the internal
#else
-int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
+int drm_pci_init(struct drm_driver *driver)
{
return -1;
}
#endif
-
-EXPORT_SYMBOL(drm_pci_init);
-
/*@}*/
-void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
-{
- struct drm_device *dev, *tmp;
- DRM_DEBUG("\n");
-
- if (driver->driver_features & DRIVER_MODESET) {
- pci_unregister_driver(pdriver);
- } else {
- list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
- drm_put_dev(dev);
- }
- DRM_INFO("Module unloaded\n");
-}
-EXPORT_SYMBOL(drm_pci_exit);
}
EXPORT_SYMBOL(drm_get_platform_dev);
-static int drm_platform_get_irq(struct drm_device *dev)
-{
- return platform_get_irq(dev->platformdev, 0);
-}
-
-static const char *drm_platform_get_name(struct drm_device *dev)
-{
- return dev->platformdev->name;
-}
-
-static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master)
-{
- int len, ret;
-
- master->unique_len = 13 + strlen(dev->platformdev->name);
- master->unique_size = master->unique_len;
- master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
-
- if (master->unique == NULL)
- return -ENOMEM;
-
- len = snprintf(master->unique, master->unique_len,
- "platform:%s:%02d", dev->platformdev->name, dev->platformdev->id);
-
- if (len > master->unique_len) {
- DRM_ERROR("Unique buffer overflowed\n");
- ret = -EINVAL;
- goto err;
- }
-
- dev->devname =
- kmalloc(strlen(dev->platformdev->name) +
- master->unique_len + 2, GFP_KERNEL);
-
- if (dev->devname == NULL) {
- ret = -ENOMEM;
- goto err;
- }
-
- sprintf(dev->devname, "%s@%s", dev->platformdev->name,
- master->unique);
- return 0;
-err:
- return ret;
-}
-
-static struct drm_bus drm_platform_bus = {
- .bus_type = DRIVER_BUS_PLATFORM,
- .get_irq = drm_platform_get_irq,
- .get_name = drm_platform_get_name,
- .set_busid = drm_platform_set_busid,
-};
-
/**
- * Platform device initialization. Called direct from modules.
+ * Platform device initialization. Called via drm_init at module load time,
*
* \return zero on success or a negative number on failure.
*
* after the initialization for driver customization.
*/
-int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device)
+int drm_platform_init(struct drm_driver *driver)
{
- DRM_DEBUG("\n");
-
- driver->kdriver.platform_device = platform_device;
- driver->bus = &drm_platform_bus;
- INIT_LIST_HEAD(&driver->device_list);
- return drm_get_platform_dev(platform_device, driver);
-}
-EXPORT_SYMBOL(drm_platform_init);
-
-void drm_platform_exit(struct drm_driver *driver, struct platform_device *platform_device)
-{
- struct drm_device *dev, *tmp;
- DRM_DEBUG("\n");
-
- list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
- drm_put_dev(dev);
- DRM_INFO("Module unloaded\n");
+ return drm_get_platform_dev(driver->platform_device, driver);
}
-EXPORT_SYMBOL(drm_platform_exit);
if (dev->sg)
return -EINVAL;
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
+ memset(entry, 0, sizeof(*entry));
pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages);
entry->pages = pages;
- entry->pagelist = kcalloc(pages, sizeof(*entry->pagelist), GFP_KERNEL);
+ entry->pagelist = kmalloc(pages * sizeof(*entry->pagelist), GFP_KERNEL);
if (!entry->pagelist) {
kfree(entry);
return -ENOMEM;
}
- entry->busaddr = kcalloc(pages, sizeof(*entry->busaddr), GFP_KERNEL);
+ memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
+
+ entry->busaddr = kmalloc(pages * sizeof(*entry->busaddr), GFP_KERNEL);
if (!entry->busaddr) {
kfree(entry->pagelist);
kfree(entry);
return -ENOMEM;
}
+ memset((void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr));
entry->virtual = drm_vmalloc_dma(pages << PAGE_SHIFT);
if (!entry->virtual) {
{
int ret = 0;
- sman->mm = kcalloc(num_managers, sizeof(*sman->mm), GFP_KERNEL);
+ sman->mm = (struct drm_sman_mm *) kcalloc(num_managers,
+ sizeof(*sman->mm),
+ GFP_KERNEL);
if (!sman->mm) {
ret = -ENOMEM;
goto out;
unsigned int drm_debug = 0; /* 1 to enable debug output */
EXPORT_SYMBOL(drm_debug);
-unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
-EXPORT_SYMBOL(drm_vblank_offdelay);
-
-unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
-EXPORT_SYMBOL(drm_timestamp_precision);
-
MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC);
MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(debug, "Enable debug output");
-MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
-MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
module_param_named(debug, drm_debug, int, 0600);
-module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
-module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
struct idr drm_minors_idr;
struct class *drm_class;
struct proc_dir_entry *drm_proc_root;
struct dentry *drm_debugfs_root;
-
-int drm_err(const char *func, const char *format, ...)
-{
- struct va_format vaf;
- va_list args;
- int r;
-
- va_start(args, format);
-
- vaf.fmt = format;
- vaf.va = &args;
-
- r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
-
- va_end(args);
-
- return r;
-}
-EXPORT_SYMBOL(drm_err);
-
void drm_ut_debug_printk(unsigned int request_level,
const char *prefix,
const char *function_name,
}
}
EXPORT_SYMBOL(drm_ut_debug_printk);
-
static int drm_minor_get_id(struct drm_device *dev, int type)
{
int new_id;
dev->driver = driver;
- if (dev->driver->bus->agp_init) {
- retcode = dev->driver->bus->agp_init(dev);
- if (retcode)
+ if (drm_core_has_AGP(dev)) {
+ if (drm_device_is_agp(dev))
+ dev->agp = drm_agp_init(dev);
+ if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
+ && (dev->agp == NULL)) {
+ DRM_ERROR("Cannot initialize the agpgart module.\n");
+ retcode = -EINVAL;
goto error_out_unreg;
+ }
+ if (drm_core_has_MTRR(dev)) {
+ if (dev->agp)
+ dev->agp->agp_mtrr =
+ mtrr_add(dev->agp->agp_info.aper_base,
+ dev->agp->agp_info.aper_size *
+ 1024 * 1024, MTRR_TYPE_WRCOMB, 1);
+ }
}
-
retcode = drm_ctxbitmap_init(dev);
if (retcode) {
DRM_ERROR("Cannot allocate memory for context bitmap.\n");
*
* Cleans up all DRM device, calling drm_lastclose().
*
+ * \sa drm_init
*/
void drm_put_dev(struct drm_device *dev)
{
drm_put_minor(&dev->primary);
- list_del(&dev->driver_item);
if (dev->devname) {
kfree(dev->devname);
dev->devname = NULL;
{
struct drm_connector *connector = to_drm_connector(device);
enum drm_connector_status status;
- int ret;
-
- ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex);
- if (ret)
- return ret;
status = connector->funcs->detect(connector, true);
- mutex_unlock(&connector->dev->mode_config.mutex);
-
return snprintf(buf, PAGE_SIZE, "%s\n",
drm_get_connector_status_name(status));
}
static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
{
#ifdef __alpha__
- return dev->hose->dense_mem_base;
+ return dev->hose->dense_mem_base - dev->hose->mem_space->start;
#else
return 0;
#endif
}
#else
- if(!cpu_is_omap3530())
+ if(!(cpu_is_omap3530() || cpu_is_omap3517()))
{
OSWriteHWReg(psDevInfo->pvRegsBaseKM, 0xFF08, 0x80000000);//OCP Bypass mode
}
#else
#define ON_EACH_CPU(func, info, wait) on_each_cpu(func, info, 0, wait)
#endif
-/*
+
#if defined(PVR_LINUX_USING_WORKQUEUES) && !defined(CONFIG_PREEMPT)
-#error "A preemptible Linux kernel is required when using workqueues"
+//#error "A preemptible Linux kernel is required when using workqueues"
#endif
-*/
+
#define EVENT_OBJECT_TIMEOUT_MS (100)
#define HOST_ALLOC_MEM_USING_KMALLOC ((IMG_HANDLE)0)
static inline int is_vmalloc_addr(const void *pvCpuVAddr)
{
- unsigned long lAddr = (unsigned long)pvCpuVAddr;
- return lAddr >= VMALLOC_START && lAddr < VMALLOC_END;
+ unsigned long lAddr = (unsigned long)pvCpuVAddr;
+ return lAddr >= VMALLOC_START && lAddr < VMALLOC_END;
}
-#endif
-
+#endif
-
#if !defined(DEBUG_LINUX_MEMORY_ALLOCATIONS)
PVRSRV_ERROR OSFreeMem_Impl(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID pvCpuVAddr, IMG_HANDLE hBlockAlloc)
#else
}
-
IMG_VOID OSWaitus(IMG_UINT32 ui32Timeus)
{
udelay(ui32Timeus);
}
+
IMG_VOID OSSleepms(IMG_UINT32 ui32Timems)
{
msleep(ui32Timems);
}
typedef void (*InnerCacheOp_t)(const void *pvStart, const void *pvEnd);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
-typedef void (*InnerCacheOp_mapUnmap_t)(const void *pvStart, const IMG_UINT32 size, const IMG_UINT32 type);
-#endif
-
typedef void (*OuterCacheOp_t)(unsigned long ulStart, unsigned long ulEnd);
#if defined(CONFIG_OUTER_CACHE)
return IMG_NULL;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
+
static
IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length,
- void * pfnInnerCacheOp_ptr,
- OuterCacheOp_t pfnOuterCacheOp,
- IMG_UINT32 map_unmap)
-#else
-static
-IMG_BOOL CheckExecuteCacheOp(IMG_HANDLE hOSMemHandle,
- IMG_VOID *pvRangeAddrStart,
- IMG_UINT32 ui32Length,
- InnerCacheOp_t pfnInnerCacheOp,
- OuterCacheOp_t pfnOuterCacheOp)
-#endif
-
+ InnerCacheOp_t pfnInnerCacheOp,
+ OuterCacheOp_t pfnOuterCacheOp)
{
LinuxMemArea *psLinuxMemArea = (LinuxMemArea *)hOSMemHandle;
IMG_UINT32 ui32AreaLength, ui32AreaOffset = 0;
struct list_head *psMMapOffsetStructList;
IMG_VOID *pvMinVAddr;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
- InnerCacheOp_t pfnInnerCacheOp = (InnerCacheOp_t)pfnInnerCacheOp_ptr;
- InnerCacheOp_mapUnmap_t pfnInnerCacheOp_mapUnamp = (InnerCacheOp_mapUnmap_t)pfnInnerCacheOp_ptr;
-#endif
-
#if defined(CONFIG_OUTER_CACHE)
MemAreaToPhys_t pfnMemAreaToPhys = IMG_NULL;
IMG_UINT32 ui32PageNumOffset = 0;
{
case LINUX_MEM_AREA_VMALLOC:
{
- if(is_vmalloc_addr(pvRangeAddrStart))
- {
-
- pvMinVAddr = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress + ui32AreaOffset;
-
- if(pvRangeAddrStart < pvMinVAddr)
- goto err_blocked;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
- if (map_unmap == 0 ) {
-
- pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-
- } else if (map_unmap == 1) {
-
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_TO_DEVICE);
-
- } else {
-
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_FROM_DEVICE);
-
- }
-#else
-pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-#endif
-
-// pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
- }
-
- else
- {
-
- pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList,pvRangeAddrStart, ui32Length);
- if(!pvMinVAddr)
- goto err_blocked;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
- if (map_unmap == 0 ) {
-
- pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-
- } else if (map_unmap == 1) {
-
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_TO_DEVICE);
-
- } else {
+ if(is_vmalloc_addr(pvRangeAddrStart))
+ {
+ pvMinVAddr = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress + ui32AreaOffset;
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_FROM_DEVICE);
+
+ if(pvRangeAddrStart < pvMinVAddr)
+ goto err_blocked;
- }
-#else
-pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-#endif
+ pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
+ }
+ else
+ {
+
+
+ pvMinVAddr = FindMMapBaseVAddr(psMMapOffsetStructList,
+ pvRangeAddrStart, ui32Length);
+ if(!pvMinVAddr)
+ goto err_blocked;
-// pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-
+ pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
#if defined(CONFIG_OUTER_CACHE)
- pvRangeAddrStart = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress +(ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr);
- }
+
+ pvRangeAddrStart = psLinuxMemArea->uData.sVmalloc.pvVmallocAddress +
+ (ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr);
+ }
pfnMemAreaToPhys = VMallocAreaToPhys;
-#else
-}
-#endif
+#else
+ }
+#endif
break;
}
pvRangeAddrStart, ui32Length);
if(!pvMinVAddr)
goto err_blocked;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
- if (map_unmap == 0 ) {
-
- pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-
- } else if (map_unmap == 1) {
-
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_TO_DEVICE);
-
- } else {
-
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_FROM_DEVICE);
-
- }
-#else
-pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-#endif
-
-// pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
+ pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
#if defined(CONFIG_OUTER_CACHE)
ui32PageNumOffset = ((ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT;
pvRangeAddrStart, ui32Length);
if(!pvMinVAddr)
goto err_blocked;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
- if (map_unmap == 0 ) {
-
- pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-
- } else if (map_unmap == 1) {
-
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_TO_DEVICE);
- } else {
-
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_FROM_DEVICE);
-
- }
-#else
-pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-#endif
-
- // pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
+ pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
#if defined(CONFIG_OUTER_CACHE)
ui32PageNumOffset = ((ui32AreaOffset & PAGE_MASK) + (pvRangeAddrStart - pvMinVAddr)) >> PAGE_SHIFT;
PVR_DBG_BREAK;
}
-#if 0
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
- if (map_unmap == 0 ) {
-
- pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-
- } else if (map_unmap == 1) {
-
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_TO_DEVICE);
-
- } else {
-
- pfnInnerCacheOp_mapUnamp (pvRangeAddrStart, ui32Length, DMA_FROM_DEVICE);
-
- }
-#else
-pfnInnerCacheOp(pvRangeAddrStart, pvRangeAddrStart + ui32Length);
-#endif
-#endif
-
#if defined(CONFIG_OUTER_CACHE)
-
-// if (pfnMemAreaToPhys != IMG_NULL)
- PVR_ASSERT(pfnMemAreaToPhys != IMG_NULL);
+ PVR_ASSERT(pfnMemAreaToPhys != IMG_NULL);
+
{
unsigned long ulStart, ulEnd, ulLength, ulStartOffset, ulEndOffset;
IMG_UINT32 i, ui32NumPages;
pfnOuterCacheOp(ulStart, ulEnd);
}
}
-// else
-// {
-// PVR_DBG_BREAK;
-// }
#endif
return IMG_TRUE;
psLinuxMemArea->eAreaType));
return IMG_FALSE;
}
-#endif
+
+#endif
#if defined(__i386__)
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
+
return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- (void *) x86_flush_cache_range, IMG_NULL, 0);
-#else
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- x86_flush_cache_range, IMG_NULL);
-
-#endif
+ x86_flush_cache_range, IMG_NULL);
}
IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
+
return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- (void *) x86_flush_cache_range, IMG_NULL, 0);
-#else
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- x86_flush_cache_range, IMG_NULL);
-#endif
+ x86_flush_cache_range, IMG_NULL);
}
IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
+
return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- (void *) x86_flush_cache_range, IMG_NULL, 0);
-#else
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- x86_flush_cache_range, IMG_NULL);
-#endif
+ x86_flush_cache_range, IMG_NULL);
}
#else
outer_flush_all();
#endif
}
+static inline size_t pvr_dmac_range_len(const void *pvStart, const void *pvEnd)
+{
+ return (size_t)((char *)pvEnd - (char *)pvStart);
+}
-IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
- IMG_VOID *pvRangeAddrStart,
- IMG_UINT32 ui32Length)
+
+static void pvr_dmac_inv_range(const void *pvStart, const void *pvEnd)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- (void *) dmac_flush_range, outer_flush_range, 0);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34))
+ dmac_inv_range(pvStart, pvEnd);
#else
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- dmac_flush_range, outer_flush_range);
+ dmac_map_area(pvStart, pvr_dmac_range_len(pvStart, pvEnd), DMA_FROM_DEVICE);
#endif
+}
+static void pvr_dmac_clean_range(const void *pvStart, const void *pvEnd)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34))
+ dmac_clean_range(pvStart, pvEnd);
+#else
+ dmac_map_area(pvStart, pvr_dmac_range_len(pvStart, pvEnd), DMA_TO_DEVICE);
+#endif
}
-IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+
+IMG_BOOL OSFlushCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
-{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- (void *) dmac_map_area, outer_clean_range, 2);
-#else
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- dmac_clean_range, outer_clean_range);
-#endif
+{
+ return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,dmac_flush_range, (OuterCacheOp_t)outer_flush_range);
+}
+IMG_BOOL OSCleanCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
+ IMG_VOID *pvRangeAddrStart,
+ IMG_UINT32 ui32Length)
+{
+ return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,pvr_dmac_clean_range, (OuterCacheOp_t)outer_clean_range);
}
IMG_BOOL OSInvalidateCPUCacheRangeKM(IMG_HANDLE hOSMemHandle,
IMG_VOID *pvRangeAddrStart,
IMG_UINT32 ui32Length)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- (void *) dmac_unmap_area, outer_inv_range, 1);
-#else
- return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,
- dmac_inv_range, outer_inv_range);
-#endif
+ return CheckExecuteCacheOp(hOSMemHandle, pvRangeAddrStart, ui32Length,pvr_dmac_inv_range, (OuterCacheOp_t)outer_inv_range);
}
#else
#if defined(__mips__)
-
IMG_VOID OSCleanCPUCacheKM(IMG_VOID)
{
return IMG_TRUE;
}
-
-#else
+#else
#error "Implement CPU cache flush/clean/invalidate primitives for this CPU!"