From a9dc3db1569ff451f89df32c906cbebfc82b0bd8 Mon Sep 17 00:00:00 2001 From: kettenis Date: Sat, 17 Oct 2015 21:41:12 +0000 Subject: [PATCH] Fix the code that sets up the MCH BAR on systems where the (buggy) BIOS 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 | 6 ++- sys/dev/pci/drm/i915/i915_dma.c | 82 ++++++++++++++++----------------- sys/dev/pci/drm/i915/i915_drv.c | 6 ++- sys/dev/pci/drm/i915/i915_drv.h | 4 +- 4 files changed, 50 insertions(+), 48 deletions(-) diff --git a/sys/dev/pci/drm/drm_linux.h b/sys/dev/pci/drm/drm_linux.h index 4021be08c75..12d92618092 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.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; diff --git a/sys/dev/pci/drm/i915/i915_dma.c b/sys/dev/pci/drm/i915/i915_dma.c index 6f70ddaa900..373f70b75a9 100644 --- a/sys/dev/pci/drm/i915/i915_dma.c +++ b/sys/dev/pci/drm/i915/i915_dma.c @@ -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__ diff --git a/sys/dev/pci/drm/i915/i915_drv.c b/sys/dev/pci/drm/i915/i915_drv.c index fc84f332489..60741a5e102 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.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 * @@ -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. diff --git a/sys/dev/pci/drm/i915/i915_drv.h b/sys/dev/pci/drm/i915/i915_drv.h index a0241012474..025108d13ad 100644 --- a/sys/dev/pci/drm/i915/i915_drv.h +++ b/sys/dev/pci/drm/i915/i915_drv.h @@ -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; -- 2.20.1