Fix the code that sets up the MCH BAR on systems where the (buggy) BIOS
authorkettenis <kettenis@openbsd.org>
Sat, 17 Oct 2015 21:41:12 +0000 (21:41 +0000)
committerkettenis <kettenis@openbsd.org>
Sat, 17 Oct 2015 21:41:12 +0000 (21:41 +0000)
doesn't do this for us.  The code was poking registers on the wrong PCI
device.  We were just lucky that it worked on most systems.

This should fix machines such as the Asus EeePC 701 and get rid of the

error: [drm:pid0:i915_gem_detect_bit_6_swizzle] *ERROR* Couldn't read from
MC HBAR.  Disabling tiling.

messages on that machine.

sys/dev/pci/drm/drm_linux.h
sys/dev/pci/drm/i915/i915_dma.c
sys/dev/pci/drm/i915/i915_drv.c
sys/dev/pci/drm/i915/i915_drv.h

index 4021be0..12d9261 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: drm_linux.h,v 1.41 2015/09/27 21:28:14 kettenis Exp $ */
+/*     $OpenBSD: drm_linux.h,v 1.42 2015/10/17 21:41:12 kettenis Exp $ */
 /*
  * Copyright (c) 2013, 2014, 2015 Mark Kettenis
  *
@@ -971,6 +971,10 @@ struct dmi_system_id {
 #define        DMI_EXACT_MATCH(a, b) {(a), (b)}
 int dmi_check_system(const struct dmi_system_id *);
 
+struct resource {
+       u_long  start;
+};
+
 struct pci_dev {
        uint16_t        vendor;
        uint16_t        device;
index 6f70dda..373f70b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: i915_dma.c,v 1.23 2015/09/23 23:12:11 kettenis Exp $  */
+/*     $OpenBSD: i915_dma.c,v 1.24 2015/10/17 21:41:12 kettenis Exp $  */
 /* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
  */
 /*
@@ -1128,6 +1128,17 @@ static int i915_get_bridge_dev(struct drm_device *dev)
        }
        return 0;
 }
+#else
+int i915_get_bridge_dev(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->bridge_dev = malloc(sizeof(*dev_priv->bridge_dev),
+                                     M_DEVBUF, M_WAITOK);
+       dev_priv->bridge_dev->pc = dev->pdev->pc;
+       dev_priv->bridge_dev->tag = pci_make_tag(dev->pdev->pc, 0, 0, 0);
+       return 0;
+}
 #endif
 
 #define MCHBAR_I915 0x44
@@ -1145,35 +1156,27 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
        int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp_lo, temp_hi = 0;
        u64 mchbar_addr;
-       u_long addr;
 
        if (INTEL_INFO(dev)->gen >= 4)
-               temp_hi = pci_conf_read(dev_priv->pc, dev_priv->tag, reg + 4);
-       temp_lo = pci_conf_read(dev_priv->pc, dev_priv->tag, reg);
+               pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
+       pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
        mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
 
-       if (mchbar_addr == 0) {
-               addr = (u_long)mchbar_addr;
-               if (dev_priv->memex == NULL || extent_alloc(dev_priv->memex,
-                   MCHBAR_SIZE, MCHBAR_SIZE, 0, 0, 0, &addr)) {
-                       return -ENOMEM;
-               } else {
-                       mchbar_addr = addr;
-                       /* We've allocated it, now fill in the BAR again */
-                       if (INTEL_INFO(dev)->gen >= 4)
-                               pci_conf_write(dev_priv->pc, dev_priv->tag,
-                                   reg + 4, upper_32_bits(mchbar_addr));
-                       pci_conf_write(dev_priv->pc, dev_priv->tag,
-                           reg, lower_32_bits(mchbar_addr));
-               }
+       if (mchbar_addr)
+               return 0;
+
+       /* Get some space for it */
+       if (dev_priv->memex == NULL || extent_alloc(dev_priv->memex,
+           MCHBAR_SIZE, MCHBAR_SIZE, 0, 0, 0, &dev_priv->mch_res.start)) {
+               return -ENOMEM;
        }
 
        if (INTEL_INFO(dev)->gen >= 4)
-               pci_conf_write(dev_priv->pc, dev_priv->tag, reg + 4,
-                   upper_32_bits(mchbar_addr));
+               pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
+                                      upper_32_bits(dev_priv->mch_res.start));
 
-       pci_conf_write(dev_priv->pc, dev_priv->tag, reg,
-           lower_32_bits(mchbar_addr));
+       pci_write_config_dword(dev_priv->bridge_dev, reg,
+                              lower_32_bits(dev_priv->mch_res.start));
        return 0;
 }
 
