Commit b897e6fb authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-intel-next' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel

* 'drm-intel-next' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel:
  drm/i915: fix scheduling while holding the new active list spinlock
  drm/i915: Allow tiling of objects with bit 17 swizzling by the CPU.
  drm/i915: Correctly set the write flag for get_user_pages in pread.
  drm/i915: Fix use of uninitialized var in 40a5f0de
  drm/i915: indicate framebuffer restore key in SysRq help message
  drm/i915: sync hdmi detection by hdmi identifier with 2D
  drm/i915: Fix a mismerge of the IGD patch (new .find_pll hooks missed)
  drm/i915: Implement batch and ring buffer dumping
parents 6f66cbc6 68c84342
...@@ -446,6 +446,9 @@ struct drm_i915_gem_object { ...@@ -446,6 +446,9 @@ struct drm_i915_gem_object {
uint32_t tiling_mode; uint32_t tiling_mode;
uint32_t stride; uint32_t stride;
/** Record of address bit 17 of each page at last unbind. */
long *bit_17;
/** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */ /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
uint32_t agp_type; uint32_t agp_type;
...@@ -635,9 +638,13 @@ int i915_gem_attach_phys_object(struct drm_device *dev, ...@@ -635,9 +638,13 @@ int i915_gem_attach_phys_object(struct drm_device *dev,
void i915_gem_detach_phys_object(struct drm_device *dev, void i915_gem_detach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj); struct drm_gem_object *obj);
void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_free_all_phys_object(struct drm_device *dev);
int i915_gem_object_get_pages(struct drm_gem_object *obj);
void i915_gem_object_put_pages(struct drm_gem_object *obj);
/* i915_gem_tiling.c */ /* i915_gem_tiling.c */
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj);
void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj);
/* i915_gem_debug.c */ /* i915_gem_debug.c */
void i915_gem_dump_object(struct drm_gem_object *obj, int len, void i915_gem_dump_object(struct drm_gem_object *obj, int len,
......
This diff is collapsed.
...@@ -234,6 +234,96 @@ static int i915_hws_info(struct seq_file *m, void *data) ...@@ -234,6 +234,96 @@ static int i915_hws_info(struct seq_file *m, void *data)
return 0; return 0;
} }
static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_count)
{
int page, i;
uint32_t *mem;
for (page = 0; page < page_count; page++) {
mem = kmap(pages[page]);
for (i = 0; i < PAGE_SIZE; i += 4)
seq_printf(m, "%08x : %08x\n", i, mem[i / 4]);
kunmap(pages[page]);
}
}
static int i915_batchbuffer_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
int ret;
spin_lock(&dev_priv->mm.active_list_lock);
list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
obj = obj_priv->obj;
if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
ret = i915_gem_object_get_pages(obj);
if (ret) {
DRM_ERROR("Failed to get pages: %d\n", ret);
spin_unlock(&dev_priv->mm.active_list_lock);
return ret;
}
seq_printf(m, "--- gtt_offset = 0x%08x\n", obj_priv->gtt_offset);
i915_dump_pages(m, obj_priv->pages, obj->size / PAGE_SIZE);
i915_gem_object_put_pages(obj);
}
}
spin_unlock(&dev_priv->mm.active_list_lock);
return 0;
}
static int i915_ringbuffer_data(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u8 *virt;
uint32_t *ptr, off;
if (!dev_priv->ring.ring_obj) {
seq_printf(m, "No ringbuffer setup\n");
return 0;
}
virt = dev_priv->ring.virtual_start;
for (off = 0; off < dev_priv->ring.Size; off += 4) {
ptr = (uint32_t *)(virt + off);
seq_printf(m, "%08x : %08x\n", off, *ptr);
}
return 0;
}
static int i915_ringbuffer_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
unsigned int head, tail, mask;
head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
mask = dev_priv->ring.tail_mask;
seq_printf(m, "RingHead : %08x\n", head);
seq_printf(m, "RingTail : %08x\n", tail);
seq_printf(m, "RingMask : %08x\n", mask);
seq_printf(m, "RingSize : %08lx\n", dev_priv->ring.Size);
seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
return 0;
}
static struct drm_info_list i915_gem_debugfs_list[] = { static struct drm_info_list i915_gem_debugfs_list[] = {
{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
{"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
...@@ -243,6 +333,9 @@ static struct drm_info_list i915_gem_debugfs_list[] = { ...@@ -243,6 +333,9 @@ static struct drm_info_list i915_gem_debugfs_list[] = {
{"i915_gem_fence_regs", i915_gem_fence_regs_info, 0}, {"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
{"i915_gem_interrupt", i915_interrupt_info, 0}, {"i915_gem_interrupt", i915_interrupt_info, 0},
{"i915_gem_hws", i915_hws_info, 0}, {"i915_gem_hws", i915_hws_info, 0},
{"i915_ringbuffer_data", i915_ringbuffer_data, 0},
{"i915_ringbuffer_info", i915_ringbuffer_info, 0},
{"i915_batchbuffers", i915_batchbuffer_info, 0},
}; };
#define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list) #define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list)
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
* *
*/ */
#include "linux/string.h"
#include "linux/bitops.h"
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
#include "i915_drm.h" #include "i915_drm.h"
...@@ -127,8 +129,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) ...@@ -127,8 +129,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
swizzle_y = I915_BIT_6_SWIZZLE_9_11; swizzle_y = I915_BIT_6_SWIZZLE_9_11;
} else { } else {
/* Bit 17 swizzling by the CPU in addition. */ /* Bit 17 swizzling by the CPU in addition. */
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; swizzle_x = I915_BIT_6_SWIZZLE_9_10_17;
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; swizzle_y = I915_BIT_6_SWIZZLE_9_17;
} }
break; break;
} }
...@@ -288,6 +290,19 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, ...@@ -288,6 +290,19 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
else else
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y; args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
/* Hide bit 17 swizzling from the user. This prevents old Mesa
* from aborting the application on sw fallbacks to bit 17,
* and we use the pread/pwrite bit17 paths to swizzle for it.
* If there was a user that was relying on the swizzle
* information for drm_intel_bo_map()ed reads/writes this would
* break it, but we don't have any of those.
*/
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17)
args->swizzle_mode = I915_BIT_6_SWIZZLE_9;
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10;
/* If we can't handle the swizzling, make it untiled. */ /* If we can't handle the swizzling, make it untiled. */
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) { if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
args->tiling_mode = I915_TILING_NONE; args->tiling_mode = I915_TILING_NONE;
...@@ -354,8 +369,100 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, ...@@ -354,8 +369,100 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
DRM_ERROR("unknown tiling mode\n"); DRM_ERROR("unknown tiling mode\n");
} }
/* Hide bit 17 from the user -- see comment in i915_gem_set_tiling */
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17)
args->swizzle_mode = I915_BIT_6_SWIZZLE_9;
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10;
drm_gem_object_unreference(obj); drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return 0; return 0;
} }
/**
* Swap every 64 bytes of this page around, to account for it having a new
* bit 17 of its physical address and therefore being interpreted differently
* by the GPU.
*/
static int
i915_gem_swizzle_page(struct page *page)
{
char *vaddr;
int i;
char temp[64];
vaddr = kmap(page);
if (vaddr == NULL)
return -ENOMEM;
for (i = 0; i < PAGE_SIZE; i += 128) {
memcpy(temp, &vaddr[i], 64);
memcpy(&vaddr[i], &vaddr[i + 64], 64);
memcpy(&vaddr[i + 64], temp, 64);
}
kunmap(page);
return 0;
}
void
i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
int page_count = obj->size >> PAGE_SHIFT;
int i;
if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17)
return;
if (obj_priv->bit_17 == NULL)
return;
for (i = 0; i < page_count; i++) {
char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17;
if ((new_bit_17 & 0x1) !=
(test_bit(i, obj_priv->bit_17) != 0)) {
int ret = i915_gem_swizzle_page(obj_priv->pages[i]);
if (ret != 0) {
DRM_ERROR("Failed to swizzle page\n");
return;
}
set_page_dirty(obj_priv->pages[i]);
}
}
}
void
i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
int page_count = obj->size >> PAGE_SHIFT;
int i;
if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17)
return;
if (obj_priv->bit_17 == NULL) {
obj_priv->bit_17 = kmalloc(BITS_TO_LONGS(page_count) *
sizeof(long), GFP_KERNEL);
if (obj_priv->bit_17 == NULL) {
DRM_ERROR("Failed to allocate memory for bit 17 "
"record\n");
return;
}
}
for (i = 0; i < page_count; i++) {
if (page_to_phys(obj_priv->pages[i]) & (1 << 17))
__set_bit(i, obj_priv->bit_17);
else
__clear_bit(i, obj_priv->bit_17);
}
}
...@@ -367,6 +367,7 @@ static const intel_limit_t intel_limits[] = { ...@@ -367,6 +367,7 @@ static const intel_limit_t intel_limits[] = {
.p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
}, },
{ /* INTEL_LIMIT_IGD_LVDS */ { /* INTEL_LIMIT_IGD_LVDS */
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
...@@ -380,6 +381,7 @@ static const intel_limit_t intel_limits[] = { ...@@ -380,6 +381,7 @@ static const intel_limit_t intel_limits[] = {
/* IGD only supports single-channel mode. */ /* IGD only supports single-channel mode. */
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW }, .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
.find_pll = intel_find_best_PLL,
}, },
}; };
......
...@@ -864,8 +864,8 @@ static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3) ...@@ -864,8 +864,8 @@ static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3)
static struct sysrq_key_op sysrq_intelfb_restore_op = { static struct sysrq_key_op sysrq_intelfb_restore_op = {
.handler = intelfb_sysrq, .handler = intelfb_sysrq,
.help_msg = "force fb", .help_msg = "force-fb(G)",
.action_msg = "force restore of fb console", .action_msg = "Restore framebuffer console",
}; };
int intelfb_probe(struct drm_device *dev) int intelfb_probe(struct drm_device *dev)
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
struct intel_hdmi_priv { struct intel_hdmi_priv {
u32 sdvox_reg; u32 sdvox_reg;
u32 save_SDVOX; u32 save_SDVOX;
int has_hdmi_sink; bool has_hdmi_sink;
}; };
static void intel_hdmi_mode_set(struct drm_encoder *encoder, static void intel_hdmi_mode_set(struct drm_encoder *encoder,
...@@ -128,6 +128,22 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, ...@@ -128,6 +128,22 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
return true; return true;
} }
static void
intel_hdmi_sink_detect(struct drm_connector *connector)
{
struct intel_output *intel_output = to_intel_output(connector);
struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
struct edid *edid = NULL;
edid = drm_get_edid(&intel_output->base,
&intel_output->ddc_bus->adapter);
if (edid != NULL) {
hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
kfree(edid);
intel_output->base.display_info.raw_edid = NULL;
}
}
static enum drm_connector_status static enum drm_connector_status
intel_hdmi_detect(struct drm_connector *connector) intel_hdmi_detect(struct drm_connector *connector)
{ {
...@@ -158,9 +174,10 @@ intel_hdmi_detect(struct drm_connector *connector) ...@@ -158,9 +174,10 @@ intel_hdmi_detect(struct drm_connector *connector)
return connector_status_unknown; return connector_status_unknown;
} }
if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) {
intel_hdmi_sink_detect(connector);
return connector_status_connected; return connector_status_connected;
else } else
return connector_status_disconnected; return connector_status_disconnected;
} }
......
...@@ -1357,6 +1357,23 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) ...@@ -1357,6 +1357,23 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
intel_sdvo_read_response(intel_output, &response, 2); intel_sdvo_read_response(intel_output, &response, 2);
} }
static void
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
{
struct intel_output *intel_output = to_intel_output(connector);
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
struct edid *edid = NULL;
intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
edid = drm_get_edid(&intel_output->base,
&intel_output->ddc_bus->adapter);
if (edid != NULL) {
sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid);
kfree(edid);
intel_output->base.display_info.raw_edid = NULL;
}
}
static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
{ {
u8 response[2]; u8 response[2];
...@@ -1371,9 +1388,10 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect ...@@ -1371,9 +1388,10 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
if (status != SDVO_CMD_STATUS_SUCCESS) if (status != SDVO_CMD_STATUS_SUCCESS)
return connector_status_unknown; return connector_status_unknown;
if ((response[0] != 0) || (response[1] != 0)) if ((response[0] != 0) || (response[1] != 0)) {
intel_sdvo_hdmi_sink_detect(connector);
return connector_status_connected; return connector_status_connected;
else } else
return connector_status_disconnected; return connector_status_disconnected;
} }
......
...@@ -594,6 +594,9 @@ struct drm_i915_gem_busy { ...@@ -594,6 +594,9 @@ struct drm_i915_gem_busy {
#define I915_BIT_6_SWIZZLE_9_10_11 4 #define I915_BIT_6_SWIZZLE_9_10_11 4
/* Not seen by userland */ /* Not seen by userland */
#define I915_BIT_6_SWIZZLE_UNKNOWN 5 #define I915_BIT_6_SWIZZLE_UNKNOWN 5
/* Seen by userland. */
#define I915_BIT_6_SWIZZLE_9_17 6
#define I915_BIT_6_SWIZZLE_9_10_17 7
struct drm_i915_gem_set_tiling { struct drm_i915_gem_set_tiling {
/** Handle of the buffer to have its tiling state updated */ /** Handle of the buffer to have its tiling state updated */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment