LCOV - code coverage report
Current view: top level - dev/pci/drm/i915 - i915_gem_stolen.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 294 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 18 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2008-2012 Intel Corporation
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice (including the next
      12             :  * paragraph) shall be included in all copies or substantial portions of the
      13             :  * Software.
      14             :  *
      15             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      18             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      20             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
      21             :  * IN THE SOFTWARE.
      22             :  *
      23             :  * Authors:
      24             :  *    Eric Anholt <eric@anholt.net>
      25             :  *    Chris Wilson <chris@chris-wilson.co.uk>
      26             :  *
      27             :  */
      28             : 
      29             : #include <dev/pci/drm/drmP.h>
      30             : #include <dev/pci/drm/i915_drm.h>
      31             : #include "i915_drv.h"
      32             : 
      33             : #define KB(x) ((x) * 1024)
      34             : #define MB(x) (KB(x) * 1024)
      35             : 
      36             : /*
      37             :  * The BIOS typically reserves some of the system's memory for the exclusive
      38             :  * use of the integrated graphics. This memory is no longer available for
      39             :  * use by the OS and so the user finds that his system has less memory
      40             :  * available than he put in. We refer to this memory as stolen.
      41             :  *
      42             :  * The BIOS will allocate its framebuffer from the stolen memory. Our
      43             :  * goal is try to reuse that object for our own fbcon which must always
      44             :  * be available for panics. Anything else we can reuse the stolen memory
      45             :  * for is a boon.
      46             :  */
      47             : 
      48           0 : int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv,
      49             :                                          struct drm_mm_node *node, u64 size,
      50             :                                          unsigned alignment, u64 start, u64 end)
      51             : {
      52             :         int ret;
      53             : 
      54           0 :         if (!drm_mm_initialized(&dev_priv->mm.stolen))
      55           0 :                 return -ENODEV;
      56             : 
      57             :         /* See the comment at the drm_mm_init() call for more about this check.
      58             :          * WaSkipStolenMemoryFirstPage:bdw,chv (incomplete) */
      59           0 :         if (start < 4096 && (IS_GEN8(dev_priv) ||
      60           0 :                         IS_KBL_REVID(dev_priv, 0, KBL_REVID_A0)))
      61           0 :                 start = 4096;
      62             : 
      63           0 :         mutex_lock(&dev_priv->mm.stolen_lock);
      64           0 :         ret = drm_mm_insert_node_in_range(&dev_priv->mm.stolen, node, size,
      65             :                                           alignment, start, end,
      66             :                                           DRM_MM_SEARCH_DEFAULT);
      67           0 :         mutex_unlock(&dev_priv->mm.stolen_lock);
      68             : 
      69           0 :         return ret;
      70           0 : }
      71             : 
      72           0 : int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv,
      73             :                                 struct drm_mm_node *node, u64 size,
      74             :                                 unsigned alignment)
      75             : {
      76           0 :         return i915_gem_stolen_insert_node_in_range(dev_priv, node, size,
      77             :                                         alignment, 0,
      78           0 :                                         dev_priv->gtt.stolen_usable_size);
      79             : }
      80             : 
      81           0 : void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv,
      82             :                                  struct drm_mm_node *node)
      83             : {
      84           0 :         mutex_lock(&dev_priv->mm.stolen_lock);
      85           0 :         drm_mm_remove_node(node);
      86           0 :         mutex_unlock(&dev_priv->mm.stolen_lock);
      87           0 : }
      88             : 
      89           0 : static unsigned long i915_stolen_to_physical(struct drm_device *dev)
      90             : {
      91           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
      92             : #ifdef __linux__
      93             :         struct resource *r;
      94             : #endif
      95           0 :         u32 base;
      96             : 
      97             :         /* Almost universally we can find the Graphics Base of Stolen Memory
      98             :          * at offset 0x5c in the igfx configuration space. On a few (desktop)
      99             :          * machines this is also mirrored in the bridge device at different
     100             :          * locations, or in the MCHBAR.
     101             :          *
     102             :          * On 865 we just check the TOUD register.
     103             :          *
     104             :          * On 830/845/85x the stolen memory base isn't available in any
     105             :          * register. We need to calculate it as TOM-TSEG_SIZE-stolen_size.
     106             :          *
     107             :          */
     108           0 :         base = 0;
     109           0 :         if (INTEL_INFO(dev)->gen >= 3) {
     110             :                 /* Read Graphics Base of Stolen Memory directly */
     111           0 :                 pci_read_config_dword(dev->pdev, 0x5c, &base);
     112           0 :                 base &= ~((1<<20) - 1);
     113           0 :         } else if (IS_I865G(dev)) {
     114             :                 u32 tseg_size = 0;
     115           0 :                 u16 toud = 0;
     116           0 :                 u8 tmp;
     117             : 
     118           0 :                 pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
     119             :                                          I845_ESMRAMC, &tmp);
     120             : 
     121           0 :                 if (tmp & TSEG_ENABLE) {
     122           0 :                         switch (tmp & I845_TSEG_SIZE_MASK) {
     123             :                         case I845_TSEG_SIZE_512K:
     124             :                                 tseg_size = KB(512);
     125           0 :                                 break;
     126             :                         case I845_TSEG_SIZE_1M:
     127             :                                 tseg_size = MB(1);
     128           0 :                                 break;
     129             :                         }
     130             :                 }
     131             : 
     132           0 :                 pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 0),
     133             :                                          I865_TOUD, &toud);
     134             : 
     135           0 :                 base = (toud << 16) + tseg_size;
     136           0 :         } else if (IS_I85X(dev)) {
     137             :                 u32 tseg_size = 0;
     138             :                 u32 tom;
     139           0 :                 u8 tmp;
     140             : 
     141           0 :                 pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
     142             :                                          I85X_ESMRAMC, &tmp);
     143             : 
     144           0 :                 if (tmp & TSEG_ENABLE)
     145           0 :                         tseg_size = MB(1);
     146             : 
     147           0 :                 pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 1),
     148             :                                          I85X_DRB3, &tmp);
     149           0 :                 tom = tmp * MB(32);
     150             : 
     151           0 :                 base = tom - tseg_size - dev_priv->gtt.stolen_size;
     152           0 :         } else if (IS_845G(dev)) {
     153             :                 u32 tseg_size = 0;
     154             :                 u32 tom;
     155           0 :                 u8 tmp;
     156             : 
     157           0 :                 pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
     158             :                                          I845_ESMRAMC, &tmp);
     159             : 
     160           0 :                 if (tmp & TSEG_ENABLE) {
     161           0 :                         switch (tmp & I845_TSEG_SIZE_MASK) {
     162             :                         case I845_TSEG_SIZE_512K:
     163             :                                 tseg_size = KB(512);
     164           0 :                                 break;
     165             :                         case I845_TSEG_SIZE_1M:
     166             :                                 tseg_size = MB(1);
     167           0 :                                 break;
     168             :                         }
     169             :                 }
     170             : 
     171           0 :                 pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
     172             :                                          I830_DRB3, &tmp);
     173           0 :                 tom = tmp * MB(32);
     174             : 
     175           0 :                 base = tom - tseg_size - dev_priv->gtt.stolen_size;
     176           0 :         } else if (IS_I830(dev)) {
     177             :                 u32 tseg_size = 0;
     178             :                 u32 tom;
     179           0 :                 u8 tmp;
     180             : 
     181           0 :                 pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
     182             :                                          I830_ESMRAMC, &tmp);
     183             : 
     184           0 :                 if (tmp & TSEG_ENABLE) {
     185           0 :                         if (tmp & I830_TSEG_SIZE_1M)
     186           0 :                                 tseg_size = MB(1);
     187             :                         else
     188             :                                 tseg_size = KB(512);
     189             :                 }
     190             : 
     191           0 :                 pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
     192             :                                          I830_DRB3, &tmp);
     193           0 :                 tom = tmp * MB(32);
     194             : 
     195           0 :                 base = tom - tseg_size - dev_priv->gtt.stolen_size;
     196           0 :         }
     197             : 
     198           0 :         if (base == 0)
     199           0 :                 return 0;
     200             : 
     201             :         /* make sure we don't clobber the GTT if it's within stolen memory */
     202           0 :         if (INTEL_INFO(dev)->gen <= 4 && !IS_G33(dev) && !IS_G4X(dev)) {
     203             :                 struct {
     204             :                         u32 start, end;
     205             :                 } stolen[2] = {
     206           0 :                         { .start = base, .end = base + dev_priv->gtt.stolen_size, },
     207             :                         { .start = base, .end = base + dev_priv->gtt.stolen_size, },
     208             :                 };
     209             :                 u64 gtt_start, gtt_end;
     210             : 
     211           0 :                 gtt_start = I915_READ(PGTBL_CTL);
     212           0 :                 if (IS_GEN4(dev))
     213           0 :                         gtt_start = (gtt_start & PGTBL_ADDRESS_LO_MASK) |
     214           0 :                                 (gtt_start & PGTBL_ADDRESS_HI_MASK) << 28;
     215             :                 else
     216             :                         gtt_start &= PGTBL_ADDRESS_LO_MASK;
     217           0 :                 gtt_end = gtt_start + gtt_total_entries(dev_priv->gtt) * 4;
     218             : 
     219           0 :                 if (gtt_start >= stolen[0].start && gtt_start < stolen[0].end)
     220           0 :                         stolen[0].end = gtt_start;
     221           0 :                 if (gtt_end > stolen[1].start && gtt_end <= stolen[1].end)
     222           0 :                         stolen[1].start = gtt_end;
     223             : 
     224             :                 /* pick the larger of the two chunks */
     225           0 :                 if (stolen[0].end - stolen[0].start >
     226           0 :                     stolen[1].end - stolen[1].start) {
     227           0 :                         base = stolen[0].start;
     228           0 :                         dev_priv->gtt.stolen_size = stolen[0].end - stolen[0].start;
     229           0 :                 } else {
     230           0 :                         base = stolen[1].start;
     231           0 :                         dev_priv->gtt.stolen_size = stolen[1].end - stolen[1].start;
     232             :                 }
     233             : 
     234             :                 if (stolen[0].start != stolen[1].start ||
     235             :                     stolen[0].end != stolen[1].end) {
     236             :                         DRM_DEBUG_KMS("GTT within stolen memory at 0x%llx-0x%llx\n",
     237             :                                       (unsigned long long) gtt_start,
     238             :                                       (unsigned long long) gtt_end - 1);
     239             :                         DRM_DEBUG_KMS("Stolen memory adjusted to 0x%x-0x%x\n",
     240             :                                       base, base + (u32) dev_priv->gtt.stolen_size - 1);
     241             :                 }
     242           0 :         }
     243             : 
     244             : 
     245             : #ifdef __linux__
     246             :         /* Verify that nothing else uses this physical address. Stolen
     247             :          * memory should be reserved by the BIOS and hidden from the
     248             :          * kernel. So if the region is already marked as busy, something
     249             :          * is seriously wrong.
     250             :          */
     251             :         r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size,
     252             :                                     "Graphics Stolen Memory");
     253             :         if (r == NULL) {
     254             :                 /*
     255             :                  * One more attempt but this time requesting region from
     256             :                  * base + 1, as we have seen that this resolves the region
     257             :                  * conflict with the PCI Bus.
     258             :                  * This is a BIOS w/a: Some BIOS wrap stolen in the root
     259             :                  * PCI bus, but have an off-by-one error. Hence retry the
     260             :                  * reservation starting from 1 instead of 0.
     261             :                  */
     262             :                 r = devm_request_mem_region(dev->dev, base + 1,
     263             :                                             dev_priv->gtt.stolen_size - 1,
     264             :                                             "Graphics Stolen Memory");
     265             :                 /*
     266             :                  * GEN3 firmware likes to smash pci bridges into the stolen
     267             :                  * range. Apparently this works.
     268             :                  */
     269             :                 if (r == NULL && !IS_GEN3(dev)) {
     270             :                         DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
     271             :                                   base, base + (uint32_t)dev_priv->gtt.stolen_size);
     272             :                         base = 0;
     273             :                 }
     274             :         }
     275             : #endif
     276             : 
     277           0 :         return base;
     278           0 : }
     279             : 
     280           0 : void i915_gem_cleanup_stolen(struct drm_device *dev)
     281             : {
     282           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     283             : 
     284           0 :         if (!drm_mm_initialized(&dev_priv->mm.stolen))
     285           0 :                 return;
     286             : 
     287           0 :         drm_mm_takedown(&dev_priv->mm.stolen);
     288           0 : }
     289             : 
     290           0 : static void g4x_get_stolen_reserved(struct drm_i915_private *dev_priv,
     291             :                                     unsigned long *base, unsigned long *size)
     292             : {
     293           0 :         uint32_t reg_val = I915_READ(IS_GM45(dev_priv) ?
     294             :                                      CTG_STOLEN_RESERVED :
     295             :                                      ELK_STOLEN_RESERVED);
     296           0 :         unsigned long stolen_top = dev_priv->mm.stolen_base +
     297           0 :                 dev_priv->gtt.stolen_size;
     298             : 
     299           0 :         *base = (reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK) << 16;
     300             : 
     301           0 :         WARN_ON((reg_val & G4X_STOLEN_RESERVED_ADDR1_MASK) < *base);
     302             : 
     303             :         /* On these platforms, the register doesn't have a size field, so the
     304             :          * size is the distance between the base and the top of the stolen
     305             :          * memory. We also have the genuine case where base is zero and there's
     306             :          * nothing reserved. */
     307           0 :         if (*base == 0)
     308           0 :                 *size = 0;
     309             :         else
     310           0 :                 *size = stolen_top - *base;
     311           0 : }
     312             : 
     313           0 : static void gen6_get_stolen_reserved(struct drm_i915_private *dev_priv,
     314             :                                      unsigned long *base, unsigned long *size)
     315             : {
     316           0 :         uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
     317             : 
     318           0 :         *base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
     319             : 
     320           0 :         switch (reg_val & GEN6_STOLEN_RESERVED_SIZE_MASK) {
     321             :         case GEN6_STOLEN_RESERVED_1M:
     322           0 :                 *size = 1024 * 1024;
     323           0 :                 break;
     324             :         case GEN6_STOLEN_RESERVED_512K:
     325           0 :                 *size = 512 * 1024;
     326           0 :                 break;
     327             :         case GEN6_STOLEN_RESERVED_256K:
     328           0 :                 *size = 256 * 1024;
     329           0 :                 break;
     330             :         case GEN6_STOLEN_RESERVED_128K:
     331           0 :                 *size = 128 * 1024;
     332           0 :                 break;
     333             :         default:
     334             :                 *size = 1024 * 1024;
     335             :                 MISSING_CASE(reg_val & GEN6_STOLEN_RESERVED_SIZE_MASK);
     336             :         }
     337           0 : }
     338             : 
     339           0 : static void gen7_get_stolen_reserved(struct drm_i915_private *dev_priv,
     340             :                                      unsigned long *base, unsigned long *size)
     341             : {
     342           0 :         uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
     343             : 
     344           0 :         *base = reg_val & GEN7_STOLEN_RESERVED_ADDR_MASK;
     345             : 
     346           0 :         switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) {
     347             :         case GEN7_STOLEN_RESERVED_1M:
     348           0 :                 *size = 1024 * 1024;
     349           0 :                 break;
     350             :         case GEN7_STOLEN_RESERVED_256K:
     351           0 :                 *size = 256 * 1024;
     352           0 :                 break;
     353             :         default:
     354             :                 *size = 1024 * 1024;
     355             :                 MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK);
     356             :         }
     357           0 : }
     358             : 
     359           0 : static void gen8_get_stolen_reserved(struct drm_i915_private *dev_priv,
     360             :                                      unsigned long *base, unsigned long *size)
     361             : {
     362           0 :         uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
     363             : 
     364           0 :         *base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
     365             : 
     366           0 :         switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) {
     367             :         case GEN8_STOLEN_RESERVED_1M:
     368           0 :                 *size = 1024 * 1024;
     369           0 :                 break;
     370             :         case GEN8_STOLEN_RESERVED_2M:
     371           0 :                 *size = 2 * 1024 * 1024;
     372           0 :                 break;
     373             :         case GEN8_STOLEN_RESERVED_4M:
     374           0 :                 *size = 4 * 1024 * 1024;
     375           0 :                 break;
     376             :         case GEN8_STOLEN_RESERVED_8M:
     377           0 :                 *size = 8 * 1024 * 1024;
     378           0 :                 break;
     379             :         default:
     380             :                 *size = 8 * 1024 * 1024;
     381             :                 MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK);
     382             :         }
     383           0 : }
     384             : 
     385           0 : static void bdw_get_stolen_reserved(struct drm_i915_private *dev_priv,
     386             :                                     unsigned long *base, unsigned long *size)
     387             : {
     388           0 :         uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
     389             :         unsigned long stolen_top;
     390             : 
     391           0 :         stolen_top = dev_priv->mm.stolen_base + dev_priv->gtt.stolen_size;
     392             : 
     393           0 :         *base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
     394             : 
     395             :         /* On these platforms, the register doesn't have a size field, so the
     396             :          * size is the distance between the base and the top of the stolen
     397             :          * memory. We also have the genuine case where base is zero and there's
     398             :          * nothing reserved. */
     399           0 :         if (*base == 0)
     400           0 :                 *size = 0;
     401             :         else
     402           0 :                 *size = stolen_top - *base;
     403           0 : }
     404             : 
     405           0 : int i915_gem_init_stolen(struct drm_device *dev)
     406             : {
     407           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     408           0 :         unsigned long reserved_total, reserved_base = 0, reserved_size;
     409             :         unsigned long stolen_top;
     410             : 
     411           0 :         rw_init(&dev_priv->mm.stolen_lock, "stln");
     412             : 
     413             : #ifdef CONFIG_INTEL_IOMMU
     414             :         if (intel_iommu_gfx_mapped && INTEL_INFO(dev)->gen < 8) {
     415             :                 DRM_INFO("DMAR active, disabling use of stolen memory\n");
     416             :                 return 0;
     417             :         }
     418             : #endif
     419             : 
     420           0 :         if (dev_priv->gtt.stolen_size == 0)
     421           0 :                 return 0;
     422             : 
     423           0 :         dev_priv->mm.stolen_base = i915_stolen_to_physical(dev);
     424           0 :         if (dev_priv->mm.stolen_base == 0)
     425           0 :                 return 0;
     426             : 
     427           0 :         stolen_top = dev_priv->mm.stolen_base + dev_priv->gtt.stolen_size;
     428             : 
     429           0 :         switch (INTEL_INFO(dev_priv)->gen) {
     430             :         case 2:
     431             :         case 3:
     432             :                 break;
     433             :         case 4:
     434           0 :                 if (IS_G4X(dev))
     435           0 :                         g4x_get_stolen_reserved(dev_priv, &reserved_base,
     436             :                                                 &reserved_size);
     437             :                 break;
     438             :         case 5:
     439             :                 /* Assume the gen6 maximum for the older platforms. */
     440           0 :                 reserved_size = 1024 * 1024;
     441           0 :                 reserved_base = stolen_top - reserved_size;
     442           0 :                 break;
     443             :         case 6:
     444           0 :                 gen6_get_stolen_reserved(dev_priv, &reserved_base,
     445             :                                          &reserved_size);
     446           0 :                 break;
     447             :         case 7:
     448           0 :                 gen7_get_stolen_reserved(dev_priv, &reserved_base,
     449             :                                          &reserved_size);
     450           0 :                 break;
     451             :         default:
     452           0 :                 if (IS_BROADWELL(dev_priv) ||
     453           0 :                     IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev))
     454           0 :                         bdw_get_stolen_reserved(dev_priv, &reserved_base,
     455             :                                                 &reserved_size);
     456             :                 else
     457           0 :                         gen8_get_stolen_reserved(dev_priv, &reserved_base,
     458             :                                                  &reserved_size);
     459             :                 break;
     460             :         }
     461             : 
     462             :         /* It is possible for the reserved base to be zero, but the register
     463             :          * field for size doesn't have a zero option. */
     464           0 :         if (reserved_base == 0) {
     465           0 :                 reserved_size = 0;
     466           0 :                 reserved_base = stolen_top;
     467           0 :         }
     468             : 
     469           0 :         if (reserved_base < dev_priv->mm.stolen_base ||
     470           0 :             reserved_base + reserved_size > stolen_top) {
     471             :                 DRM_DEBUG_KMS("Stolen reserved area [0x%08lx - 0x%08lx] outside stolen memory [0x%08lx - 0x%08lx]\n",
     472             :                               reserved_base, reserved_base + reserved_size,
     473             :                               dev_priv->mm.stolen_base, stolen_top);
     474           0 :                 return 0;
     475             :         }
     476             : 
     477             :         /* It is possible for the reserved area to end before the end of stolen
     478             :          * memory, so just consider the start. */
     479           0 :         reserved_total = stolen_top - reserved_base;
     480             : 
     481             :         DRM_DEBUG_KMS("Memory reserved for graphics device: %zuK, usable: %luK\n",
     482             :                       dev_priv->gtt.stolen_size >> 10,
     483             :                       (dev_priv->gtt.stolen_size - reserved_total) >> 10);
     484             : 
     485           0 :         dev_priv->gtt.stolen_usable_size = dev_priv->gtt.stolen_size -
     486             :                                            reserved_total;
     487             : 
     488             :         /*
     489             :          * Basic memrange allocator for stolen space.
     490             :          *
     491             :          * TODO: Notice that some platforms require us to not use the first page
     492             :          * of the stolen memory but their BIOSes may still put the framebuffer
     493             :          * on the first page. So we don't reserve this page for now because of
     494             :          * that. Our current solution is to just prevent new nodes from being
     495             :          * inserted on the first page - see the check we have at
     496             :          * i915_gem_stolen_insert_node_in_range(). We may want to fix the fbcon
     497             :          * problem later.
     498             :          */
     499           0 :         drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_usable_size);
     500             : 
     501           0 :         return 0;
     502           0 : }
     503             : 
     504             : static struct sg_table *
     505           0 : i915_pages_create_for_stolen(struct drm_device *dev,
     506             :                              u32 offset, u32 size)
     507             : {
     508           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     509             :         struct sg_table *st;
     510             :         struct scatterlist *sg;
     511             : 
     512             :         DRM_DEBUG_DRIVER("offset=0x%x, size=%d\n", offset, size);
     513           0 :         BUG_ON(offset > dev_priv->gtt.stolen_size - size);
     514             : 
     515             :         /* We hide that we have no struct page backing our stolen object
     516             :          * by wrapping the contiguous physical allocation with a fake
     517             :          * dma mapping in a single scatterlist.
     518             :          */
     519             : 
     520           0 :         st = kmalloc(sizeof(*st), GFP_KERNEL);
     521           0 :         if (st == NULL)
     522           0 :                 return NULL;
     523             : 
     524           0 :         if (sg_alloc_table(st, 1, GFP_KERNEL)) {
     525           0 :                 kfree(st);
     526           0 :                 return NULL;
     527             :         }
     528             : 
     529           0 :         sg = st->sgl;
     530           0 :         sg->offset = 0;
     531           0 :         sg->length = size;
     532             : 
     533           0 :         sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset;
     534           0 :         sg_dma_len(sg) = size;
     535             : 
     536           0 :         return st;
     537           0 : }
     538             : 
     539           0 : static int i915_gem_object_get_pages_stolen(struct drm_i915_gem_object *obj)
     540             : {
     541           0 :         BUG();
     542             :         return -EINVAL;
     543             : }
     544             : 
     545           0 : static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj)
     546             : {
     547             :         /* Should only be called during free */
     548           0 :         sg_free_table(obj->pages);
     549           0 :         kfree(obj->pages);
     550           0 : }
     551             : 
     552             : 
     553             : static void
     554           0 : i915_gem_object_release_stolen(struct drm_i915_gem_object *obj)
     555             : {
     556           0 :         struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
     557             : 
     558           0 :         if (obj->stolen) {
     559           0 :                 i915_gem_stolen_remove_node(dev_priv, obj->stolen);
     560           0 :                 kfree(obj->stolen);
     561           0 :                 obj->stolen = NULL;
     562           0 :         }
     563           0 : }
     564             : static const struct drm_i915_gem_object_ops i915_gem_object_stolen_ops = {
     565             :         .get_pages = i915_gem_object_get_pages_stolen,
     566             :         .put_pages = i915_gem_object_put_pages_stolen,
     567             :         .release = i915_gem_object_release_stolen,
     568             : };
     569             : 
     570             : static struct drm_i915_gem_object *
     571           0 : _i915_gem_object_create_stolen(struct drm_device *dev,
     572             :                                struct drm_mm_node *stolen)
     573             : {
     574             :         struct drm_i915_gem_object *obj;
     575             : 
     576           0 :         obj = i915_gem_object_alloc(dev);
     577           0 :         if (obj == NULL)
     578           0 :                 return NULL;
     579             : 
     580           0 :         drm_gem_private_object_init(dev, &obj->base, stolen->size);
     581           0 :         i915_gem_object_init(obj, &i915_gem_object_stolen_ops);
     582             : 
     583           0 :         obj->pages = i915_pages_create_for_stolen(dev,
     584           0 :                                                   stolen->start, stolen->size);
     585           0 :         if (obj->pages == NULL)
     586             :                 goto cleanup;
     587             : 
     588           0 :         i915_gem_object_pin_pages(obj);
     589           0 :         obj->stolen = stolen;
     590             : 
     591           0 :         obj->base.read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT;
     592           0 :         obj->cache_level = HAS_LLC(dev) ? I915_CACHE_LLC : I915_CACHE_NONE;
     593             : 
     594           0 :         return obj;
     595             : 
     596             : cleanup:
     597           0 :         i915_gem_object_free(obj);
     598           0 :         return NULL;
     599           0 : }
     600             : 
     601             : struct drm_i915_gem_object *
     602           0 : i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
     603             : {
     604           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     605             :         struct drm_i915_gem_object *obj;
     606             :         struct drm_mm_node *stolen;
     607             :         int ret;
     608             : 
     609           0 :         if (!drm_mm_initialized(&dev_priv->mm.stolen))
     610           0 :                 return NULL;
     611             : 
     612             :         DRM_DEBUG_KMS("creating stolen object: size=%x\n", size);
     613           0 :         if (size == 0)
     614           0 :                 return NULL;
     615             : 
     616           0 :         stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
     617           0 :         if (!stolen)
     618           0 :                 return NULL;
     619             : 
     620           0 :         ret = i915_gem_stolen_insert_node(dev_priv, stolen, size, 4096);
     621           0 :         if (ret) {
     622           0 :                 kfree(stolen);
     623           0 :                 return NULL;
     624             :         }
     625             : 
     626           0 :         obj = _i915_gem_object_create_stolen(dev, stolen);
     627           0 :         if (obj)
     628           0 :                 return obj;
     629             : 
     630           0 :         i915_gem_stolen_remove_node(dev_priv, stolen);
     631           0 :         kfree(stolen);
     632           0 :         return NULL;
     633           0 : }
     634             : 
     635             : struct drm_i915_gem_object *
     636           0 : i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
     637             :                                                u32 stolen_offset,
     638             :                                                u32 gtt_offset,
     639             :                                                u32 size)
     640             : {
     641           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     642           0 :         struct i915_address_space *ggtt = &dev_priv->gtt.base;
     643             :         struct drm_i915_gem_object *obj;
     644             :         struct drm_mm_node *stolen;
     645             :         struct i915_vma *vma;
     646             :         int ret;
     647             : 
     648           0 :         if (!drm_mm_initialized(&dev_priv->mm.stolen))
     649           0 :                 return NULL;
     650             : 
     651             :         DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n",
     652             :                         stolen_offset, gtt_offset, size);
     653             : 
     654             :         /* KISS and expect everything to be page-aligned */
     655           0 :         if (WARN_ON(size == 0) || WARN_ON(size & 4095) ||
     656           0 :             WARN_ON(stolen_offset & 4095))
     657           0 :                 return NULL;
     658             : 
     659           0 :         stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
     660           0 :         if (!stolen)
     661           0 :                 return NULL;
     662             : 
     663           0 :         stolen->start = stolen_offset;
     664           0 :         stolen->size = size;
     665           0 :         mutex_lock(&dev_priv->mm.stolen_lock);
     666           0 :         ret = drm_mm_reserve_node(&dev_priv->mm.stolen, stolen);
     667           0 :         mutex_unlock(&dev_priv->mm.stolen_lock);
     668           0 :         if (ret) {
     669             :                 DRM_DEBUG_KMS("failed to allocate stolen space\n");
     670           0 :                 kfree(stolen);
     671           0 :                 return NULL;
     672             :         }
     673             : 
     674           0 :         obj = _i915_gem_object_create_stolen(dev, stolen);
     675           0 :         if (obj == NULL) {
     676             :                 DRM_DEBUG_KMS("failed to allocate stolen object\n");
     677           0 :                 i915_gem_stolen_remove_node(dev_priv, stolen);
     678           0 :                 kfree(stolen);
     679           0 :                 return NULL;
     680             :         }
     681             : 
     682             :         /* Some objects just need physical mem from stolen space */
     683           0 :         if (gtt_offset == I915_GTT_OFFSET_NONE)
     684           0 :                 return obj;
     685             : 
     686           0 :         vma = i915_gem_obj_lookup_or_create_vma(obj, ggtt);
     687           0 :         if (IS_ERR(vma)) {
     688           0 :                 ret = PTR_ERR(vma);
     689           0 :                 goto err;
     690             :         }
     691             : 
     692             :         /* To simplify the initialisation sequence between KMS and GTT,
     693             :          * we allow construction of the stolen object prior to
     694             :          * setting up the GTT space. The actual reservation will occur
     695             :          * later.
     696             :          */
     697           0 :         vma->node.start = gtt_offset;
     698           0 :         vma->node.size = size;
     699           0 :         if (drm_mm_initialized(&ggtt->mm)) {
     700           0 :                 ret = drm_mm_reserve_node(&ggtt->mm, &vma->node);
     701           0 :                 if (ret) {
     702             :                         DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
     703             :                         goto err;
     704             :                 }
     705             : 
     706           0 :                 vma->bound |= GLOBAL_BIND;
     707           0 :                 __i915_vma_set_map_and_fenceable(vma);
     708           0 :                 list_add_tail(&vma->mm_list, &ggtt->inactive_list);
     709           0 :         }
     710             : 
     711           0 :         list_add_tail(&obj->global_list, &dev_priv->mm.bound_list);
     712           0 :         i915_gem_object_pin_pages(obj);
     713             : 
     714           0 :         return obj;
     715             : 
     716             : err:
     717           0 :         drm_gem_object_unreference(&obj->base);
     718           0 :         return NULL;
     719           0 : }

Generated by: LCOV version 1.13