@@ -1183,16 +1186,16 @@ intel_setup_mchbar(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
-       pcireg_t temp;
+       u32 temp;
        bool enabled;
 
        dev_priv->mchbar_need_disable = false;
 
        if (IS_I915G(dev) || IS_I915GM(dev)) {
-               temp = pci_conf_read(dev_priv->pc, dev_priv->tag, DEVEN_REG);
+               pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
                enabled = !!(temp & DEVEN_MCHBAR_EN);
        } else {
-               temp = pci_conf_read(dev_priv->pc, dev_priv->tag, mchbar_reg);
+               pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
                enabled = temp & 1;
        }
 
@@ -1207,11 +1210,11 @@ intel_setup_mchbar(struct drm_device *dev)
 
        /* Space is allocated or reserved, so enable it. */
        if (IS_I915G(dev) || IS_I915GM(dev)) {
-               pci_conf_write(dev_priv->pc, dev_priv->tag, DEVEN_REG,
-                   temp | DEVEN_MCHBAR_EN);
+               pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
+                                      temp | DEVEN_MCHBAR_EN);
        } else {
-               temp = pci_conf_read(dev_priv->pc, dev_priv->tag, mchbar_reg);
-               pci_conf_write(dev_priv->pc, dev_priv->tag, mchbar_reg, temp | 1);
+               pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
+               pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
        }
 }
 
@@ -1220,28 +1223,23 @@ intel_teardown_mchbar(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
-       pcireg_t temp;
-       u_int64_t mchbar_addr;
-       pcireg_t low, high = 0;
+       u32 temp;
 
        if (dev_priv->mchbar_need_disable) {
                if (IS_I915G(dev) || IS_I915GM(dev)) {
-                       temp = pci_conf_read(dev_priv->pc, dev_priv->tag, DEVEN_REG);
+                       pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
                        temp &= ~DEVEN_MCHBAR_EN;
-                       pci_conf_write(dev_priv->pc, dev_priv->tag, DEVEN_REG, temp);
+                       pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
                } else {
-                       temp = pci_conf_read(dev_priv->pc, dev_priv->tag, mchbar_reg);
+                       pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
                        temp &= ~1;
-                       pci_conf_write(dev_priv->pc, dev_priv->tag, mchbar_reg, temp);
+                       pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp);
                }
        }
 
-       if (INTEL_INFO(dev)->gen >= 4)
-               high = pci_conf_read(dev_priv->pc, dev_priv->tag, mchbar_reg + 4);
-       low = pci_conf_read(dev_priv->pc, dev_priv->tag, mchbar_reg);
-       mchbar_addr = ((u_int64_t)high << 32) | low;
-       if (dev_priv->memex)
-               extent_free(dev_priv->memex, mchbar_addr, MCHBAR_SIZE, 0);
+       if (dev_priv->mch_res.start)
+               extent_free(dev_priv->memex, dev_priv->mch_res.start,
+                           MCHBAR_SIZE, 0);
 }
 
 #ifdef __linux__
index fc84f33..60741a5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: i915_drv.c,v 1.93 2015/09/28 17:29:56 kettenis Exp $ */
+/* $OpenBSD: i915_drv.c,v 1.94 2015/10/17 21:41:12 kettenis Exp $ */
 /*
  * Copyright (c) 2008-2009 Owain G. Ainsworth <oga@openbsd.org>
  *
@@ -197,6 +197,7 @@ void        i965_alloc_ifp(struct inteldrm_softc *, struct pci_attach_args *);
 void   intel_gtt_chipset_setup(struct drm_device *);
 
 /* i915_dma.c */
+int    i915_get_bridge_dev(struct drm_device *);
 void   intel_setup_mchbar(struct drm_device *);
 void   intel_teardown_mchbar(struct drm_device *);
 int    i915_load_modeset_init(struct drm_device *);
@@ -1203,6 +1204,7 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
        dev_priv->tag = pa->pa_tag;
        dev_priv->dmat = pa->pa_dmat;
        dev_priv->bst = pa->pa_memt;
+       dev_priv->memex = pa->pa_memex;
 
        printf("\n");
 
@@ -1240,12 +1242,12 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
        if (IS_HSW_EARLY_SDV(dev))
                DRM_INFO("This is an early pre-production Haswell machine. "
                         "It may not be fully functional.\n");
+#endif
 
        if (i915_get_bridge_dev(dev)) {
                ret = -EIO;
                goto free_priv;
        }
-#endif
 
        mmio_bar = IS_GEN2(dev) ? 1 : 0;
        /* Before gen4, the registers and the GTT are behind different BARs.
index a024101..025108d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: i915_drv.h,v 1.69 2015/09/28 17:29:56 kettenis Exp $ */
+/* $OpenBSD: i915_drv.h,v 1.70 2015/10/17 21:41:12 kettenis Exp $ */
 /* i915_drv.h -- Private header for the I915 driver -*- linux-c -*-
  */
 /*
@@ -1498,9 +1498,7 @@ typedef struct inteldrm_softc {
        uint32_t last_seqno, next_seqno;
 
        drm_dma_handle_t *status_page_dmah;
-#ifdef __linux__
        struct resource mch_res;
-#endif
        union flush {
                struct {
                        bus_space_tag_t         bst;