summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2015-09-26 22:00:01 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2015-09-26 22:00:01 +0000
commit5b51ed28a6f04b49b8fa01674c5c7cc25a08c4e5 (patch)
treeb2b629b4d81b21bdb9780a4d6474b63d89d19641 /sys/dev/pci
parent7c2a190511f8aa92075125450b736ad7785eec24 (diff)
Try a little bit harder to clean up if attaching inteldrm(4) fails.
The crucial bit is that we now clear dev->dev_priv, which prevents the X server from opening /dev/drmN and crashing the kernel because the driver isn't fully initialized. While there, try a little bit harder to print error messages the proper way. Things will still look ugly though if the failure is somewhere in the Linux code.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/drm/drm_linux.h15
-rw-r--r--sys/dev/pci/drm/i915/i915_drv.c115
-rw-r--r--sys/dev/pci/drm/i915/intel_i2c.c7
3 files changed, 87 insertions, 50 deletions
diff --git a/sys/dev/pci/drm/drm_linux.h b/sys/dev/pci/drm/drm_linux.h
index eb9eb5c6225..2fbfe9407c2 100644
--- a/sys/dev/pci/drm/drm_linux.h
+++ b/sys/dev/pci/drm/drm_linux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: drm_linux.h,v 1.38 2015/09/26 19:52:16 kettenis Exp $ */
+/* $OpenBSD: drm_linux.h,v 1.39 2015/09/26 22:00:00 kettenis Exp $ */
/*
* Copyright (c) 2013, 2014, 2015 Mark Kettenis
*
@@ -426,6 +426,19 @@ complete_all(struct completion *x)
struct workqueue_struct;
+static inline struct workqueue_struct *
+alloc_ordered_workqueue(const char *name, int flags)
+{
+ struct taskq *tq = taskq_create(name, 1, IPL_TTY, 0);
+ return (struct workqueue_struct *)tq;
+}
+
+static inline void
+destroy_workqueue(struct workqueue_struct *wq)
+{
+ taskq_destroy((struct taskq *)wq);
+}
+
struct work_struct {
struct task task;
struct taskq *tq;
diff --git a/sys/dev/pci/drm/i915/i915_drv.c b/sys/dev/pci/drm/i915/i915_drv.c
index b3e7b00d677..e0d3ae49f0a 100644
--- a/sys/dev/pci/drm/i915/i915_drv.c
+++ b/sys/dev/pci/drm/i915/i915_drv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i915_drv.c,v 1.90 2015/09/26 19:52:16 kettenis Exp $ */
+/* $OpenBSD: i915_drv.c,v 1.91 2015/09/26 22:00:00 kettenis Exp $ */
/*
* Copyright (c) 2008-2009 Owain G. Ainsworth <oga@openbsd.org>
*
@@ -198,6 +198,7 @@ void intel_gtt_chipset_setup(struct drm_device *);
/* i915_dma.c */
void intel_setup_mchbar(struct drm_device *);
+void intel_teardown_mchbar(struct drm_device *);
int i915_load_modeset_init(struct drm_device *);
#undef INTEL_VGA_DEVICE
@@ -1177,22 +1178,20 @@ inteldrm_intr(void *arg)
void
inteldrm_attach(struct device *parent, struct device *self, void *aux)
{
- struct inteldrm_softc *dev_priv = (struct inteldrm_softc *)self;
- struct vga_pci_softc *vga_sc = (struct vga_pci_softc *)parent;
- struct pci_attach_args *pa = aux;
- struct vga_pci_bar *bar;
- struct drm_device *dev;
- const struct drm_pcidev *id_entry;
- int i;
- uint16_t pci_device;
+ struct inteldrm_softc *dev_priv = (struct inteldrm_softc *)self;
+ struct vga_pci_softc *vga_sc = (struct vga_pci_softc *)parent;
+ struct pci_attach_args *pa = aux;
+ struct rasops_info *ri = &dev_priv->ro;
+ struct wsemuldisplaydev_attach_args aa;
+ extern int wsdisplay_console_initted;
+ struct vga_pci_bar *bar;
+ struct drm_device *dev;
const struct intel_device_info *info;
int ret = 0, mmio_bar, mmio_size;
uint32_t aperture_size;
+ int i;
- id_entry = drm_find_description(PCI_VENDOR(pa->pa_id),
- PCI_PRODUCT(pa->pa_id), pciidlist);
- pci_device = PCI_PRODUCT(pa->pa_id);
- info = i915_get_device_id(pci_device);
+ info = i915_get_device_id(PCI_PRODUCT(pa->pa_id));
KASSERT(info->gen != 0);
dev_priv->info = info;
@@ -1213,8 +1212,6 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
dev = dev_priv->dev = (struct drm_device *)
drm_attach_pci(&inteldrm_driver, pa, 1, 1, self);
- printf("%s", dev_priv->sc_dev.dv_xname);
-
intel_gtt_chipset_setup(dev);
mtx_init(&mchdev_lock, IPL_TTY);
@@ -1232,7 +1229,6 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
intel_display_crc_init(dev);
i915_dump_device_info(dev_priv);
-#endif
/* Not all pre-production machines fall into this category, only the
* very first ones. Almost everything should work, except for maybe
@@ -1242,7 +1238,6 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
DRM_INFO("This is an early pre-production Haswell machine. "
"It may not be fully functional.\n");
-#ifdef __linux__
if (i915_get_bridge_dev(dev)) {
ret = -EIO;
goto free_priv;
@@ -1265,14 +1260,16 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
/* we need to use this api for now due to sharing with intagp */
bar = vga_pci_bar_info(vga_sc, mmio_bar);
if (bar == NULL) {
- printf(": can't get BAR info\n");
- return;
+ printf("%s: can't get BAR info\n",
+ dev_priv->sc_dev.dv_xname);
+ goto free_priv;
}
dev_priv->regs = vga_pci_bar_map(vga_sc, bar->addr, mmio_size, 0);
if (dev_priv->regs == NULL) {
- printf(": can't map mmio space\n");
- return;
+ printf("%s: can't map mmio space\n",
+ dev_priv->sc_dev.dv_xname);
+ goto free_priv;
}
intel_uncore_early_sanitize(dev);
@@ -1357,21 +1354,12 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
* so there is no point in running more than one instance of the
* workqueue at any time. Use an ordered one.
*/
-#ifdef __linux__
dev_priv->wq = alloc_ordered_workqueue("i915", 0);
if (dev_priv->wq == NULL) {
DRM_ERROR("Failed to create our workqueue.\n");
ret = -ENOMEM;
goto out_mtrrfree;
}
-#else
- dev_priv->wq = (struct workqueue_struct *)
- taskq_create("intelrel", 1, IPL_TTY, 0);
- if (dev_priv->wq == NULL) {
- printf(": couldn't create taskq\n");
- goto out_mtrrfree;
- }
-#endif
intel_irq_init(dev);
intel_uncore_sanitize(dev);
@@ -1401,17 +1389,20 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
if (pci_intr_map_msi(pa, &dev_priv->ih) != 0 &&
pci_intr_map(pa, &dev_priv->ih) != 0) {
- printf(": couldn't map interrupt\n");
- return;
+ printf("%s: couldn't map interrupt\n",
+ dev_priv->sc_dev.dv_xname);
+ goto out_gem_unload;
}
- printf(": %s", pci_intr_string(dev_priv->pc, dev_priv->ih));
+ printf("%s: %s\n", dev_priv->sc_dev.dv_xname,
+ pci_intr_string(dev_priv->pc, dev_priv->ih));
dev_priv->irqh = pci_intr_establish(dev_priv->pc, dev_priv->ih,
IPL_TTY, inteldrm_intr, dev_priv, dev_priv->sc_dev.dv_xname);
if (dev_priv->irqh == NULL) {
- printf(": couldn't establish interrupt\n");
- return;
+ printf("%s: couldn't establish interrupt\n",
+ dev_priv->sc_dev.dv_xname);
+ goto out_gem_unload;
}
dev_priv->num_plane = 1;
@@ -1454,15 +1445,13 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
intel_init_runtime_pm(dev_priv);
-#if 1
-{
- extern int wsdisplay_console_initted;
- struct wsemuldisplaydev_attach_args aa;
- struct rasops_info *ri = &dev_priv->ro;
-
+ /* Check if we managed to set up a framebuffer. */
if (ri->ri_bits == NULL)
return;
+ printf("%s: %dx%d\n", dev_priv->sc_dev.dv_xname,
+ ri->ri_width, ri->ri_height);
+
intel_fbdev_restore_mode(dev);
ri->ri_flg = RI_CENTER | RI_WRONLY | RI_VCONS;
@@ -1493,17 +1482,46 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
aa.console = 1;
}
- printf(", %dx%d\n", ri->ri_width, ri->ri_height);
-
vga_sc->sc_type = -1;
config_found(parent, &aa, wsemuldisplaydevprint);
-}
-#endif
+ return;
out_power_well:
+ intel_power_domains_remove(dev);
+ drm_vblank_cleanup(dev);
out_gem_unload:
+#ifdef notyet
+ if (dev_priv->mm.inactive_shrinker.scan_objects)
+ unregister_shrinker(&dev_priv->mm.inactive_shrinker);
+#endif
+
+ if (dev_priv->irqh)
+ pci_intr_disestablish(dev_priv->pc, dev_priv->irqh);
+
+ list_del(&dev_priv->gtt.base.global_link);
+ drm_mm_takedown(&dev_priv->gtt.base.mm);
+ dev_priv->gtt.base.cleanup(&dev_priv->gtt.base);
+
+ intel_teardown_gmbus(dev);
+ intel_teardown_mchbar(dev);
+#ifdef notyet
+ pm_qos_remove_request(&dev_priv->pm_qos);
+#endif
+ destroy_workqueue(dev_priv->wq);
out_mtrrfree:
+#ifdef __linux__
+ arch_phys_wc_del(dev_priv->gtt.mtrr);
+ io_mapping_free(dev_priv->gtt.mappable);
+#endif
out_regs:
+ intel_uncore_fini(dev);
+#ifdef __linux__
+ pci_iounmap(dev->pdev, dev_priv->regs);
+#else
+ vga_pci_bar_unmap(dev_priv->regs);
+#endif
+free_priv:
+ dev->dev_private = NULL;
return;
}
@@ -1621,7 +1639,7 @@ i915_alloc_ifp(struct inteldrm_softc *dev_priv, struct pci_attach_args *bpa)
nope:
dev_priv->ifp.i9xx.bsh = 0;
- printf(": no ifp ");
+ printf("%s: no ifp\n", dev_priv->sc_dev.dv_xname);
}
void
@@ -1658,7 +1676,7 @@ i965_alloc_ifp(struct inteldrm_softc *dev_priv, struct pci_attach_args *bpa)
nope:
dev_priv->ifp.i9xx.bsh = 0;
- printf(": no ifp ");
+ printf("%s: no ifp\n", dev_priv->sc_dev.dv_xname);
}
void
@@ -1671,7 +1689,8 @@ intel_gtt_chipset_setup(struct drm_device *dev)
return;
if (pci_find_device(&bpa, inteldrm_gmch_match) == 0) {
- printf(": can't find GMCH\n");
+ printf("%s: can't find GMCH\n",
+ dev_priv->sc_dev.dv_xname);
return;
}
diff --git a/sys/dev/pci/drm/i915/intel_i2c.c b/sys/dev/pci/drm/i915/intel_i2c.c
index 8d8242e7554..b941b1f6fab 100644
--- a/sys/dev/pci/drm/i915/intel_i2c.c
+++ b/sys/dev/pci/drm/i915/intel_i2c.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intel_i2c.c,v 1.6 2015/09/23 23:12:12 kettenis Exp $ */
+/* $OpenBSD: intel_i2c.c,v 1.7 2015/09/26 22:00:00 kettenis Exp $ */
/*
* Copyright (c) 2012, 2013 Mark Kettenis <kettenis@openbsd.org>
*
@@ -403,6 +403,11 @@ intel_setup_gmbus(struct drm_device *dev)
return (0);
}
+void
+intel_teardown_gmbus(struct drm_device *dev)
+{
+}
+
struct i2c_controller *
intel_gmbus_get_adapter(drm_i915_private_t *dev_priv, unsigned port)
{