提交 fc1caf6e 编写于 作者: L Linus Torvalds

Merge branch 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (204 commits)
  agp: intel-agp: do not use PCI resources before pci_enable_device()
  agp: efficeon-agp: do not use PCI resources before pci_enable_device()
  drm: kill BKL from common code
  drm/kms: Simplify setup of the initial I2C encoder config.
  drm,io-mapping: Specify slot to use for atomic mappings
  drm/radeon/kms: only expose underscan on avivo chips
  drm/radeon: add new pci ids
  drm: Cleanup after failing to create master->unique and dev->name
  drm/radeon: tone down overchatty acpi debug messages.
  drm/radeon/kms: enable underscan option for digital connectors
  drm/radeon/kms: fix calculation of h/v scaling factors
  drm/radeon/kms/igp: sideport is AMD only
  drm/radeon/kms: handle the case of no active displays properly in the bandwidth code
  drm: move ttm global code to core drm
  drm/i915: Clear the Ironlake dithering flags when the pipe doesn't want it.
  drm/radeon/kms: make sure HPD is set to NONE on analog-only connectors
  drm/radeon/kms: make sure rio_mem is valid before unmapping it
  drm/agp/i915: trim stolen space to 32M
  drm/i915: Unset cursor if out-of-bounds upon mode change (v4)
  drm/i915: Unreference object not handle on creation
  ...
