Commit 65439b68 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'topic/drm-misc-2016-06-01' of git://anongit.freedesktop.org/drm-intel into drm-next

Frist -misc pull for 4.8, with pretty much just random all over plus a few
more lockless gem BO patches acked/reviewed by driver maintainers.

I'm starting a bit earlier this time around because there's a few invasive
patch series to land (nonblocking atomic prep work, fence prep work,
rst/sphinx kerneldoc finally happening) and I need a baseline with all the
branches merged.

* tag 'topic/drm-misc-2016-06-01' of git://anongit.freedesktop.org/drm-intel: (21 commits)
  drm/vc4: Use lockless gem BO free callback
  drm/vc4: Use drm_gem_object_unreference_unlocked
  drm: Initialize a linear gamma table by default
  drm/vgem: Use lockless gem BO free callback
  drm/qxl: Don't set a gamma table size
  drm/msm: Nuke dummy gamma_set/get functions
  drm/cirrus: Drop redundnant gamma size check
  drm/fb-helper: Remove dead code in setcolreg
  drm/mediatek: Use lockless gem BO free callback
  drm/hisilicon: Use lockless gem BO free callback
  drm/hlcd: Use lockless gem BO free callback
  vga_switcheroo: Support deferred probing of audio clients
  vga_switcheroo: Add helper for deferred probing
  virtio-gpu: fix output lookup
  drm/doc: Unify KMS Locking docs
  drm/atomic-helper: Do not call ->mode_fixup for CRTC which will be disabled
  Fix annoyingly awkward typo in drm_edid_load.c
  drm/doc: Drop vblank_disable_allow wording
  drm: use seqlock for vblank time/count
  drm/mm: avoid possible null pointer dereference
  ...
