Skip to content

Commit

Permalink
drm/i915: Demidlayer driver loading
Browse files Browse the repository at this point in the history
Take control over allocating, loading and registering the driver from the
DRM midlayer by performing it manually from i915_pci_probe. This allows
us to carefully control the order of when we setup the hardware vs when
it becomes visible to third parties (including userspace). The current
ordering makes the driver visible to userspace first (in order to
coordinate with removed DRI1 userspace), but that ordering incurs risk.
The risk increases as we strive for more asynchronous loading.

One side effect of controlling the allocation is that we can allocate
both the drm_device + drm_i915_private in one block, the next step
towards subclassing.

Unload is still left as before, a mix of midlayer and driver.

v2: After drm_dev_init(), we should call drm_dev_unref() so that we call
drm_dev_release() and free everything from drm_dev_init().
v3: Fixup missed error code for failing to allocate dev_priv

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1466773227-7994-6-git-send-email-chris@chris-wilson.co.uk
  • Loading branch information
Chris Wilson committed Jun 24, 2016
1 parent 1dac891 commit 8f460e2
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 32 deletions.
78 changes: 49 additions & 29 deletions drivers/gpu/drm/i915/i915_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1075,9 +1075,10 @@ static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv)
* function hooks not requiring accessing the device.
*/
static int i915_driver_init_early(struct drm_i915_private *dev_priv,
struct drm_device *dev,
struct intel_device_info *info)
const struct pci_device_id *ent)
{
const struct intel_device_info *match_info =
(struct intel_device_info *)ent->driver_data;
struct intel_device_info *device_info;
int ret = 0;

Expand All @@ -1086,8 +1087,8 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,

/* Setup the write-once "constant" device info */
device_info = (struct intel_device_info *)&dev_priv->info;
memcpy(device_info, info, sizeof(dev_priv->info));
device_info->device_id = dev->pdev->device;
memcpy(device_info, match_info, sizeof(*device_info));
device_info->device_id = dev_priv->drm.pdev->device;

BUG_ON(device_info->gen > sizeof(device_info->gen_mask) * BITS_PER_BYTE);
device_info->gen_mask = BIT(device_info->gen - 1);
Expand All @@ -1113,26 +1114,26 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
goto err_workqueues;

/* This must be called before any calls to HAS_PCH_* */
intel_detect_pch(dev);
intel_detect_pch(&dev_priv->drm);

intel_pm_setup(dev);
intel_pm_setup(&dev_priv->drm);
intel_init_dpio(dev_priv);
intel_power_domains_init(dev_priv);
intel_irq_init(dev_priv);
intel_init_display_hooks(dev_priv);
intel_init_clock_gating_hooks(dev_priv);
intel_init_audio_hooks(dev_priv);
i915_gem_load_init(dev);
i915_gem_load_init(&dev_priv->drm);

intel_display_crc_init(dev);
intel_display_crc_init(&dev_priv->drm);

i915_dump_device_info(dev_priv);

/* Not all pre-production machines fall into this category, only the
* very first ones. Almost everything should work, except for maybe
* suspend/resume. And we don't implement workarounds that affect only
* pre-production machines. */
if (IS_HSW_EARLY_SDV(dev))
if (IS_HSW_EARLY_SDV(dev_priv))
DRM_INFO("This is an early pre-production Haswell machine. "
"It may not be fully functional.\n");

Expand Down Expand Up @@ -1390,16 +1391,21 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;

i915_gem_shrinker_init(dev_priv);

/*
* Notify a valid surface after modesetting,
* when running inside a VM.
*/
if (intel_vgpu_active(dev_priv))
I915_WRITE(vgtif_reg(display_ready), VGT_DRV_DISPLAY_READY);

i915_debugfs_register(dev_priv);
i915_setup_sysfs(dev);
intel_modeset_register(dev_priv);
/* Reveal our presence to userspace */
if (drm_dev_register(dev, 0) == 0) {
i915_debugfs_register(dev_priv);
i915_setup_sysfs(dev);
intel_modeset_register(dev_priv);
} else
DRM_ERROR("Failed to register driver for userspace access!\n");

if (INTEL_INFO(dev_priv)->num_pipes) {
/* Must be done after probing outputs */
Expand Down Expand Up @@ -1449,24 +1455,38 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
* - allocate initial config memory
* - setup the DRM framebuffer with the allocated memory
*/
int i915_driver_load(struct drm_device *dev, unsigned long flags)
int i915_driver_load(struct pci_dev *pdev,
const struct pci_device_id *ent,
struct drm_driver *driver)
{
struct drm_i915_private *dev_priv;
int ret = 0;
int ret;

ret = -ENOMEM;
dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
if (dev_priv == NULL)
return -ENOMEM;
if (dev_priv)
ret = drm_dev_init(&dev_priv->drm, driver, &pdev->dev);
if (ret) {
dev_printk(KERN_ERR, &pdev->dev,
"[" DRM_NAME ":%s] allocation failed\n", __func__);
kfree(dev_priv);
return ret;
}

dev->dev_private = dev_priv;
/* Must be set before calling __i915_printk */
dev_priv->dev = dev;
dev_priv->drm.pdev = pdev;
dev_priv->drm.dev_private = dev_priv;
dev_priv->dev = &dev_priv->drm;

ret = i915_driver_init_early(dev_priv, dev,
(struct intel_device_info *)flags);
ret = pci_enable_device(pdev);
if (ret)
goto out_free_priv;

pci_set_drvdata(pdev, &dev_priv->drm);

ret = i915_driver_init_early(dev_priv, ent);
if (ret < 0)
goto out_free_priv;
goto out_pci_disable;

intel_runtime_pm_get(dev_priv);

Expand All @@ -1483,13 +1503,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
* of the i915_driver_init_/i915_driver_register functions according
* to the role/effect of the given init step.
*/
if (INTEL_INFO(dev)->num_pipes) {
ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes);
if (INTEL_INFO(dev_priv)->num_pipes) {
ret = drm_vblank_init(dev_priv->dev,
INTEL_INFO(dev_priv)->num_pipes);
if (ret)
goto out_cleanup_hw;
}

ret = i915_load_modeset_init(dev);
ret = i915_load_modeset_init(dev_priv->dev);
if (ret < 0)
goto out_cleanup_vblank;

Expand All @@ -1502,19 +1523,19 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
return 0;

out_cleanup_vblank:
drm_vblank_cleanup(dev);
drm_vblank_cleanup(dev_priv->dev);
out_cleanup_hw:
i915_driver_cleanup_hw(dev_priv);
out_cleanup_mmio:
i915_driver_cleanup_mmio(dev_priv);
out_runtime_pm_put:
intel_runtime_pm_put(dev_priv);
i915_driver_cleanup_early(dev_priv);
out_pci_disable:
pci_disable_device(pdev);
out_free_priv:
i915_load_error(dev_priv, "Device initialization failed (%d)\n", ret);

kfree(dev_priv);

drm_dev_unref(&dev_priv->drm);
return ret;
}

Expand Down Expand Up @@ -1579,7 +1600,6 @@ int i915_driver_unload(struct drm_device *dev)
intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);

i915_driver_cleanup_early(dev_priv);
kfree(dev_priv);

return 0;
}
Expand Down
3 changes: 1 addition & 2 deletions drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (vga_switcheroo_client_probe_defer(pdev))
return -EPROBE_DEFER;