...@@ -371,6 +371,17 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, ...@@ -371,6 +371,17 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
bridge->dev = pdev; bridge->dev = pdev;
bridge->capndx = cap_ptr; bridge->capndx = cap_ptr;
/*
* If the device has not been properly setup, the following will catch
* the problem and should stop the system from crashing.
* 20030610 - hamish@zot.org
*/
if (pci_enable_device(pdev)) {
printk(KERN_ERR PFX "Unable to Enable PCI device\n");
agp_put_bridge(bridge);
return -ENODEV;
}
/* /*
* The following fixes the case where the BIOS has "forgotten" to * The following fixes the case where the BIOS has "forgotten" to
* provide an address range for the GART. * provide an address range for the GART.
...@@ -385,17 +396,6 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, ...@@ -385,17 +396,6 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
} }
} }
/*
* If the device has not been properly setup, the following will catch
* the problem and should stop the system from crashing.
* 20030610 - hamish@zot.org
*/
if (pci_enable_device(pdev)) {
printk(KERN_ERR PFX "Unable to Enable PCI device\n");
agp_put_bridge(bridge);
return -ENODEV;
}
/* Fill in the mode register */ /* Fill in the mode register */
if (cap_ptr) { if (cap_ptr) {
pci_read_config_dword(pdev, pci_read_config_dword(pdev,
......
...@@ -816,9 +816,9 @@ static const struct intel_driver_description { ...@@ -816,9 +816,9 @@ static const struct intel_driver_description {
{ PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
"HD Graphics", NULL, &intel_i965_driver }, "HD Graphics", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG,
"Sandybridge", NULL, &intel_i965_driver }, "Sandybridge", NULL, &intel_gen6_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG,
"Sandybridge", NULL, &intel_i965_driver }, "Sandybridge", NULL, &intel_gen6_driver },
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
...@@ -907,6 +907,17 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, ...@@ -907,6 +907,17 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
/*
* If the device has not been properly setup, the following will catch
* the problem and should stop the system from crashing.
* 20030610 - hamish@zot.org
*/
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev, "can't enable PCI device\n");
agp_put_bridge(bridge);
return -ENODEV;
}
/* /*
* The following fixes the case where the BIOS has "forgotten" to * The following fixes the case where the BIOS has "forgotten" to
* provide an address range for the GART. * provide an address range for the GART.
...@@ -921,17 +932,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, ...@@ -921,17 +932,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
} }
} }
/*
* If the device has not been properly setup, the following will catch
* the problem and should stop the system from crashing.
* 20030610 - hamish@zot.org
*/
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev, "can't enable PCI device\n");
agp_put_bridge(bridge);
return -ENODEV;
}
/* Fill in the mode register */ /* Fill in the mode register */
if (cap_ptr) { if (cap_ptr) {
pci_read_config_dword(pdev, pci_read_config_dword(pdev,
......
...@@ -60,6 +60,12 @@ ...@@ -60,6 +60,12 @@
#define I810_PTE_LOCAL 0x00000002 #define I810_PTE_LOCAL 0x00000002
#define I810_PTE_VALID 0x00000001 #define I810_PTE_VALID 0x00000001
#define I830_PTE_SYSTEM_CACHED 0x00000006 #define I830_PTE_SYSTEM_CACHED 0x00000006
/* GT PTE cache control fields */
#define GEN6_PTE_UNCACHED 0x00000002
#define GEN6_PTE_LLC 0x00000004
#define GEN6_PTE_LLC_MLC 0x00000006
#define GEN6_PTE_GFDT 0x00000008
#define I810_SMRAM_MISCC 0x70 #define I810_SMRAM_MISCC 0x70
#define I810_GFX_MEM_WIN_SIZE 0x00010000 #define I810_GFX_MEM_WIN_SIZE 0x00010000
#define I810_GFX_MEM_WIN_32M 0x00010000 #define I810_GFX_MEM_WIN_32M 0x00010000
......
...@@ -25,6 +25,10 @@ ...@@ -25,6 +25,10 @@
#define USE_PCI_DMA_API 1 #define USE_PCI_DMA_API 1
#endif #endif
/* Max amount of stolen space, anything above will be returned to Linux */
int intel_max_stolen = 32 * 1024 * 1024;
EXPORT_SYMBOL(intel_max_stolen);
static const struct aper_size_info_fixed intel_i810_sizes[] = static const struct aper_size_info_fixed intel_i810_sizes[] =
{ {
{64, 16384, 4}, {64, 16384, 4},
...@@ -104,7 +108,7 @@ static int intel_agp_map_memory(struct agp_memory *mem) ...@@ -104,7 +108,7 @@ static int intel_agp_map_memory(struct agp_memory *mem)
DBG("try mapping %lu pages\n", (unsigned long)mem->page_count); DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL)) if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
return -ENOMEM; goto err;
mem->sg_list = sg = st.sgl; mem->sg_list = sg = st.sgl;
...@@ -113,11 +117,14 @@ static int intel_agp_map_memory(struct agp_memory *mem) ...@@ -113,11 +117,14 @@ static int intel_agp_map_memory(struct agp_memory *mem)
mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list, mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
mem->page_count, PCI_DMA_BIDIRECTIONAL); mem->page_count, PCI_DMA_BIDIRECTIONAL);
if (unlikely(!mem->num_sg)) { if (unlikely(!mem->num_sg))
intel_agp_free_sglist(mem); goto err;
return -ENOMEM;
}
return 0; return 0;
err:
sg_free_table(&st);
return -ENOMEM;
} }
static void intel_agp_unmap_memory(struct agp_memory *mem) static void intel_agp_unmap_memory(struct agp_memory *mem)
...@@ -176,7 +183,7 @@ static void intel_agp_insert_sg_entries(struct agp_memory *mem, ...@@ -176,7 +183,7 @@ static void intel_agp_insert_sg_entries(struct agp_memory *mem,
if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
{ {
cache_bits = I830_PTE_SYSTEM_CACHED; cache_bits = GEN6_PTE_LLC_MLC;
} }
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
...@@ -710,7 +717,12 @@ static void intel_i830_init_gtt_entries(void) ...@@ -710,7 +717,12 @@ static void intel_i830_init_gtt_entries(void)
break; break;
} }
} }
if (gtt_entries > 0) { if (!local && gtt_entries > intel_max_stolen) {
dev_info(&agp_bridge->dev->dev,
"detected %dK stolen memory, trimming to %dK\n",
gtt_entries / KB(1), intel_max_stolen / KB(1));
gtt_entries = intel_max_stolen / KB(4);
} else if (gtt_entries > 0) {
dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n", dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
gtt_entries / KB(1), local ? "local" : "stolen"); gtt_entries / KB(1), local ? "local" : "stolen");
gtt_entries /= KB(4); gtt_entries /= KB(4);
...@@ -797,6 +809,10 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) ...@@ -797,6 +809,10 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
/* we have to call this as early as possible after the MMIO base address is known */ /* we have to call this as early as possible after the MMIO base address is known */
intel_i830_init_gtt_entries(); intel_i830_init_gtt_entries();
if (intel_private.gtt_entries == 0) {
iounmap(intel_private.registers);
return -ENOMEM;
}
agp_bridge->gatt_table = NULL; agp_bridge->gatt_table = NULL;
...@@ -1282,6 +1298,11 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) ...@@ -1282,6 +1298,11 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
/* we have to call this as early as possible after the MMIO base address is known */ /* we have to call this as early as possible after the MMIO base address is known */
intel_i830_init_gtt_entries(); intel_i830_init_gtt_entries();
if (intel_private.gtt_entries == 0) {
iounmap(intel_private.gtt);
iounmap(intel_private.registers);
return -ENOMEM;
}
agp_bridge->gatt_table = NULL; agp_bridge->gatt_table = NULL;
...@@ -1309,6 +1330,16 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, ...@@ -1309,6 +1330,16 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
return addr | bridge->driver->masks[type].mask; return addr | bridge->driver->masks[type].mask;
} }
static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge,
dma_addr_t addr, int type)
{
/* Shift high bits down */
addr |= (addr >> 28) & 0xff;
/* Type checking must be done elsewhere */
return addr | bridge->driver->masks[type].mask;
}
static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
{ {
u16 snb_gmch_ctl; u16 snb_gmch_ctl;
...@@ -1390,6 +1421,11 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) ...@@ -1390,6 +1421,11 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
/* we have to call this as early as possible after the MMIO base address is known */ /* we have to call this as early as possible after the MMIO base address is known */
intel_i830_init_gtt_entries(); intel_i830_init_gtt_entries();
if (intel_private.gtt_entries == 0) {
iounmap(intel_private.gtt);
iounmap(intel_private.registers);
return -ENOMEM;
}
agp_bridge->gatt_table = NULL; agp_bridge->gatt_table = NULL;
...@@ -1517,6 +1553,39 @@ static const struct agp_bridge_driver intel_i965_driver = { ...@@ -1517,6 +1553,39 @@ static const struct agp_bridge_driver intel_i965_driver = {
#endif #endif
}; };
static const struct agp_bridge_driver intel_gen6_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
.num_aperture_sizes = 4,
.needs_scratch_page = true,
.configure = intel_i9xx_configure,
.fetch_size = intel_i9xx_fetch_size,
.cleanup = intel_i915_cleanup,
.mask_memory = intel_gen6_mask_memory,
.masks = intel_i810_masks,
.agp_enable = intel_i810_agp_enable,
.cache_flush = global_cache_flush,
.create_gatt_table = intel_i965_create_gatt_table,
.free_gatt_table = intel_i830_free_gatt_table,
.insert_memory = intel_i915_insert_entries,
.remove_memory = intel_i915_remove_entries,
.alloc_by_type = intel_i830_alloc_by_type,
.free_by_type = intel_i810_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_alloc_pages = agp_generic_alloc_pages,
.agp_destroy_page = agp_generic_destroy_page,
.agp_destroy_pages = agp_generic_destroy_pages,
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
.chipset_flush = intel_i915_chipset_flush,
#ifdef USE_PCI_DMA_API
.agp_map_page = intel_agp_map_page,
.agp_unmap_page = intel_agp_unmap_page,
.agp_map_memory = intel_agp_map_memory,
.agp_unmap_memory = intel_agp_unmap_memory,
#endif
};
static const struct agp_bridge_driver intel_g33_driver = { static const struct agp_bridge_driver intel_g33_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes, .aperture_sizes = intel_i830_sizes,
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# #
menuconfig DRM menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU
select I2C select I2C
select I2C_ALGOBIT select I2C_ALGOBIT
select SLOW_WORK select SLOW_WORK
...@@ -17,7 +17,7 @@ menuconfig DRM ...@@ -17,7 +17,7 @@ menuconfig DRM
These modules provide support for synchronization, security, and These modules provide support for synchronization, security, and
DMA transfers. Please see <http://dri.sourceforge.net/> for more DMA transfers. Please see <http://dri.sourceforge.net/> for more
details. You should also select and configure AGP details. You should also select and configure AGP
(/dev/agpgart) support. (/dev/agpgart) support if it is available for your platform.
config DRM_KMS_HELPER config DRM_KMS_HELPER
tristate tristate
...@@ -61,6 +61,7 @@ config DRM_RADEON ...@@ -61,6 +61,7 @@ config DRM_RADEON
select DRM_KMS_HELPER select DRM_KMS_HELPER
select DRM_TTM select DRM_TTM
select POWER_SUPPLY select POWER_SUPPLY
select HWMON
help help
Choose this option if you have an ATI Radeon graphics card. There Choose this option if you have an ATI Radeon graphics card. There
are both PCI and AGP versions. You don't need to choose this to are both PCI and AGP versions. You don't need to choose this to
...@@ -130,7 +131,7 @@ endchoice ...@@ -130,7 +131,7 @@ endchoice
config DRM_MGA config DRM_MGA
tristate "Matrox g200/g400" tristate "Matrox g200/g400"
depends on DRM depends on DRM && PCI
select FW_LOADER select FW_LOADER
help help
Choose this option if you have a Matrox G200, G400 or G450 graphics Choose this option if you have a Matrox G200, G400 or G450 graphics
...@@ -148,14 +149,14 @@ config DRM_SIS ...@@ -148,14 +149,14 @@ config DRM_SIS
config DRM_VIA config DRM_VIA
tristate "Via unichrome video cards" tristate "Via unichrome video cards"
depends on DRM depends on DRM && PCI
help help
Choose this option if you have a Via unichrome or compatible video Choose this option if you have a Via unichrome or compatible video
chipset. If M is selected the module will be called via. chipset. If M is selected the module will be called via.
config DRM_SAVAGE config DRM_SAVAGE
tristate "Savage video cards" tristate "Savage video cards"
depends on DRM depends on DRM && PCI
help help
Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
chipset. If M is selected the module will be called savage. chipset. If M is selected the module will be called savage.
...@@ -9,9 +9,10 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ ...@@ -9,9 +9,10 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \ drm_platform.o drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \
drm_crtc.o drm_modes.o drm_edid.o \ drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o drm_info.o drm_debugfs.o drm_encoder_slave.o \
drm_trace_points.o drm_global.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_COMPAT) += drm_ioc32.o
...@@ -19,6 +20,8 @@ drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o ...@@ -19,6 +20,8 @@ drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
CFLAGS_drm_trace_points.o := -I$(src)
obj-$(CONFIG_DRM) += drm.o obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_TTM) += ttm/ obj-$(CONFIG_DRM_TTM) += ttm/
obj-$(CONFIG_DRM_TDFX) += tdfx/ obj-$(CONFIG_DRM_TDFX) += tdfx/
......
...@@ -39,19 +39,6 @@ ...@@ -39,19 +39,6 @@
#include <asm/shmparam.h> #include <asm/shmparam.h>
#include "drmP.h" #include "drmP.h"
resource_size_t drm_get_resource_start(struct drm_device *dev, unsigned int resource)
{
return pci_resource_start(dev->pdev, resource);
}
EXPORT_SYMBOL(drm_get_resource_start);
resource_size_t drm_get_resource_len(struct drm_device *dev, unsigned int resource)
{
return pci_resource_len(dev->pdev, resource);
}
EXPORT_SYMBOL(drm_get_resource_len);
static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
struct drm_local_map *map) struct drm_local_map *map)
{ {
...@@ -189,7 +176,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, ...@@ -189,7 +176,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
switch (map->type) { switch (map->type) {
case _DRM_REGISTERS: case _DRM_REGISTERS:
case _DRM_FRAME_BUFFER: case _DRM_FRAME_BUFFER:
#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) #if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__)
if (map->offset + (map->size-1) < map->offset || if (map->offset + (map->size-1) < map->offset ||
map->offset < virt_to_phys(high_memory)) { map->offset < virt_to_phys(high_memory)) {
kfree(map); kfree(map);
......
...@@ -80,6 +80,7 @@ static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = ...@@ -80,6 +80,7 @@ static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
{ {
{ DRM_MODE_DITHERING_OFF, "Off" }, { DRM_MODE_DITHERING_OFF, "Off" },
{ DRM_MODE_DITHERING_ON, "On" }, { DRM_MODE_DITHERING_ON, "On" },
{ DRM_MODE_DITHERING_AUTO, "Automatic" },
}; };
/* /*
...@@ -1126,7 +1127,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -1126,7 +1127,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
list_for_each_entry(crtc, &dev->mode_config.crtc_list, list_for_each_entry(crtc, &dev->mode_config.crtc_list,
head) { head) {
DRM_DEBUG_KMS("CRTC ID is %d\n", crtc->base.id); DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
if (put_user(crtc->base.id, crtc_id + copied)) { if (put_user(crtc->base.id, crtc_id + copied)) {
ret = -EFAULT; ret = -EFAULT;
goto out; goto out;
...@@ -1154,8 +1155,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -1154,8 +1155,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
list_for_each_entry(encoder, list_for_each_entry(encoder,
&dev->mode_config.encoder_list, &dev->mode_config.encoder_list,
head) { head) {
DRM_DEBUG_KMS("ENCODER ID is %d\n", DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
encoder->base.id); drm_get_encoder_name(encoder));
if (put_user(encoder->base.id, encoder_id + if (put_user(encoder->base.id, encoder_id +
copied)) { copied)) {
ret = -EFAULT; ret = -EFAULT;
...@@ -1185,8 +1186,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -1185,8 +1186,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
list_for_each_entry(connector, list_for_each_entry(connector,
&dev->mode_config.connector_list, &dev->mode_config.connector_list,
head) { head) {
DRM_DEBUG_KMS("CONNECTOR ID is %d\n", DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id); connector->base.id,
drm_get_connector_name(connector));
if (put_user(connector->base.id, if (put_user(connector->base.id,
connector_id + copied)) { connector_id + copied)) {
ret = -EFAULT; ret = -EFAULT;
...@@ -1209,7 +1211,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -1209,7 +1211,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
} }
card_res->count_connectors = connector_count; card_res->count_connectors = connector_count;
DRM_DEBUG_KMS("Counted %d %d %d\n", card_res->count_crtcs, DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs,
card_res->count_connectors, card_res->count_encoders); card_res->count_connectors, card_res->count_encoders);
out: out:
...@@ -1312,7 +1314,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, ...@@ -1312,7 +1314,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
DRM_DEBUG_KMS("connector id %d:\n", out_resp->connector_id); DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.mutex);
...@@ -1493,6 +1495,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ...@@ -1493,6 +1495,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
goto out; goto out;
} }
crtc = obj_to_crtc(obj); crtc = obj_to_crtc(obj);
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
if (crtc_req->mode_valid) { if (crtc_req->mode_valid) {
/* If we have a mode we need a framebuffer. */ /* If we have a mode we need a framebuffer. */
...@@ -1569,6 +1572,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ...@@ -1569,6 +1572,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
goto out; goto out;
} }
connector = obj_to_connector(obj); connector = obj_to_connector(obj);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id,
drm_get_connector_name(connector));
connector_set[i] = connector; connector_set[i] = connector;
} }
...@@ -1684,6 +1690,7 @@ int drm_mode_addfb(struct drm_device *dev, ...@@ -1684,6 +1690,7 @@ int drm_mode_addfb(struct drm_device *dev,
r->fb_id = fb->base.id; r->fb_id = fb->base.id;
list_add(&fb->filp_head, &file_priv->fbs); list_add(&fb->filp_head, &file_priv->fbs);
DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
out: out:
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
...@@ -2610,6 +2617,15 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -2610,6 +2617,15 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
goto out; goto out;
crtc = obj_to_crtc(obj); crtc = obj_to_crtc(obj);
if (crtc->fb == NULL) {
/* The framebuffer is currently unbound, presumably
* due to a hotplug event, that userspace has not
* yet discovered.
*/
ret = -EBUSY;
goto out;
}
if (crtc->funcs->page_flip == NULL) if (crtc->funcs->page_flip == NULL)
goto out; goto out;
......
...@@ -86,7 +86,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, ...@@ -86,7 +86,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
int count = 0; int count = 0;
int mode_flags = 0; int mode_flags = 0;
DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector)); DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
drm_get_connector_name(connector));
/* set all modes to the unverified state */ /* set all modes to the unverified state */
list_for_each_entry_safe(mode, t, &connector->modes, head) list_for_each_entry_safe(mode, t, &connector->modes, head)
mode->status = MODE_UNVERIFIED; mode->status = MODE_UNVERIFIED;
...@@ -102,8 +103,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, ...@@ -102,8 +103,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
connector->status = connector->funcs->detect(connector); connector->status = connector->funcs->detect(connector);
if (connector->status == connector_status_disconnected) { if (connector->status == connector_status_disconnected) {
DRM_DEBUG_KMS("%s is disconnected\n", DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
drm_get_connector_name(connector)); connector->base.id, drm_get_connector_name(connector));
drm_mode_connector_update_edid_property(connector, NULL); drm_mode_connector_update_edid_property(connector, NULL);
goto prune; goto prune;
} }
...@@ -141,8 +142,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, ...@@ -141,8 +142,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
drm_mode_sort(&connector->modes); drm_mode_sort(&connector->modes);
DRM_DEBUG_KMS("Probed modes for %s\n", DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
drm_get_connector_name(connector)); drm_get_connector_name(connector));
list_for_each_entry_safe(mode, t, &connector->modes, head) { list_for_each_entry_safe(mode, t, &connector->modes, head) {
mode->vrefresh = drm_mode_vrefresh(mode); mode->vrefresh = drm_mode_vrefresh(mode);
...@@ -201,6 +202,17 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) ...@@ -201,6 +202,17 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
} }
EXPORT_SYMBOL(drm_helper_crtc_in_use); EXPORT_SYMBOL(drm_helper_crtc_in_use);
static void
drm_encoder_disable(struct drm_encoder *encoder)
{
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
if (encoder_funcs->disable)
(*encoder_funcs->disable)(encoder);
else
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
}
/** /**
* drm_helper_disable_unused_functions - disable unused objects * drm_helper_disable_unused_functions - disable unused objects
* @dev: DRM device * @dev: DRM device
...@@ -215,7 +227,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) ...@@ -215,7 +227,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
{ {
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_encoder_helper_funcs *encoder_funcs;
struct drm_crtc *crtc; struct drm_crtc *crtc;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
...@@ -226,12 +237,8 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) ...@@ -226,12 +237,8 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
} }
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
encoder_funcs = encoder->helper_private;
if (!drm_helper_encoder_in_use(encoder)) { if (!drm_helper_encoder_in_use(encoder)) {
if (encoder_funcs->disable) drm_encoder_disable(encoder);
(*encoder_funcs->disable)(encoder);
else
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
/* disconnector encoder from any connector */ /* disconnector encoder from any connector */
encoder->crtc = NULL; encoder->crtc = NULL;
} }
...@@ -241,7 +248,10 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) ...@@ -241,7 +248,10 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
crtc->enabled = drm_helper_crtc_in_use(crtc); crtc->enabled = drm_helper_crtc_in_use(crtc);
if (!crtc->enabled) { if (!crtc->enabled) {
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); if (crtc_funcs->disable)
(*crtc_funcs->disable)(crtc);
else
(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
crtc->fb = NULL; crtc->fb = NULL;
} }
} }
...@@ -292,11 +302,11 @@ drm_crtc_prepare_encoders(struct drm_device *dev) ...@@ -292,11 +302,11 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
encoder_funcs = encoder->helper_private; encoder_funcs = encoder->helper_private;
/* Disable unused encoders */ /* Disable unused encoders */
if (encoder->crtc == NULL) if (encoder->crtc == NULL)
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); drm_encoder_disable(encoder);
/* Disable encoders whose CRTC is about to change */ /* Disable encoders whose CRTC is about to change */
if (encoder_funcs->get_crtc && if (encoder_funcs->get_crtc &&
encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); drm_encoder_disable(encoder);
} }
} }
...@@ -365,6 +375,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -365,6 +375,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
goto done; goto done;
} }
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
/* Prepare the encoders and CRTCs before setting the mode. */ /* Prepare the encoders and CRTCs before setting the mode. */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
...@@ -392,8 +403,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -392,8 +403,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (encoder->crtc != crtc) if (encoder->crtc != crtc)
continue; continue;
DRM_DEBUG("%s: set mode %s %x\n", drm_get_encoder_name(encoder), DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
mode->name, mode->base.id); encoder->base.id, drm_get_encoder_name(encoder),
mode->base.id, mode->name);
encoder_funcs = encoder->helper_private; encoder_funcs = encoder->helper_private;
encoder_funcs->mode_set(encoder, mode, adjusted_mode); encoder_funcs->mode_set(encoder, mode, adjusted_mode);
} }
...@@ -469,10 +481,15 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -469,10 +481,15 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
crtc_funcs = set->crtc->helper_private; crtc_funcs = set->crtc->helper_private;
DRM_DEBUG_KMS("crtc: %p %d fb: %p connectors: %p num_connectors:" if (set->fb) {
" %d (x, y) (%i, %i)\n", DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
set->crtc, set->crtc->base.id, set->fb, set->connectors, set->crtc->base.id, set->fb->base.id,
(int)set->num_connectors, set->x, set->y); (int)set->num_connectors, set->x, set->y);
} else {
DRM_DEBUG_KMS("[CRTC:%d] [NOFB] #connectors=%d (x y) (%i %i)\n",
set->crtc->base.id, (int)set->num_connectors,
set->x, set->y);
}
dev = set->crtc->dev; dev = set->crtc->dev;
...@@ -601,8 +618,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -601,8 +618,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
mode_changed = true; mode_changed = true;
connector->encoder->crtc = new_crtc; connector->encoder->crtc = new_crtc;
} }
DRM_DEBUG_KMS("setting connector %d crtc to %p\n", if (new_crtc) {
connector->base.id, new_crtc); DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
connector->base.id, drm_get_connector_name(connector),
new_crtc->base.id);
} else {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
connector->base.id, drm_get_connector_name(connector));
}
} }
/* mode_set_base is not a required function */ /* mode_set_base is not a required function */
...@@ -620,8 +643,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -620,8 +643,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
if (!drm_crtc_helper_set_mode(set->crtc, set->mode, if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
set->x, set->y, set->x, set->y,
old_fb)) { old_fb)) {
DRM_ERROR("failed to set mode on crtc %p\n", DRM_ERROR("failed to set mode on [CRTC:%d]\n",
set->crtc); set->crtc->base.id);
ret = -EINVAL; ret = -EINVAL;
goto fail; goto fail;
} }
......
...@@ -243,47 +243,20 @@ int drm_lastclose(struct drm_device * dev) ...@@ -243,47 +243,20 @@ int drm_lastclose(struct drm_device * dev)
* *
* Initializes an array of drm_device structures, and attempts to * Initializes an array of drm_device structures, and attempts to
* initialize all available devices, using consecutive minors, registering the * initialize all available devices, using consecutive minors, registering the
* stubs and initializing the AGP device. * stubs and initializing the device.
* *
* Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
* after the initialization for driver customization. * after the initialization for driver customization.
*/ */
int drm_init(struct drm_driver *driver) int drm_init(struct drm_driver *driver)
{ {
struct pci_dev *pdev = NULL;
const struct pci_device_id *pid;
int i;
DRM_DEBUG("\n"); DRM_DEBUG("\n");
INIT_LIST_HEAD(&driver->device_list); INIT_LIST_HEAD(&driver->device_list);
if (driver->driver_features & DRIVER_MODESET) if (driver->driver_features & DRIVER_USE_PLATFORM_DEVICE)
return pci_register_driver(&driver->pci_driver); return drm_platform_init(driver);
else
/* If not using KMS, fall back to stealth mode manual scanning. */ return drm_pci_init(driver);
for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
pid = &driver->pci_driver.id_table[i];
/* Loop around setting up a DRM device for each PCI device
* matching our ID and device class. If we had the internal
* function that pci_get_subsys and pci_get_class used, we'd
* be able to just pass pid in instead of doing a two-stage
* thing.
*/
pdev = NULL;
while ((pdev =
pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
pid->subdevice, pdev)) != NULL) {
if ((pdev->class & pid->class_mask) != pid->class)
continue;
/* stealth mode requires a manual probe */
pci_dev_get(pdev);
drm_get_dev(pdev, pid, driver);
}
}
return 0;
} }
EXPORT_SYMBOL(drm_init); EXPORT_SYMBOL(drm_init);
...@@ -315,6 +288,7 @@ static int __init drm_core_init(void) ...@@ -315,6 +288,7 @@ static int __init drm_core_init(void)
{ {
int ret = -ENOMEM; int ret = -ENOMEM;
drm_global_init();
idr_init(&drm_minors_idr); idr_init(&drm_minors_idr);
if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))
...@@ -362,6 +336,7 @@ static void __exit drm_core_exit(void) ...@@ -362,6 +336,7 @@ static void __exit drm_core_exit(void)
unregister_chrdev(DRM_MAJOR, "drm"); unregister_chrdev(DRM_MAJOR, "drm");
idr_remove_all(&drm_minors_idr);
idr_destroy(&drm_minors_idr); idr_destroy(&drm_minors_idr);
} }
...@@ -506,9 +481,9 @@ long drm_ioctl(struct file *filp, ...@@ -506,9 +481,9 @@ long drm_ioctl(struct file *filp,
if (ioctl->flags & DRM_UNLOCKED) if (ioctl->flags & DRM_UNLOCKED)
retcode = func(dev, kdata, file_priv); retcode = func(dev, kdata, file_priv);
else { else {
lock_kernel(); mutex_lock(&drm_global_mutex);
retcode = func(dev, kdata, file_priv); retcode = func(dev, kdata, file_priv);
unlock_kernel(); mutex_unlock(&drm_global_mutex);
} }
if (cmd & IOC_OUT) { if (cmd & IOC_OUT) {
......
...@@ -282,7 +282,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) ...@@ -282,7 +282,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
return block; return block;
carp: carp:
dev_warn(&connector->dev->pdev->dev, "%s: EDID block %d invalid.\n", dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n",
drm_get_connector_name(connector), j); drm_get_connector_name(connector), j);
out: out:
...@@ -1623,7 +1623,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) ...@@ -1623,7 +1623,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
return 0; return 0;
} }
if (!drm_edid_is_valid(edid)) { if (!drm_edid_is_valid(edid)) {
dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", dev_warn(connector->dev->dev, "%s: EDID invalid.\n",
drm_get_connector_name(connector)); drm_get_connector_name(connector));
return 0; return 0;
} }
......
...@@ -41,6 +41,9 @@ ...@@ -41,6 +41,9 @@
* &drm_encoder_slave. The @slave_funcs field will be initialized with * &drm_encoder_slave. The @slave_funcs field will be initialized with
* the hooks provided by the slave driver. * the hooks provided by the slave driver.
* *
* If @info->platform_data is non-NULL it will be used as the initial
* slave config.
*
* Returns 0 on success or a negative errno on failure, in particular, * Returns 0 on success or a negative errno on failure, in particular,
* -ENODEV is returned when no matching driver is found. * -ENODEV is returned when no matching driver is found.
*/ */
...@@ -85,6 +88,10 @@ int drm_i2c_encoder_init(struct drm_device *dev, ...@@ -85,6 +88,10 @@ int drm_i2c_encoder_init(struct drm_device *dev,
if (err) if (err)
goto fail_unregister; goto fail_unregister;
if (info->platform_data)
encoder->slave_funcs->set_config(&encoder->base,
info->platform_data);
return 0; return 0;
fail_unregister: fail_unregister:
......
...@@ -39,6 +39,9 @@ ...@@ -39,6 +39,9 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
/* from BKL pushdown: note that nothing else serializes idr_find() */
DEFINE_MUTEX(drm_global_mutex);
static int drm_open_helper(struct inode *inode, struct file *filp, static int drm_open_helper(struct inode *inode, struct file *filp,
struct drm_device * dev); struct drm_device * dev);
...@@ -175,8 +178,7 @@ int drm_stub_open(struct inode *inode, struct file *filp) ...@@ -175,8 +178,7 @@ int drm_stub_open(struct inode *inode, struct file *filp)
DRM_DEBUG("\n"); DRM_DEBUG("\n");
/* BKL pushdown: note that nothing else serializes idr_find() */ mutex_lock(&drm_global_mutex);
lock_kernel();
minor = idr_find(&drm_minors_idr, minor_id); minor = idr_find(&drm_minors_idr, minor_id);
if (!minor) if (!minor)
goto out; goto out;
...@@ -197,7 +199,7 @@ int drm_stub_open(struct inode *inode, struct file *filp) ...@@ -197,7 +199,7 @@ int drm_stub_open(struct inode *inode, struct file *filp)
fops_put(old_fops); fops_put(old_fops);
out: out:
unlock_kernel(); mutex_unlock(&drm_global_mutex);
return err; return err;
} }
...@@ -472,7 +474,7 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -472,7 +474,7 @@ int drm_release(struct inode *inode, struct file *filp)
struct drm_device *dev = file_priv->minor->dev; struct drm_device *dev = file_priv->minor->dev;
int retcode = 0; int retcode = 0;
lock_kernel(); mutex_lock(&drm_global_mutex);
DRM_DEBUG("open_count = %d\n", dev->open_count); DRM_DEBUG("open_count = %d\n", dev->open_count);
...@@ -573,17 +575,14 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -573,17 +575,14 @@ int drm_release(struct inode *inode, struct file *filp)
if (atomic_read(&dev->ioctl_count)) { if (atomic_read(&dev->ioctl_count)) {
DRM_ERROR("Device busy: %d\n", DRM_ERROR("Device busy: %d\n",
atomic_read(&dev->ioctl_count)); atomic_read(&dev->ioctl_count));
spin_unlock(&dev->count_lock); retcode = -EBUSY;
unlock_kernel(); goto out;
return -EBUSY;
} }
spin_unlock(&dev->count_lock); retcode = drm_lastclose(dev);
unlock_kernel();
return drm_lastclose(dev);
} }
out:
spin_unlock(&dev->count_lock); spin_unlock(&dev->count_lock);
mutex_unlock(&drm_global_mutex);
unlock_kernel();
return retcode; return retcode;
} }
......
...@@ -68,8 +68,18 @@ ...@@ -68,8 +68,18 @@
* We make up offsets for buffer objects so we can recognize them at * We make up offsets for buffer objects so we can recognize them at
* mmap time. * mmap time.
*/ */
/* pgoff in mmap is an unsigned long, so we need to make sure that
* the faked up offset will fit
*/
#if BITS_PER_LONG == 64
#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
#else
#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1)
#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16)
#endif
/** /**
* Initialize the GEM device fields * Initialize the GEM device fields
...@@ -419,6 +429,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private) ...@@ -419,6 +429,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
idr_for_each(&file_private->object_idr, idr_for_each(&file_private->object_idr,
&drm_gem_object_release_handle, NULL); &drm_gem_object_release_handle, NULL);
idr_remove_all(&file_private->object_idr);
idr_destroy(&file_private->object_idr); idr_destroy(&file_private->object_idr);
} }
......
...@@ -28,45 +28,45 @@ ...@@ -28,45 +28,45 @@
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
*/ */
#include "ttm/ttm_module.h"
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include "drm_global.h"
struct ttm_global_item { struct drm_global_item {
struct mutex mutex; struct mutex mutex;
void *object; void *object;
int refcount; int refcount;
}; };
static struct ttm_global_item glob[TTM_GLOBAL_NUM]; static struct drm_global_item glob[DRM_GLOBAL_NUM];
void ttm_global_init(void) void drm_global_init(void)
{ {
int i; int i;
for (i = 0; i < TTM_GLOBAL_NUM; ++i) { for (i = 0; i < DRM_GLOBAL_NUM; ++i) {
struct ttm_global_item *item = &glob[i]; struct drm_global_item *item = &glob[i];
mutex_init(&item->mutex); mutex_init(&item->mutex);
item->object = NULL; item->object = NULL;
item->refcount = 0; item->refcount = 0;
} }
} }
void ttm_global_release(void) void drm_global_release(void)
{ {
int i; int i;
for (i = 0; i < TTM_GLOBAL_NUM; ++i) { for (i = 0; i < DRM_GLOBAL_NUM; ++i) {
struct ttm_global_item *item = &glob[i]; struct drm_global_item *item = &glob[i];
BUG_ON(item->object != NULL); BUG_ON(item->object != NULL);
BUG_ON(item->refcount != 0); BUG_ON(item->refcount != 0);
} }
} }
int ttm_global_item_ref(struct ttm_global_reference *ref) int drm_global_item_ref(struct drm_global_reference *ref)
{ {
int ret; int ret;
struct ttm_global_item *item = &glob[ref->global_type]; struct drm_global_item *item = &glob[ref->global_type];
void *object; void *object;
mutex_lock(&item->mutex); mutex_lock(&item->mutex);
...@@ -93,11 +93,11 @@ int ttm_global_item_ref(struct ttm_global_reference *ref) ...@@ -93,11 +93,11 @@ int ttm_global_item_ref(struct ttm_global_reference *ref)
item->object = NULL; item->object = NULL;
return ret; return ret;
} }
EXPORT_SYMBOL(ttm_global_item_ref); EXPORT_SYMBOL(drm_global_item_ref);
void ttm_global_item_unref(struct ttm_global_reference *ref) void drm_global_item_unref(struct drm_global_reference *ref)
{ {
struct ttm_global_item *item = &glob[ref->global_type]; struct drm_global_item *item = &glob[ref->global_type];
mutex_lock(&item->mutex); mutex_lock(&item->mutex);
BUG_ON(item->refcount == 0); BUG_ON(item->refcount == 0);
...@@ -108,5 +108,5 @@ void ttm_global_item_unref(struct ttm_global_reference *ref) ...@@ -108,5 +108,5 @@ void ttm_global_item_unref(struct ttm_global_reference *ref)
} }
mutex_unlock(&item->mutex); mutex_unlock(&item->mutex);
} }
EXPORT_SYMBOL(ttm_global_item_unref); EXPORT_SYMBOL(drm_global_item_unref);
...@@ -51,13 +51,24 @@ int drm_name_info(struct seq_file *m, void *data) ...@@ -51,13 +51,24 @@ int drm_name_info(struct seq_file *m, void *data)
if (!master) if (!master)
return 0; return 0;
if (master->unique) { if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
seq_printf(m, "%s %s %s\n", if (master->unique) {
dev->driver->pci_driver.name, seq_printf(m, "%s %s %s\n",
pci_name(dev->pdev), master->unique); dev->driver->platform_device->name,
dev_name(dev->dev), master->unique);
} else {
seq_printf(m, "%s\n",
dev->driver->platform_device->name);
}
} else { } else {
seq_printf(m, "%s %s\n", dev->driver->pci_driver.name, if (master->unique) {
pci_name(dev->pdev)); seq_printf(m, "%s %s %s\n",
dev->driver->pci_driver.name,
dev_name(dev->dev), master->unique);
} else {
seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
dev_name(dev->dev));
}
} }
return 0; return 0;
......
...@@ -64,6 +64,19 @@ int drm_getunique(struct drm_device *dev, void *data, ...@@ -64,6 +64,19 @@ int drm_getunique(struct drm_device *dev, void *data,
return 0; return 0;
} }
static void
drm_unset_busid(struct drm_device *dev,
struct drm_master *master)
{
kfree(dev->devname);
dev->devname = NULL;
kfree(master->unique);
master->unique = NULL;
master->unique_len = 0;
master->unique_size = 0;
}
/** /**
* Set the bus id. * Set the bus id.
* *
...@@ -94,17 +107,24 @@ int drm_setunique(struct drm_device *dev, void *data, ...@@ -94,17 +107,24 @@ int drm_setunique(struct drm_device *dev, void *data,
master->unique_len = u->unique_len; master->unique_len = u->unique_len;
master->unique_size = u->unique_len + 1; master->unique_size = u->unique_len + 1;
master->unique = kmalloc(master->unique_size, GFP_KERNEL); master->unique = kmalloc(master->unique_size, GFP_KERNEL);
if (!master->unique) if (!master->unique) {
return -ENOMEM; ret = -ENOMEM;
if (copy_from_user(master->unique, u->unique, master->unique_len)) goto err;
return -EFAULT; }
if (copy_from_user(master->unique, u->unique, master->unique_len)) {
ret = -EFAULT;
goto err;
}
master->unique[master->unique_len] = '\0'; master->unique[master->unique_len] = '\0';
dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
strlen(master->unique) + 2, GFP_KERNEL); strlen(master->unique) + 2, GFP_KERNEL);
if (!dev->devname) if (!dev->devname) {
return -ENOMEM; ret = -ENOMEM;
goto err;
}
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
master->unique); master->unique);
...@@ -113,53 +133,103 @@ int drm_setunique(struct drm_device *dev, void *data, ...@@ -113,53 +133,103 @@ int drm_setunique(struct drm_device *dev, void *data,
* busid. * busid.
*/ */
ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
if (ret != 3) if (ret != 3) {
return -EINVAL; ret = -EINVAL;
goto err;
}
domain = bus >> 8; domain = bus >> 8;
bus &= 0xff; bus &= 0xff;
if ((domain != drm_get_pci_domain(dev)) || if ((domain != drm_get_pci_domain(dev)) ||
(bus != dev->pdev->bus->number) || (bus != dev->pdev->bus->number) ||
(slot != PCI_SLOT(dev->pdev->devfn)) || (slot != PCI_SLOT(dev->pdev->devfn)) ||
(func != PCI_FUNC(dev->pdev->devfn))) (func != PCI_FUNC(dev->pdev->devfn))) {
return -EINVAL; ret = -EINVAL;
goto err;
}
return 0; return 0;
err:
drm_unset_busid(dev, master);
return ret;
} }
static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
{ {
struct drm_master *master = file_priv->master; struct drm_master *master = file_priv->master;
int len; int len, ret;
if (master->unique != NULL) if (master->unique != NULL)
return -EBUSY; drm_unset_busid(dev, master);
master->unique_len = 40; if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
master->unique_size = master->unique_len; master->unique_len = 10 + strlen(dev->platformdev->name);
master->unique = kmalloc(master->unique_size, GFP_KERNEL); master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
if (master->unique == NULL)
return -ENOMEM;
len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d",
drm_get_pci_domain(dev),
dev->pdev->bus->number,
PCI_SLOT(dev->pdev->devfn),
PCI_FUNC(dev->pdev->devfn));
if (len >= master->unique_len)
DRM_ERROR("buffer overflow");
else
master->unique_len = len;
dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + if (master->unique == NULL)
master->unique_len + 2, GFP_KERNEL); return -ENOMEM;
if (dev->devname == NULL)
return -ENOMEM;
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, len = snprintf(master->unique, master->unique_len,
master->unique); "platform:%s", dev->platformdev->name);
if (len > master->unique_len) {
DRM_ERROR("Unique buffer overflowed\n");
ret = -EINVAL;
goto err;
}
dev->devname =
kmalloc(strlen(dev->platformdev->name) +
master->unique_len + 2, GFP_KERNEL);
if (dev->devname == NULL) {
ret = -ENOMEM;
goto err;
}
sprintf(dev->devname, "%s@%s", dev->platformdev->name,
master->unique);
} else {
master->unique_len = 40;
master->unique_size = master->unique_len;
master->unique = kmalloc(master->unique_size, GFP_KERNEL);
if (master->unique == NULL)
return -ENOMEM;
len = snprintf(master->unique, master->unique_len,
"pci:%04x:%02x:%02x.%d",
drm_get_pci_domain(dev),
dev->pdev->bus->number,
PCI_SLOT(dev->pdev->devfn),
PCI_FUNC(dev->pdev->devfn));
if (len >= master->unique_len) {
DRM_ERROR("buffer overflow");
ret = -EINVAL;
goto err;
} else
master->unique_len = len;
dev->devname =
kmalloc(strlen(dev->driver->pci_driver.name) +
master->unique_len + 2, GFP_KERNEL);
if (dev->devname == NULL) {
ret = -ENOMEM;
goto err;
}
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
master->unique);
}
return 0; return 0;
err:
drm_unset_busid(dev, master);
return ret;
} }
/** /**
...@@ -323,7 +393,9 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri ...@@ -323,7 +393,9 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri
/* /*
* Version 1.1 includes tying of DRM to specific device * Version 1.1 includes tying of DRM to specific device
*/ */
drm_set_busid(dev, file_priv); retcode = drm_set_busid(dev, file_priv);
if (retcode)
goto done;
} }
} }
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
*/ */
#include "drmP.h" #include "drmP.h"
#include "drm_trace.h"
#include <linux/interrupt.h> /* For task queue support */ #include <linux/interrupt.h> /* For task queue support */
#include <linux/slab.h> #include <linux/slab.h>
...@@ -57,6 +58,9 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, ...@@ -57,6 +58,9 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
{ {
struct drm_irq_busid *p = data; struct drm_irq_busid *p = data;
if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
return -EINVAL;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL; return -EINVAL;
...@@ -211,7 +215,7 @@ int drm_irq_install(struct drm_device *dev) ...@@ -211,7 +215,7 @@ int drm_irq_install(struct drm_device *dev)
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL; return -EINVAL;
if (dev->pdev->irq == 0) if (drm_dev_to_irq(dev) == 0)
return -EINVAL; return -EINVAL;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
...@@ -229,7 +233,7 @@ int drm_irq_install(struct drm_device *dev) ...@@ -229,7 +233,7 @@ int drm_irq_install(struct drm_device *dev)
dev->irq_enabled = 1; dev->irq_enabled = 1;
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
DRM_DEBUG("irq=%d\n", dev->pdev->irq); DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
/* Before installing handler */ /* Before installing handler */
dev->driver->irq_preinstall(dev); dev->driver->irq_preinstall(dev);
...@@ -302,14 +306,14 @@ int drm_irq_uninstall(struct drm_device * dev) ...@@ -302,14 +306,14 @@ int drm_irq_uninstall(struct drm_device * dev)
if (!irq_enabled) if (!irq_enabled)
return -EINVAL; return -EINVAL;
DRM_DEBUG("irq=%d\n", dev->pdev->irq); DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
vga_client_register(dev->pdev, NULL, NULL, NULL); vga_client_register(dev->pdev, NULL, NULL, NULL);
dev->driver->irq_uninstall(dev); dev->driver->irq_uninstall(dev);
free_irq(dev->pdev->irq, dev); free_irq(drm_dev_to_irq(dev), dev);
return 0; return 0;
} }
...@@ -341,7 +345,7 @@ int drm_control(struct drm_device *dev, void *data, ...@@ -341,7 +345,7 @@ int drm_control(struct drm_device *dev, void *data,
if (drm_core_check_feature(dev, DRIVER_MODESET)) if (drm_core_check_feature(dev, DRIVER_MODESET))
return 0; return 0;
if (dev->if_version < DRM_IF_VERSION(1, 2) && if (dev->if_version < DRM_IF_VERSION(1, 2) &&
ctl->irq != dev->pdev->irq) ctl->irq != drm_dev_to_irq(dev))
return -EINVAL; return -EINVAL;
return drm_irq_install(dev); return drm_irq_install(dev);
case DRM_UNINST_HANDLER: case DRM_UNINST_HANDLER:
...@@ -587,6 +591,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, ...@@ -587,6 +591,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
return -ENOMEM; return -ENOMEM;
e->pipe = pipe; e->pipe = pipe;
e->base.pid = current->pid;
e->event.base.type = DRM_EVENT_VBLANK; e->event.base.type = DRM_EVENT_VBLANK;
e->event.base.length = sizeof e->event; e->event.base.length = sizeof e->event;
e->event.user_data = vblwait->request.signal; e->event.user_data = vblwait->request.signal;
...@@ -614,6 +619,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, ...@@ -614,6 +619,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n", DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
vblwait->request.sequence, seq, pipe); vblwait->request.sequence, seq, pipe);
trace_drm_vblank_event_queued(current->pid, pipe,
vblwait->request.sequence);
e->event.sequence = vblwait->request.sequence; e->event.sequence = vblwait->request.sequence;
if ((seq - vblwait->request.sequence) <= (1 << 23)) { if ((seq - vblwait->request.sequence) <= (1 << 23)) {
e->event.tv_sec = now.tv_sec; e->event.tv_sec = now.tv_sec;
...@@ -621,6 +629,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, ...@@ -621,6 +629,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
drm_vblank_put(dev, e->pipe); drm_vblank_put(dev, e->pipe);
list_add_tail(&e->base.link, &e->base.file_priv->event_list); list_add_tail(&e->base.link, &e->base.file_priv->event_list);
wake_up_interruptible(&e->base.file_priv->event_wait); wake_up_interruptible(&e->base.file_priv->event_wait);
trace_drm_vblank_event_delivered(current->pid, pipe,
vblwait->request.sequence);
} else { } else {
list_add_tail(&e->base.link, &dev->vblank_event_list); list_add_tail(&e->base.link, &dev->vblank_event_list);
} }
...@@ -651,7 +661,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, ...@@ -651,7 +661,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
int ret = 0; int ret = 0;
unsigned int flags, seq, crtc; unsigned int flags, seq, crtc;
if ((!dev->pdev->irq) || (!dev->irq_enabled)) if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
return -EINVAL; return -EINVAL;
if (vblwait->request.type & _DRM_VBLANK_SIGNAL) if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
...@@ -751,9 +761,13 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) ...@@ -751,9 +761,13 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc)
drm_vblank_put(dev, e->pipe); drm_vblank_put(dev, e->pipe);
list_move_tail(&e->base.link, &e->base.file_priv->event_list); list_move_tail(&e->base.link, &e->base.file_priv->event_list);
wake_up_interruptible(&e->base.file_priv->event_wait); wake_up_interruptible(&e->base.file_priv->event_wait);
trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
e->event.sequence);
} }
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
trace_drm_vblank_event(crtc, seq);
} }
/** /**
......
...@@ -48,44 +48,14 @@ ...@@ -48,44 +48,14 @@
#define MM_UNUSED_TARGET 4 #define MM_UNUSED_TARGET 4
unsigned long drm_mm_tail_space(struct drm_mm *mm)
{
struct list_head *tail_node;
struct drm_mm_node *entry;
tail_node = mm->ml_entry.prev;
entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
if (!entry->free)
return 0;
return entry->size;
}
int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size)
{
struct list_head *tail_node;
struct drm_mm_node *entry;
tail_node = mm->ml_entry.prev;
entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
if (!entry->free)
return -ENOMEM;
if (entry->size <= size)
return -ENOMEM;
entry->size -= size;
return 0;
}
static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic) static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
{ {
struct drm_mm_node *child; struct drm_mm_node *child;
if (atomic) if (atomic)
child = kmalloc(sizeof(*child), GFP_ATOMIC); child = kzalloc(sizeof(*child), GFP_ATOMIC);
else else
child = kmalloc(sizeof(*child), GFP_KERNEL); child = kzalloc(sizeof(*child), GFP_KERNEL);
if (unlikely(child == NULL)) { if (unlikely(child == NULL)) {
spin_lock(&mm->unused_lock); spin_lock(&mm->unused_lock);
...@@ -94,8 +64,8 @@ static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic) ...@@ -94,8 +64,8 @@ static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
else { else {
child = child =
list_entry(mm->unused_nodes.next, list_entry(mm->unused_nodes.next,
struct drm_mm_node, fl_entry); struct drm_mm_node, free_stack);
list_del(&child->fl_entry); list_del(&child->free_stack);
--mm->num_unused; --mm->num_unused;
} }
spin_unlock(&mm->unused_lock); spin_unlock(&mm->unused_lock);
...@@ -115,7 +85,7 @@ int drm_mm_pre_get(struct drm_mm *mm) ...@@ -115,7 +85,7 @@ int drm_mm_pre_get(struct drm_mm *mm)
spin_lock(&mm->unused_lock); spin_lock(&mm->unused_lock);
while (mm->num_unused < MM_UNUSED_TARGET) { while (mm->num_unused < MM_UNUSED_TARGET) {
spin_unlock(&mm->unused_lock); spin_unlock(&mm->unused_lock);
node = kmalloc(sizeof(*node), GFP_KERNEL); node = kzalloc(sizeof(*node), GFP_KERNEL);
spin_lock(&mm->unused_lock); spin_lock(&mm->unused_lock);
if (unlikely(node == NULL)) { if (unlikely(node == NULL)) {
...@@ -124,7 +94,7 @@ int drm_mm_pre_get(struct drm_mm *mm) ...@@ -124,7 +94,7 @@ int drm_mm_pre_get(struct drm_mm *mm)
return ret; return ret;
} }
++mm->num_unused; ++mm->num_unused;
list_add_tail(&node->fl_entry, &mm->unused_nodes); list_add_tail(&node->free_stack, &mm->unused_nodes);
} }
spin_unlock(&mm->unused_lock); spin_unlock(&mm->unused_lock);
return 0; return 0;
...@@ -146,27 +116,12 @@ static int drm_mm_create_tail_node(struct drm_mm *mm, ...@@ -146,27 +116,12 @@ static int drm_mm_create_tail_node(struct drm_mm *mm,
child->start = start; child->start = start;
child->mm = mm; child->mm = mm;
list_add_tail(&child->ml_entry, &mm->ml_entry); list_add_tail(&child->node_list, &mm->node_list);
list_add_tail(&child->fl_entry, &mm->fl_entry); list_add_tail(&child->free_stack, &mm->free_stack);
return 0; return 0;
} }
int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic)
{
struct list_head *tail_node;
struct drm_mm_node *entry;
tail_node = mm->ml_entry.prev;
entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
if (!entry->free) {
return drm_mm_create_tail_node(mm, entry->start + entry->size,
size, atomic);
}
entry->size += size;
return 0;
}
static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent, static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
unsigned long size, unsigned long size,
int atomic) int atomic)
...@@ -177,15 +132,14 @@ static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent, ...@@ -177,15 +132,14 @@ static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
if (unlikely(child == NULL)) if (unlikely(child == NULL))
return NULL; return NULL;
INIT_LIST_HEAD(&child->fl_entry); INIT_LIST_HEAD(&child->free_stack);
child->free = 0;
child->size = size; child->size = size;
child->start = parent->start; child->start = parent->start;
child->mm = parent->mm; child->mm = parent->mm;
list_add_tail(&child->ml_entry, &parent->ml_entry); list_add_tail(&child->node_list, &parent->node_list);
INIT_LIST_HEAD(&child->fl_entry); INIT_LIST_HEAD(&child->free_stack);
parent->size -= size; parent->size -= size;
parent->start += size; parent->start += size;
...@@ -213,7 +167,7 @@ struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, ...@@ -213,7 +167,7 @@ struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
} }
if (node->size == size) { if (node->size == size) {
list_del_init(&node->fl_entry); list_del_init(&node->free_stack);
node->free = 0; node->free = 0;
} else { } else {
node = drm_mm_split_at_start(node, size, atomic); node = drm_mm_split_at_start(node, size, atomic);
...@@ -251,7 +205,7 @@ struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *node, ...@@ -251,7 +205,7 @@ struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *node,
} }
if (node->size == size) { if (node->size == size) {
list_del_init(&node->fl_entry); list_del_init(&node->free_stack);
node->free = 0; node->free = 0;
} else { } else {
node = drm_mm_split_at_start(node, size, atomic); node = drm_mm_split_at_start(node, size, atomic);
...@@ -273,16 +227,19 @@ void drm_mm_put_block(struct drm_mm_node *cur) ...@@ -273,16 +227,19 @@ void drm_mm_put_block(struct drm_mm_node *cur)
{ {
struct drm_mm *mm = cur->mm; struct drm_mm *mm = cur->mm;
struct list_head *cur_head = &cur->ml_entry; struct list_head *cur_head = &cur->node_list;
struct list_head *root_head = &mm->ml_entry; struct list_head *root_head = &mm->node_list;
struct drm_mm_node *prev_node = NULL; struct drm_mm_node *prev_node = NULL;
struct drm_mm_node *next_node; struct drm_mm_node *next_node;
int merged = 0; int merged = 0;
BUG_ON(cur->scanned_block || cur->scanned_prev_free
|| cur->scanned_next_free);
if (cur_head->prev != root_head) { if (cur_head->prev != root_head) {
prev_node = prev_node =
list_entry(cur_head->prev, struct drm_mm_node, ml_entry); list_entry(cur_head->prev, struct drm_mm_node, node_list);
if (prev_node->free) { if (prev_node->free) {
prev_node->size += cur->size; prev_node->size += cur->size;
merged = 1; merged = 1;
...@@ -290,15 +247,15 @@ void drm_mm_put_block(struct drm_mm_node *cur) ...@@ -290,15 +247,15 @@ void drm_mm_put_block(struct drm_mm_node *cur)
} }
if (cur_head->next != root_head) { if (cur_head->next != root_head) {
next_node = next_node =
list_entry(cur_head->next, struct drm_mm_node, ml_entry); list_entry(cur_head->next, struct drm_mm_node, node_list);
if (next_node->free) { if (next_node->free) {
if (merged) { if (merged) {
prev_node->size += next_node->size; prev_node->size += next_node->size;
list_del(&next_node->ml_entry); list_del(&next_node->node_list);
list_del(&next_node->fl_entry); list_del(&next_node->free_stack);
spin_lock(&mm->unused_lock); spin_lock(&mm->unused_lock);
if (mm->num_unused < MM_UNUSED_TARGET) { if (mm->num_unused < MM_UNUSED_TARGET) {
list_add(&next_node->fl_entry, list_add(&next_node->free_stack,
&mm->unused_nodes); &mm->unused_nodes);
++mm->num_unused; ++mm->num_unused;
} else } else
...@@ -313,12 +270,12 @@ void drm_mm_put_block(struct drm_mm_node *cur) ...@@ -313,12 +270,12 @@ void drm_mm_put_block(struct drm_mm_node *cur)
} }
if (!merged) { if (!merged) {
cur->free = 1; cur->free = 1;
list_add(&cur->fl_entry, &mm->fl_entry); list_add(&cur->free_stack, &mm->free_stack);
} else { } else {
list_del(&cur->ml_entry); list_del(&cur->node_list);
spin_lock(&mm->unused_lock); spin_lock(&mm->unused_lock);
if (mm->num_unused < MM_UNUSED_TARGET) { if (mm->num_unused < MM_UNUSED_TARGET) {
list_add(&cur->fl_entry, &mm->unused_nodes); list_add(&cur->free_stack, &mm->unused_nodes);
++mm->num_unused; ++mm->num_unused;
} else } else
kfree(cur); kfree(cur);
...@@ -328,40 +285,50 @@ void drm_mm_put_block(struct drm_mm_node *cur) ...@@ -328,40 +285,50 @@ void drm_mm_put_block(struct drm_mm_node *cur)
EXPORT_SYMBOL(drm_mm_put_block); EXPORT_SYMBOL(drm_mm_put_block);
static int check_free_mm_node(struct drm_mm_node *entry, unsigned long size,
unsigned alignment)
{
unsigned wasted = 0;
if (entry->size < size)
return 0;
if (alignment) {
register unsigned tmp = entry->start % alignment;
if (tmp)
wasted = alignment - tmp;
}
if (entry->size >= size + wasted) {
return 1;
}
return 0;
}
struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
unsigned long size, unsigned long size,
unsigned alignment, int best_match) unsigned alignment, int best_match)
{ {
struct list_head *list;
const struct list_head *free_stack = &mm->fl_entry;
struct drm_mm_node *entry; struct drm_mm_node *entry;
struct drm_mm_node *best; struct drm_mm_node *best;
unsigned long best_size; unsigned long best_size;
unsigned wasted;
BUG_ON(mm->scanned_blocks);
best = NULL; best = NULL;
best_size = ~0UL; best_size = ~0UL;
list_for_each(list, free_stack) { list_for_each_entry(entry, &mm->free_stack, free_stack) {
entry = list_entry(list, struct drm_mm_node, fl_entry); if (!check_free_mm_node(entry, size, alignment))
wasted = 0;
if (entry->size < size)
continue; continue;
if (alignment) { if (!best_match)
register unsigned tmp = entry->start % alignment; return entry;
if (tmp)
wasted += alignment - tmp;
}
if (entry->size >= size + wasted) { if (entry->size < best_size) {
if (!best_match) best = entry;
return entry; best_size = entry->size;
if (entry->size < best_size) {
best = entry;
best_size = entry->size;
}
} }
} }
...@@ -376,43 +343,28 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, ...@@ -376,43 +343,28 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
unsigned long end, unsigned long end,
int best_match) int best_match)
{ {
struct list_head *list;
const struct list_head *free_stack = &mm->fl_entry;
struct drm_mm_node *entry; struct drm_mm_node *entry;
struct drm_mm_node *best; struct drm_mm_node *best;
unsigned long best_size; unsigned long best_size;
unsigned wasted;
BUG_ON(mm->scanned_blocks);
best = NULL; best = NULL;
best_size = ~0UL; best_size = ~0UL;
list_for_each(list, free_stack) { list_for_each_entry(entry, &mm->free_stack, free_stack) {
entry = list_entry(list, struct drm_mm_node, fl_entry);
wasted = 0;
if (entry->size < size)
continue;
if (entry->start > end || (entry->start+entry->size) < start) if (entry->start > end || (entry->start+entry->size) < start)
continue; continue;
if (entry->start < start) if (!check_free_mm_node(entry, size, alignment))
wasted += start - entry->start; continue;
if (alignment) { if (!best_match)
register unsigned tmp = (entry->start + wasted) % alignment; return entry;
if (tmp)
wasted += alignment - tmp;
}
if (entry->size >= size + wasted && if (entry->size < best_size) {
(entry->start + wasted + size) <= end) { best = entry;
if (!best_match) best_size = entry->size;
return entry;
if (entry->size < best_size) {
best = entry;
best_size = entry->size;
}
} }
} }
...@@ -420,9 +372,161 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, ...@@ -420,9 +372,161 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
} }
EXPORT_SYMBOL(drm_mm_search_free_in_range); EXPORT_SYMBOL(drm_mm_search_free_in_range);
/**
* Initializa lru scanning.
*
* This simply sets up the scanning routines with the parameters for the desired
* hole.
*
* Warning: As long as the scan list is non-empty, no other operations than
* adding/removing nodes to/from the scan list are allowed.
*/
void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
unsigned alignment)
{
mm->scan_alignment = alignment;
mm->scan_size = size;
mm->scanned_blocks = 0;
mm->scan_hit_start = 0;
mm->scan_hit_size = 0;
}
EXPORT_SYMBOL(drm_mm_init_scan);
/**
* Add a node to the scan list that might be freed to make space for the desired
* hole.
*
* Returns non-zero, if a hole has been found, zero otherwise.
*/
int drm_mm_scan_add_block(struct drm_mm_node *node)
{
struct drm_mm *mm = node->mm;
struct list_head *prev_free, *next_free;
struct drm_mm_node *prev_node, *next_node;
mm->scanned_blocks++;
prev_free = next_free = NULL;
BUG_ON(node->free);
node->scanned_block = 1;
node->free = 1;
if (node->node_list.prev != &mm->node_list) {
prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
node_list);
if (prev_node->free) {
list_del(&prev_node->node_list);
node->start = prev_node->start;
node->size += prev_node->size;
prev_node->scanned_prev_free = 1;
prev_free = &prev_node->free_stack;
}
}
if (node->node_list.next != &mm->node_list) {
next_node = list_entry(node->node_list.next, struct drm_mm_node,
node_list);
if (next_node->free) {
list_del(&next_node->node_list);
node->size += next_node->size;
next_node->scanned_next_free = 1;
next_free = &next_node->free_stack;
}
}
/* The free_stack list is not used for allocated objects, so these two
* pointers can be abused (as long as no allocations in this memory
* manager happens). */
node->free_stack.prev = prev_free;
node->free_stack.next = next_free;
if (check_free_mm_node(node, mm->scan_size, mm->scan_alignment)) {
mm->scan_hit_start = node->start;
mm->scan_hit_size = node->size;
return 1;
}
return 0;
}
EXPORT_SYMBOL(drm_mm_scan_add_block);
/**
* Remove a node from the scan list.
*
* Nodes _must_ be removed in the exact same order from the scan list as they
* have been added, otherwise the internal state of the memory manager will be
* corrupted.
*
* When the scan list is empty, the selected memory nodes can be freed. An
* immediatly following drm_mm_search_free with best_match = 0 will then return
* the just freed block (because its at the top of the free_stack list).
*
* Returns one if this block should be evicted, zero otherwise. Will always
* return zero when no hole has been found.
*/
int drm_mm_scan_remove_block(struct drm_mm_node *node)
{
struct drm_mm *mm = node->mm;
struct drm_mm_node *prev_node, *next_node;
mm->scanned_blocks--;
BUG_ON(!node->scanned_block);
node->scanned_block = 0;
node->free = 0;
prev_node = list_entry(node->free_stack.prev, struct drm_mm_node,
free_stack);
next_node = list_entry(node->free_stack.next, struct drm_mm_node,
free_stack);
if (prev_node) {
BUG_ON(!prev_node->scanned_prev_free);
prev_node->scanned_prev_free = 0;
list_add_tail(&prev_node->node_list, &node->node_list);
node->start = prev_node->start + prev_node->size;
node->size -= prev_node->size;
}
if (next_node) {
BUG_ON(!next_node->scanned_next_free);
next_node->scanned_next_free = 0;
list_add(&next_node->node_list, &node->node_list);
node->size -= next_node->size;
}
INIT_LIST_HEAD(&node->free_stack);
/* Only need to check for containement because start&size for the
* complete resulting free block (not just the desired part) is
* stored. */
if (node->start >= mm->scan_hit_start &&
node->start + node->size
<= mm->scan_hit_start + mm->scan_hit_size) {
return 1;
}
return 0;
}
EXPORT_SYMBOL(drm_mm_scan_remove_block);
int drm_mm_clean(struct drm_mm * mm) int drm_mm_clean(struct drm_mm * mm)
{ {
struct list_head *head = &mm->ml_entry; struct list_head *head = &mm->node_list;
return (head->next->next == head); return (head->next->next == head);
} }
...@@ -430,10 +534,11 @@ EXPORT_SYMBOL(drm_mm_clean); ...@@ -430,10 +534,11 @@ EXPORT_SYMBOL(drm_mm_clean);
int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
{ {
INIT_LIST_HEAD(&mm->ml_entry); INIT_LIST_HEAD(&mm->node_list);
INIT_LIST_HEAD(&mm->fl_entry); INIT_LIST_HEAD(&mm->free_stack);
INIT_LIST_HEAD(&mm->unused_nodes); INIT_LIST_HEAD(&mm->unused_nodes);
mm->num_unused = 0; mm->num_unused = 0;
mm->scanned_blocks = 0;
spin_lock_init(&mm->unused_lock); spin_lock_init(&mm->unused_lock);
return drm_mm_create_tail_node(mm, start, size, 0); return drm_mm_create_tail_node(mm, start, size, 0);
...@@ -442,25 +547,25 @@ EXPORT_SYMBOL(drm_mm_init); ...@@ -442,25 +547,25 @@ EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(struct drm_mm * mm) void drm_mm_takedown(struct drm_mm * mm)
{ {
struct list_head *bnode = mm->fl_entry.next; struct list_head *bnode = mm->free_stack.next;
struct drm_mm_node *entry; struct drm_mm_node *entry;
struct drm_mm_node *next; struct drm_mm_node *next;
entry = list_entry(bnode, struct drm_mm_node, fl_entry); entry = list_entry(bnode, struct drm_mm_node, free_stack);
if (entry->ml_entry.next != &mm->ml_entry || if (entry->node_list.next != &mm->node_list ||
entry->fl_entry.next != &mm->fl_entry) { entry->free_stack.next != &mm->free_stack) {
DRM_ERROR("Memory manager not clean. Delaying takedown\n"); DRM_ERROR("Memory manager not clean. Delaying takedown\n");
return; return;
} }
list_del(&entry->fl_entry); list_del(&entry->free_stack);
list_del(&entry->ml_entry); list_del(&entry->node_list);
kfree(entry); kfree(entry);
spin_lock(&mm->unused_lock); spin_lock(&mm->unused_lock);
list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) { list_for_each_entry_safe(entry, next, &mm->unused_nodes, free_stack) {
list_del(&entry->fl_entry); list_del(&entry->free_stack);
kfree(entry); kfree(entry);
--mm->num_unused; --mm->num_unused;
} }
...@@ -475,7 +580,7 @@ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix) ...@@ -475,7 +580,7 @@ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
struct drm_mm_node *entry; struct drm_mm_node *entry;
int total_used = 0, total_free = 0, total = 0; int total_used = 0, total_free = 0, total = 0;
list_for_each_entry(entry, &mm->ml_entry, ml_entry) { list_for_each_entry(entry, &mm->node_list, node_list) {
printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8ld: %s\n", printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8ld: %s\n",
prefix, entry->start, entry->start + entry->size, prefix, entry->start, entry->start + entry->size,
entry->size, entry->free ? "free" : "used"); entry->size, entry->free ? "free" : "used");
...@@ -496,7 +601,7 @@ int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm) ...@@ -496,7 +601,7 @@ int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
struct drm_mm_node *entry; struct drm_mm_node *entry;
int total_used = 0, total_free = 0, total = 0; int total_used = 0, total_free = 0, total = 0;
list_for_each_entry(entry, &mm->ml_entry, ml_entry) { list_for_each_entry(entry, &mm->node_list, node_list) {
seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: %s\n", entry->start, entry->start + entry->size, entry->size, entry->free ? "free" : "used"); seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: %s\n", entry->start, entry->start + entry->size, entry->size, entry->free ? "free" : "used");
total += entry->size; total += entry->size;
if (entry->free) if (entry->free)
......
...@@ -124,4 +124,147 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) ...@@ -124,4 +124,147 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
EXPORT_SYMBOL(drm_pci_free); EXPORT_SYMBOL(drm_pci_free);
#ifdef CONFIG_PCI
/**
* Register.
*
* \param pdev - PCI device structure
* \param ent entry from the PCI ID table with device type flags
* \return zero on success or a negative number on failure.
*
* Attempt to gets inter module "drm" information. If we are first
* then register the character device and inter module information.
* Try and register, if we fail to register, backout previous work.
*/
int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver)
{
struct drm_device *dev;
int ret;
DRM_DEBUG("\n");
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
ret = pci_enable_device(pdev);
if (ret)
goto err_g1;
pci_set_master(pdev);
dev->pdev = pdev;
dev->dev = &pdev->dev;
dev->pci_device = pdev->device;
dev->pci_vendor = pdev->vendor;
#ifdef __alpha__
dev->hose = pdev->sysdata;
#endif
if ((ret = drm_fill_in_dev(dev, ent, driver))) {
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
goto err_g2;
}
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
pci_set_drvdata(pdev, dev);
ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
if (ret)
goto err_g2;
}
if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
goto err_g3;
if (dev->driver->load) {
ret = dev->driver->load(dev, ent->driver_data);
if (ret)
goto err_g4;
}
/* setup the grouping for the legacy output */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = drm_mode_group_init_legacy_group(dev,
&dev->primary->mode_group);
if (ret)
goto err_g4;
}
list_add_tail(&dev->driver_item, &driver->device_list);
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, pci_name(pdev), dev->primary->index);
return 0;
err_g4:
drm_put_minor(&dev->primary);
err_g3:
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_put_minor(&dev->control);
err_g2:
pci_disable_device(pdev);
err_g1:
kfree(dev);
return ret;
}
EXPORT_SYMBOL(drm_get_pci_dev);
/**
* PCI device initialization. Called via drm_init at module load time,
*
* \return zero on success or a negative number on failure.
*
* Initializes a drm_device structures,registering the
* stubs and initializing the AGP device.
*
* Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
* after the initialization for driver customization.
*/
int drm_pci_init(struct drm_driver *driver)
{
struct pci_dev *pdev = NULL;
const struct pci_device_id *pid;
int i;
if (driver->driver_features & DRIVER_MODESET)
return pci_register_driver(&driver->pci_driver);
/* If not using KMS, fall back to stealth mode manual scanning. */
for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
pid = &driver->pci_driver.id_table[i];
/* Loop around setting up a DRM device for each PCI device
* matching our ID and device class. If we had the internal
* function that pci_get_subsys and pci_get_class used, we'd
* be able to just pass pid in instead of doing a two-stage
* thing.
*/
pdev = NULL;
while ((pdev =
pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
pid->subdevice, pdev)) != NULL) {
if ((pdev->class & pid->class_mask) != pid->class)
continue;
/* stealth mode requires a manual probe */
pci_dev_get(pdev);
drm_get_pci_dev(pdev, pid, driver);
}
}
return 0;
}
#else
int drm_pci_init(struct drm_driver *driver)
{
return -1;
}
#endif
/*@}*/ /*@}*/
/*
* Derived from drm_pci.c
*
* Copyright 2003 José Fonseca.
* Copyright 2003 Leif Delgass.
* Copyright (c) 2009, Code Aurora Forum.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "drmP.h"
/**
* Register.
*
* \param platdev - Platform device struture
* \return zero on success or a negative number on failure.
*
* Attempt to gets inter module "drm" information. If we are first
* then register the character device and inter module information.
* Try and register, if we fail to register, backout previous work.
*/
int drm_get_platform_dev(struct platform_device *platdev,
struct drm_driver *driver)
{
struct drm_device *dev;
int ret;
DRM_DEBUG("\n");
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->platformdev = platdev;
dev->dev = &platdev->dev;
ret = drm_fill_in_dev(dev, NULL, driver);
if (ret) {
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
goto err_g1;
}
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
dev_set_drvdata(&platdev->dev, dev);
ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
if (ret)
goto err_g1;
}
ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY);
if (ret)
goto err_g2;
if (dev->driver->load) {
ret = dev->driver->load(dev, 0);
if (ret)
goto err_g3;
}
/* setup the grouping for the legacy output */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = drm_mode_group_init_legacy_group(dev,
&dev->primary->mode_group);
if (ret)
goto err_g3;
}
list_add_tail(&dev->driver_item, &driver->device_list);
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, dev->primary->index);
return 0;
err_g3:
drm_put_minor(&dev->primary);
err_g2:
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_put_minor(&dev->control);
err_g1:
kfree(dev);
return ret;
}
EXPORT_SYMBOL(drm_get_platform_dev);
/**
* Platform device initialization. Called via drm_init at module load time,
*
* \return zero on success or a negative number on failure.
*
* Initializes a drm_device structures,registering the
* stubs
*
* Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
* after the initialization for driver customization.
*/
int drm_platform_init(struct drm_driver *driver)
{
return drm_get_platform_dev(driver->platform_device, driver);
}
...@@ -156,6 +156,9 @@ static void drm_master_destroy(struct kref *kref) ...@@ -156,6 +156,9 @@ static void drm_master_destroy(struct kref *kref)
master->unique_len = 0; master->unique_len = 0;
} }
kfree(dev->devname);
dev->devname = NULL;
list_for_each_entry_safe(pt, next, &master->magicfree, head) { list_for_each_entry_safe(pt, next, &master->magicfree, head) {
list_del(&pt->head); list_del(&pt->head);
drm_ht_remove_item(&master->magiclist, &pt->hash_item); drm_ht_remove_item(&master->magiclist, &pt->hash_item);
...@@ -224,7 +227,7 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, ...@@ -224,7 +227,7 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
return 0; return 0;
} }
static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, int drm_fill_in_dev(struct drm_device *dev,
const struct pci_device_id *ent, const struct pci_device_id *ent,
struct drm_driver *driver) struct drm_driver *driver)
{ {
...@@ -245,14 +248,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, ...@@ -245,14 +248,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
idr_init(&dev->drw_idr); idr_init(&dev->drw_idr);
dev->pdev = pdev;
dev->pci_device = pdev->device;
dev->pci_vendor = pdev->vendor;
#ifdef __alpha__
dev->hose = pdev->sysdata;
#endif
if (drm_ht_create(&dev->map_hash, 12)) { if (drm_ht_create(&dev->map_hash, 12)) {
return -ENOMEM; return -ENOMEM;
} }
...@@ -321,7 +316,7 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, ...@@ -321,7 +316,7 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
* create the proc init entry via proc_init(). This routines assigns * create the proc init entry via proc_init(). This routines assigns
* minor numbers to secondary heads of multi-headed cards * minor numbers to secondary heads of multi-headed cards
*/ */
static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
{ {
struct drm_minor *new_minor; struct drm_minor *new_minor;
int ret; int ret;
...@@ -387,83 +382,6 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t ...@@ -387,83 +382,6 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t
return ret; return ret;
} }
/**
* Register.
*
* \param pdev - PCI device structure
* \param ent entry from the PCI ID table with device type flags
* \return zero on success or a negative number on failure.
*
* Attempt to gets inter module "drm" information. If we are first
* then register the character device and inter module information.
* Try and register, if we fail to register, backout previous work.
*/
int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver)
{
struct drm_device *dev;
int ret;
DRM_DEBUG("\n");
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
ret = pci_enable_device(pdev);
if (ret)
goto err_g1;
pci_set_master(pdev);
if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
goto err_g2;
}
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
pci_set_drvdata(pdev, dev);
ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
if (ret)
goto err_g2;
}
if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
goto err_g3;
if (dev->driver->load) {
ret = dev->driver->load(dev, ent->driver_data);
if (ret)
goto err_g4;
}
/* setup the grouping for the legacy output */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group);
if (ret)
goto err_g4;
}
list_add_tail(&dev->driver_item, &driver->device_list);
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, pci_name(pdev), dev->primary->index);
return 0;
err_g4:
drm_put_minor(&dev->primary);
err_g3:
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_put_minor(&dev->control);
err_g2:
pci_disable_device(pdev);
err_g1:
kfree(dev);
return ret;
}
EXPORT_SYMBOL(drm_get_dev);
/** /**
* Put a secondary minor number. * Put a secondary minor number.
* *
......
...@@ -489,7 +489,8 @@ int drm_sysfs_device_add(struct drm_minor *minor) ...@@ -489,7 +489,8 @@ int drm_sysfs_device_add(struct drm_minor *minor)
int err; int err;
char *minor_str; char *minor_str;
minor->kdev.parent = &minor->dev->pdev->dev; minor->kdev.parent = minor->dev->dev;
minor->kdev.class = drm_class; minor->kdev.class = drm_class;
minor->kdev.release = drm_sysfs_device_release; minor->kdev.release = drm_sysfs_device_release;
minor->kdev.devt = minor->device; minor->kdev.devt = minor->device;
......
#if !defined(_DRM_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _DRM_TRACE_H_
#include <linux/stringify.h>
#include <linux/types.h>
#include <linux/tracepoint.h>
#undef TRACE_SYSTEM
#define TRACE_SYSTEM drm
#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM)
#define TRACE_INCLUDE_FILE drm_trace
TRACE_EVENT(drm_vblank_event,
TP_PROTO(int crtc, unsigned int seq),
TP_ARGS(crtc, seq),
TP_STRUCT__entry(
__field(int, crtc)
__field(unsigned int, seq)
),
TP_fast_assign(
__entry->crtc = crtc;
__entry->seq = seq;
),
TP_printk("crtc=%d, seq=%d", __entry->crtc, __entry->seq)
);
TRACE_EVENT(drm_vblank_event_queued,
TP_PROTO(pid_t pid, int crtc, unsigned int seq),
TP_ARGS(pid, crtc, seq),
TP_STRUCT__entry(
__field(pid_t, pid)
__field(int, crtc)
__field(unsigned int, seq)
),
TP_fast_assign(
__entry->pid = pid;
__entry->crtc = crtc;
__entry->seq = seq;
),
TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \
__entry->seq)
);
TRACE_EVENT(drm_vblank_event_delivered,
TP_PROTO(pid_t pid, int crtc, unsigned int seq),
TP_ARGS(pid, crtc, seq),
TP_STRUCT__entry(
__field(pid_t, pid)
__field(int, crtc)
__field(unsigned int, seq)
),
TP_fast_assign(
__entry->pid = pid;
__entry->crtc = crtc;
__entry->seq = seq;
),
TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \
__entry->seq)
);
#endif /* _DRM_TRACE_H_ */
/* This part must be outside protection */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#include <trace/define_trace.h>
#include "drmP.h"
#define CREATE_TRACE_POINTS
#include "drm_trace.h"
...@@ -61,7 +61,7 @@ static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) ...@@ -61,7 +61,7 @@ static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
tmp = pgprot_writecombine(tmp); tmp = pgprot_writecombine(tmp);
else else
tmp = pgprot_noncached(tmp); tmp = pgprot_noncached(tmp);
#elif defined(__sparc__) #elif defined(__sparc__) || defined(__arm__)
tmp = pgprot_noncached(tmp); tmp = pgprot_noncached(tmp);
#endif #endif
return tmp; return tmp;
...@@ -601,6 +601,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) ...@@ -601,6 +601,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
} }
switch (map->type) { switch (map->type) {
#if !defined(__arm__)
case _DRM_AGP: case _DRM_AGP:
if (drm_core_has_AGP(dev) && dev->agp->cant_use_aperture) { if (drm_core_has_AGP(dev) && dev->agp->cant_use_aperture) {
/* /*
...@@ -615,20 +616,31 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) ...@@ -615,20 +616,31 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
break; break;
} }
/* fall through to _DRM_FRAME_BUFFER... */ /* fall through to _DRM_FRAME_BUFFER... */
#endif
case _DRM_FRAME_BUFFER: case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS: case _DRM_REGISTERS:
offset = dev->driver->get_reg_ofs(dev); offset = dev->driver->get_reg_ofs(dev);
vma->vm_flags |= VM_IO; /* not in core dump */ vma->vm_flags |= VM_IO; /* not in core dump */
vma->vm_page_prot = drm_io_prot(map->type, vma); vma->vm_page_prot = drm_io_prot(map->type, vma);
#if !defined(__arm__)
if (io_remap_pfn_range(vma, vma->vm_start, if (io_remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT, (map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_end - vma->vm_start,
vma->vm_page_prot)) vma->vm_page_prot))
return -EAGAIN; return -EAGAIN;
#else
if (remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
#endif
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%llx\n", " offset = 0x%llx\n",
map->type, map->type,
vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset)); vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset));
vma->vm_ops = &drm_vm_ops; vma->vm_ops = &drm_vm_ops;
break; break;
case _DRM_CONSISTENT: case _DRM_CONSISTENT:
......
...@@ -2,3 +2,6 @@ ccflags-y := -Iinclude/drm ...@@ -2,3 +2,6 @@ ccflags-y := -Iinclude/drm
ch7006-y := ch7006_drv.o ch7006_mode.o ch7006-y := ch7006_drv.o ch7006_mode.o
obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
sil164-y := sil164_drv.o
obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o
...@@ -33,7 +33,7 @@ static void ch7006_encoder_set_config(struct drm_encoder *encoder, ...@@ -33,7 +33,7 @@ static void ch7006_encoder_set_config(struct drm_encoder *encoder,
{ {
struct ch7006_priv *priv = to_ch7006_priv(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder);
priv->params = params; priv->params = *(struct ch7006_encoder_params *)params;
} }
static void ch7006_encoder_destroy(struct drm_encoder *encoder) static void ch7006_encoder_destroy(struct drm_encoder *encoder)
...@@ -114,7 +114,7 @@ static void ch7006_encoder_mode_set(struct drm_encoder *encoder, ...@@ -114,7 +114,7 @@ static void ch7006_encoder_mode_set(struct drm_encoder *encoder,
{ {
struct i2c_client *client = drm_i2c_encoder_get_client(encoder); struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
struct ch7006_priv *priv = to_ch7006_priv(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder);
struct ch7006_encoder_params *params = priv->params; struct ch7006_encoder_params *params = &priv->params;
struct ch7006_state *state = &priv->state; struct ch7006_state *state = &priv->state;
uint8_t *regs = state->regs; uint8_t *regs = state->regs;
struct ch7006_mode *mode = priv->mode; struct ch7006_mode *mode = priv->mode;
...@@ -428,6 +428,22 @@ static int ch7006_remove(struct i2c_client *client) ...@@ -428,6 +428,22 @@ static int ch7006_remove(struct i2c_client *client)
return 0; return 0;
} }
static int ch7006_suspend(struct i2c_client *client, pm_message_t mesg)
{
ch7006_dbg(client, "\n");
return 0;
}
static int ch7006_resume(struct i2c_client *client)
{
ch7006_dbg(client, "\n");
ch7006_write(client, 0x3d, 0x0);
return 0;
}
static int ch7006_encoder_init(struct i2c_client *client, static int ch7006_encoder_init(struct i2c_client *client,
struct drm_device *dev, struct drm_device *dev,
struct drm_encoder_slave *encoder) struct drm_encoder_slave *encoder)
...@@ -487,6 +503,8 @@ static struct drm_i2c_encoder_driver ch7006_driver = { ...@@ -487,6 +503,8 @@ static struct drm_i2c_encoder_driver ch7006_driver = {
.i2c_driver = { .i2c_driver = {
.probe = ch7006_probe, .probe = ch7006_probe,
.remove = ch7006_remove, .remove = ch7006_remove,
.suspend = ch7006_suspend,
.resume = ch7006_resume,
.driver = { .driver = {
.name = "ch7006", .name = "ch7006",
......
...@@ -77,7 +77,7 @@ struct ch7006_state { ...@@ -77,7 +77,7 @@ struct ch7006_state {
}; };
struct ch7006_priv { struct ch7006_priv {
struct ch7006_encoder_params *params; struct ch7006_encoder_params params;
struct ch7006_mode *mode; struct ch7006_mode *mode;
struct ch7006_state state; struct ch7006_state state;
......
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "drmP.h"
#include "drm_crtc_helper.h"
#include "drm_encoder_slave.h"
#include "i2c/sil164.h"
struct sil164_priv {
struct sil164_encoder_params config;
struct i2c_client *duallink_slave;
uint8_t saved_state[0x10];
uint8_t saved_slave_state[0x10];
};
#define to_sil164_priv(x) \
((struct sil164_priv *)to_encoder_slave(x)->slave_priv)
#define sil164_dbg(client, format, ...) do { \
if (drm_debug & DRM_UT_KMS) \
dev_printk(KERN_DEBUG, &client->dev, \
"%s: " format, __func__, ## __VA_ARGS__); \
} while (0)
#define sil164_info(client, format, ...) \
dev_info(&client->dev, format, __VA_ARGS__)
#define sil164_err(client, format, ...) \
dev_err(&client->dev, format, __VA_ARGS__)
#define SIL164_I2C_ADDR_MASTER 0x38
#define SIL164_I2C_ADDR_SLAVE 0x39
/* HW register definitions */
#define SIL164_VENDOR_LO 0x0
#define SIL164_VENDOR_HI 0x1
#define SIL164_DEVICE_LO 0x2
#define SIL164_DEVICE_HI 0x3
#define SIL164_REVISION 0x4
#define SIL164_FREQ_MIN 0x6
#define SIL164_FREQ_MAX 0x7
#define SIL164_CONTROL0 0x8
# define SIL164_CONTROL0_POWER_ON 0x01
# define SIL164_CONTROL0_EDGE_RISING 0x02
# define SIL164_CONTROL0_INPUT_24BIT 0x04
# define SIL164_CONTROL0_DUAL_EDGE 0x08
# define SIL164_CONTROL0_HSYNC_ON 0x10
# define SIL164_CONTROL0_VSYNC_ON 0x20
#define SIL164_DETECT 0x9
# define SIL164_DETECT_INTR_STAT 0x01
# define SIL164_DETECT_HOTPLUG_STAT 0x02
# define SIL164_DETECT_RECEIVER_STAT 0x04
# define SIL164_DETECT_INTR_MODE_RECEIVER 0x00
# define SIL164_DETECT_INTR_MODE_HOTPLUG 0x08
# define SIL164_DETECT_OUT_MODE_HIGH 0x00
# define SIL164_DETECT_OUT_MODE_INTR 0x10
# define SIL164_DETECT_OUT_MODE_RECEIVER 0x20
# define SIL164_DETECT_OUT_MODE_HOTPLUG 0x30
# define SIL164_DETECT_VSWING_STAT 0x80
#define SIL164_CONTROL1 0xa
# define SIL164_CONTROL1_DESKEW_ENABLE 0x10
# define SIL164_CONTROL1_DESKEW_INCR_SHIFT 5
#define SIL164_GPIO 0xb
#define SIL164_CONTROL2 0xc
# define SIL164_CONTROL2_FILTER_ENABLE 0x01
# define SIL164_CONTROL2_FILTER_SETTING_SHIFT 1
# define SIL164_CONTROL2_DUALLINK_MASTER 0x40
# define SIL164_CONTROL2_SYNC_CONT 0x80
#define SIL164_DUALLINK 0xd
# define SIL164_DUALLINK_ENABLE 0x10
# define SIL164_DUALLINK_SKEW_SHIFT 5
#define SIL164_PLLZONE 0xe
# define SIL164_PLLZONE_STAT 0x08
# define SIL164_PLLZONE_FORCE_ON 0x10
# define SIL164_PLLZONE_FORCE_HIGH 0x20
/* HW access functions */
static void
sil164_write(struct i2c_client *client, uint8_t addr, uint8_t val)
{
uint8_t buf[] = {addr, val};
int ret;
ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
if (ret < 0)
sil164_err(client, "Error %d writing to subaddress 0x%x\n",
ret, addr);
}
static uint8_t
sil164_read(struct i2c_client *client, uint8_t addr)
{
uint8_t val;
int ret;
ret = i2c_master_send(client, &addr, sizeof(addr));
if (ret < 0)
goto fail;
ret = i2c_master_recv(client, &val, sizeof(val));
if (ret < 0)
goto fail;
return val;
fail:
sil164_err(client, "Error %d reading from subaddress 0x%x\n",
ret, addr);
return 0;
}
static void
sil164_save_state(struct i2c_client *client, uint8_t *state)
{
int i;
for (i = 0x8; i <= 0xe; i++)
state[i] = sil164_read(client, i);
}
static void
sil164_restore_state(struct i2c_client *client, uint8_t *state)
{
int i;
for (i = 0x8; i <= 0xe; i++)
sil164_write(client, i, state[i]);
}
static void
sil164_set_power_state(struct i2c_client *client, bool on)
{
uint8_t control0 = sil164_read(client, SIL164_CONTROL0);
if (on)
control0 |= SIL164_CONTROL0_POWER_ON;
else
control0 &= ~SIL164_CONTROL0_POWER_ON;
sil164_write(client, SIL164_CONTROL0, control0);
}
static void
sil164_init_state(struct i2c_client *client,
struct sil164_encoder_params *config,
bool duallink)
{
sil164_write(client, SIL164_CONTROL0,
SIL164_CONTROL0_HSYNC_ON |
SIL164_CONTROL0_VSYNC_ON |
(config->input_edge ? SIL164_CONTROL0_EDGE_RISING : 0) |
(config->input_width ? SIL164_CONTROL0_INPUT_24BIT : 0) |
(config->input_dual ? SIL164_CONTROL0_DUAL_EDGE : 0));
sil164_write(client, SIL164_DETECT,
SIL164_DETECT_INTR_STAT |
SIL164_DETECT_OUT_MODE_RECEIVER);
sil164_write(client, SIL164_CONTROL1,
(config->input_skew ? SIL164_CONTROL1_DESKEW_ENABLE : 0) |
(((config->input_skew + 4) & 0x7)
<< SIL164_CONTROL1_DESKEW_INCR_SHIFT));
sil164_write(client, SIL164_CONTROL2,
SIL164_CONTROL2_SYNC_CONT |
(config->pll_filter ? 0 : SIL164_CONTROL2_FILTER_ENABLE) |
(4 << SIL164_CONTROL2_FILTER_SETTING_SHIFT));
sil164_write(client, SIL164_PLLZONE, 0);
if (duallink)
sil164_write(client, SIL164_DUALLINK,
SIL164_DUALLINK_ENABLE |
(((config->duallink_skew + 4) & 0x7)
<< SIL164_DUALLINK_SKEW_SHIFT));
else
sil164_write(client, SIL164_DUALLINK, 0);
}
/* DRM encoder functions */
static void
sil164_encoder_set_config(struct drm_encoder *encoder, void *params)
{
struct sil164_priv *priv = to_sil164_priv(encoder);
priv->config = *(struct sil164_encoder_params *)params;
}
static void
sil164_encoder_dpms(struct drm_encoder *encoder, int mode)
{
struct sil164_priv *priv = to_sil164_priv(encoder);
bool on = (mode == DRM_MODE_DPMS_ON);
bool duallink = (on && encoder->crtc->mode.clock > 165000);
sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on);
if (priv->duallink_slave)
sil164_set_power_state(priv->duallink_slave, duallink);
}
static void
sil164_encoder_save(struct drm_encoder *encoder)
{
struct sil164_priv *priv = to_sil164_priv(encoder);
sil164_save_state(drm_i2c_encoder_get_client(encoder),
priv->saved_state);
if (priv->duallink_slave)
sil164_save_state(priv->duallink_slave,
priv->saved_slave_state);
}
static void
sil164_encoder_restore(struct drm_encoder *encoder)
{
struct sil164_priv *priv = to_sil164_priv(encoder);
sil164_restore_state(drm_i2c_encoder_get_client(encoder),
priv->saved_state);
if (priv->duallink_slave)
sil164_restore_state(priv->duallink_slave,
priv->saved_slave_state);
}
static bool
sil164_encoder_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static int
sil164_encoder_mode_valid(struct drm_encoder *encoder,
struct drm_display_mode *mode)
{
struct sil164_priv *priv = to_sil164_priv(encoder);
if (mode->clock < 32000)
return MODE_CLOCK_LOW;
if (mode->clock > 330000 ||
(mode->clock > 165000 && !priv->duallink_slave))
return MODE_CLOCK_HIGH;
return MODE_OK;
}
static void
sil164_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct sil164_priv *priv = to_sil164_priv(encoder);
bool duallink = adjusted_mode->clock > 165000;
sil164_init_state(drm_i2c_encoder_get_client(encoder),
&priv->config, duallink);
if (priv->duallink_slave)
sil164_init_state(priv->duallink_slave,
&priv->config, duallink);
sil164_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
}
static enum drm_connector_status
sil164_encoder_detect(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
if (sil164_read(client, SIL164_DETECT) & SIL164_DETECT_HOTPLUG_STAT)
return connector_status_connected;
else
return connector_status_disconnected;
}
static int
sil164_encoder_get_modes(struct drm_encoder *encoder,
struct drm_connector *connector)
{
return 0;
}
static int
sil164_encoder_create_resources(struct drm_encoder *encoder,
struct drm_connector *connector)
{
return 0;
}
static int
sil164_encoder_set_property(struct drm_encoder *encoder,
struct drm_connector *connector,
struct drm_property *property,
uint64_t val)
{
return 0;
}
static void
sil164_encoder_destroy(struct drm_encoder *encoder)
{
struct sil164_priv *priv = to_sil164_priv(encoder);
if (priv->duallink_slave)
i2c_unregister_device(priv->duallink_slave);
kfree(priv);
drm_i2c_encoder_destroy(encoder);
}
static struct drm_encoder_slave_funcs sil164_encoder_funcs = {
.set_config = sil164_encoder_set_config,
.destroy = sil164_encoder_destroy,
.dpms = sil164_encoder_dpms,
.save = sil164_encoder_save,
.restore = sil164_encoder_restore,
.mode_fixup = sil164_encoder_mode_fixup,
.mode_valid = sil164_encoder_mode_valid,
.mode_set = sil164_encoder_mode_set,
.detect = sil164_encoder_detect,
.get_modes = sil164_encoder_get_modes,
.create_resources = sil164_encoder_create_resources,
.set_property = sil164_encoder_set_property,
};
/* I2C driver functions */
static int
sil164_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 |
sil164_read(client, SIL164_VENDOR_LO);
int device = sil164_read(client, SIL164_DEVICE_HI) << 8 |
sil164_read(client, SIL164_DEVICE_LO);
int rev = sil164_read(client, SIL164_REVISION);
if (vendor != 0x1 || device != 0x6) {
sil164_dbg(client, "Unknown device %x:%x.%x\n",
vendor, device, rev);
return -ENODEV;
}
sil164_info(client, "Detected device %x:%x.%x\n",
vendor, device, rev);
return 0;
}
static int
sil164_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_client *
sil164_detect_slave(struct i2c_client *client)
{
struct i2c_adapter *adap = client->adapter;
struct i2c_msg msg = {
.addr = SIL164_I2C_ADDR_SLAVE,
.len = 0,
};
const struct i2c_board_info info = {
I2C_BOARD_INFO("sil164", SIL164_I2C_ADDR_SLAVE)
};
if (i2c_transfer(adap, &msg, 1) != 1) {
sil164_dbg(adap, "No dual-link slave found.");
return NULL;
}
return i2c_new_device(adap, &info);
}
static int
sil164_encoder_init(struct i2c_client *client,
struct drm_device *dev,
struct drm_encoder_slave *encoder)
{
struct sil164_priv *priv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
encoder->slave_priv = priv;
encoder->slave_funcs = &sil164_encoder_funcs;
priv->duallink_slave = sil164_detect_slave(client);
return 0;
}
static struct i2c_device_id sil164_ids[] = {
{ "sil164", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, sil164_ids);
static struct drm_i2c_encoder_driver sil164_driver = {
.i2c_driver = {
.probe = sil164_probe,
.remove = sil164_remove,
.driver = {
.name = "sil164",
},
.id_table = sil164_ids,
},
.encoder_init = sil164_encoder_init,
};
/* Module initialization */
static int __init
sil164_init(void)
{
return drm_i2c_encoder_register(THIS_MODULE, &sil164_driver);
}
static void __exit
sil164_exit(void)
{
drm_i2c_encoder_unregister(&sil164_driver);
}
MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>");
MODULE_DESCRIPTION("Silicon Image sil164 TMDS transmitter driver");
MODULE_LICENSE("GPL and additional rights");
module_init(sil164_init);
module_exit(sil164_exit);
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/interrupt.h> /* For task queue support */ #include <linux/interrupt.h> /* For task queue support */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#define I810_BUF_FREE 2 #define I810_BUF_FREE 2
...@@ -60,9 +61,8 @@ static struct drm_buf *i810_freelist_get(struct drm_device * dev) ...@@ -60,9 +61,8 @@ static struct drm_buf *i810_freelist_get(struct drm_device * dev)
/* In use is already a pointer */ /* In use is already a pointer */
used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
I810_BUF_CLIENT); I810_BUF_CLIENT);
if (used == I810_BUF_FREE) { if (used == I810_BUF_FREE)
return buf; return buf;
}
} }
return NULL; return NULL;
} }
...@@ -71,7 +71,7 @@ static struct drm_buf *i810_freelist_get(struct drm_device * dev) ...@@ -71,7 +71,7 @@ static struct drm_buf *i810_freelist_get(struct drm_device * dev)
* yet, the hardware updates in use for us once its on the ring buffer. * yet, the hardware updates in use for us once its on the ring buffer.
*/ */
static int i810_freelist_put(struct drm_device * dev, struct drm_buf * buf) static int i810_freelist_put(struct drm_device *dev, struct drm_buf *buf)
{ {
drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_buf_priv_t *buf_priv = buf->dev_private;
int used; int used;
...@@ -121,7 +121,7 @@ static const struct file_operations i810_buffer_fops = { ...@@ -121,7 +121,7 @@ static const struct file_operations i810_buffer_fops = {
.fasync = drm_fasync, .fasync = drm_fasync,
}; };
static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
{ {
struct drm_device *dev = file_priv->minor->dev; struct drm_device *dev = file_priv->minor->dev;
drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_buf_priv_t *buf_priv = buf->dev_private;
...@@ -152,7 +152,7 @@ static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) ...@@ -152,7 +152,7 @@ static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
return retcode; return retcode;
} }
static int i810_unmap_buffer(struct drm_buf * buf) static int i810_unmap_buffer(struct drm_buf *buf)
{ {
drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_buf_priv_t *buf_priv = buf->dev_private;
int retcode = 0; int retcode = 0;
...@@ -172,7 +172,7 @@ static int i810_unmap_buffer(struct drm_buf * buf) ...@@ -172,7 +172,7 @@ static int i810_unmap_buffer(struct drm_buf * buf)
return retcode; return retcode;
} }
static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d, static int i810_dma_get_buffer(struct drm_device *dev, drm_i810_dma_t *d,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_buf *buf; struct drm_buf *buf;
...@@ -202,7 +202,7 @@ static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d, ...@@ -202,7 +202,7 @@ static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
return retcode; return retcode;
} }
static int i810_dma_cleanup(struct drm_device * dev) static int i810_dma_cleanup(struct drm_device *dev)
{ {
struct drm_device_dma *dma = dev->dma; struct drm_device_dma *dma = dev->dma;
...@@ -218,9 +218,8 @@ static int i810_dma_cleanup(struct drm_device * dev) ...@@ -218,9 +218,8 @@ static int i810_dma_cleanup(struct drm_device * dev)
drm_i810_private_t *dev_priv = drm_i810_private_t *dev_priv =
(drm_i810_private_t *) dev->dev_private; (drm_i810_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) { if (dev_priv->ring.virtual_start)
drm_core_ioremapfree(&dev_priv->ring.map, dev); drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) { if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE, pci_free_consistent(dev->pdev, PAGE_SIZE,
dev_priv->hw_status_page, dev_priv->hw_status_page,
...@@ -242,7 +241,7 @@ static int i810_dma_cleanup(struct drm_device * dev) ...@@ -242,7 +241,7 @@ static int i810_dma_cleanup(struct drm_device * dev)
return 0; return 0;
} }
static int i810_wait_ring(struct drm_device * dev, int n) static int i810_wait_ring(struct drm_device *dev, int n)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_ring_buffer_t *ring = &(dev_priv->ring); drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
...@@ -271,11 +270,11 @@ static int i810_wait_ring(struct drm_device * dev, int n) ...@@ -271,11 +270,11 @@ static int i810_wait_ring(struct drm_device * dev, int n)
udelay(1); udelay(1);
} }
out_wait_ring: out_wait_ring:
return iters; return iters;
} }
static void i810_kernel_lost_context(struct drm_device * dev) static void i810_kernel_lost_context(struct drm_device *dev)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_ring_buffer_t *ring = &(dev_priv->ring); drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
...@@ -287,7 +286,7 @@ static void i810_kernel_lost_context(struct drm_device * dev) ...@@ -287,7 +286,7 @@ static void i810_kernel_lost_context(struct drm_device * dev)
ring->space += ring->Size; ring->space += ring->Size;
} }
static int i810_freelist_init(struct drm_device * dev, drm_i810_private_t * dev_priv) static int i810_freelist_init(struct drm_device *dev, drm_i810_private_t *dev_priv)
{ {
struct drm_device_dma *dma = dev->dma; struct drm_device_dma *dma = dev->dma;
int my_idx = 24; int my_idx = 24;
...@@ -322,9 +321,9 @@ static int i810_freelist_init(struct drm_device * dev, drm_i810_private_t * dev_ ...@@ -322,9 +321,9 @@ static int i810_freelist_init(struct drm_device * dev, drm_i810_private_t * dev_
return 0; return 0;
} }
static int i810_dma_initialize(struct drm_device * dev, static int i810_dma_initialize(struct drm_device *dev,
drm_i810_private_t * dev_priv, drm_i810_private_t *dev_priv,
drm_i810_init_t * init) drm_i810_init_t *init)
{ {
struct drm_map_list *r_list; struct drm_map_list *r_list;
memset(dev_priv, 0, sizeof(drm_i810_private_t)); memset(dev_priv, 0, sizeof(drm_i810_private_t));
...@@ -462,7 +461,7 @@ static int i810_dma_init(struct drm_device *dev, void *data, ...@@ -462,7 +461,7 @@ static int i810_dma_init(struct drm_device *dev, void *data,
* Use 'volatile' & local var tmp to force the emitted values to be * Use 'volatile' & local var tmp to force the emitted values to be
* identical to the verified ones. * identical to the verified ones.
*/ */
static void i810EmitContextVerified(struct drm_device * dev, static void i810EmitContextVerified(struct drm_device *dev,
volatile unsigned int *code) volatile unsigned int *code)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
...@@ -495,7 +494,7 @@ static void i810EmitContextVerified(struct drm_device * dev, ...@@ -495,7 +494,7 @@ static void i810EmitContextVerified(struct drm_device * dev,
ADVANCE_LP_RING(); ADVANCE_LP_RING();
} }
static void i810EmitTexVerified(struct drm_device * dev, volatile unsigned int *code) static void i810EmitTexVerified(struct drm_device *dev, volatile unsigned int *code)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
int i, j = 0; int i, j = 0;
...@@ -528,7 +527,7 @@ static void i810EmitTexVerified(struct drm_device * dev, volatile unsigned int * ...@@ -528,7 +527,7 @@ static void i810EmitTexVerified(struct drm_device * dev, volatile unsigned int *
/* Need to do some additional checking when setting the dest buffer. /* Need to do some additional checking when setting the dest buffer.
*/ */
static void i810EmitDestVerified(struct drm_device * dev, static void i810EmitDestVerified(struct drm_device *dev,
volatile unsigned int *code) volatile unsigned int *code)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
...@@ -563,7 +562,7 @@ static void i810EmitDestVerified(struct drm_device * dev, ...@@ -563,7 +562,7 @@ static void i810EmitDestVerified(struct drm_device * dev,
ADVANCE_LP_RING(); ADVANCE_LP_RING();
} }
static void i810EmitState(struct drm_device * dev) static void i810EmitState(struct drm_device *dev)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
...@@ -594,7 +593,7 @@ static void i810EmitState(struct drm_device * dev) ...@@ -594,7 +593,7 @@ static void i810EmitState(struct drm_device * dev)
/* need to verify /* need to verify
*/ */
static void i810_dma_dispatch_clear(struct drm_device * dev, int flags, static void i810_dma_dispatch_clear(struct drm_device *dev, int flags,
unsigned int clear_color, unsigned int clear_color,
unsigned int clear_zval) unsigned int clear_zval)
{ {
...@@ -669,7 +668,7 @@ static void i810_dma_dispatch_clear(struct drm_device * dev, int flags, ...@@ -669,7 +668,7 @@ static void i810_dma_dispatch_clear(struct drm_device * dev, int flags,
} }
} }
static void i810_dma_dispatch_swap(struct drm_device * dev) static void i810_dma_dispatch_swap(struct drm_device *dev)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
...@@ -715,8 +714,8 @@ static void i810_dma_dispatch_swap(struct drm_device * dev) ...@@ -715,8 +714,8 @@ static void i810_dma_dispatch_swap(struct drm_device * dev)
} }
} }
static void i810_dma_dispatch_vertex(struct drm_device * dev, static void i810_dma_dispatch_vertex(struct drm_device *dev,
struct drm_buf * buf, int discard, int used) struct drm_buf *buf, int discard, int used)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_buf_priv_t *buf_priv = buf->dev_private;
...@@ -795,7 +794,7 @@ static void i810_dma_dispatch_vertex(struct drm_device * dev, ...@@ -795,7 +794,7 @@ static void i810_dma_dispatch_vertex(struct drm_device * dev,
} }
} }
static void i810_dma_dispatch_flip(struct drm_device * dev) static void i810_dma_dispatch_flip(struct drm_device *dev)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
int pitch = dev_priv->pitch; int pitch = dev_priv->pitch;
...@@ -841,7 +840,7 @@ static void i810_dma_dispatch_flip(struct drm_device * dev) ...@@ -841,7 +840,7 @@ static void i810_dma_dispatch_flip(struct drm_device * dev)
} }
static void i810_dma_quiescent(struct drm_device * dev) static void i810_dma_quiescent(struct drm_device *dev)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
RING_LOCALS; RING_LOCALS;
...@@ -858,7 +857,7 @@ static void i810_dma_quiescent(struct drm_device * dev) ...@@ -858,7 +857,7 @@ static void i810_dma_quiescent(struct drm_device * dev)
i810_wait_ring(dev, dev_priv->ring.Size - 8); i810_wait_ring(dev, dev_priv->ring.Size - 8);
} }
static int i810_flush_queue(struct drm_device * dev) static int i810_flush_queue(struct drm_device *dev)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma; struct drm_device_dma *dma = dev->dma;
...@@ -891,7 +890,7 @@ static int i810_flush_queue(struct drm_device * dev) ...@@ -891,7 +890,7 @@ static int i810_flush_queue(struct drm_device * dev)
} }
/* Must be called with the lock held */ /* Must be called with the lock held */
static void i810_reclaim_buffers(struct drm_device * dev, static void i810_reclaim_buffers(struct drm_device *dev,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_device_dma *dma = dev->dma; struct drm_device_dma *dma = dev->dma;
...@@ -969,9 +968,8 @@ static int i810_clear_bufs(struct drm_device *dev, void *data, ...@@ -969,9 +968,8 @@ static int i810_clear_bufs(struct drm_device *dev, void *data,
LOCK_TEST_WITH_RETURN(dev, file_priv); LOCK_TEST_WITH_RETURN(dev, file_priv);
/* GH: Someone's doing nasty things... */ /* GH: Someone's doing nasty things... */
if (!dev->dev_private) { if (!dev->dev_private)
return -EINVAL; return -EINVAL;
}
i810_dma_dispatch_clear(dev, clear->flags, i810_dma_dispatch_clear(dev, clear->flags,
clear->clear_color, clear->clear_depth); clear->clear_color, clear->clear_depth);
...@@ -1039,7 +1037,7 @@ static int i810_docopy(struct drm_device *dev, void *data, ...@@ -1039,7 +1037,7 @@ static int i810_docopy(struct drm_device *dev, void *data,
return 0; return 0;
} }
static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf, int used, static void i810_dma_dispatch_mc(struct drm_device *dev, struct drm_buf *buf, int used,
unsigned int last_render) unsigned int last_render)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
...@@ -1053,9 +1051,8 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf, ...@@ -1053,9 +1051,8 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf,
i810_kernel_lost_context(dev); i810_kernel_lost_context(dev);
u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_HARDWARE); u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_HARDWARE);
if (u != I810_BUF_CLIENT) { if (u != I810_BUF_CLIENT)
DRM_DEBUG("MC found buffer that isn't mine!\n"); DRM_DEBUG("MC found buffer that isn't mine!\n");
}
if (used > 4 * 1024) if (used > 4 * 1024)
used = 0; used = 0;
...@@ -1160,7 +1157,7 @@ static int i810_ov0_flip(struct drm_device *dev, void *data, ...@@ -1160,7 +1157,7 @@ static int i810_ov0_flip(struct drm_device *dev, void *data,
LOCK_TEST_WITH_RETURN(dev, file_priv); LOCK_TEST_WITH_RETURN(dev, file_priv);
//Tell the overlay to update /* Tell the overlay to update */
I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000); I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000);
return 0; return 0;
...@@ -1168,7 +1165,7 @@ static int i810_ov0_flip(struct drm_device *dev, void *data, ...@@ -1168,7 +1165,7 @@ static int i810_ov0_flip(struct drm_device *dev, void *data,
/* Not sure why this isn't set all the time: /* Not sure why this isn't set all the time:
*/ */
static void i810_do_init_pageflip(struct drm_device * dev) static void i810_do_init_pageflip(struct drm_device *dev)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
...@@ -1178,7 +1175,7 @@ static void i810_do_init_pageflip(struct drm_device * dev) ...@@ -1178,7 +1175,7 @@ static void i810_do_init_pageflip(struct drm_device * dev)
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
} }
static int i810_do_cleanup_pageflip(struct drm_device * dev) static int i810_do_cleanup_pageflip(struct drm_device *dev)
{ {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
...@@ -1218,49 +1215,61 @@ int i810_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -1218,49 +1215,61 @@ int i810_driver_load(struct drm_device *dev, unsigned long flags)
return 0; return 0;
} }
void i810_driver_lastclose(struct drm_device * dev) void i810_driver_lastclose(struct drm_device *dev)
{ {
i810_dma_cleanup(dev); i810_dma_cleanup(dev);
} }
void i810_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) void i810_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
{ {
if (dev->dev_private) { if (dev->dev_private) {
drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_private_t *dev_priv = dev->dev_private;
if (dev_priv->page_flipping) { if (dev_priv->page_flipping)
i810_do_cleanup_pageflip(dev); i810_do_cleanup_pageflip(dev);
}
} }
} }
void i810_driver_reclaim_buffers_locked(struct drm_device * dev, void i810_driver_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
i810_reclaim_buffers(dev, file_priv); i810_reclaim_buffers(dev, file_priv);
} }
int i810_driver_dma_quiescent(struct drm_device * dev) int i810_driver_dma_quiescent(struct drm_device *dev)
{ {
i810_dma_quiescent(dev); i810_dma_quiescent(dev);
return 0; return 0;
} }
/*
* call the drm_ioctl under the big kernel lock because
* to lock against the i810_mmap_buffers function.
*/
long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
lock_kernel();
ret = drm_ioctl(file, cmd, arg);
unlock_kernel();
return ret;
}
struct drm_ioctl_desc i810_ioctls[] = { struct drm_ioctl_desc i810_ioctls[] = {
DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH), DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH) DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED),
}; };
int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls); int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
...@@ -1276,7 +1285,7 @@ int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls); ...@@ -1276,7 +1285,7 @@ int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
* \returns * \returns
* A value of 1 is always retured to indictate every i810 is AGP. * A value of 1 is always retured to indictate every i810 is AGP.
*/ */
int i810_driver_device_is_agp(struct drm_device * dev) int i810_driver_device_is_agp(struct drm_device *dev)
{ {
return 1; return 1;
} }
...@@ -59,7 +59,7 @@ static struct drm_driver driver = { ...@@ -59,7 +59,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_open, .open = drm_open,
.release = drm_release, .release = drm_release,
.unlocked_ioctl = drm_ioctl, .unlocked_ioctl = i810_ioctl,
.mmap = drm_mmap, .mmap = drm_mmap,
.poll = drm_poll, .poll = drm_poll,
.fasync = drm_fasync, .fasync = drm_fasync,
......
...@@ -115,56 +115,59 @@ typedef struct drm_i810_private { ...@@ -115,56 +115,59 @@ typedef struct drm_i810_private {
} drm_i810_private_t; } drm_i810_private_t;
/* i810_dma.c */ /* i810_dma.c */
extern int i810_driver_dma_quiescent(struct drm_device * dev); extern int i810_driver_dma_quiescent(struct drm_device *dev);
extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev, extern void i810_driver_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int i810_driver_load(struct drm_device *, unsigned long flags); extern int i810_driver_load(struct drm_device *, unsigned long flags);
extern void i810_driver_lastclose(struct drm_device * dev); extern void i810_driver_lastclose(struct drm_device *dev);
extern void i810_driver_preclose(struct drm_device * dev, extern void i810_driver_preclose(struct drm_device *dev,
struct drm_file *file_priv); struct drm_file *file_priv);
extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev, extern void i810_driver_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int i810_driver_device_is_agp(struct drm_device * dev); extern int i810_driver_device_is_agp(struct drm_device *dev);
extern long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
extern struct drm_ioctl_desc i810_ioctls[]; extern struct drm_ioctl_desc i810_ioctls[];
extern int i810_max_ioctl; extern int i810_max_ioctl;
#define I810_BASE(reg) ((unsigned long) \ #define I810_BASE(reg) ((unsigned long) \
dev_priv->mmio_map->handle) dev_priv->mmio_map->handle)
#define I810_ADDR(reg) (I810_BASE(reg) + reg) #define I810_ADDR(reg) (I810_BASE(reg) + reg)
#define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg) #define I810_DEREF(reg) (*(__volatile__ int *)I810_ADDR(reg))
#define I810_READ(reg) I810_DEREF(reg) #define I810_READ(reg) I810_DEREF(reg)
#define I810_WRITE(reg,val) do { I810_DEREF(reg) = val; } while (0) #define I810_WRITE(reg, val) do { I810_DEREF(reg) = val; } while (0)
#define I810_DEREF16(reg) *(__volatile__ u16 *)I810_ADDR(reg) #define I810_DEREF16(reg) (*(__volatile__ u16 *)I810_ADDR(reg))
#define I810_READ16(reg) I810_DEREF16(reg) #define I810_READ16(reg) I810_DEREF16(reg)
#define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0) #define I810_WRITE16(reg, val) do { I810_DEREF16(reg) = val; } while (0)
#define I810_VERBOSE 0 #define I810_VERBOSE 0
#define RING_LOCALS unsigned int outring, ringmask; \ #define RING_LOCALS unsigned int outring, ringmask; \
volatile char *virt; volatile char *virt;
#define BEGIN_LP_RING(n) do { \ #define BEGIN_LP_RING(n) do { \
if (I810_VERBOSE) \ if (I810_VERBOSE) \
DRM_DEBUG("BEGIN_LP_RING(%d)\n", n); \ DRM_DEBUG("BEGIN_LP_RING(%d)\n", n); \
if (dev_priv->ring.space < n*4) \ if (dev_priv->ring.space < n*4) \
i810_wait_ring(dev, n*4); \ i810_wait_ring(dev, n*4); \
dev_priv->ring.space -= n*4; \ dev_priv->ring.space -= n*4; \
outring = dev_priv->ring.tail; \ outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \ ringmask = dev_priv->ring.tail_mask; \
virt = dev_priv->ring.virtual_start; \ virt = dev_priv->ring.virtual_start; \
} while (0) } while (0)
#define ADVANCE_LP_RING() do { \ #define ADVANCE_LP_RING() do { \
if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ if (I810_VERBOSE) \
DRM_DEBUG("ADVANCE_LP_RING\n"); \
dev_priv->ring.tail = outring; \ dev_priv->ring.tail = outring; \
I810_WRITE(LP_RING + RING_TAIL, outring); \ I810_WRITE(LP_RING + RING_TAIL, outring); \
} while(0) } while (0)
#define OUT_RING(n) do { \ #define OUT_RING(n) do { \
if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ if (I810_VERBOSE) \
*(volatile unsigned int *)(virt + outring) = n; \ DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
outring += 4; \ *(volatile unsigned int *)(virt + outring) = n; \
outring &= ringmask; \ outring += 4; \
outring &= ringmask; \
} while (0) } while (0)
#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "i830_drm.h" #include "i830_drm.h"
#include "i830_drv.h" #include "i830_drv.h"
#include <linux/interrupt.h> /* For task queue support */ #include <linux/interrupt.h> /* For task queue support */
#include <linux/smp_lock.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -62,9 +63,8 @@ static struct drm_buf *i830_freelist_get(struct drm_device * dev) ...@@ -62,9 +63,8 @@ static struct drm_buf *i830_freelist_get(struct drm_device * dev)
/* In use is already a pointer */ /* In use is already a pointer */
used = cmpxchg(buf_priv->in_use, I830_BUF_FREE, used = cmpxchg(buf_priv->in_use, I830_BUF_FREE,
I830_BUF_CLIENT); I830_BUF_CLIENT);
if (used == I830_BUF_FREE) { if (used == I830_BUF_FREE)
return buf; return buf;
}
} }
return NULL; return NULL;
} }
...@@ -73,7 +73,7 @@ static struct drm_buf *i830_freelist_get(struct drm_device * dev) ...@@ -73,7 +73,7 @@ static struct drm_buf *i830_freelist_get(struct drm_device * dev)
* yet, the hardware updates in use for us once its on the ring buffer. * yet, the hardware updates in use for us once its on the ring buffer.
*/ */
static int i830_freelist_put(struct drm_device * dev, struct drm_buf * buf) static int i830_freelist_put(struct drm_device *dev, struct drm_buf *buf)
{ {
drm_i830_buf_priv_t *buf_priv = buf->dev_private; drm_i830_buf_priv_t *buf_priv = buf->dev_private;
int used; int used;
...@@ -123,7 +123,7 @@ static const struct file_operations i830_buffer_fops = { ...@@ -123,7 +123,7 @@ static const struct file_operations i830_buffer_fops = {
.fasync = drm_fasync, .fasync = drm_fasync,
}; };
static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) static int i830_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
{ {
struct drm_device *dev = file_priv->minor->dev; struct drm_device *dev = file_priv->minor->dev;
drm_i830_buf_priv_t *buf_priv = buf->dev_private; drm_i830_buf_priv_t *buf_priv = buf->dev_private;
...@@ -156,7 +156,7 @@ static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) ...@@ -156,7 +156,7 @@ static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
return retcode; return retcode;
} }
static int i830_unmap_buffer(struct drm_buf * buf) static int i830_unmap_buffer(struct drm_buf *buf)
{ {
drm_i830_buf_priv_t *buf_priv = buf->dev_private; drm_i830_buf_priv_t *buf_priv = buf->dev_private;
int retcode = 0; int retcode = 0;
...@@ -176,7 +176,7 @@ static int i830_unmap_buffer(struct drm_buf * buf) ...@@ -176,7 +176,7 @@ static int i830_unmap_buffer(struct drm_buf * buf)
return retcode; return retcode;
} }
static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d, static int i830_dma_get_buffer(struct drm_device *dev, drm_i830_dma_t *d,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_buf *buf; struct drm_buf *buf;
...@@ -206,7 +206,7 @@ static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d, ...@@ -206,7 +206,7 @@ static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
return retcode; return retcode;
} }
static int i830_dma_cleanup(struct drm_device * dev) static int i830_dma_cleanup(struct drm_device *dev)
{ {
struct drm_device_dma *dma = dev->dma; struct drm_device_dma *dma = dev->dma;
...@@ -222,9 +222,8 @@ static int i830_dma_cleanup(struct drm_device * dev) ...@@ -222,9 +222,8 @@ static int i830_dma_cleanup(struct drm_device * dev)
drm_i830_private_t *dev_priv = drm_i830_private_t *dev_priv =
(drm_i830_private_t *) dev->dev_private; (drm_i830_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) { if (dev_priv->ring.virtual_start)
drm_core_ioremapfree(&dev_priv->ring.map, dev); drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) { if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE, pci_free_consistent(dev->pdev, PAGE_SIZE,
dev_priv->hw_status_page, dev_priv->hw_status_page,
...@@ -246,7 +245,7 @@ static int i830_dma_cleanup(struct drm_device * dev) ...@@ -246,7 +245,7 @@ static int i830_dma_cleanup(struct drm_device * dev)
return 0; return 0;
} }
int i830_wait_ring(struct drm_device * dev, int n, const char *caller) int i830_wait_ring(struct drm_device *dev, int n, const char *caller)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_ring_buffer_t *ring = &(dev_priv->ring); drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
...@@ -276,11 +275,11 @@ int i830_wait_ring(struct drm_device * dev, int n, const char *caller) ...@@ -276,11 +275,11 @@ int i830_wait_ring(struct drm_device * dev, int n, const char *caller)
dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT; dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
} }
out_wait_ring: out_wait_ring:
return iters; return iters;
} }
static void i830_kernel_lost_context(struct drm_device * dev) static void i830_kernel_lost_context(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_ring_buffer_t *ring = &(dev_priv->ring); drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
...@@ -295,7 +294,7 @@ static void i830_kernel_lost_context(struct drm_device * dev) ...@@ -295,7 +294,7 @@ static void i830_kernel_lost_context(struct drm_device * dev)
dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY; dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY;
} }
static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_priv) static int i830_freelist_init(struct drm_device *dev, drm_i830_private_t *dev_priv)
{ {
struct drm_device_dma *dma = dev->dma; struct drm_device_dma *dma = dev->dma;
int my_idx = 36; int my_idx = 36;
...@@ -329,9 +328,9 @@ static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_ ...@@ -329,9 +328,9 @@ static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_
return 0; return 0;
} }
static int i830_dma_initialize(struct drm_device * dev, static int i830_dma_initialize(struct drm_device *dev,
drm_i830_private_t * dev_priv, drm_i830_private_t *dev_priv,
drm_i830_init_t * init) drm_i830_init_t *init)
{ {
struct drm_map_list *r_list; struct drm_map_list *r_list;
...@@ -482,7 +481,7 @@ static int i830_dma_init(struct drm_device *dev, void *data, ...@@ -482,7 +481,7 @@ static int i830_dma_init(struct drm_device *dev, void *data,
/* Most efficient way to verify state for the i830 is as it is /* Most efficient way to verify state for the i830 is as it is
* emitted. Non-conformant state is silently dropped. * emitted. Non-conformant state is silently dropped.
*/ */
static void i830EmitContextVerified(struct drm_device * dev, unsigned int *code) static void i830EmitContextVerified(struct drm_device *dev, unsigned int *code)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
int i, j = 0; int i, j = 0;
...@@ -527,7 +526,7 @@ static void i830EmitContextVerified(struct drm_device * dev, unsigned int *code) ...@@ -527,7 +526,7 @@ static void i830EmitContextVerified(struct drm_device * dev, unsigned int *code)
ADVANCE_LP_RING(); ADVANCE_LP_RING();
} }
static void i830EmitTexVerified(struct drm_device * dev, unsigned int *code) static void i830EmitTexVerified(struct drm_device *dev, unsigned int *code)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
int i, j = 0; int i, j = 0;
...@@ -561,7 +560,7 @@ static void i830EmitTexVerified(struct drm_device * dev, unsigned int *code) ...@@ -561,7 +560,7 @@ static void i830EmitTexVerified(struct drm_device * dev, unsigned int *code)
printk("rejected packet %x\n", code[0]); printk("rejected packet %x\n", code[0]);
} }
static void i830EmitTexBlendVerified(struct drm_device * dev, static void i830EmitTexBlendVerified(struct drm_device *dev,
unsigned int *code, unsigned int num) unsigned int *code, unsigned int num)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
...@@ -586,7 +585,7 @@ static void i830EmitTexBlendVerified(struct drm_device * dev, ...@@ -586,7 +585,7 @@ static void i830EmitTexBlendVerified(struct drm_device * dev,
ADVANCE_LP_RING(); ADVANCE_LP_RING();
} }
static void i830EmitTexPalette(struct drm_device * dev, static void i830EmitTexPalette(struct drm_device *dev,
unsigned int *palette, int number, int is_shared) unsigned int *palette, int number, int is_shared)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
...@@ -603,9 +602,8 @@ static void i830EmitTexPalette(struct drm_device * dev, ...@@ -603,9 +602,8 @@ static void i830EmitTexPalette(struct drm_device * dev,
} else { } else {
OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number)); OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number));
} }
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++)
OUT_RING(palette[i]); OUT_RING(palette[i]);
}
OUT_RING(0); OUT_RING(0);
/* KW: WHERE IS THE ADVANCE_LP_RING? This is effectively a noop! /* KW: WHERE IS THE ADVANCE_LP_RING? This is effectively a noop!
*/ */
...@@ -613,7 +611,7 @@ static void i830EmitTexPalette(struct drm_device * dev, ...@@ -613,7 +611,7 @@ static void i830EmitTexPalette(struct drm_device * dev,
/* Need to do some additional checking when setting the dest buffer. /* Need to do some additional checking when setting the dest buffer.
*/ */
static void i830EmitDestVerified(struct drm_device * dev, unsigned int *code) static void i830EmitDestVerified(struct drm_device *dev, unsigned int *code)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
unsigned int tmp; unsigned int tmp;
...@@ -674,7 +672,7 @@ static void i830EmitDestVerified(struct drm_device * dev, unsigned int *code) ...@@ -674,7 +672,7 @@ static void i830EmitDestVerified(struct drm_device * dev, unsigned int *code)
ADVANCE_LP_RING(); ADVANCE_LP_RING();
} }
static void i830EmitStippleVerified(struct drm_device * dev, unsigned int *code) static void i830EmitStippleVerified(struct drm_device *dev, unsigned int *code)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS; RING_LOCALS;
...@@ -685,7 +683,7 @@ static void i830EmitStippleVerified(struct drm_device * dev, unsigned int *code) ...@@ -685,7 +683,7 @@ static void i830EmitStippleVerified(struct drm_device * dev, unsigned int *code)
ADVANCE_LP_RING(); ADVANCE_LP_RING();
} }
static void i830EmitState(struct drm_device * dev) static void i830EmitState(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
...@@ -788,7 +786,7 @@ static void i830EmitState(struct drm_device * dev) ...@@ -788,7 +786,7 @@ static void i830EmitState(struct drm_device * dev)
* Performance monitoring functions * Performance monitoring functions
*/ */
static void i830_fill_box(struct drm_device * dev, static void i830_fill_box(struct drm_device *dev,
int x, int y, int w, int h, int r, int g, int b) int x, int y, int w, int h, int r, int g, int b)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
...@@ -816,17 +814,16 @@ static void i830_fill_box(struct drm_device * dev, ...@@ -816,17 +814,16 @@ static void i830_fill_box(struct drm_device * dev,
OUT_RING((y << 16) | x); OUT_RING((y << 16) | x);
OUT_RING(((y + h) << 16) | (x + w)); OUT_RING(((y + h) << 16) | (x + w));
if (dev_priv->current_page == 1) { if (dev_priv->current_page == 1)
OUT_RING(dev_priv->front_offset); OUT_RING(dev_priv->front_offset);
} else { else
OUT_RING(dev_priv->back_offset); OUT_RING(dev_priv->back_offset);
}
OUT_RING(color); OUT_RING(color);
ADVANCE_LP_RING(); ADVANCE_LP_RING();
} }
static void i830_cp_performance_boxes(struct drm_device * dev) static void i830_cp_performance_boxes(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
...@@ -871,7 +868,7 @@ static void i830_cp_performance_boxes(struct drm_device * dev) ...@@ -871,7 +868,7 @@ static void i830_cp_performance_boxes(struct drm_device * dev)
dev_priv->sarea_priv->perf_boxes = 0; dev_priv->sarea_priv->perf_boxes = 0;
} }
static void i830_dma_dispatch_clear(struct drm_device * dev, int flags, static void i830_dma_dispatch_clear(struct drm_device *dev, int flags,
unsigned int clear_color, unsigned int clear_color,
unsigned int clear_zval, unsigned int clear_zval,
unsigned int clear_depthmask) unsigned int clear_depthmask)
...@@ -966,7 +963,7 @@ static void i830_dma_dispatch_clear(struct drm_device * dev, int flags, ...@@ -966,7 +963,7 @@ static void i830_dma_dispatch_clear(struct drm_device * dev, int flags,
} }
} }
static void i830_dma_dispatch_swap(struct drm_device * dev) static void i830_dma_dispatch_swap(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
...@@ -1036,7 +1033,7 @@ static void i830_dma_dispatch_swap(struct drm_device * dev) ...@@ -1036,7 +1033,7 @@ static void i830_dma_dispatch_swap(struct drm_device * dev)
} }
} }
static void i830_dma_dispatch_flip(struct drm_device * dev) static void i830_dma_dispatch_flip(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS; RING_LOCALS;
...@@ -1079,8 +1076,8 @@ static void i830_dma_dispatch_flip(struct drm_device * dev) ...@@ -1079,8 +1076,8 @@ static void i830_dma_dispatch_flip(struct drm_device * dev)
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
} }
static void i830_dma_dispatch_vertex(struct drm_device * dev, static void i830_dma_dispatch_vertex(struct drm_device *dev,
struct drm_buf * buf, int discard, int used) struct drm_buf *buf, int discard, int used)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_buf_priv_t *buf_priv = buf->dev_private; drm_i830_buf_priv_t *buf_priv = buf->dev_private;
...@@ -1100,9 +1097,8 @@ static void i830_dma_dispatch_vertex(struct drm_device * dev, ...@@ -1100,9 +1097,8 @@ static void i830_dma_dispatch_vertex(struct drm_device * dev,
if (discard) { if (discard) {
u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
I830_BUF_HARDWARE); I830_BUF_HARDWARE);
if (u != I830_BUF_CLIENT) { if (u != I830_BUF_CLIENT)
DRM_DEBUG("xxxx 2\n"); DRM_DEBUG("xxxx 2\n");
}
} }
if (used > 4 * 1023) if (used > 4 * 1023)
...@@ -1191,7 +1187,7 @@ static void i830_dma_dispatch_vertex(struct drm_device * dev, ...@@ -1191,7 +1187,7 @@ static void i830_dma_dispatch_vertex(struct drm_device * dev,
} }
} }
static void i830_dma_quiescent(struct drm_device * dev) static void i830_dma_quiescent(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS; RING_LOCALS;
...@@ -1208,7 +1204,7 @@ static void i830_dma_quiescent(struct drm_device * dev) ...@@ -1208,7 +1204,7 @@ static void i830_dma_quiescent(struct drm_device * dev)
i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__); i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
} }
static int i830_flush_queue(struct drm_device * dev) static int i830_flush_queue(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma; struct drm_device_dma *dma = dev->dma;
...@@ -1241,7 +1237,7 @@ static int i830_flush_queue(struct drm_device * dev) ...@@ -1241,7 +1237,7 @@ static int i830_flush_queue(struct drm_device * dev)
} }
/* Must be called with the lock held */ /* Must be called with the lock held */
static void i830_reclaim_buffers(struct drm_device * dev, struct drm_file *file_priv) static void i830_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
{ {
struct drm_device_dma *dma = dev->dma; struct drm_device_dma *dma = dev->dma;
int i; int i;
...@@ -1316,9 +1312,8 @@ static int i830_clear_bufs(struct drm_device *dev, void *data, ...@@ -1316,9 +1312,8 @@ static int i830_clear_bufs(struct drm_device *dev, void *data,
LOCK_TEST_WITH_RETURN(dev, file_priv); LOCK_TEST_WITH_RETURN(dev, file_priv);
/* GH: Someone's doing nasty things... */ /* GH: Someone's doing nasty things... */
if (!dev->dev_private) { if (!dev->dev_private)
return -EINVAL; return -EINVAL;
}
i830_dma_dispatch_clear(dev, clear->flags, i830_dma_dispatch_clear(dev, clear->flags,
clear->clear_color, clear->clear_color,
...@@ -1339,7 +1334,7 @@ static int i830_swap_bufs(struct drm_device *dev, void *data, ...@@ -1339,7 +1334,7 @@ static int i830_swap_bufs(struct drm_device *dev, void *data,
/* Not sure why this isn't set all the time: /* Not sure why this isn't set all the time:
*/ */
static void i830_do_init_pageflip(struct drm_device * dev) static void i830_do_init_pageflip(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
...@@ -1349,7 +1344,7 @@ static void i830_do_init_pageflip(struct drm_device * dev) ...@@ -1349,7 +1344,7 @@ static void i830_do_init_pageflip(struct drm_device * dev)
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
} }
static int i830_do_cleanup_pageflip(struct drm_device * dev) static int i830_do_cleanup_pageflip(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
...@@ -1490,47 +1485,59 @@ int i830_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -1490,47 +1485,59 @@ int i830_driver_load(struct drm_device *dev, unsigned long flags)
return 0; return 0;
} }
void i830_driver_lastclose(struct drm_device * dev) void i830_driver_lastclose(struct drm_device *dev)
{ {
i830_dma_cleanup(dev); i830_dma_cleanup(dev);
} }
void i830_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) void i830_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
{ {
if (dev->dev_private) { if (dev->dev_private) {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
if (dev_priv->page_flipping) { if (dev_priv->page_flipping)
i830_do_cleanup_pageflip(dev); i830_do_cleanup_pageflip(dev);
}
} }
} }
void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct drm_file *file_priv) void i830_driver_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv)
{ {
i830_reclaim_buffers(dev, file_priv); i830_reclaim_buffers(dev, file_priv);
} }
int i830_driver_dma_quiescent(struct drm_device * dev) int i830_driver_dma_quiescent(struct drm_device *dev)
{ {
i830_dma_quiescent(dev); i830_dma_quiescent(dev);
return 0; return 0;
} }
/*
* call the drm_ioctl under the big kernel lock because
* to lock against the i830_mmap_buffers function.
*/
long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
lock_kernel();
ret = drm_ioctl(file, cmd, arg);
unlock_kernel();
return ret;
}
struct drm_ioctl_desc i830_ioctls[] = { struct drm_ioctl_desc i830_ioctls[] = {
DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH), DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH) DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH|DRM_UNLOCKED),
}; };
int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls); int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
...@@ -1546,7 +1553,7 @@ int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls); ...@@ -1546,7 +1553,7 @@ int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
* \returns * \returns
* A value of 1 is always retured to indictate every i8xx is AGP. * A value of 1 is always retured to indictate every i8xx is AGP.
*/ */
int i830_driver_device_is_agp(struct drm_device * dev) int i830_driver_device_is_agp(struct drm_device *dev)
{ {
return 1; return 1;
} }
...@@ -70,7 +70,7 @@ static struct drm_driver driver = { ...@@ -70,7 +70,7 @@ static struct drm_driver driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_open, .open = drm_open,
.release = drm_release, .release = drm_release,
.unlocked_ioctl = drm_ioctl, .unlocked_ioctl = i830_ioctl,
.mmap = drm_mmap, .mmap = drm_mmap,
.poll = drm_poll, .poll = drm_poll,
.fasync = drm_fasync, .fasync = drm_fasync,
......
...@@ -122,6 +122,7 @@ typedef struct drm_i830_private { ...@@ -122,6 +122,7 @@ typedef struct drm_i830_private {
} drm_i830_private_t; } drm_i830_private_t;
long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
extern struct drm_ioctl_desc i830_ioctls[]; extern struct drm_ioctl_desc i830_ioctls[];
extern int i830_max_ioctl; extern int i830_max_ioctl;
...@@ -132,33 +133,33 @@ extern int i830_irq_wait(struct drm_device *dev, void *data, ...@@ -132,33 +133,33 @@ extern int i830_irq_wait(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS); extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS);
extern void i830_driver_irq_preinstall(struct drm_device * dev); extern void i830_driver_irq_preinstall(struct drm_device *dev);
extern void i830_driver_irq_postinstall(struct drm_device * dev); extern void i830_driver_irq_postinstall(struct drm_device *dev);
extern void i830_driver_irq_uninstall(struct drm_device * dev); extern void i830_driver_irq_uninstall(struct drm_device *dev);
extern int i830_driver_load(struct drm_device *, unsigned long flags); extern int i830_driver_load(struct drm_device *, unsigned long flags);
extern void i830_driver_preclose(struct drm_device * dev, extern void i830_driver_preclose(struct drm_device *dev,
struct drm_file *file_priv); struct drm_file *file_priv);
extern void i830_driver_lastclose(struct drm_device * dev); extern void i830_driver_lastclose(struct drm_device *dev);
extern void i830_driver_reclaim_buffers_locked(struct drm_device * dev, extern void i830_driver_reclaim_buffers_locked(struct drm_device *dev,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int i830_driver_dma_quiescent(struct drm_device * dev); extern int i830_driver_dma_quiescent(struct drm_device *dev);
extern int i830_driver_device_is_agp(struct drm_device * dev); extern int i830_driver_device_is_agp(struct drm_device *dev);
#define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg) #define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg)
#define I830_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val) #define I830_WRITE(reg, val) DRM_WRITE32(dev_priv->mmio_map, reg, val)
#define I830_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg) #define I830_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg)
#define I830_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, reg, val) #define I830_WRITE16(reg, val) DRM_WRITE16(dev_priv->mmio_map, reg, val)
#define I830_VERBOSE 0 #define I830_VERBOSE 0
#define RING_LOCALS unsigned int outring, ringmask, outcount; \ #define RING_LOCALS unsigned int outring, ringmask, outcount; \
volatile char *virt; volatile char *virt;
#define BEGIN_LP_RING(n) do { \ #define BEGIN_LP_RING(n) do { \
if (I830_VERBOSE) \ if (I830_VERBOSE) \
printk("BEGIN_LP_RING(%d)\n", (n)); \ printk("BEGIN_LP_RING(%d)\n", (n)); \
if (dev_priv->ring.space < n*4) \ if (dev_priv->ring.space < n*4) \
i830_wait_ring(dev, n*4, __func__); \ i830_wait_ring(dev, n*4, __func__); \
outcount = 0; \ outcount = 0; \
outring = dev_priv->ring.tail; \ outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \ ringmask = dev_priv->ring.tail_mask; \
...@@ -166,21 +167,23 @@ extern int i830_driver_device_is_agp(struct drm_device * dev); ...@@ -166,21 +167,23 @@ extern int i830_driver_device_is_agp(struct drm_device * dev);
} while (0) } while (0)
#define OUT_RING(n) do { \ #define OUT_RING(n) do { \
if (I830_VERBOSE) printk(" OUT_RING %x\n", (int)(n)); \ if (I830_VERBOSE) \
printk(" OUT_RING %x\n", (int)(n)); \
*(volatile unsigned int *)(virt + outring) = n; \ *(volatile unsigned int *)(virt + outring) = n; \
outcount++; \ outcount++; \
outring += 4; \ outring += 4; \
outring &= ringmask; \ outring &= ringmask; \
} while (0) } while (0)
#define ADVANCE_LP_RING() do { \ #define ADVANCE_LP_RING() do { \
if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring); \ if (I830_VERBOSE) \
dev_priv->ring.tail = outring; \ printk("ADVANCE_LP_RING %x\n", outring); \
dev_priv->ring.space -= outcount * 4; \ dev_priv->ring.tail = outring; \
I830_WRITE(LP_RING + RING_TAIL, outring); \ dev_priv->ring.space -= outcount * 4; \
} while(0) I830_WRITE(LP_RING + RING_TAIL, outring); \
} while (0)
extern int i830_wait_ring(struct drm_device * dev, int n, const char *caller); extern int i830_wait_ring(struct drm_device *dev, int n, const char *caller);
#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) #define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
......
...@@ -53,7 +53,7 @@ irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -53,7 +53,7 @@ irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int i830_emit_irq(struct drm_device * dev) static int i830_emit_irq(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS; RING_LOCALS;
...@@ -70,7 +70,7 @@ static int i830_emit_irq(struct drm_device * dev) ...@@ -70,7 +70,7 @@ static int i830_emit_irq(struct drm_device * dev)
return atomic_read(&dev_priv->irq_emitted); return atomic_read(&dev_priv->irq_emitted);
} }
static int i830_wait_irq(struct drm_device * dev, int irq_nr) static int i830_wait_irq(struct drm_device *dev, int irq_nr)
{ {
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
DECLARE_WAITQUEUE(entry, current); DECLARE_WAITQUEUE(entry, current);
...@@ -156,7 +156,7 @@ int i830_irq_wait(struct drm_device *dev, void *data, ...@@ -156,7 +156,7 @@ int i830_irq_wait(struct drm_device *dev, void *data,
/* drm_dma.h hooks /* drm_dma.h hooks
*/ */
void i830_driver_irq_preinstall(struct drm_device * dev) void i830_driver_irq_preinstall(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
...@@ -168,14 +168,14 @@ void i830_driver_irq_preinstall(struct drm_device * dev) ...@@ -168,14 +168,14 @@ void i830_driver_irq_preinstall(struct drm_device * dev)
init_waitqueue_head(&dev_priv->irq_queue); init_waitqueue_head(&dev_priv->irq_queue);
} }
void i830_driver_irq_postinstall(struct drm_device * dev) void i830_driver_irq_postinstall(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
I830_WRITE16(I830REG_INT_ENABLE_R, 0x2); I830_WRITE16(I830REG_INT_ENABLE_R, 0x2);
} }
void i830_driver_irq_uninstall(struct drm_device * dev) void i830_driver_irq_uninstall(struct drm_device *dev)
{ {
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
if (!dev_priv) if (!dev_priv)
......
...@@ -34,12 +34,15 @@ ...@@ -34,12 +34,15 @@
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
#include "i915_trace.h" #include "i915_trace.h"
#include <linux/pci.h>
#include <linux/vgaarb.h> #include <linux/vgaarb.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/pnp.h> #include <linux/pnp.h>
#include <linux/vga_switcheroo.h> #include <linux/vga_switcheroo.h>
#include <linux/slab.h> #include <linux/slab.h>
extern int intel_max_stolen; /* from AGP driver */
/** /**
* Sets up the hardware status page for devices that need a physical address * Sets up the hardware status page for devices that need a physical address
* in the register. * in the register.
...@@ -1256,7 +1259,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) ...@@ -1256,7 +1259,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
drm_mm_put_block(compressed_fb); drm_mm_put_block(compressed_fb);
} }
if (!IS_GM45(dev)) { if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096, compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
4096, 0); 4096, 0);
if (!compressed_llb) { if (!compressed_llb) {
...@@ -1282,8 +1285,9 @@ static void i915_setup_compression(struct drm_device *dev, int size) ...@@ -1282,8 +1285,9 @@ static void i915_setup_compression(struct drm_device *dev, int size)
intel_disable_fbc(dev); intel_disable_fbc(dev);
dev_priv->compressed_fb = compressed_fb; dev_priv->compressed_fb = compressed_fb;
if (IS_IRONLAKE_M(dev))
if (IS_GM45(dev)) { I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
else if (IS_GM45(dev)) {
I915_WRITE(DPFC_CB_BASE, compressed_fb->start); I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
} else { } else {
I915_WRITE(FBC_CFB_BASE, cfb_base); I915_WRITE(FBC_CFB_BASE, cfb_base);
...@@ -1291,7 +1295,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) ...@@ -1291,7 +1295,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
dev_priv->compressed_llb = compressed_llb; dev_priv->compressed_llb = compressed_llb;
} }
DRM_DEBUG("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base, DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
ll_base, size >> 20); ll_base, size >> 20);
} }
...@@ -1354,7 +1358,7 @@ static int i915_load_modeset_init(struct drm_device *dev, ...@@ -1354,7 +1358,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
int fb_bar = IS_I9XX(dev) ? 2 : 0; int fb_bar = IS_I9XX(dev) ? 2 : 0;
int ret = 0; int ret = 0;
dev->mode_config.fb_base = drm_get_resource_start(dev, fb_bar) & dev->mode_config.fb_base = pci_resource_start(dev->pdev, fb_bar) &
0xff000000; 0xff000000;
/* Basic memrange allocator for stolen space (aka vram) */ /* Basic memrange allocator for stolen space (aka vram) */
...@@ -2063,8 +2067,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -2063,8 +2067,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
/* Add register map (needed for suspend/resume) */ /* Add register map (needed for suspend/resume) */
mmio_bar = IS_I9XX(dev) ? 0 : 1; mmio_bar = IS_I9XX(dev) ? 0 : 1;
base = drm_get_resource_start(dev, mmio_bar); base = pci_resource_start(dev->pdev, mmio_bar);
size = drm_get_resource_len(dev, mmio_bar); size = pci_resource_len(dev->pdev, mmio_bar);
if (i915_get_bridge_dev(dev)) { if (i915_get_bridge_dev(dev)) {
ret = -EIO; ret = -EIO;
...@@ -2104,6 +2108,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -2104,6 +2108,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (ret) if (ret)
goto out_iomapfree; goto out_iomapfree;
if (prealloc_size > intel_max_stolen) {
DRM_INFO("detected %dM stolen memory, trimming to %dM\n",
prealloc_size >> 20, intel_max_stolen >> 20);
prealloc_size = intel_max_stolen;
}
dev_priv->wq = create_singlethread_workqueue("i915"); dev_priv->wq = create_singlethread_workqueue("i915");
if (dev_priv->wq == NULL) { if (dev_priv->wq == NULL) {
DRM_ERROR("Failed to create our workqueue.\n"); DRM_ERROR("Failed to create our workqueue.\n");
......
...@@ -93,11 +93,11 @@ static const struct intel_device_info intel_i945gm_info = { ...@@ -93,11 +93,11 @@ static const struct intel_device_info intel_i945gm_info = {
}; };
static const struct intel_device_info intel_i965g_info = { static const struct intel_device_info intel_i965g_info = {
.is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1,
}; };
static const struct intel_device_info intel_i965gm_info = { static const struct intel_device_info intel_i965gm_info = {
.is_i965g = 1, .is_mobile = 1, .is_i965gm = 1, .is_i9xx = 1, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1,
.is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1,
.has_hotplug = 1, .has_hotplug = 1,
}; };
...@@ -114,7 +114,7 @@ static const struct intel_device_info intel_g45_info = { ...@@ -114,7 +114,7 @@ static const struct intel_device_info intel_g45_info = {
}; };
static const struct intel_device_info intel_gm45_info = { static const struct intel_device_info intel_gm45_info = {
.is_i965g = 1, .is_mobile = 1, .is_g4x = 1, .is_i9xx = 1, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1,
.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
.has_pipe_cxsr = 1, .has_pipe_cxsr = 1,
.has_hotplug = 1, .has_hotplug = 1,
...@@ -134,7 +134,7 @@ static const struct intel_device_info intel_ironlake_d_info = { ...@@ -134,7 +134,7 @@ static const struct intel_device_info intel_ironlake_d_info = {
static const struct intel_device_info intel_ironlake_m_info = { static const struct intel_device_info intel_ironlake_m_info = {
.is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1,
.need_gfx_hws = 1, .has_rc6 = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
.has_hotplug = 1, .has_hotplug = 1,
}; };
...@@ -148,33 +148,33 @@ static const struct intel_device_info intel_sandybridge_m_info = { ...@@ -148,33 +148,33 @@ static const struct intel_device_info intel_sandybridge_m_info = {
.has_hotplug = 1, .is_gen6 = 1, .has_hotplug = 1, .is_gen6 = 1,
}; };
static const struct pci_device_id pciidlist[] = { static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_VGA_DEVICE(0x3577, &intel_i830_info), INTEL_VGA_DEVICE(0x3577, &intel_i830_info), /* I830_M */
INTEL_VGA_DEVICE(0x2562, &intel_845g_info), INTEL_VGA_DEVICE(0x2562, &intel_845g_info), /* 845_G */
INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), /* I855_GM */
INTEL_VGA_DEVICE(0x358e, &intel_i85x_info), INTEL_VGA_DEVICE(0x358e, &intel_i85x_info),
INTEL_VGA_DEVICE(0x2572, &intel_i865g_info), INTEL_VGA_DEVICE(0x2572, &intel_i865g_info), /* I865_G */
INTEL_VGA_DEVICE(0x2582, &intel_i915g_info), INTEL_VGA_DEVICE(0x2582, &intel_i915g_info), /* I915_G */
INTEL_VGA_DEVICE(0x258a, &intel_i915g_info), INTEL_VGA_DEVICE(0x258a, &intel_i915g_info), /* E7221_G */
INTEL_VGA_DEVICE(0x2592, &intel_i915gm_info), INTEL_VGA_DEVICE(0x2592, &intel_i915gm_info), /* I915_GM */
INTEL_VGA_DEVICE(0x2772, &intel_i945g_info), INTEL_VGA_DEVICE(0x2772, &intel_i945g_info), /* I945_G */
INTEL_VGA_DEVICE(0x27a2, &intel_i945gm_info), INTEL_VGA_DEVICE(0x27a2, &intel_i945gm_info), /* I945_GM */
INTEL_VGA_DEVICE(0x27ae, &intel_i945gm_info), INTEL_VGA_DEVICE(0x27ae, &intel_i945gm_info), /* I945_GME */
INTEL_VGA_DEVICE(0x2972, &intel_i965g_info), INTEL_VGA_DEVICE(0x2972, &intel_i965g_info), /* I946_GZ */
INTEL_VGA_DEVICE(0x2982, &intel_i965g_info), INTEL_VGA_DEVICE(0x2982, &intel_i965g_info), /* G35_G */
INTEL_VGA_DEVICE(0x2992, &intel_i965g_info), INTEL_VGA_DEVICE(0x2992, &intel_i965g_info), /* I965_Q */
INTEL_VGA_DEVICE(0x29a2, &intel_i965g_info), INTEL_VGA_DEVICE(0x29a2, &intel_i965g_info), /* I965_G */
INTEL_VGA_DEVICE(0x29b2, &intel_g33_info), INTEL_VGA_DEVICE(0x29b2, &intel_g33_info), /* Q35_G */
INTEL_VGA_DEVICE(0x29c2, &intel_g33_info), INTEL_VGA_DEVICE(0x29c2, &intel_g33_info), /* G33_G */
INTEL_VGA_DEVICE(0x29d2, &intel_g33_info), INTEL_VGA_DEVICE(0x29d2, &intel_g33_info), /* Q33_G */
INTEL_VGA_DEVICE(0x2a02, &intel_i965gm_info), INTEL_VGA_DEVICE(0x2a02, &intel_i965gm_info), /* I965_GM */
INTEL_VGA_DEVICE(0x2a12, &intel_i965gm_info), INTEL_VGA_DEVICE(0x2a12, &intel_i965gm_info), /* I965_GME */
INTEL_VGA_DEVICE(0x2a42, &intel_gm45_info), INTEL_VGA_DEVICE(0x2a42, &intel_gm45_info), /* GM45_G */
INTEL_VGA_DEVICE(0x2e02, &intel_g45_info), INTEL_VGA_DEVICE(0x2e02, &intel_g45_info), /* IGD_E_G */
INTEL_VGA_DEVICE(0x2e12, &intel_g45_info), INTEL_VGA_DEVICE(0x2e12, &intel_g45_info), /* Q45_G */
INTEL_VGA_DEVICE(0x2e22, &intel_g45_info), INTEL_VGA_DEVICE(0x2e22, &intel_g45_info), /* G45_G */
INTEL_VGA_DEVICE(0x2e32, &intel_g45_info), INTEL_VGA_DEVICE(0x2e32, &intel_g45_info), /* G41_G */
INTEL_VGA_DEVICE(0x2e42, &intel_g45_info), INTEL_VGA_DEVICE(0x2e42, &intel_g45_info), /* B43_G */
INTEL_VGA_DEVICE(0xa001, &intel_pineview_info), INTEL_VGA_DEVICE(0xa001, &intel_pineview_info),
INTEL_VGA_DEVICE(0xa011, &intel_pineview_info), INTEL_VGA_DEVICE(0xa011, &intel_pineview_info),
INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info), INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info),
...@@ -340,7 +340,7 @@ int i965_reset(struct drm_device *dev, u8 flags) ...@@ -340,7 +340,7 @@ int i965_reset(struct drm_device *dev, u8 flags)
/* /*
* Clear request list * Clear request list
*/ */
i915_gem_retire_requests(dev, &dev_priv->render_ring); i915_gem_retire_requests(dev);
if (need_display) if (need_display)
i915_save_display(dev); i915_save_display(dev);
...@@ -413,7 +413,7 @@ int i965_reset(struct drm_device *dev, u8 flags) ...@@ -413,7 +413,7 @@ int i965_reset(struct drm_device *dev, u8 flags)
static int __devinit static int __devinit
i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
return drm_get_dev(pdev, ent, &driver); return drm_get_pci_dev(pdev, ent, &driver);
} }
static void static void
...@@ -482,7 +482,7 @@ static int i915_pm_poweroff(struct device *dev) ...@@ -482,7 +482,7 @@ static int i915_pm_poweroff(struct device *dev)
return i915_drm_freeze(drm_dev); return i915_drm_freeze(drm_dev);
} }
const struct dev_pm_ops i915_pm_ops = { static const struct dev_pm_ops i915_pm_ops = {
.suspend = i915_pm_suspend, .suspend = i915_pm_suspend,
.resume = i915_pm_resume, .resume = i915_pm_resume,
.freeze = i915_pm_freeze, .freeze = i915_pm_freeze,
......
...@@ -176,7 +176,8 @@ struct drm_i915_display_funcs { ...@@ -176,7 +176,8 @@ struct drm_i915_display_funcs {
int (*get_display_clock_speed)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev);
int (*get_fifo_size)(struct drm_device *dev, int plane); int (*get_fifo_size)(struct drm_device *dev, int plane);
void (*update_wm)(struct drm_device *dev, int planea_clock, void (*update_wm)(struct drm_device *dev, int planea_clock,
int planeb_clock, int sr_hdisplay, int pixel_size); int planeb_clock, int sr_hdisplay, int sr_htotal,
int pixel_size);
/* clock updates for mode set */ /* clock updates for mode set */
/* cursor updates */ /* cursor updates */
/* render clock increase/decrease */ /* render clock increase/decrease */
...@@ -200,6 +201,8 @@ struct intel_device_info { ...@@ -200,6 +201,8 @@ struct intel_device_info {
u8 need_gfx_hws : 1; u8 need_gfx_hws : 1;
u8 is_g4x : 1; u8 is_g4x : 1;
u8 is_pineview : 1; u8 is_pineview : 1;
u8 is_broadwater : 1;
u8 is_crestline : 1;
u8 is_ironlake : 1; u8 is_ironlake : 1;
u8 is_gen6 : 1; u8 is_gen6 : 1;
u8 has_fbc : 1; u8 has_fbc : 1;
...@@ -288,6 +291,8 @@ typedef struct drm_i915_private { ...@@ -288,6 +291,8 @@ typedef struct drm_i915_private {
struct timer_list hangcheck_timer; struct timer_list hangcheck_timer;
int hangcheck_count; int hangcheck_count;
uint32_t last_acthd; uint32_t last_acthd;
uint32_t last_instdone;
uint32_t last_instdone1;
struct drm_mm vram; struct drm_mm vram;
...@@ -546,6 +551,14 @@ typedef struct drm_i915_private { ...@@ -546,6 +551,14 @@ typedef struct drm_i915_private {
/** LRU list of objects with fence regs on them. */ /** LRU list of objects with fence regs on them. */
struct list_head fence_list; struct list_head fence_list;
/**
* List of objects currently pending being freed.
*
* These objects are no longer in use, but due to a signal
* we were prevented from freeing them at the appointed time.
*/
struct list_head deferred_free_list;
/** /**
* We leave the user IRQ off as much as possible, * We leave the user IRQ off as much as possible,
* but this means that requests will finish and never * but this means that requests will finish and never
...@@ -677,7 +690,7 @@ struct drm_i915_gem_object { ...@@ -677,7 +690,7 @@ struct drm_i915_gem_object {
* *
* Size: 4 bits for 16 fences + sign (for FENCE_REG_NONE) * Size: 4 bits for 16 fences + sign (for FENCE_REG_NONE)
*/ */
int fence_reg : 5; signed int fence_reg : 5;
/** /**
* Used for checking the object doesn't appear more than once * Used for checking the object doesn't appear more than once
...@@ -713,7 +726,7 @@ struct drm_i915_gem_object { ...@@ -713,7 +726,7 @@ struct drm_i915_gem_object {
* *
* In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
* bits with absolutely no headroom. So use 4 bits. */ * bits with absolutely no headroom. So use 4 bits. */
int pin_count : 4; unsigned int pin_count : 4;
#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf #define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
/** AGP memory structure for our GTT binding. */ /** AGP memory structure for our GTT binding. */
...@@ -743,7 +756,7 @@ struct drm_i915_gem_object { ...@@ -743,7 +756,7 @@ struct drm_i915_gem_object {
uint32_t stride; uint32_t stride;
/** Record of address bit 17 of each page at last unbind. */ /** Record of address bit 17 of each page at last unbind. */
long *bit_17; unsigned long *bit_17;
/** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */ /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
uint32_t agp_type; uint32_t agp_type;
...@@ -955,8 +968,7 @@ uint32_t i915_get_gem_seqno(struct drm_device *dev, ...@@ -955,8 +968,7 @@ uint32_t i915_get_gem_seqno(struct drm_device *dev,
bool i915_seqno_passed(uint32_t seq1, uint32_t seq2); bool i915_seqno_passed(uint32_t seq1, uint32_t seq2);
int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
void i915_gem_retire_requests(struct drm_device *dev, void i915_gem_retire_requests(struct drm_device *dev);
struct intel_ring_buffer *ring);
void i915_gem_retire_work_handler(struct work_struct *work); void i915_gem_retire_work_handler(struct work_struct *work);
void i915_gem_clflush_object(struct drm_gem_object *obj); void i915_gem_clflush_object(struct drm_gem_object *obj);
int i915_gem_object_set_domain(struct drm_gem_object *obj, int i915_gem_object_set_domain(struct drm_gem_object *obj,
...@@ -986,7 +998,7 @@ void i915_gem_free_all_phys_object(struct drm_device *dev); ...@@ -986,7 +998,7 @@ void i915_gem_free_all_phys_object(struct drm_device *dev);
int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
void i915_gem_object_put_pages(struct drm_gem_object *obj); void i915_gem_object_put_pages(struct drm_gem_object *obj);
void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
void i915_gem_object_flush_write_domain(struct drm_gem_object *obj); int i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
void i915_gem_shrinker_init(void); void i915_gem_shrinker_init(void);
void i915_gem_shrinker_exit(void); void i915_gem_shrinker_exit(void);
...@@ -1046,6 +1058,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev); ...@@ -1046,6 +1058,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev);
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
extern void i8xx_disable_fbc(struct drm_device *dev); extern void i8xx_disable_fbc(struct drm_device *dev);
extern void g4x_disable_fbc(struct drm_device *dev); extern void g4x_disable_fbc(struct drm_device *dev);
extern void ironlake_disable_fbc(struct drm_device *dev);
extern void intel_disable_fbc(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev);
extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
extern bool intel_fbc_enabled(struct drm_device *dev); extern bool intel_fbc_enabled(struct drm_device *dev);
...@@ -1135,6 +1148,8 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); ...@@ -1135,6 +1148,8 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
#define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm) #define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm)
#define IS_I965G(dev) (INTEL_INFO(dev)->is_i965g) #define IS_I965G(dev) (INTEL_INFO(dev)->is_i965g)
#define IS_I965GM(dev) (INTEL_INFO(dev)->is_i965gm) #define IS_I965GM(dev) (INTEL_INFO(dev)->is_i965gm)
#define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater)
#define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline)
#define IS_GM45(dev) ((dev)->pci_device == 0x2A42) #define IS_GM45(dev) ((dev)->pci_device == 0x2A42)
#define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x) #define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x)
#define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001) #define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001)
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/pci.h> #include <linux/pci.h>
static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj,
...@@ -53,6 +53,7 @@ static int i915_gem_evict_from_inactive_list(struct drm_device *dev); ...@@ -53,6 +53,7 @@ static int i915_gem_evict_from_inactive_list(struct drm_device *dev);
static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
struct drm_i915_gem_pwrite *args, struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv); struct drm_file *file_priv);
static void i915_gem_free_object_tail(struct drm_gem_object *obj);
static LIST_HEAD(shrink_list); static LIST_HEAD(shrink_list);
static DEFINE_SPINLOCK(shrink_list_lock); static DEFINE_SPINLOCK(shrink_list_lock);
...@@ -127,8 +128,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, ...@@ -127,8 +128,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
return -ENOMEM; return -ENOMEM;
ret = drm_gem_handle_create(file_priv, obj, &handle); ret = drm_gem_handle_create(file_priv, obj, &handle);
drm_gem_object_handle_unreference_unlocked(obj); drm_gem_object_unreference_unlocked(obj);
if (ret) if (ret)
return ret; return ret;
...@@ -496,10 +496,10 @@ fast_user_write(struct io_mapping *mapping, ...@@ -496,10 +496,10 @@ fast_user_write(struct io_mapping *mapping,
char *vaddr_atomic; char *vaddr_atomic;
unsigned long unwritten; unsigned long unwritten;
vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base); vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base, KM_USER0);
unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset, unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset,
user_data, length); user_data, length);
io_mapping_unmap_atomic(vaddr_atomic); io_mapping_unmap_atomic(vaddr_atomic, KM_USER0);
if (unwritten) if (unwritten)
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -1709,9 +1709,9 @@ i915_get_gem_seqno(struct drm_device *dev, ...@@ -1709,9 +1709,9 @@ i915_get_gem_seqno(struct drm_device *dev,
/** /**
* This function clears the request list as sequence numbers are passed. * This function clears the request list as sequence numbers are passed.
*/ */
void static void
i915_gem_retire_requests(struct drm_device *dev, i915_gem_retire_requests_ring(struct drm_device *dev,
struct intel_ring_buffer *ring) struct intel_ring_buffer *ring)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno; uint32_t seqno;
...@@ -1750,6 +1750,30 @@ i915_gem_retire_requests(struct drm_device *dev, ...@@ -1750,6 +1750,30 @@ i915_gem_retire_requests(struct drm_device *dev,
} }
} }
void
i915_gem_retire_requests(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
if (!list_empty(&dev_priv->mm.deferred_free_list)) {
struct drm_i915_gem_object *obj_priv, *tmp;
/* We must be careful that during unbind() we do not
* accidentally infinitely recurse into retire requests.
* Currently:
* retire -> free -> unbind -> wait -> retire_ring
*/
list_for_each_entry_safe(obj_priv, tmp,
&dev_priv->mm.deferred_free_list,
list)
i915_gem_free_object_tail(&obj_priv->base);
}
i915_gem_retire_requests_ring(dev, &dev_priv->render_ring);
if (HAS_BSD(dev))
i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
}
void void
i915_gem_retire_work_handler(struct work_struct *work) i915_gem_retire_work_handler(struct work_struct *work)
{ {
...@@ -1761,10 +1785,7 @@ i915_gem_retire_work_handler(struct work_struct *work) ...@@ -1761,10 +1785,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
dev = dev_priv->dev; dev = dev_priv->dev;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
i915_gem_retire_requests(dev, &dev_priv->render_ring); i915_gem_retire_requests(dev);
if (HAS_BSD(dev))
i915_gem_retire_requests(dev, &dev_priv->bsd_ring);
if (!dev_priv->mm.suspended && if (!dev_priv->mm.suspended &&
(!list_empty(&dev_priv->render_ring.request_list) || (!list_empty(&dev_priv->render_ring.request_list) ||
...@@ -1832,7 +1853,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, ...@@ -1832,7 +1853,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
* a separate wait queue to handle that. * a separate wait queue to handle that.
*/ */
if (ret == 0) if (ret == 0)
i915_gem_retire_requests(dev, ring); i915_gem_retire_requests_ring(dev, ring);
return ret; return ret;
} }
...@@ -1945,11 +1966,12 @@ i915_gem_object_unbind(struct drm_gem_object *obj) ...@@ -1945,11 +1966,12 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
* before we unbind. * before we unbind.
*/ */
ret = i915_gem_object_set_to_cpu_domain(obj, 1); ret = i915_gem_object_set_to_cpu_domain(obj, 1);
if (ret) { if (ret == -ERESTARTSYS)
if (ret != -ERESTARTSYS)
DRM_ERROR("set_domain failed: %d\n", ret);
return ret; return ret;
} /* Continue on if we fail due to EIO, the GPU is hung so we
* should be safe and we need to cleanup or else we might
* cause memory corruption through use-after-free.
*/
BUG_ON(obj_priv->active); BUG_ON(obj_priv->active);
...@@ -1985,7 +2007,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) ...@@ -1985,7 +2007,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
trace_i915_gem_object_unbind(obj); trace_i915_gem_object_unbind(obj);
return 0; return ret;
} }
static struct drm_gem_object * static struct drm_gem_object *
...@@ -2107,10 +2129,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) ...@@ -2107,10 +2129,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
struct intel_ring_buffer *render_ring = &dev_priv->render_ring; struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring;
for (;;) { for (;;) {
i915_gem_retire_requests(dev, render_ring); i915_gem_retire_requests(dev);
if (HAS_BSD(dev))
i915_gem_retire_requests(dev, bsd_ring);
/* If there's an inactive buffer available now, grab it /* If there's an inactive buffer available now, grab it
* and be done. * and be done.
...@@ -2583,7 +2602,10 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj) ...@@ -2583,7 +2602,10 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
if (!IS_I965G(dev)) { if (!IS_I965G(dev)) {
int ret; int ret;
i915_gem_object_flush_gpu_write_domain(obj); ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret != 0)
return ret;
ret = i915_gem_object_wait_rendering(obj); ret = i915_gem_object_wait_rendering(obj);
if (ret != 0) if (ret != 0)
return ret; return ret;
...@@ -2634,10 +2656,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) ...@@ -2634,10 +2656,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
if (free_space != NULL) { if (free_space != NULL) {
obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size, obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size,
alignment); alignment);
if (obj_priv->gtt_space != NULL) { if (obj_priv->gtt_space != NULL)
obj_priv->gtt_space->private = obj;
obj_priv->gtt_offset = obj_priv->gtt_space->start; obj_priv->gtt_offset = obj_priv->gtt_space->start;
}
} }
if (obj_priv->gtt_space == NULL) { if (obj_priv->gtt_space == NULL) {
/* If the gtt is empty and we're still having trouble /* If the gtt is empty and we're still having trouble
...@@ -2733,7 +2753,7 @@ i915_gem_clflush_object(struct drm_gem_object *obj) ...@@ -2733,7 +2753,7 @@ i915_gem_clflush_object(struct drm_gem_object *obj)
} }
/** Flushes any GPU write domain for the object if it's dirty. */ /** Flushes any GPU write domain for the object if it's dirty. */
static void static int
i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
...@@ -2741,17 +2761,18 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) ...@@ -2741,17 +2761,18 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
return; return 0;
/* Queue the GPU write cache flushing we need. */ /* Queue the GPU write cache flushing we need. */
old_write_domain = obj->write_domain; old_write_domain = obj->write_domain;
i915_gem_flush(dev, 0, obj->write_domain); i915_gem_flush(dev, 0, obj->write_domain);
(void) i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring); if (i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring) == 0)
BUG_ON(obj->write_domain); return -ENOMEM;
trace_i915_gem_object_change_domain(obj, trace_i915_gem_object_change_domain(obj,
obj->read_domains, obj->read_domains,
old_write_domain); old_write_domain);
return 0;
} }
/** Flushes the GTT write domain for the object if it's dirty. */ /** Flushes the GTT write domain for the object if it's dirty. */
...@@ -2795,9 +2816,11 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj) ...@@ -2795,9 +2816,11 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj)
old_write_domain); old_write_domain);
} }
void int
i915_gem_object_flush_write_domain(struct drm_gem_object *obj) i915_gem_object_flush_write_domain(struct drm_gem_object *obj)
{ {
int ret = 0;
switch (obj->write_domain) { switch (obj->write_domain) {
case I915_GEM_DOMAIN_GTT: case I915_GEM_DOMAIN_GTT:
i915_gem_object_flush_gtt_write_domain(obj); i915_gem_object_flush_gtt_write_domain(obj);
...@@ -2806,9 +2829,11 @@ i915_gem_object_flush_write_domain(struct drm_gem_object *obj) ...@@ -2806,9 +2829,11 @@ i915_gem_object_flush_write_domain(struct drm_gem_object *obj)
i915_gem_object_flush_cpu_write_domain(obj); i915_gem_object_flush_cpu_write_domain(obj);
break; break;
default: default:
i915_gem_object_flush_gpu_write_domain(obj); ret = i915_gem_object_flush_gpu_write_domain(obj);
break; break;
} }
return ret;
} }
/** /**
...@@ -2828,7 +2853,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) ...@@ -2828,7 +2853,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
if (obj_priv->gtt_space == NULL) if (obj_priv->gtt_space == NULL)
return -EINVAL; return -EINVAL;
i915_gem_object_flush_gpu_write_domain(obj); ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret != 0)
return ret;
/* Wait on any GPU rendering and flushing to occur. */ /* Wait on any GPU rendering and flushing to occur. */
ret = i915_gem_object_wait_rendering(obj); ret = i915_gem_object_wait_rendering(obj);
if (ret != 0) if (ret != 0)
...@@ -2878,7 +2906,9 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) ...@@ -2878,7 +2906,9 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
if (obj_priv->gtt_space == NULL) if (obj_priv->gtt_space == NULL)
return -EINVAL; return -EINVAL;
i915_gem_object_flush_gpu_write_domain(obj); ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret)
return ret;
/* Wait on any GPU rendering and flushing to occur. */ /* Wait on any GPU rendering and flushing to occur. */
if (obj_priv->active) { if (obj_priv->active) {
...@@ -2926,7 +2956,10 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) ...@@ -2926,7 +2956,10 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
uint32_t old_write_domain, old_read_domains; uint32_t old_write_domain, old_read_domains;
int ret; int ret;
i915_gem_object_flush_gpu_write_domain(obj); ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret)
return ret;
/* Wait on any GPU rendering and flushing to occur. */ /* Wait on any GPU rendering and flushing to occur. */
ret = i915_gem_object_wait_rendering(obj); ret = i915_gem_object_wait_rendering(obj);
if (ret != 0) if (ret != 0)
...@@ -3216,7 +3249,10 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, ...@@ -3216,7 +3249,10 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
if (offset == 0 && size == obj->size) if (offset == 0 && size == obj->size)
return i915_gem_object_set_to_cpu_domain(obj, 0); return i915_gem_object_set_to_cpu_domain(obj, 0);
i915_gem_object_flush_gpu_write_domain(obj); ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret)
return ret;
/* Wait on any GPU rendering and flushing to occur. */ /* Wait on any GPU rendering and flushing to occur. */
ret = i915_gem_object_wait_rendering(obj); ret = i915_gem_object_wait_rendering(obj);
if (ret != 0) if (ret != 0)
...@@ -3451,7 +3487,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, ...@@ -3451,7 +3487,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
reloc_offset = obj_priv->gtt_offset + reloc->offset; reloc_offset = obj_priv->gtt_offset + reloc->offset;
reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
(reloc_offset & (reloc_offset &
~(PAGE_SIZE - 1))); ~(PAGE_SIZE - 1)),
KM_USER0);
reloc_entry = (uint32_t __iomem *)(reloc_page + reloc_entry = (uint32_t __iomem *)(reloc_page +
(reloc_offset & (PAGE_SIZE - 1))); (reloc_offset & (PAGE_SIZE - 1)));
reloc_val = target_obj_priv->gtt_offset + reloc->delta; reloc_val = target_obj_priv->gtt_offset + reloc->delta;
...@@ -3462,7 +3499,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, ...@@ -3462,7 +3499,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
readl(reloc_entry), reloc_val); readl(reloc_entry), reloc_val);
#endif #endif
writel(reloc_val, reloc_entry); writel(reloc_val, reloc_entry);
io_mapping_unmap_atomic(reloc_page); io_mapping_unmap_atomic(reloc_page, KM_USER0);
/* The updated presumed offset for this entry will be /* The updated presumed offset for this entry will be
* copied back out to the user. * copied back out to the user.
...@@ -4313,7 +4350,6 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, ...@@ -4313,7 +4350,6 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_busy *args = data; struct drm_i915_gem_busy *args = data;
struct drm_gem_object *obj; struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv; struct drm_i915_gem_object *obj_priv;
drm_i915_private_t *dev_priv = dev->dev_private;
obj = drm_gem_object_lookup(dev, file_priv, args->handle); obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL) { if (obj == NULL) {
...@@ -4328,10 +4364,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, ...@@ -4328,10 +4364,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
* actually unmasked, and our working set ends up being larger than * actually unmasked, and our working set ends up being larger than
* required. * required.
*/ */
i915_gem_retire_requests(dev, &dev_priv->render_ring); i915_gem_retire_requests(dev);
if (HAS_BSD(dev))
i915_gem_retire_requests(dev, &dev_priv->bsd_ring);
obj_priv = to_intel_bo(obj); obj_priv = to_intel_bo(obj);
/* Don't count being on the flushing list against the object being /* Don't count being on the flushing list against the object being
...@@ -4441,20 +4474,19 @@ int i915_gem_init_object(struct drm_gem_object *obj) ...@@ -4441,20 +4474,19 @@ int i915_gem_init_object(struct drm_gem_object *obj)
return 0; return 0;
} }
void i915_gem_free_object(struct drm_gem_object *obj) static void i915_gem_free_object_tail(struct drm_gem_object *obj)
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret;
trace_i915_gem_object_destroy(obj); ret = i915_gem_object_unbind(obj);
if (ret == -ERESTARTSYS) {
while (obj_priv->pin_count > 0) list_move(&obj_priv->list,
i915_gem_object_unpin(obj); &dev_priv->mm.deferred_free_list);
return;
if (obj_priv->phys_obj) }
i915_gem_detach_phys_object(dev, obj);
i915_gem_object_unbind(obj);
if (obj_priv->mmap_offset) if (obj_priv->mmap_offset)
i915_gem_free_mmap_offset(obj); i915_gem_free_mmap_offset(obj);
...@@ -4466,6 +4498,22 @@ void i915_gem_free_object(struct drm_gem_object *obj) ...@@ -4466,6 +4498,22 @@ void i915_gem_free_object(struct drm_gem_object *obj)
kfree(obj_priv); kfree(obj_priv);
} }
void i915_gem_free_object(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
trace_i915_gem_object_destroy(obj);
while (obj_priv->pin_count > 0)
i915_gem_object_unpin(obj);
if (obj_priv->phys_obj)
i915_gem_detach_phys_object(dev, obj);
i915_gem_free_object_tail(obj);
}
/** Unbinds all inactive objects. */ /** Unbinds all inactive objects. */
static int static int
i915_gem_evict_from_inactive_list(struct drm_device *dev) i915_gem_evict_from_inactive_list(struct drm_device *dev)
...@@ -4689,9 +4737,19 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, ...@@ -4689,9 +4737,19 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list)); BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list));
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
drm_irq_install(dev); ret = drm_irq_install(dev);
if (ret)
goto cleanup_ringbuffer;
return 0; return 0;
cleanup_ringbuffer:
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
dev_priv->mm.suspended = 1;
mutex_unlock(&dev->struct_mutex);
return ret;
} }
int int
...@@ -4729,6 +4787,7 @@ i915_gem_load(struct drm_device *dev) ...@@ -4729,6 +4787,7 @@ i915_gem_load(struct drm_device *dev)
INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list); INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
INIT_LIST_HEAD(&dev_priv->mm.inactive_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list);
INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
INIT_LIST_HEAD(&dev_priv->render_ring.active_list); INIT_LIST_HEAD(&dev_priv->render_ring.active_list);
INIT_LIST_HEAD(&dev_priv->render_ring.request_list); INIT_LIST_HEAD(&dev_priv->render_ring.request_list);
if (HAS_BSD(dev)) { if (HAS_BSD(dev)) {
...@@ -5027,10 +5086,7 @@ i915_gem_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) ...@@ -5027,10 +5086,7 @@ i915_gem_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
continue; continue;
spin_unlock(&shrink_list_lock); spin_unlock(&shrink_list_lock);
i915_gem_retire_requests(dev, &dev_priv->render_ring); i915_gem_retire_requests(dev);
if (HAS_BSD(dev))
i915_gem_retire_requests(dev, &dev_priv->bsd_ring);
list_for_each_entry_safe(obj_priv, next_obj, list_for_each_entry_safe(obj_priv, next_obj,
&dev_priv->mm.inactive_list, &dev_priv->mm.inactive_list,
......
...@@ -333,8 +333,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, ...@@ -333,8 +333,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
i915_gem_release_mmap(obj); i915_gem_release_mmap(obj);
if (ret != 0) { if (ret != 0) {
WARN(ret != -ERESTARTSYS,
"failed to reset object for tiling switch");
args->tiling_mode = obj_priv->tiling_mode; args->tiling_mode = obj_priv->tiling_mode;
args->stride = obj_priv->stride; args->stride = obj_priv->stride;
goto err; goto err;
......
...@@ -171,10 +171,10 @@ void intel_enable_asle (struct drm_device *dev) ...@@ -171,10 +171,10 @@ void intel_enable_asle (struct drm_device *dev)
ironlake_enable_display_irq(dev_priv, DE_GSE); ironlake_enable_display_irq(dev_priv, DE_GSE);
else { else {
i915_enable_pipestat(dev_priv, 1, i915_enable_pipestat(dev_priv, 1,
I915_LEGACY_BLC_EVENT_ENABLE); PIPE_LEGACY_BLC_EVENT_ENABLE);
if (IS_I965G(dev)) if (IS_I965G(dev))
i915_enable_pipestat(dev_priv, 0, i915_enable_pipestat(dev_priv, 0,
I915_LEGACY_BLC_EVENT_ENABLE); PIPE_LEGACY_BLC_EVENT_ENABLE);
} }
} }
...@@ -842,7 +842,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -842,7 +842,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
u32 iir, new_iir; u32 iir, new_iir;
u32 pipea_stats, pipeb_stats; u32 pipea_stats, pipeb_stats;
u32 vblank_status; u32 vblank_status;
u32 vblank_enable;
int vblank = 0; int vblank = 0;
unsigned long irqflags; unsigned long irqflags;
int irq_received; int irq_received;
...@@ -856,13 +855,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -856,13 +855,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
iir = I915_READ(IIR); iir = I915_READ(IIR);
if (IS_I965G(dev)) { if (IS_I965G(dev))
vblank_status = I915_START_VBLANK_INTERRUPT_STATUS; vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS;
vblank_enable = PIPE_START_VBLANK_INTERRUPT_ENABLE; else
} else { vblank_status = PIPE_VBLANK_INTERRUPT_STATUS;
vblank_status = I915_VBLANK_INTERRUPT_STATUS;
vblank_enable = I915_VBLANK_INTERRUPT_ENABLE;
}
for (;;) { for (;;) {
irq_received = iir != 0; irq_received = iir != 0;
...@@ -966,8 +962,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -966,8 +962,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
intel_finish_page_flip(dev, 1); intel_finish_page_flip(dev, 1);
} }
if ((pipea_stats & I915_LEGACY_BLC_EVENT_STATUS) || if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
(pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) || (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
(iir & I915_ASLE_INTERRUPT)) (iir & I915_ASLE_INTERRUPT))
opregion_asle_intr(dev); opregion_asle_intr(dev);
...@@ -1233,16 +1229,21 @@ void i915_hangcheck_elapsed(unsigned long data) ...@@ -1233,16 +1229,21 @@ void i915_hangcheck_elapsed(unsigned long data)
{ {
struct drm_device *dev = (struct drm_device *)data; struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t acthd; uint32_t acthd, instdone, instdone1;
/* No reset support on this chip yet. */ /* No reset support on this chip yet. */
if (IS_GEN6(dev)) if (IS_GEN6(dev))
return; return;
if (!IS_I965G(dev)) if (!IS_I965G(dev)) {
acthd = I915_READ(ACTHD); acthd = I915_READ(ACTHD);
else instdone = I915_READ(INSTDONE);
instdone1 = 0;
} else {
acthd = I915_READ(ACTHD_I965); acthd = I915_READ(ACTHD_I965);
instdone = I915_READ(INSTDONE_I965);
instdone1 = I915_READ(INSTDONE1);
}
/* If all work is done then ACTHD clearly hasn't advanced. */ /* If all work is done then ACTHD clearly hasn't advanced. */
if (list_empty(&dev_priv->render_ring.request_list) || if (list_empty(&dev_priv->render_ring.request_list) ||
...@@ -1253,21 +1254,24 @@ void i915_hangcheck_elapsed(unsigned long data) ...@@ -1253,21 +1254,24 @@ void i915_hangcheck_elapsed(unsigned long data)
return; return;
} }
if (dev_priv->last_acthd == acthd && dev_priv->hangcheck_count > 0) { if (dev_priv->last_acthd == acthd &&
DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); dev_priv->last_instdone == instdone &&
i915_handle_error(dev, true); dev_priv->last_instdone1 == instdone1) {
return; if (dev_priv->hangcheck_count++ > 1) {
} DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
i915_handle_error(dev, true);
return;
}
} else {
dev_priv->hangcheck_count = 0;
dev_priv->last_acthd = acthd;
dev_priv->last_instdone = instdone;
dev_priv->last_instdone1 = instdone1;
}
/* Reset timer case chip hangs without another request being added */ /* Reset timer case chip hangs without another request being added */
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
if (acthd != dev_priv->last_acthd)
dev_priv->hangcheck_count = 0;
else
dev_priv->hangcheck_count++;
dev_priv->last_acthd = acthd;
} }
/* drm_dma.h hooks /* drm_dma.h hooks
......
...@@ -442,7 +442,7 @@ ...@@ -442,7 +442,7 @@
#define GEN6_RENDER_IMR 0x20a8 #define GEN6_RENDER_IMR 0x20a8
#define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8) #define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8)
#define GEN6_RENDER_PPGTT_PAGE_FAULT (1 << 7) #define GEN6_RENDER_PPGTT_PAGE_FAULT (1 << 7)
#define GEN6_RENDER TIMEOUT_COUNTER_EXPIRED (1 << 6) #define GEN6_RENDER_TIMEOUT_COUNTER_EXPIRED (1 << 6)
#define GEN6_RENDER_L3_PARITY_ERROR (1 << 5) #define GEN6_RENDER_L3_PARITY_ERROR (1 << 5)
#define GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 4) #define GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 4)
#define GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR (1 << 3) #define GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR (1 << 3)
...@@ -530,6 +530,21 @@ ...@@ -530,6 +530,21 @@
#define DPFC_CHICKEN 0x3224 #define DPFC_CHICKEN 0x3224
#define DPFC_HT_MODIFY (1<<31) #define DPFC_HT_MODIFY (1<<31)
/* Framebuffer compression for Ironlake */
#define ILK_DPFC_CB_BASE 0x43200
#define ILK_DPFC_CONTROL 0x43208
/* The bit 28-8 is reserved */
#define DPFC_RESERVED (0x1FFFFF00)
#define ILK_DPFC_RECOMP_CTL 0x4320c
#define ILK_DPFC_STATUS 0x43210
#define ILK_DPFC_FENCE_YOFF 0x43218
#define ILK_DPFC_CHICKEN 0x43224
#define ILK_FBC_RT_BASE 0x2128
#define ILK_FBC_RT_VALID (1<<0)
#define ILK_DISPLAY_CHICKEN1 0x42000
#define ILK_FBCQ_DIS (1<<22)
/* /*
* GPIO regs * GPIO regs
*/ */
...@@ -595,32 +610,6 @@ ...@@ -595,32 +610,6 @@
#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ #define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
#define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */ #define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */
#define I915_FIFO_UNDERRUN_STATUS (1UL<<31)
#define I915_CRC_ERROR_ENABLE (1UL<<29)
#define I915_CRC_DONE_ENABLE (1UL<<28)
#define I915_GMBUS_EVENT_ENABLE (1UL<<27)
#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25)
#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
#define I915_DPST_EVENT_ENABLE (1UL<<23)
#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
#define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */
#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16)
#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11)
#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9)
#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8)
#define I915_DPST_EVENT_STATUS (1UL<<7)
#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6)
#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5)
#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4)
#define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
#define I915_VBLANK_INTERRUPT_STATUS (1UL<<1)
#define I915_OVERLAY_UPDATED_STATUS (1UL<<0)
#define SRX_INDEX 0x3c4 #define SRX_INDEX 0x3c4
#define SRX_DATA 0x3c5 #define SRX_DATA 0x3c5
#define SR01 1 #define SR01 1
...@@ -2166,7 +2155,8 @@ ...@@ -2166,7 +2155,8 @@
#define I830_FIFO_LINE_SIZE 32 #define I830_FIFO_LINE_SIZE 32
#define G4X_FIFO_SIZE 127 #define G4X_FIFO_SIZE 127
#define I945_FIFO_SIZE 127 /* 945 & 965 */ #define I965_FIFO_SIZE 512
#define I945_FIFO_SIZE 127
#define I915_FIFO_SIZE 95 #define I915_FIFO_SIZE 95
#define I855GM_FIFO_SIZE 127 /* In cachelines */ #define I855GM_FIFO_SIZE 127 /* In cachelines */
#define I830_FIFO_SIZE 95 #define I830_FIFO_SIZE 95
...@@ -2185,6 +2175,9 @@ ...@@ -2185,6 +2175,9 @@
#define PINEVIEW_CURSOR_DFT_WM 0 #define PINEVIEW_CURSOR_DFT_WM 0
#define PINEVIEW_CURSOR_GUARD_WM 5 #define PINEVIEW_CURSOR_GUARD_WM 5
#define I965_CURSOR_FIFO 64
#define I965_CURSOR_MAX_WM 32
#define I965_CURSOR_DFT_WM 8
/* define the Watermark register on Ironlake */ /* define the Watermark register on Ironlake */
#define WM0_PIPEA_ILK 0x45100 #define WM0_PIPEA_ILK 0x45100
...@@ -2212,6 +2205,9 @@ ...@@ -2212,6 +2205,9 @@
#define ILK_DISPLAY_FIFO 128 #define ILK_DISPLAY_FIFO 128
#define ILK_DISPLAY_MAXWM 64 #define ILK_DISPLAY_MAXWM 64
#define ILK_DISPLAY_DFTWM 8 #define ILK_DISPLAY_DFTWM 8
#define ILK_CURSOR_FIFO 32
#define ILK_CURSOR_MAXWM 16
#define ILK_CURSOR_DFTWM 8
#define ILK_DISPLAY_SR_FIFO 512 #define ILK_DISPLAY_SR_FIFO 512
#define ILK_DISPLAY_MAX_SRWM 0x1ff #define ILK_DISPLAY_MAX_SRWM 0x1ff
...@@ -2510,6 +2506,10 @@ ...@@ -2510,6 +2506,10 @@
#define ILK_VSDPFD_FULL (1<<21) #define ILK_VSDPFD_FULL (1<<21)
#define ILK_DSPCLK_GATE 0x42020 #define ILK_DSPCLK_GATE 0x42020
#define ILK_DPARB_CLK_GATE (1<<5) #define ILK_DPARB_CLK_GATE (1<<5)
/* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */
#define ILK_CLK_FBC (1<<7)
#define ILK_DPFC_DIS1 (1<<8)
#define ILK_DPFC_DIS2 (1<<9)
#define DISP_ARB_CTL 0x45000 #define DISP_ARB_CTL 0x45000
#define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_TILE_SURFACE_SWIZZLING (1<<13)
......
...@@ -602,7 +602,9 @@ void i915_save_display(struct drm_device *dev) ...@@ -602,7 +602,9 @@ void i915_save_display(struct drm_device *dev)
/* Only save FBC state on the platform that supports FBC */ /* Only save FBC state on the platform that supports FBC */
if (I915_HAS_FBC(dev)) { if (I915_HAS_FBC(dev)) {
if (IS_GM45(dev)) { if (IS_IRONLAKE_M(dev)) {
dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE);
} else if (IS_GM45(dev)) {
dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE); dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
} else { } else {
dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
...@@ -706,7 +708,10 @@ void i915_restore_display(struct drm_device *dev) ...@@ -706,7 +708,10 @@ void i915_restore_display(struct drm_device *dev)
/* only restore FBC info on the platform that supports FBC*/ /* only restore FBC info on the platform that supports FBC*/
if (I915_HAS_FBC(dev)) { if (I915_HAS_FBC(dev)) {
if (IS_GM45(dev)) { if (IS_IRONLAKE_M(dev)) {
ironlake_disable_fbc(dev);
I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
} else if (IS_GM45(dev)) {
g4x_disable_fbc(dev); g4x_disable_fbc(dev);
I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
} else { } else {
......
...@@ -262,6 +262,42 @@ DEFINE_EVENT(i915_ring, i915_ring_wait_end, ...@@ -262,6 +262,42 @@ DEFINE_EVENT(i915_ring, i915_ring_wait_end,
TP_ARGS(dev) TP_ARGS(dev)
); );
TRACE_EVENT(i915_flip_request,
TP_PROTO(int plane, struct drm_gem_object *obj),
TP_ARGS(plane, obj),
TP_STRUCT__entry(
__field(int, plane)
__field(struct drm_gem_object *, obj)
),
TP_fast_assign(
__entry->plane = plane;
__entry->obj = obj;
),
TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj)
);
TRACE_EVENT(i915_flip_complete,
TP_PROTO(int plane, struct drm_gem_object *obj),
TP_ARGS(plane, obj),
TP_STRUCT__entry(
__field(int, plane)
__field(struct drm_gem_object *, obj)
),
TP_fast_assign(
__entry->plane = plane;
__entry->obj = obj;
),
TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj)
);
#endif /* _I915_TRACE_H_ */ #endif /* _I915_TRACE_H_ */
/* This part must be outside protection */ /* This part must be outside protection */
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#define DP_LINK_CONFIGURATION_SIZE 9 #define DP_LINK_CONFIGURATION_SIZE 9
#define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP) #define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP)
#define IS_PCH_eDP(dp_priv) ((dp_priv)->is_pch_edp)
struct intel_dp_priv { struct intel_dp_priv {
uint32_t output_reg; uint32_t output_reg;
...@@ -56,6 +57,7 @@ struct intel_dp_priv { ...@@ -56,6 +57,7 @@ struct intel_dp_priv {
struct intel_encoder *intel_encoder; struct intel_encoder *intel_encoder;
struct i2c_adapter adapter; struct i2c_adapter adapter;
struct i2c_algo_dp_aux_data algo; struct i2c_algo_dp_aux_data algo;
bool is_pch_edp;
}; };
static void static void
...@@ -128,8 +130,9 @@ intel_dp_link_required(struct drm_device *dev, ...@@ -128,8 +130,9 @@ intel_dp_link_required(struct drm_device *dev,
struct intel_encoder *intel_encoder, int pixel_clock) struct intel_encoder *intel_encoder, int pixel_clock)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
if (IS_eDP(intel_encoder)) if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv))
return (pixel_clock * dev_priv->edp_bpp) / 8; return (pixel_clock * dev_priv->edp_bpp) / 8;
else else
return pixel_clock * 3; return pixel_clock * 3;
...@@ -147,9 +150,21 @@ intel_dp_mode_valid(struct drm_connector *connector, ...@@ -147,9 +150,21 @@ intel_dp_mode_valid(struct drm_connector *connector,
{ {
struct drm_encoder *encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_encoder)); int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_encoder));
int max_lanes = intel_dp_max_lane_count(intel_encoder); int max_lanes = intel_dp_max_lane_count(intel_encoder);
if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) &&
dev_priv->panel_fixed_mode) {
if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay)
return MODE_PANEL;
if (mode->vdisplay > dev_priv->panel_fixed_mode->vdisplay)
return MODE_PANEL;
}
/* only refuse the mode on non eDP since we have seen some wierd eDP panels /* only refuse the mode on non eDP since we have seen some wierd eDP panels
which are outside spec tolerances but somehow work by magic */ which are outside spec tolerances but somehow work by magic */
if (!IS_eDP(intel_encoder) && if (!IS_eDP(intel_encoder) &&
...@@ -508,11 +523,37 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -508,11 +523,37 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
{ {
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int lane_count, clock; int lane_count, clock;
int max_lane_count = intel_dp_max_lane_count(intel_encoder); int max_lane_count = intel_dp_max_lane_count(intel_encoder);
int max_clock = intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0; int max_clock = intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0;
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) &&
dev_priv->panel_fixed_mode) {
struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
adjusted_mode->hdisplay = fixed_mode->hdisplay;
adjusted_mode->hsync_start = fixed_mode->hsync_start;
adjusted_mode->hsync_end = fixed_mode->hsync_end;
adjusted_mode->htotal = fixed_mode->htotal;
adjusted_mode->vdisplay = fixed_mode->vdisplay;
adjusted_mode->vsync_start = fixed_mode->vsync_start;
adjusted_mode->vsync_end = fixed_mode->vsync_end;
adjusted_mode->vtotal = fixed_mode->vtotal;
adjusted_mode->clock = fixed_mode->clock;
drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
/*
* the mode->clock is used to calculate the Data&Link M/N
* of the pipe. For the eDP the fixed clock should be used.
*/
mode->clock = dev_priv->panel_fixed_mode->clock;
}
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
for (clock = 0; clock <= max_clock; clock++) { for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
...@@ -531,7 +572,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -531,7 +572,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
} }
} }
if (IS_eDP(intel_encoder)) { if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
/* okay we failed just pick the highest */ /* okay we failed just pick the highest */
dp_priv->lane_count = max_lane_count; dp_priv->lane_count = max_lane_count;
dp_priv->link_bw = bws[max_clock]; dp_priv->link_bw = bws[max_clock];
...@@ -563,14 +604,14 @@ intel_reduce_ratio(uint32_t *num, uint32_t *den) ...@@ -563,14 +604,14 @@ intel_reduce_ratio(uint32_t *num, uint32_t *den)
} }
static void static void
intel_dp_compute_m_n(int bytes_per_pixel, intel_dp_compute_m_n(int bpp,
int nlanes, int nlanes,
int pixel_clock, int pixel_clock,
int link_clock, int link_clock,
struct intel_dp_m_n *m_n) struct intel_dp_m_n *m_n)
{ {
m_n->tu = 64; m_n->tu = 64;
m_n->gmch_m = pixel_clock * bytes_per_pixel; m_n->gmch_m = (pixel_clock * bpp) >> 3;
m_n->gmch_n = link_clock * nlanes; m_n->gmch_n = link_clock * nlanes;
intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
m_n->link_m = pixel_clock; m_n->link_m = pixel_clock;
...@@ -578,6 +619,28 @@ intel_dp_compute_m_n(int bytes_per_pixel, ...@@ -578,6 +619,28 @@ intel_dp_compute_m_n(int bytes_per_pixel,
intel_reduce_ratio(&m_n->link_m, &m_n->link_n); intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
} }
bool intel_pch_has_edp(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_encoder *encoder;
list_for_each_entry(encoder, &mode_config->encoder_list, head) {
struct intel_encoder *intel_encoder;
struct intel_dp_priv *dp_priv;
if (!encoder || encoder->crtc != crtc)
continue;
intel_encoder = enc_to_intel_encoder(encoder);
dp_priv = intel_encoder->dev_priv;
if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT)
return dp_priv->is_pch_edp;
}
return false;
}
void void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
...@@ -587,7 +650,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -587,7 +650,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int lane_count = 4; int lane_count = 4, bpp = 24;
struct intel_dp_m_n m_n; struct intel_dp_m_n m_n;
/* /*
...@@ -605,6 +668,8 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -605,6 +668,8 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
lane_count = dp_priv->lane_count; lane_count = dp_priv->lane_count;
if (IS_PCH_eDP(dp_priv))
bpp = dev_priv->edp_bpp;
break; break;
} }
} }
...@@ -614,7 +679,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -614,7 +679,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
* the number of bytes_per_pixel post-LUT, which we always * the number of bytes_per_pixel post-LUT, which we always
* set up for 8-bits of R/G/B, or 3 bytes total. * set up for 8-bits of R/G/B, or 3 bytes total.
*/ */
intel_dp_compute_m_n(3, lane_count, intel_dp_compute_m_n(bpp, lane_count,
mode->clock, adjusted_mode->clock, &m_n); mode->clock, adjusted_mode->clock, &m_n);
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
...@@ -796,7 +861,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ...@@ -796,7 +861,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (mode != DRM_MODE_DPMS_ON) { if (mode != DRM_MODE_DPMS_ON) {
if (dp_reg & DP_PORT_EN) { if (dp_reg & DP_PORT_EN) {
intel_dp_link_down(intel_encoder, dp_priv->DP); intel_dp_link_down(intel_encoder, dp_priv->DP);
if (IS_eDP(intel_encoder)) { if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
ironlake_edp_backlight_off(dev); ironlake_edp_backlight_off(dev);
ironlake_edp_panel_off(dev); ironlake_edp_panel_off(dev);
} }
...@@ -804,7 +869,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ...@@ -804,7 +869,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
} else { } else {
if (!(dp_reg & DP_PORT_EN)) { if (!(dp_reg & DP_PORT_EN)) {
intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration); intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration);
if (IS_eDP(intel_encoder)) { if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
ironlake_edp_panel_on(dev); ironlake_edp_panel_on(dev);
ironlake_edp_backlight_on(dev); ironlake_edp_backlight_on(dev);
} }
...@@ -1340,17 +1405,32 @@ static int intel_dp_get_modes(struct drm_connector *connector) ...@@ -1340,17 +1405,32 @@ static int intel_dp_get_modes(struct drm_connector *connector)
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
struct drm_device *dev = intel_encoder->enc.dev; struct drm_device *dev = intel_encoder->enc.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
int ret; int ret;
/* We should parse the EDID data and find out if it has an audio sink /* We should parse the EDID data and find out if it has an audio sink
*/ */
ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
if (ret) if (ret) {
if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) &&
!dev_priv->panel_fixed_mode) {
struct drm_display_mode *newmode;
list_for_each_entry(newmode, &connector->probed_modes,
head) {
if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
dev_priv->panel_fixed_mode =
drm_mode_duplicate(dev, newmode);
break;
}
}
}
return ret; return ret;
}
/* if eDP has no EDID, try to use fixed panel mode from VBT */ /* if eDP has no EDID, try to use fixed panel mode from VBT */
if (IS_eDP(intel_encoder)) { if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) {
if (dev_priv->panel_fixed_mode != NULL) { if (dev_priv->panel_fixed_mode != NULL) {
struct drm_display_mode *mode; struct drm_display_mode *mode;
mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
...@@ -1435,6 +1515,26 @@ intel_trans_dp_port_sel (struct drm_crtc *crtc) ...@@ -1435,6 +1515,26 @@ intel_trans_dp_port_sel (struct drm_crtc *crtc)
return -1; return -1;
} }
/* check the VBT to see whether the eDP is on DP-D port */
bool intel_dpd_is_edp(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct child_device_config *p_child;
int i;
if (!dev_priv->child_dev_num)
return false;
for (i = 0; i < dev_priv->child_dev_num; i++) {
p_child = dev_priv->child_dev + i;
if (p_child->dvo_port == PORT_IDPD &&
p_child->device_type == DEVICE_TYPE_eDP)
return true;
}
return false;
}
void void
intel_dp_init(struct drm_device *dev, int output_reg) intel_dp_init(struct drm_device *dev, int output_reg)
{ {
...@@ -1444,6 +1544,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1444,6 +1544,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
struct intel_connector *intel_connector; struct intel_connector *intel_connector;
struct intel_dp_priv *dp_priv; struct intel_dp_priv *dp_priv;
const char *name = NULL; const char *name = NULL;
int type;
intel_encoder = kcalloc(sizeof(struct intel_encoder) + intel_encoder = kcalloc(sizeof(struct intel_encoder) +
sizeof(struct intel_dp_priv), 1, GFP_KERNEL); sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
...@@ -1458,18 +1559,24 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1458,18 +1559,24 @@ intel_dp_init(struct drm_device *dev, int output_reg)
dp_priv = (struct intel_dp_priv *)(intel_encoder + 1); dp_priv = (struct intel_dp_priv *)(intel_encoder + 1);
if (HAS_PCH_SPLIT(dev) && (output_reg == PCH_DP_D))
if (intel_dpd_is_edp(dev))
dp_priv->is_pch_edp = true;
if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) {
type = DRM_MODE_CONNECTOR_eDP;
intel_encoder->type = INTEL_OUTPUT_EDP;
} else {
type = DRM_MODE_CONNECTOR_DisplayPort;
intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
}
connector = &intel_connector->base; connector = &intel_connector->base;
drm_connector_init(dev, connector, &intel_dp_connector_funcs, drm_connector_init(dev, connector, &intel_dp_connector_funcs, type);
DRM_MODE_CONNECTOR_DisplayPort);
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_HPD;
if (output_reg == DP_A)
intel_encoder->type = INTEL_OUTPUT_EDP;
else
intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
if (output_reg == DP_B || output_reg == PCH_DP_B) if (output_reg == DP_B || output_reg == PCH_DP_B)
intel_encoder->clone_mask = (1 << INTEL_DP_B_CLONE_BIT); intel_encoder->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
else if (output_reg == DP_C || output_reg == PCH_DP_C) else if (output_reg == DP_C || output_reg == PCH_DP_C)
...@@ -1528,7 +1635,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1528,7 +1635,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
intel_encoder->ddc_bus = &dp_priv->adapter; intel_encoder->ddc_bus = &dp_priv->adapter;
intel_encoder->hot_plug = intel_dp_hot_plug; intel_encoder->hot_plug = intel_dp_hot_plug;
if (output_reg == DP_A) { if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) {
/* initialize panel mode from VBT if available for eDP */ /* initialize panel mode from VBT if available for eDP */
if (dev_priv->lfp_lvds_vbt_mode) { if (dev_priv->lfp_lvds_vbt_mode) {
dev_priv->panel_fixed_mode = dev_priv->panel_fixed_mode =
......
...@@ -143,8 +143,6 @@ struct intel_crtc { ...@@ -143,8 +143,6 @@ struct intel_crtc {
struct drm_crtc base; struct drm_crtc base;
enum pipe pipe; enum pipe pipe;
enum plane plane; enum plane plane;
struct drm_gem_object *cursor_bo;
uint32_t cursor_addr;
u8 lut_r[256], lut_g[256], lut_b[256]; u8 lut_r[256], lut_g[256], lut_b[256];
int dpms_mode; int dpms_mode;
bool busy; /* is scanout buffer being updated frequently? */ bool busy; /* is scanout buffer being updated frequently? */
...@@ -153,6 +151,12 @@ struct intel_crtc { ...@@ -153,6 +151,12 @@ struct intel_crtc {
struct intel_overlay *overlay; struct intel_overlay *overlay;
struct intel_unpin_work *unpin_work; struct intel_unpin_work *unpin_work;
int fdi_lanes; int fdi_lanes;
struct drm_gem_object *cursor_bo;
uint32_t cursor_addr;
int16_t cursor_x, cursor_y;
int16_t cursor_width, cursor_height;
bool cursor_visble;
}; };
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
...@@ -179,6 +183,8 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg); ...@@ -179,6 +183,8 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg);
void void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode); struct drm_display_mode *adjusted_mode);
extern bool intel_pch_has_edp(struct drm_crtc *crtc);
extern bool intel_dpd_is_edp(struct drm_device *dev);
extern void intel_edp_link_config (struct intel_encoder *, int *, int *); extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
......
...@@ -54,10 +54,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, ...@@ -54,10 +54,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv; struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
u32 sdvox; u32 sdvox;
sdvox = SDVO_ENCODING_HDMI | sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
SDVO_BORDER_ENABLE | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
SDVO_VSYNC_ACTIVE_HIGH | sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
SDVO_HSYNC_ACTIVE_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
if (hdmi_priv->has_hdmi_sink) { if (hdmi_priv->has_hdmi_sink) {
sdvox |= SDVO_AUDIO_ENABLE; sdvox |= SDVO_AUDIO_ENABLE;
......
此差异已折叠。
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
#define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */ #define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */
#define OCMD_TVSYNCFLIP_PARITY (0x1<<9) #define OCMD_TVSYNCFLIP_PARITY (0x1<<9)
#define OCMD_TVSYNCFLIP_ENABLE (0x1<<7) #define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)
#define OCMD_BUF_TYPE_MASK (Ox1<<5) #define OCMD_BUF_TYPE_MASK (0x1<<5)
#define OCMD_BUF_TYPE_FRAME (0x0<<5) #define OCMD_BUF_TYPE_FRAME (0x0<<5)
#define OCMD_BUF_TYPE_FIELD (0x1<<5) #define OCMD_BUF_TYPE_FIELD (0x1<<5)
#define OCMD_TEST_MODE (0x1<<4) #define OCMD_TEST_MODE (0x1<<4)
...@@ -185,7 +185,8 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over ...@@ -185,7 +185,8 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over
if (OVERLAY_NONPHYSICAL(overlay->dev)) { if (OVERLAY_NONPHYSICAL(overlay->dev)) {
regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
overlay->reg_bo->gtt_offset); overlay->reg_bo->gtt_offset,
KM_USER0);
if (!regs) { if (!regs) {
DRM_ERROR("failed to map overlay regs in GTT\n"); DRM_ERROR("failed to map overlay regs in GTT\n");
...@@ -200,7 +201,7 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over ...@@ -200,7 +201,7 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over
static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
{ {
if (OVERLAY_NONPHYSICAL(overlay->dev)) if (OVERLAY_NONPHYSICAL(overlay->dev))
io_mapping_unmap_atomic(overlay->virt_addr); io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0);
overlay->virt_addr = NULL; overlay->virt_addr = NULL;
...@@ -958,7 +959,7 @@ static int check_overlay_src(struct drm_device *dev, ...@@ -958,7 +959,7 @@ static int check_overlay_src(struct drm_device *dev,
|| rec->src_width < N_HORIZ_Y_TAPS*4) || rec->src_width < N_HORIZ_Y_TAPS*4)
return -EINVAL; return -EINVAL;
/* check alingment constrains */ /* check alignment constraints */
switch (rec->flags & I915_OVERLAY_TYPE_MASK) { switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
case I915_OVERLAY_RGB: case I915_OVERLAY_RGB:
/* not implemented */ /* not implemented */
...@@ -990,7 +991,10 @@ static int check_overlay_src(struct drm_device *dev, ...@@ -990,7 +991,10 @@ static int check_overlay_src(struct drm_device *dev,
return -EINVAL; return -EINVAL;
/* stride checking */ /* stride checking */
stride_mask = 63; if (IS_I830(dev) || IS_845G(dev))
stride_mask = 255;
else
stride_mask = 63;
if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
return -EINVAL; return -EINVAL;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -49,7 +49,10 @@ static inline struct nouveau_connector *nouveau_connector( ...@@ -49,7 +49,10 @@ static inline struct nouveau_connector *nouveau_connector(
return container_of(con, struct nouveau_connector, base); return container_of(con, struct nouveau_connector, base);
} }
int nouveau_connector_create(struct drm_device *, struct drm_connector *
struct dcb_connector_table_entry *); nouveau_connector_create(struct drm_device *, int index);
void
nouveau_connector_set_polling(struct drm_connector *);
#endif /* __NOUVEAU_CONNECTOR_H__ */ #endif /* __NOUVEAU_CONNECTOR_H__ */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册