parents 1a695a90 b82caafc
......@@ -1092,22 +1092,6 @@ int max_width, max_height;</synopsis>
operation.
</para>
</sect2>
<sect2>
<title>Locking</title>
<para>
Beside some lookup structures with their own locking (which is hidden
behind the interface functions) most of the modeset state is protected
by the <code>dev-&lt;mode_config.lock</code> mutex and additionally
per-crtc locks to allow cursor updates, pageflips and similar operations
to occur concurrently with background tasks like output detection.
Operations which cross domains like a full modeset always grab all
locks. Drivers there need to protect resources shared between crtcs with
additional locking. They also need to be careful to always grab the
relevant crtc locks if a modset functions touches crtc state, e.g. for
load detection (which does only grab the <code>mode_config.lock</code>
to allow concurrent screen updates on live crtcs).
</para>
</sect2>
</sect1>
<!-- Internals: kms initialization and cleanup -->
......@@ -2845,14 +2829,7 @@ void (*disable_vblank) (struct drm_device *dev, int crtc);</synopsis>
<para>
Drivers must initialize the vertical blanking handling core with a call to
<function>drm_vblank_init</function> in their
<methodname>load</methodname> operation. The function will set the struct
<structname>drm_device</structname>
<structfield>vblank_disable_allowed</structfield> field to 0. This will
keep vertical blanking interrupts enabled permanently until the first mode
set operation, where <structfield>vblank_disable_allowed</structfield> is
set to 1. The reason behind this is not clear. Drivers can set the field
to 1 after <function>calling drm_vblank_init</function> to make vertical
blanking interrupts dynamically managed from the beginning.
<methodname>load</methodname> operation.
</para>
<para>
Vertical blanking interrupts can be enabled by the DRM core or by drivers
......
......@@ -3854,6 +3854,9 @@ T: git git://people.freedesktop.org/~airlied/linux
S: Maintained
F: drivers/gpu/drm/
F: drivers/gpu/vga/
F: Documentation/devicetree/bindings/display/
F: Documentation/devicetree/bindings/gpu/
F: Documentation/devicetree/bindings/video/
F: Documentation/DocBook/gpu.*
F: include/drm/
F: include/uapi/drm/
......
......@@ -316,7 +316,7 @@ static struct drm_driver hdlcd_driver = {
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = hdlcd_enable_vblank,
.disable_vblank = hdlcd_disable_vblank,
.gem_free_object = drm_gem_cma_free_object,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = drm_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
......
......@@ -331,9 +331,6 @@ static void cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
int i;
if (size != CIRRUS_LUT_SIZE)
return;
for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
cirrus_crtc->lut_r[i] = red[i];
cirrus_crtc->lut_g[i] = green[i];
......
......@@ -414,6 +414,9 @@ mode_fixup(struct drm_atomic_state *state)
for_each_crtc_in_state(state, crtc, crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
if (!crtc_state->enable)
continue;
if (!crtc_state->mode_changed &&
!crtc_state->connectors_changed)
continue;
......
......@@ -5139,6 +5139,9 @@ EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
int gamma_size)
{
uint16_t *r_base, *g_base, *b_base;
int i;
crtc->gamma_size = gamma_size;
crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
......@@ -5148,6 +5151,16 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
return -ENOMEM;
}
r_base = crtc->gamma_store;
g_base = r_base + gamma_size;
b_base = g_base + gamma_size;
for (i = 0; i < gamma_size; i++) {
r_base[i] = i << 8;
g_base[i] = i << 8;
b_base[i] = i << 8;
}
return 0;
}
EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
......
......@@ -271,7 +271,7 @@ int drm_load_edid_firmware(struct drm_connector *connector)
* by commas, search through the list looking for one that
* matches the connector.
*
* If there's one or more that don't't specify a connector, keep
* If there's one or more that doesn't specify a connector, keep
* the last one found one as a fallback.
*/
fwstr = kstrdup(edid_firmware, GFP_KERNEL);
......
......@@ -1042,7 +1042,6 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb;
int pindex;
if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
u32 *palette;
......@@ -1074,38 +1073,10 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
!fb_helper->funcs->gamma_get))
return -EINVAL;
pindex = regno;
WARN_ON(fb->bits_per_pixel != 8);
if (fb->bits_per_pixel == 16) {
pindex = regno << 3;
fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
if (fb->depth == 16 && regno > 63)
return -EINVAL;
if (fb->depth == 15 && regno > 31)
return -EINVAL;
if (fb->depth == 16) {
u16 r, g, b;
int i;
if (regno < 32) {
for (i = 0; i < 8; i++)
fb_helper->funcs->gamma_set(crtc, red,
green, blue, pindex + i);
}
fb_helper->funcs->gamma_get(crtc, &r,
&g, &b,
pindex >> 1);
for (i = 0; i < 4; i++)
fb_helper->funcs->gamma_set(crtc, r,
green, b,
(pindex >> 1) + i);
}
}
if (fb->depth != 16)
fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
return 0;
}
......
......@@ -42,10 +42,6 @@
#include <linux/vgaarb.h>
#include <linux/export.h>
/* Access macro for slots in vblank timestamp ringbuffer. */
#define vblanktimestamp(dev, pipe, count) \
((dev)->vblank[pipe].time[(count) % DRM_VBLANKTIME_RBSIZE])
/* Retry timestamp calculation up to 3 times to satisfy
* drm_timestamp_precision before giving up.
*/
......@@ -82,29 +78,15 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
struct timeval *t_vblank, u32 last)
{
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
u32 tslot;
assert_spin_locked(&dev->vblank_time_lock);
vblank->last = last;
/* All writers hold the spinlock, but readers are serialized by
* the latching of vblank->count below.
*/
tslot = vblank->count + vblank_count_inc;
vblanktimestamp(dev, pipe, tslot) = *t_vblank;
/*
* vblank timestamp updates are protected on the write side with
* vblank_time_lock, but on the read side done locklessly using a
* sequence-lock on the vblank counter. Ensure correct ordering using
* memory barrriers. We need the barrier both before and also after the
* counter update to synchronize with the next timestamp write.
* The read-side barriers for this are in drm_vblank_count_and_time.
*/
smp_wmb();
write_seqlock(&vblank->seqlock);
vblank->time = *t_vblank;
vblank->count += vblank_count_inc;
smp_wmb();
write_sequnlock(&vblank->seqlock);
}
/**
......@@ -205,7 +187,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
const struct timeval *t_old;
u64 diff_ns;
t_old = &vblanktimestamp(dev, pipe, vblank->count);
t_old = &vblank->time;
diff_ns = timeval_to_ns(&t_vblank) - timeval_to_ns(t_old);
/*
......@@ -239,49 +221,6 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
diff = 1;
}
/*
* FIMXE: Need to replace this hack with proper seqlocks.
*
* Restrict the bump of the software vblank counter to a safe maximum
* value of +1 whenever there is the possibility that concurrent readers
* of vblank timestamps could be active at the moment, as the current
* implementation of the timestamp caching and updating is not safe
* against concurrent readers for calls to store_vblank() with a bump
* of anything but +1. A bump != 1 would very likely return corrupted
* timestamps to userspace, because the same slot in the cache could
* be concurrently written by store_vblank() and read by one of those
* readers without the read-retry logic detecting the collision.
*
* Concurrent readers can exist when we are called from the
* drm_vblank_off() or drm_vblank_on() functions and other non-vblank-
* irq callers. However, all those calls to us are happening with the
* vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount
* can't increase while we are executing. Therefore a zero refcount at
* this point is safe for arbitrary counter bumps if we are called
* outside vblank irq, a non-zero count is not 100% safe. Unfortunately
* we must also accept a refcount of 1, as whenever we are called from
* drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and
* we must let that one pass through in order to not lose vblank counts
* during vblank irq off - which would completely defeat the whole
* point of this routine.
*
* Whenever we are called from vblank irq, we have to assume concurrent
* readers exist or can show up any time during our execution, even if
* the refcount is currently zero, as vblank irqs are usually only
* enabled due to the presence of readers, and because when we are called
* from vblank irq we can't hold the vbl_lock to protect us from sudden
* bumps in vblank refcount. Therefore also restrict bumps to +1 when
* called from vblank irq.
*/
if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 ||
(flags & DRM_CALLED_FROM_VBLIRQ))) {
DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u "
"refcount %u, vblirq %u\n", pipe, diff,
atomic_read(&vblank->refcount),
(flags & DRM_CALLED_FROM_VBLIRQ) != 0);
diff = 1;
}
DRM_DEBUG_VBL("updating vblank count on crtc %u:"
" current=%u, diff=%u, hw=%u hw_last=%u\n",
pipe, vblank->count, diff, cur_vblank, vblank->last);
......@@ -417,6 +356,7 @@ int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs)
init_waitqueue_head(&vblank->queue);
setup_timer(&vblank->disable_timer, vblank_disable_fn,
(unsigned long)vblank);
seqlock_init(&vblank->seqlock);
}
DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n");
......@@ -986,25 +926,19 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe,
struct timeval *vblanktime)
{
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
int count = DRM_TIMESTAMP_MAXRETRIES;
u32 cur_vblank;
u32 vblank_count;
unsigned int seq;
if (WARN_ON(pipe >= dev->num_crtcs))
return 0;
/*
* Vblank timestamps are read lockless. To ensure consistency the vblank
* counter is rechecked and ordering is ensured using memory barriers.
* This works like a seqlock. The write-side barriers are in store_vblank.
*/
do {
cur_vblank = vblank->count;
smp_rmb();
*vblanktime = vblanktimestamp(dev, pipe, cur_vblank);
smp_rmb();
} while (cur_vblank != vblank->count && --count > 0);
seq = read_seqbegin(&vblank->seqlock);
vblank_count = vblank->count;
*vblanktime = vblank->time;
} while (read_seqretry(&vblank->seqlock, seq));
return cur_vblank;
return vblank_count;
}
EXPORT_SYMBOL(drm_vblank_count_and_time);
......
......@@ -179,12 +179,14 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
{
struct drm_mm_node *hole;
u64 end = node->start + node->size;
u64 end;
u64 hole_start;
u64 hole_end;
BUG_ON(node == NULL);
end = node->start + node->size;
/* Find the relevant hole to add our node to */
drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
if (hole_start > node->start || hole_end < end)
......
......@@ -30,12 +30,12 @@
*
* As KMS moves toward more fine grained locking, and atomic ioctl where
* userspace can indirectly control locking order, it becomes necessary
* to use ww_mutex and acquire-contexts to avoid deadlocks. But because
* to use &ww_mutex and acquire-contexts to avoid deadlocks. But because
* the locking is more distributed around the driver code, we want a bit
* of extra utility/tracking out of our acquire-ctx. This is provided
* by drm_modeset_lock / drm_modeset_acquire_ctx.
*
* For basic principles of ww_mutex, see: Documentation/locking/ww-mutex-design.txt
* For basic principles of &ww_mutex, see: Documentation/locking/ww-mutex-design.txt
*
* The basic usage pattern is to:
*
......@@ -51,6 +51,13 @@
* ... do stuff ...
* drm_modeset_drop_locks(&ctx);
* drm_modeset_acquire_fini(&ctx);
*
* On top of of these per-object locks using &ww_mutex there's also an overall
* dev->mode_config.lock, for protecting everything else. Mostly this means
* probe state of connectors, and preventing hotplug add/removal of connectors.
*
* Finally there's a bunch of dedicated locks to protect drm core internal
* lists and lookup data structures.
*/
/**
......
......@@ -491,7 +491,6 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
struct drm_psb_private *dev_priv = dev->dev_private;
struct gma_crtc *gma_crtc;
int i;
uint16_t *r_base, *g_base, *b_base;
/* We allocate a extra array of drm_connector pointers
* for fbdev after the crtc */
......@@ -519,16 +518,10 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
gma_crtc->pipe = pipe;
gma_crtc->plane = pipe;
r_base = gma_crtc->base.gamma_store;
g_base = r_base + 256;
b_base = g_base + 256;
for (i = 0; i < 256; i++) {
gma_crtc->lut_r[i] = i;
gma_crtc->lut_g[i] = i;
gma_crtc->lut_b[i] = i;
r_base[i] = i << 8;
g_base[i] = i << 8;
b_base[i] = i << 8;
gma_crtc->lut_adj[i] = 0;
}
......
......@@ -173,7 +173,7 @@ static struct drm_driver kirin_drm_driver = {
.fops = &kirin_drm_fops,
.set_busid = drm_platform_set_busid,
.gem_free_object = drm_gem_cma_free_object,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = kirin_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
......
......@@ -35,11 +35,9 @@
#include "i915_trace.h"
#include "intel_drv.h"
#include <linux/apple-gmux.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include <drm/drm_crtc_helper.h>
......@@ -1030,13 +1028,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (PCI_FUNC(pdev->devfn))
return -ENODEV;
/*
* apple-gmux is needed on dual GPU MacBook Pro
* to probe the panel if we're the inactive GPU.
*/
if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) &&
apple_gmux_present() && pdev != vga_default_device() &&
!vga_switcheroo_handler_flags())
if (vga_switcheroo_client_probe_defer(pdev))
return -EPROBE_DEFER;
return drm_get_pci_dev(pdev, ent, &driver);
......
......@@ -243,7 +243,7 @@ static struct drm_driver mtk_drm_driver = {
.enable_vblank = mtk_drm_crtc_enable_vblank,
.disable_vblank = mtk_drm_crtc_disable_vblank,
.gem_free_object = mtk_drm_gem_free_object,
.gem_free_object_unlocked = mtk_drm_gem_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = mtk_drm_gem_dumb_create,
.dumb_map_offset = mtk_drm_gem_dumb_map_offset,
......
......@@ -184,21 +184,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
return ret;
}
static void msm_crtc_fb_gamma_set(struct drm_crtc *crtc,
u16 red, u16 green, u16 blue, int regno)
{
DBG("fbdev: set gamma");
}
static void msm_crtc_fb_gamma_get(struct drm_crtc *crtc,
u16 *red, u16 *green, u16 *blue, int regno)
{
DBG("fbdev: get gamma");
}
static const struct drm_fb_helper_funcs msm_fb_helper_funcs = {
.gamma_set = msm_crtc_fb_gamma_set,
.gamma_get = msm_crtc_fb_gamma_get,
.fb_probe = msm_fbdev_create,
};
......
......@@ -22,13 +22,11 @@
* Authors: Ben Skeggs
*/
#include <linux/apple-gmux.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include "drmP.h"
......@@ -315,13 +313,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
bool boot = false;
int ret;
/*
* apple-gmux is needed on dual GPU MacBook Pro
* to probe the panel if we're the inactive GPU.
*/
if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) &&
apple_gmux_present() && pdev != vga_default_device() &&
!vga_switcheroo_handler_flags())
if (vga_switcheroo_client_probe_defer(pdev))
return -EPROBE_DEFER;
/* remove conflicting drivers (vesafb, efifb etc) */
......
......@@ -730,7 +730,6 @@ static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
drm_crtc_init(dev, &qxl_crtc->base, &qxl_crtc_funcs);
qxl_crtc->index = crtc_id;
drm_mode_crtc_set_gamma_size(&qxl_crtc->base, 256);
drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
return 0;
}
......
......@@ -34,11 +34,9 @@
#include "radeon_drv.h"
#include <drm/drm_pciids.h>
#include <linux/apple-gmux.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include <drm/drm_gem.h>
......@@ -340,13 +338,7 @@ static int radeon_pci_probe(struct pci_dev *pdev,
if (ret == -EPROBE_DEFER)
return ret;
/*
* apple-gmux is needed on dual GPU MacBook Pro
* to probe the panel if we're the inactive GPU.
*/
if (IS_ENABLED(CONFIG_VGA_ARB) && IS_ENABLED(CONFIG_VGA_SWITCHEROO) &&
apple_gmux_present() && pdev != vga_default_device() &&
!vga_switcheroo_handler_flags())
if (vga_switcheroo_client_probe_defer(pdev))
return -EPROBE_DEFER;
/* Get rid of things like offb */
......
......@@ -291,8 +291,6 @@ static void vc4_bo_cache_free_old(struct drm_device *dev)
/* Called on the last userspace/kernel unreference of the BO. Returns
* it to the BO cache if possible, otherwise frees it.
*
* Note that this is called with the struct_mutex held.
*/
void vc4_free_object(struct drm_gem_object *gem_bo)
{
......
......@@ -99,7 +99,7 @@ static struct drm_driver vc4_drm_driver = {
#endif
.gem_create_object = vc4_create_object,
.gem_free_object = vc4_free_object,
.gem_free_object_unlocked = vc4_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
......
......@@ -53,10 +53,8 @@ vc4_free_hang_state(struct drm_device *dev, struct vc4_hang_state *state)
{
unsigned int i;
mutex_lock(&dev->struct_mutex);
for (i = 0; i < state->user_state.bo_count; i++)
drm_gem_object_unreference(state->bo[i]);
mutex_unlock(&dev->struct_mutex);
drm_gem_object_unreference_unlocked(state->bo[i]);
kfree(state);
}
......@@ -687,11 +685,9 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
struct vc4_dev *vc4 = to_vc4_dev(dev);
unsigned i;
/* Need the struct lock for drm_gem_object_unreference(). */
mutex_lock(&dev->struct_mutex);
if (exec->bo) {
for (i = 0; i < exec->bo_count; i++)
drm_gem_object_unreference(&exec->bo[i]->base);
drm_gem_object_unreference_unlocked(&exec->bo[i]->base);
kfree(exec->bo);
}
......@@ -699,9 +695,8 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
struct vc4_bo *bo = list_first_entry(&exec->unref_list,
struct vc4_bo, unref_head);
list_del(&bo->unref_head);
drm_gem_object_unreference(&bo->base.base);
drm_gem_object_unreference_unlocked(&bo->base.base);
}
mutex_unlock(&dev->struct_mutex);
mutex_lock(&vc4->power_lock);
if (--vc4->power_refcount == 0)
......
......@@ -235,7 +235,7 @@ static const struct file_operations vgem_driver_fops = {
static struct drm_driver vgem_driver = {
.driver_features = DRIVER_GEM,
.gem_free_object = vgem_gem_free_object,
.gem_free_object_unlocked = vgem_gem_free_object,
.gem_vm_ops = &vgem_gem_vm_ops,
.ioctls = vgem_ioctls,
.fops = &vgem_driver_fops,
......
......@@ -63,11 +63,17 @@ static void virtio_gpu_plane_atomic_update(struct drm_plane *plane,
{
struct drm_device *dev = plane->dev;
struct virtio_gpu_device *vgdev = dev->dev_private;
struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(plane->crtc);
struct virtio_gpu_output *output = NULL;
struct virtio_gpu_framebuffer *vgfb;
struct virtio_gpu_object *bo;
uint32_t handle;
if (plane->state->crtc)
output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
if (old_state->crtc)
output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
WARN_ON(!output);
if (plane->state->fb) {
vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
bo = gem_to_virtio_gpu_obj(vgfb->obj);
......
......@@ -30,6 +30,7 @@
#define pr_fmt(fmt) "vga_switcheroo: " fmt
#include <linux/apple-gmux.h>
#include <linux/console.h>
#include <linux/debugfs.h>
#include <linux/fb.h>
......@@ -308,7 +309,8 @@ static int register_client(struct pci_dev *pdev,
*
* Register vga client (GPU). Enable vga_switcheroo if another GPU and a
* handler have already registered. The power state of the client is assumed
* to be ON.
* to be ON. Beforehand, vga_switcheroo_client_probe_defer() shall be called
* to ensure that all prerequisites are met.
*
* Return: 0 on success, -ENOMEM on memory allocation error.
*/
......@@ -329,7 +331,8 @@ EXPORT_SYMBOL(vga_switcheroo_register_client);
* @id: client identifier
*
* Register audio client (audio device on a GPU). The power state of the
* client is assumed to be ON.
* client is assumed to be ON. Beforehand, vga_switcheroo_client_probe_defer()
* shall be called to ensure that all prerequisites are met.
*
* Return: 0 on success, -ENOMEM on memory allocation error.
*/
......@@ -375,6 +378,33 @@ find_active_client(struct list_head *head)
return NULL;
}
/**
* vga_switcheroo_client_probe_defer() - whether to defer probing a given client
* @pdev: client pci device
*
* Determine whether any prerequisites are not fulfilled to probe a given
* client. Drivers shall invoke this early on in their ->probe callback
* and return %-EPROBE_DEFER if it evaluates to %true. Thou shalt not
* register the client ere thou hast called this.
*
* Return: %true if probing should be deferred, otherwise %false.
*/
bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev)
{
if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
/*
* apple-gmux is needed on pre-retina MacBook Pro
* to probe the panel if pdev is the inactive GPU.
*/
if (apple_gmux_present() && pdev != vga_default_device() &&
!vgasr_priv.handler_flags)
return true;
}
return false;
}
EXPORT_SYMBOL(vga_switcheroo_client_probe_defer);
/**
* vga_switcheroo_get_client_state() - obtain power state of a given client
* @pdev: client pci device
......
......@@ -52,6 +52,7 @@
#include <linux/poll.h>
#include <linux/ratelimit.h>
#include <linux/sched.h>
#include <linux/seqlock.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
......@@ -392,11 +393,6 @@ struct drm_master {
void *driver_priv;
};
/* Size of ringbuffer for vblank timestamps. Just double-buffer
* in initial implementation.
*/
#define DRM_VBLANKTIME_RBSIZE 2
/* Flags and return codes for get_vblank_timestamp() driver function. */
#define DRM_CALLED_FROM_VBLIRQ 1
#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0)
......@@ -725,10 +721,10 @@ struct drm_vblank_crtc {
wait_queue_head_t queue; /**< VBLANK wait queue */
struct timer_list disable_timer; /* delayed disable timer */
/* vblank counter, protected by dev->vblank_time_lock for writes */
u32 count;
/* vblank timestamps, protected by dev->vblank_time_lock for writes */
struct timeval time[DRM_VBLANKTIME_RBSIZE];
seqlock_t seqlock; /* protects vblank count and time */
u32 count; /* vblank counter */
struct timeval time; /* vblank timestamp */
atomic_t refcount; /* number of users of vblank interruptsper crtc */
u32 last; /* protected by dev->vbl_lock, used */
......
......@@ -165,6 +165,7 @@ int vga_switcheroo_unlock_ddc(struct pci_dev *pdev);
int vga_switcheroo_process_delayed_switch(void);
bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev);
enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev);
void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic);
......@@ -188,6 +189,7 @@ static inline enum vga_switcheroo_handler_flags_t vga_switcheroo_handler_flags(v
static inline int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { return -ENODEV; }
static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return -ENODEV; }
static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
static inline bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) { return false; }
static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }
static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic) {}
......
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