return drm_get_pci_dev(pdev, ent, &driver);
return i915_driver_load(pdev, ent, &driver);
}

static void
Expand Down Expand Up @@ -1748,7 +1748,6 @@ static struct drm_driver driver = {
.driver_features =
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME |
DRIVER_RENDER | DRIVER_MODESET,
.load = i915_driver_load,
.unload = i915_driver_unload,
.open = i915_driver_open,
.lastclose = i915_driver_lastclose,
Expand Down
6 changes: 5 additions & 1 deletion drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,8 @@ struct intel_wm_config {
};

struct drm_i915_private {
struct drm_device drm;

struct drm_device *dev;
struct kmem_cache *objects;
struct kmem_cache *vmas;
Expand Down Expand Up @@ -2909,7 +2911,9 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level,
#define i915_report_error(dev_priv, fmt, ...) \
__i915_printk(dev_priv, KERN_ERR, fmt, ##__VA_ARGS__)

extern int i915_driver_load(struct drm_device *, unsigned long flags);
extern int i915_driver_load(struct pci_dev *pdev,
const struct pci_device_id *ent,
struct drm_driver *driver);
extern int i915_driver_unload(struct drm_device *);
extern int i915_driver_open(struct drm_device *dev, struct drm_file *file);
extern void i915_driver_lastclose(struct drm_device * dev);
Expand Down

0 comments on commit 8f460e2

Please sign in to comment.