drm/i915 + agp/intel-gtt: prep work for direct setup
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 8 Jun 2012 13:55:40 +0000 (15:55 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 12 Jun 2012 20:19:49 +0000 (22:19 +0200)
To be able to directly set up the intel-gtt code from drm/i915 and
avoid setting up the fake-agp driver we need to prepare a few things:
- pass both the bridge and gpu pci_dev to the probe function and add
  code to handle the gpu pdev both being present (for drm/i915) and
  not present (fake agp).
- add refcounting to the remove function so that unloading drm/i915
  doesn't kill the fake agp driver

v2: Fix up the cleanup and refcount, noticed by Jani Nikula.

Reviewed-by: Jani Nikula <jani.nikula@linux.intel.com>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/gpu/drm/i915/i915_dma.c
include/drm/intel-gtt.h

index 764f70c..c98c568 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/smp.h>
 #include "agp.h"
 #include "intel-agp.h"
+#include <drm/intel-gtt.h>
 
 int intel_agp_enabled;
 EXPORT_SYMBOL(intel_agp_enabled);
@@ -747,7 +748,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
 
        bridge->capndx = cap_ptr;
 
-       if (intel_gmch_probe(pdev, bridge))
+       if (intel_gmch_probe(pdev, NULL, bridge))
                goto found_gmch;
 
        for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
@@ -824,7 +825,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev)
 
        agp_remove_bridge(bridge);
 
-       intel_gmch_remove(pdev);
+       intel_gmch_remove();
 
        agp_put_bridge(bridge);
 }
index c009175..cf2e764 100644 (file)
 #define PCI_DEVICE_ID_INTEL_HASWELL_SDV                0x0c16 /* SDV */
 #define PCI_DEVICE_ID_INTEL_HASWELL_E_HB                       0x0c04
 
-int intel_gmch_probe(struct pci_dev *pdev,
-                              struct agp_bridge_data *bridge);
-void intel_gmch_remove(struct pci_dev *pdev);
 #endif
index 5e6c89e..cea9f99 100644 (file)
@@ -75,6 +75,7 @@ static struct _intel_private {
        struct resource ifp_resource;
        int resource_valid;
        struct page *scratch_page;
+       int refcount;
 } intel_private;
 
 #define INTEL_GTT_GEN  intel_private.driver->gen
@@ -1522,14 +1523,32 @@ static int find_gmch(u16 device)
        return 1;
 }
 
-int intel_gmch_probe(struct pci_dev *pdev,
-                                     struct agp_bridge_data *bridge)
+int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev,
+                    struct agp_bridge_data *bridge)
 {
        int i, mask;
-       intel_private.driver = NULL;
+
+       /*
+        * Can be called from the fake agp driver but also directly from
+        * drm/i915.ko. Hence we need to check whether everything is set up
+        * already.
+        */
+       if (intel_private.driver) {
+               intel_private.refcount++;
+               return 1;
+       }
 
        for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) {
-               if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) {
+               if (gpu_pdev) {
+                       if (gpu_pdev->device ==
+                           intel_gtt_chipsets[i].gmch_chip_id) {
+                               intel_private.pcidev = pci_dev_get(gpu_pdev);
+                               intel_private.driver =
+                                       intel_gtt_chipsets[i].gtt_driver;
+
+                               break;
+                       }
+               } else if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) {
                        intel_private.driver =
                                intel_gtt_chipsets[i].gtt_driver;
                        break;
@@ -1539,15 +1558,17 @@ int intel_gmch_probe(struct pci_dev *pdev,
        if (!intel_private.driver)
                return 0;
 
+       intel_private.refcount++;
+
        if (bridge) {
                bridge->driver = &intel_fake_agp_driver;
                bridge->dev_private_data = &intel_private;
-               bridge->dev = pdev;
+               bridge->dev = bridge_pdev;
        }
 
-       intel_private.bridge_dev = pci_dev_get(pdev);
+       intel_private.bridge_dev = pci_dev_get(bridge_pdev);
 
-       dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name);
+       dev_info(&bridge_pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name);
 
        mask = intel_private.driver->dma_mask_size;
        if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
@@ -1557,8 +1578,11 @@ int intel_gmch_probe(struct pci_dev *pdev,
                pci_set_consistent_dma_mask(intel_private.pcidev,
                                            DMA_BIT_MASK(mask));
 
-       if (intel_gtt_init() != 0)
+       if (intel_gtt_init() != 0) {
+               intel_gmch_remove();
+
                return 0;
+       }
 
        return 1;
 }
@@ -1577,12 +1601,16 @@ void intel_gtt_chipset_flush(void)
 }
 EXPORT_SYMBOL(intel_gtt_chipset_flush);
 
-void intel_gmch_remove(struct pci_dev *pdev)
+void intel_gmch_remove(void)
 {
+       if (--intel_private.refcount)
+               return;
+
        if (intel_private.pcidev)
                pci_dev_put(intel_private.pcidev);
        if (intel_private.bridge_dev)
                pci_dev_put(intel_private.bridge_dev);
+       intel_private.driver = NULL;
 }
 EXPORT_SYMBOL(intel_gmch_remove);
 
index c639d43..cf512e7 100644 (file)
@@ -1474,11 +1474,18 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                goto put_bridge;
        }
 
+       ret = intel_gmch_probe(dev_priv->bridge_dev, dev->pdev, NULL);
+       if (!ret) {
+               DRM_ERROR("failed to set up gmch\n");
+               ret = -EIO;
+               goto out_rmmap;
+       }
+
        dev_priv->mm.gtt = intel_gtt_get();
        if (!dev_priv->mm.gtt) {
                DRM_ERROR("Failed to initialize GTT\n");
                ret = -ENODEV;
-               goto out_rmmap;
+               goto put_gmch;
        }
 
        aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
@@ -1489,7 +1496,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                                     aperture_size);
        if (dev_priv->mm.gtt_mapping == NULL) {
                ret = -EIO;
-               goto out_rmmap;
+               goto put_gmch;
        }
 
        i915_mtrr_setup(dev_priv, dev_priv->mm.gtt_base_addr,
@@ -1611,6 +1618,8 @@ out_mtrrfree:
                dev_priv->mm.gtt_mtrr = -1;
        }
        io_mapping_free(dev_priv->mm.gtt_mapping);
+put_gmch:
+       intel_gmch_remove();
 out_rmmap:
        pci_iounmap(dev->pdev, dev_priv->regs);
 put_bridge:
index 8048c00..84ebd71 100644 (file)
@@ -23,6 +23,10 @@ const struct intel_gtt {
        phys_addr_t gma_bus_addr;
 } *intel_gtt_get(void);
 
+int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev,
+                    struct agp_bridge_data *bridge);
+void intel_gmch_remove(void);
+
 void intel_gtt_chipset_flush(void);
 void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg);
 void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries);