From 6707ab862656d766a4c78b85e5584a29d2434126 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 26 Oct 2007 16:08:54 -0700 Subject: update DRM sysfs support Make DRM devices use real Linux devices instead of class devices, which are going away. While we're at it, clean up some of the interfaces to take struct drm_device * or struct device * and use the global drm_class where needed instead of passing it around. --- linux-core/drmP.h | 10 ++-- linux-core/drm_drv.c | 4 +- linux-core/drm_stub.c | 7 +-- linux-core/drm_sysfs.c | 151 +++++++++++++++++++++++++++++++++---------------- 4 files changed, 113 insertions(+), 59 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index d0ab2c94..82a3a23c 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -619,6 +619,8 @@ struct drm_driver { void (*postclose) (struct drm_device *, struct drm_file *); void (*lastclose) (struct drm_device *); int (*unload) (struct drm_device *); + int (*suspend) (struct drm_device *); + int (*resume) (struct drm_device *); int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); void (*dma_ready) (struct drm_device *); int (*dma_quiescent) (struct drm_device *); @@ -697,6 +699,7 @@ struct drm_head { * may contain multiple heads. */ struct drm_device { + struct device dev; /**< Linux device */ char *unique; /**< Unique identifier: e.g., busid */ int unique_len; /**< Length of unique field */ char *devname; /**< For /proc/interrupts */ @@ -1163,10 +1166,9 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah); /* sysfs support (drm_sysfs.c) */ struct drm_sysfs_class; extern struct class *drm_sysfs_create(struct module *owner, char *name); -extern void drm_sysfs_destroy(struct class *cs); -extern struct class_device *drm_sysfs_device_add(struct class *cs, - struct drm_head * head); -extern void drm_sysfs_device_remove(struct class_device *class_dev); +extern void drm_sysfs_destroy(void); +extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head * head); +extern void drm_sysfs_device_remove(struct drm_device *dev); /* * Basic memory manager support (drm_mm.c) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index fe2b1200..47d17651 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -519,7 +519,7 @@ static int __init drm_core_init(void) CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); return 0; err_p3: - drm_sysfs_destroy(drm_class); + drm_sysfs_destroy(); err_p2: unregister_chrdev(DRM_MAJOR, "drm"); drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); @@ -530,7 +530,7 @@ err_p1: static void __exit drm_core_exit(void) { remove_proc_entry("dri", NULL); - drm_sysfs_destroy(drm_class); + drm_sysfs_destroy(); unregister_chrdev(DRM_MAJOR, "drm"); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 9e140ac2..1d88d375 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -183,11 +183,10 @@ static int drm_get_head(struct drm_device * dev, struct drm_head * head) goto err_g1; } - head->dev_class = drm_sysfs_device_add(drm_class, head); - if (IS_ERR(head->dev_class)) { + ret = drm_sysfs_device_add(dev, head); + if (ret) { printk(KERN_ERR "DRM: Error sysfs_device_add.\n"); - ret = PTR_ERR(head->dev_class); goto err_g2; } *heads = head; @@ -316,7 +315,7 @@ int drm_put_head(struct drm_head * head) DRM_DEBUG("release secondary minor %d\n", minor); drm_proc_cleanup(minor, drm_proc_root, head->dev_root); - drm_sysfs_device_remove(head->dev_class); + drm_sysfs_device_remove(head->dev); *head = (struct drm_head){.dev = NULL}; diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index cf4349b0..6f8623ce 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -19,6 +19,45 @@ #include "drm_core.h" #include "drmP.h" +#define to_drm_device(d) container_of(d, struct drm_device, dev) + +/** + * drm_sysfs_suspend - DRM class suspend hook + * @dev: Linux device to suspend + * @state: power state to enter + * + * Just figures out what the actual struct drm_device associated with + * @dev is and calls its suspend hook, if present. + */ +static int drm_sysfs_suspend(struct device *dev, pm_message_t state) +{ + struct drm_device *drm_dev = to_drm_device(dev); + + printk(KERN_ERR "%s\n", __FUNCTION__); + + if (drm_dev->driver->suspend) + return drm_dev->driver->suspend(drm_dev); + + return 0; +} + +/** + * drm_sysfs_resume - DRM class resume hook + * @dev: Linux device to resume + * + * Just figures out what the actual struct drm_device associated with + * @dev is and calls its resume hook, if present. + */ +static int drm_sysfs_resume(struct device *dev) +{ + struct drm_device *drm_dev = to_drm_device(dev); + + if (drm_dev->driver->resume) + return drm_dev->driver->resume(drm_dev); + + return 0; +} + /* Display the version of drm_core. This doesn't work right in current design */ static ssize_t version_show(struct class *dev, char *buf) { @@ -33,7 +72,7 @@ static CLASS_ATTR(version, S_IRUGO, version_show, NULL); * @owner: pointer to the module that is to "own" this struct drm_sysfs_class * @name: pointer to a string for the name of this class. * - * This is used to create a struct drm_sysfs_class pointer that can then be used + * This is used to create DRM class pointer that can then be used * in calls to drm_sysfs_device_add(). * * Note, the pointer created here is to be destroyed when finished by making a @@ -50,6 +89,9 @@ struct class *drm_sysfs_create(struct module *owner, char *name) goto err_out; } + class->suspend = drm_sysfs_suspend; + class->resume = drm_sysfs_resume; + err = class_create_file(class, &class_attr_version); if (err) goto err_out_class; @@ -63,94 +105,105 @@ err_out: } /** - * drm_sysfs_destroy - destroys a struct drm_sysfs_class structure - * @cs: pointer to the struct drm_sysfs_class that is to be destroyed + * drm_sysfs_destroy - destroys DRM class * - * Note, the pointer to be destroyed must have been created with a call to - * drm_sysfs_create(). + * Destroy the DRM device class. */ -void drm_sysfs_destroy(struct class *class) +void drm_sysfs_destroy(void) { - if ((class == NULL) || (IS_ERR(class))) + if ((drm_class == NULL) || (IS_ERR(drm_class))) return; - - class_remove_file(class, &class_attr_version); - class_destroy(class); + class_remove_file(drm_class, &class_attr_version); + class_destroy(drm_class); } -static ssize_t show_dri(struct class_device *class_device, char *buf) +static ssize_t show_dri(struct device *device, struct device_attribute *attr, + char *buf) { - struct drm_device * dev = ((struct drm_head *)class_get_devdata(class_device))->dev; + struct drm_device *dev = to_drm_device(device); if (dev->driver->dri_library_name) return dev->driver->dri_library_name(dev, buf); return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); } -static struct class_device_attribute class_device_attrs[] = { +static struct device_attribute device_attrs[] = { __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), }; +/** + * drm_sysfs_device_release - do nothing + * @dev: Linux device + * + * Normally, this would free the DRM device associated with @dev, along + * with cleaning up any other stuff. But we do that in the DRM core, so + * this function can just return and hope that the core does its job. + */ +static void drm_sysfs_device_release(struct device *dev) +{ + return; +} + /** * drm_sysfs_device_add - adds a class device to sysfs for a character driver - * @cs: pointer to the struct class that this device should be registered to. - * @dev: the dev_t for the device to be added. - * @device: a pointer to a struct device that is assiociated with this class device. - * @fmt: string for the class device's name + * @dev: DRM device to be added + * @head: DRM head in question * - * A struct class_device will be created in sysfs, registered to the specified - * class. A "dev" file will be created, showing the dev_t for the device. The - * pointer to the struct class_device will be returned from the call. Any further - * sysfs files that might be required can be created using this pointer. - * Note: the struct class passed to this function must have previously been - * created with a call to drm_sysfs_create(). + * Add a DRM device to the DRM's device model class. We use @dev's PCI device + * as the parent for the Linux device, and make sure it has a file containing + * the driver we're using (for userspace compatibility). */ -struct class_device *drm_sysfs_device_add(struct class *cs, struct drm_head *head) +int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) { - struct class_device *class_dev; - int i, j, err; - - class_dev = class_device_create(cs, NULL, - MKDEV(DRM_MAJOR, head->minor), - &(head->dev->pdev)->dev, - "card%d", head->minor); - if (IS_ERR(class_dev)) { - err = PTR_ERR(class_dev); + int err; + int i, j; + + dev->dev.parent = &dev->pdev->dev; + dev->dev.class = drm_class; + dev->dev.release = drm_sysfs_device_release; + /* + * This will actually add the major:minor file so that udev + * will create the device node. We don't want to do that just + * yet... + */ + /* dev->dev.devt = head->device; */ + snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor); + + err = device_register(&dev->dev); + if (err) { + DRM_ERROR("device add failed: %d\n", err); goto err_out; } - class_set_devdata(class_dev, head); - - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { - err = class_device_create_file(class_dev, - &class_device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { + err = device_create_file(&dev->dev, &device_attrs[i]); if (err) goto err_out_files; } - return class_dev; + return 0; err_out_files: if (i > 0) for (j = 0; j < i; j++) - class_device_remove_file(class_dev, - &class_device_attrs[i]); - class_device_unregister(class_dev); + device_remove_file(&dev->dev, &device_attrs[i]); + device_unregister(&dev->dev); err_out: - return ERR_PTR(err); + + return err; } /** - * drm_sysfs_device_remove - removes a class device that was created with drm_sysfs_device_add() - * @dev: the dev_t of the device that was previously registered. + * drm_sysfs_device_remove - remove DRM device + * @dev: DRM device to remove * * This call unregisters and cleans up a class device that was created with a * call to drm_sysfs_device_add() */ -void drm_sysfs_device_remove(struct class_device *class_dev) +void drm_sysfs_device_remove(struct drm_device *dev) { int i; - for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) - class_device_remove_file(class_dev, &class_device_attrs[i]); - class_device_unregister(class_dev); + for (i = 0; i < ARRAY_SIZE(device_attrs); i++) + device_remove_file(&dev->dev, &device_attrs[i]); + device_unregister(&dev->dev); } -- cgit v1.2.3 From 1e2a2bababf3fbaa0a665983856761c2284dba30 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 26 Oct 2007 16:10:02 -0700 Subject: i915: suspend/resume support Add suspend/resume support to the i915 driver. Moves some of the initialization into the driver load routine, and fixes up places where we assumed no dev_private existed in some of the cleanup paths. This allows us to suspend/resume properly even if X isn't running. --- linux-core/i915_drv.c | 455 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 455 insertions(+) (limited to 'linux-core') diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index e337e1d2..f34d218c 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -69,6 +69,458 @@ static struct drm_bo_driver i915_bo_driver = { }; #endif +enum pipe { + PIPE_A = 0, + PIPE_B, +}; + +static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (pipe == PIPE_A) + return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE); + else + return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE); +} + +static void i915_save_palette(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); + u32 *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (pipe == PIPE_A) + array = dev_priv->save_palette_a; + else + array = dev_priv->save_palette_b; + + for(i = 0; i < 256; i++) + array[i] = I915_READ(reg + (i << 2)); +} + +static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); + u32 *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (pipe == PIPE_A) + array = dev_priv->save_palette_a; + else + array = dev_priv->save_palette_b; + + for(i = 0; i < 256; i++) + I915_WRITE(reg + (i << 2), array[i]); +} + +static u8 i915_read_indexed(u16 index_port, u16 data_port, u8 reg) +{ + outb(reg, index_port); + return inb(data_port); +} + +static u8 i915_read_ar(u16 st01, u8 reg, u16 palette_enable) +{ + inb(st01); + outb(palette_enable | reg, VGA_AR_INDEX); + return inb(VGA_AR_DATA_READ); +} + +static void i915_write_ar(u8 st01, u8 reg, u8 val, u16 palette_enable) +{ + inb(st01); + outb(palette_enable | reg, VGA_AR_INDEX); + outb(val, VGA_AR_DATA_WRITE); +} + +static void i915_write_indexed(u16 index_port, u16 data_port, u8 reg, u8 val) +{ + outb(reg, index_port); + outb(val, data_port); +} + +static void i915_save_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + u16 cr_index, cr_data, st01; + + /* VGA color palette registers */ + dev_priv->saveDACMASK = inb(VGA_DACMASK); + /* DACCRX automatically increments during read */ + outb(0, VGA_DACRX); + /* Read 3 bytes of color data from each index */ + for (i = 0; i < 256 * 3; i++) + dev_priv->saveDACDATA[i] = inb(VGA_DACDATA); + + /* MSR bits */ + dev_priv->saveMSR = inb(VGA_MSR_READ); + if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { + cr_index = VGA_CR_INDEX_CGA; + cr_data = VGA_CR_DATA_CGA; + st01 = VGA_ST01_CGA; + } else { + cr_index = VGA_CR_INDEX_MDA; + cr_data = VGA_CR_DATA_MDA; + st01 = VGA_ST01_MDA; + } + + /* CRT controller regs */ + i915_write_indexed(cr_index, cr_data, 0x11, + i915_read_indexed(cr_index, cr_data, 0x11) & + (~0x80)); + for (i = 0; i < 0x24; i++) + dev_priv->saveCR[i] = + i915_read_indexed(cr_index, cr_data, i); + /* Make sure we don't turn off CR group 0 writes */ + dev_priv->saveCR[0x11] &= ~0x80; + + /* Attribute controller registers */ + inb(st01); + dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX); + for (i = 0; i < 20; i++) + dev_priv->saveAR[i] = i915_read_ar(st01, i, 0); + inb(st01); + outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX); + + /* Graphics controller registers */ + for (i = 0; i < 9; i++) + dev_priv->saveGR[i] = + i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, i); + + dev_priv->saveGR[0x10] = + i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10); + dev_priv->saveGR[0x11] = + i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11); + dev_priv->saveGR[0x18] = + i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18); + + /* Sequencer registers */ + for (i = 0; i < 8; i++) + dev_priv->saveSR[i] = + i915_read_indexed(VGA_SR_INDEX, VGA_SR_DATA, i); +} + +static void i915_restore_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + u16 cr_index, cr_data, st01; + + /* MSR bits */ + outb(dev_priv->saveMSR, VGA_MSR_WRITE); + if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { + cr_index = VGA_CR_INDEX_CGA; + cr_data = VGA_CR_DATA_CGA; + st01 = VGA_ST01_CGA; + } else { + cr_index = VGA_CR_INDEX_MDA; + cr_data = VGA_CR_DATA_MDA; + st01 = VGA_ST01_MDA; + } + + /* Sequencer registers, don't write SR07 */ + for (i = 0; i < 7; i++) + i915_write_indexed(VGA_SR_INDEX, VGA_SR_DATA, i, + dev_priv->saveSR[i]); + + /* CRT controller regs */ + /* Enable CR group 0 writes */ + i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]); + for (i = 0; i < 0x24; i++) + i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]); + + /* Graphics controller regs */ + for (i = 0; i < 9; i++) + i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, i, + dev_priv->saveGR[i]); + + i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10, + dev_priv->saveGR[0x10]); + i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11, + dev_priv->saveGR[0x11]); + i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18, + dev_priv->saveGR[0x18]); + + /* Attribute controller registers */ + for (i = 0; i < 20; i++) + i915_write_ar(st01, i, dev_priv->saveAR[i], 0); + inb(st01); /* switch back to index mode */ + outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX); + + /* VGA color palette registers */ + outb(dev_priv->saveDACMASK, VGA_DACMASK); + /* DACCRX automatically increments during read */ + outb(0, VGA_DACWX); + /* Read 3 bytes of color data from each index */ + for (i = 0; i < 256 * 3; i++) + outb(dev_priv->saveDACDATA[i], VGA_DACDATA); + +} + +static int i915_suspend(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + if (!dev || !dev_priv) { + printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv); + printk(KERN_ERR "DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } + + pci_save_state(dev->pdev); + pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); + + /* Pipe & plane A info */ + dev_priv->savePIPEACONF = I915_READ(PIPEACONF); + dev_priv->savePIPEASRC = I915_READ(PIPEASRC); + dev_priv->saveFPA0 = I915_READ(FPA0); + dev_priv->saveFPA1 = I915_READ(FPA1); + dev_priv->saveDPLL_A = I915_READ(DPLL_A); + if (IS_I965G(dev)) + dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD); + dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A); + dev_priv->saveHBLANK_A = I915_READ(HBLANK_A); + dev_priv->saveHSYNC_A = I915_READ(HSYNC_A); + dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A); + dev_priv->saveVBLANK_A = I915_READ(VBLANK_A); + dev_priv->saveVSYNC_A = I915_READ(VSYNC_A); + dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); + + dev_priv->saveDSPACNTR = I915_READ(DSPACNTR); + dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE); + dev_priv->saveDSPASIZE = I915_READ(DSPASIZE); + dev_priv->saveDSPAPOS = I915_READ(DSPAPOS); + dev_priv->saveDSPABASE = I915_READ(DSPABASE); + if (IS_I965G(dev)) { + dev_priv->saveDSPASURF = I915_READ(DSPASURF); + dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); + } + i915_save_palette(dev, PIPE_A); + + /* Pipe & plane B info */ + dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); + dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); + dev_priv->saveFPB0 = I915_READ(FPB0); + dev_priv->saveFPB1 = I915_READ(FPB1); + dev_priv->saveDPLL_B = I915_READ(DPLL_B); + if (IS_I965G(dev)) + dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD); + dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B); + dev_priv->saveHBLANK_B = I915_READ(HBLANK_B); + dev_priv->saveHSYNC_B = I915_READ(HSYNC_B); + dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B); + dev_priv->saveVBLANK_B = I915_READ(VBLANK_B); + dev_priv->saveVSYNC_B = I915_READ(VSYNC_B); + dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); + + dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR); + dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE); + dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); + dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); + dev_priv->saveDSPBBASE = I915_READ(DSPBBASE); + if (IS_I965GM(dev)) { + dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); + dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); + } + i915_save_palette(dev, PIPE_B); + + /* CRT state */ + dev_priv->saveADPA = I915_READ(ADPA); + + /* LVDS state */ + dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); + dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); + dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + if (IS_I965G(dev)) + dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); + if (IS_MOBILE(dev) && !IS_I830(dev)) + dev_priv->saveLVDS = I915_READ(LVDS); + if (!IS_I830(dev) && !IS_845G(dev)) + dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); + dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON); + dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF); + dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE); + + /* FIXME: save TV & SDVO state */ + + /* FBC state */ + dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); + dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE); + dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); + dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); + + /* VGA state */ + dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); + dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); + dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); + dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); + + /* Scratch space */ + for (i = 0; i < 16; i++) { + dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2)); + dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2)); + } + for (i = 0; i < 3; i++) + dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2)); + + i915_save_vga(dev); + + /* Shut down the device */ + pci_disable_device(dev->pdev); + pci_set_power_state(dev->pdev, PCI_D3hot); + + return 0; +} + +static int i915_resume(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + pci_set_power_state(dev->pdev, PCI_D0); + pci_restore_state(dev->pdev); + if (pci_enable_device(dev->pdev)) + return -1; + + pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); + + /* Pipe & plane A info */ + /* Prime the clock */ + if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A & + ~DPLL_VCO_ENABLE); + udelay(150); + } + I915_WRITE(FPA0, dev_priv->saveFPA0); + I915_WRITE(FPA1, dev_priv->saveFPA1); + /* Actually enable it */ + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A); + udelay(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); + udelay(150); + + /* Restore mode */ + I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); + I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A); + I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A); + I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); + I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); + I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); + I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); + + /* Restore plane info */ + I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); + I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); + I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); + I915_WRITE(DSPABASE, dev_priv->saveDSPABASE); + I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); + if (IS_I965G(dev)) { + I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); + I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); + } + I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); + i915_restore_palette(dev, PIPE_A); + /* Enable the plane */ + I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); + I915_WRITE(DSPABASE, I915_READ(DSPABASE)); + + /* Pipe & plane B info */ + if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B & + ~DPLL_VCO_ENABLE); + udelay(150); + } + I915_WRITE(FPB0, dev_priv->saveFPB0); + I915_WRITE(FPB1, dev_priv->saveFPB1); + /* Actually enable it */ + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); + udelay(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); + udelay(150); + + /* Restore mode */ + I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); + I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B); + I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B); + I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); + I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); + I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); + I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); + + /* Restore plane info */ + I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); + I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); + I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); + I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE); + I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); + if (IS_I965G(dev)) { + I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); + I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); + } + I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); + i915_restore_palette(dev, PIPE_A); + /* Enable the plane */ + I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); + I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); + + /* CRT state */ + I915_WRITE(ADPA, dev_priv->saveADPA); + + /* LVDS state */ + if (IS_I965G(dev)) + I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); + if (IS_MOBILE(dev) && !IS_I830(dev)) + I915_WRITE(LVDS, dev_priv->saveLVDS); + if (!IS_I830(dev) && !IS_845G(dev)) + I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); + + I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); + I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); + I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON); + I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF); + I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE); + I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); + + /* FIXME: restore TV & SDVO state */ + + /* FBC info */ + I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE); + I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE); + I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2); + I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL); + + /* VGA state */ + I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); + I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0); + I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1); + I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); + udelay(150); + + for (i = 0; i < 16; i++) { + I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]); + I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); + } + for (i = 0; i < 3; i++) + I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); + + i915_restore_vga(dev); + + return 0; +} + static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { /* don't use mtrr's here, the Xserver or user space app should @@ -79,9 +531,12 @@ static struct drm_driver driver = { DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, .load = i915_driver_load, + .unload = i915_driver_unload, .firstopen = i915_driver_firstopen, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, + .suspend = i915_suspend, + .resume = i915_resume, .device_is_agp = i915_driver_device_is_agp, .vblank_wait = i915_driver_vblank_wait, .vblank_wait2 = i915_driver_vblank_wait2, -- cgit v1.2.3 From ff5889f8316e0c16112f114c1c8f57645b8dc54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 29 Oct 2007 19:32:32 -0400 Subject: Move struct drm_drawable_info out of public header file. --- linux-core/drmP.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 82a3a23c..ac3ca4d2 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -586,6 +586,15 @@ struct drm_vbl_sig { struct task_struct *task; }; +/** + * Drawable information. + */ +struct drm_drawable_info { + unsigned int num_rects; + struct drm_clip_rect *rects; +}; + + /* location of GART table */ #define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_FB 2 -- cgit v1.2.3 From 50dec29c800a6e980a01be38190e44a0ba7916b5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 30 Oct 2007 17:51:59 +1000 Subject: drm/i915: add driver cache flush entry point Use clflush on Intel hardware to flush cached objects. --- linux-core/drm_objects.h | 1 + linux-core/drm_ttm.c | 7 +++++-- linux-core/i915_buffer.c | 33 +++++++++++++++++++++++++++++++++ linux-core/i915_drv.c | 1 + 4 files changed, 40 insertions(+), 2 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 8b14ac6f..cea811eb 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -464,6 +464,7 @@ struct drm_bo_driver { uint32_t(*evict_mask) (struct drm_buffer_object *bo); int (*move) (struct drm_buffer_object * bo, int evict, int no_wait, struct drm_bo_mem_reg * new_mem); + void (*ttm_cache_flush)(struct drm_ttm *ttm); }; /* diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 33bbe1d4..df9e7e44 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -207,6 +207,7 @@ struct page *drm_ttm_get_page(struct drm_ttm * ttm, int index) } return p; } +EXPORT_SYMBOL(drm_ttm_get_page); int drm_ttm_populate(struct drm_ttm * ttm) { @@ -311,7 +312,7 @@ void drm_ttm_unbind(struct drm_ttm * ttm) int drm_bind_ttm(struct drm_ttm * ttm, struct drm_bo_mem_reg *bo_mem) { - + struct drm_bo_driver *bo_driver = ttm->dev->driver->bo_driver; int ret = 0; struct drm_ttm_backend *be; @@ -328,7 +329,9 @@ int drm_bind_ttm(struct drm_ttm * ttm, struct drm_bo_mem_reg *bo_mem) if (ttm->state == ttm_unbound && !(bo_mem->flags & DRM_BO_FLAG_CACHED)) { drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); - } + } else if ((bo_mem->flags & DRM_BO_FLAG_CACHED) && + bo_driver->ttm_cache_flush) + bo_driver->ttm_cache_flush(ttm); if ((ret = be->func->bind(be, bo_mem))) { ttm->state = ttm_evicted; diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index f81def8f..bbc7e1db 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -249,3 +249,36 @@ int i915_move(struct drm_buffer_object * bo, } return 0; } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) +static inline void clflush(volatile void *__p) +{ + asm volatile("clflush %0" : "+m" (*(char __force *)__p)); +} +#endif + +static inline void drm_cache_flush_addr(void *virt) +{ + int i; + + for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) + clflush(virt+i); +} + +static inline void drm_cache_flush_page(struct page *p) +{ + drm_cache_flush_addr(page_address(p)); +} + +void i915_flush_ttm(struct drm_ttm *ttm) +{ + int i; + + if (!ttm) + return; + + DRM_MEMORYBARRIER(); + for (i = ttm->num_pages-1; i >= 0; i--) + drm_cache_flush_page(drm_ttm_get_page(ttm, i)); + DRM_MEMORYBARRIER(); +} diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index f34d218c..124db68f 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -66,6 +66,7 @@ static struct drm_bo_driver i915_bo_driver = { .init_mem_type = i915_init_mem_type, .evict_mask = i915_evict_mask, .move = i915_move, + .ttm_cache_flush = i915_flush_ttm, }; #endif -- cgit v1.2.3 From c106a7d8b9ddc1f6da3d462e3114af2ca72b3b46 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 31 Oct 2007 11:21:05 +1100 Subject: drm: call driver load after initing agp subsystem --- linux-core/drm_stub.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 1d88d375..dabd174b 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -111,10 +111,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, dev->driver = driver; - if (dev->driver->load) - if ((retcode = dev->driver->load(dev, ent->driver_data))) - goto error_out_unreg; - if (drm_core_has_AGP(dev)) { if (drm_device_is_agp(dev)) dev->agp = drm_agp_init(dev); @@ -134,6 +130,11 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, } } + if (dev->driver->load) + if ((retcode = dev->driver->load(dev, ent->driver_data))) + goto error_out_unreg; + + retcode = drm_ctxbitmap_init(dev); if (retcode) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); -- cgit v1.2.3 From 2489062a3319c72197914ee06b089ae581c5f0a8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 31 Oct 2007 11:27:44 +1100 Subject: i915: add backwards compat chipset flushing code --- linux-core/Makefile.kernel | 2 +- linux-core/i915_compat.c | 141 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 linux-core/i915_compat.c (limited to 'linux-core') diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 79136431..f1ae28e6 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -19,7 +19,7 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ - i915_buffer.o + i915_buffer.o i915_compat.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o nouveau_notifier.o nouveau_swmthd.o \ nouveau_sgdma.o nouveau_dma.o \ diff --git a/linux-core/i915_compat.c b/linux-core/i915_compat.c new file mode 100644 index 00000000..86eb1e1c --- /dev/null +++ b/linux-core/i915_compat.c @@ -0,0 +1,141 @@ +#include "drmP.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + +#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970 +#define PCI_DEVICE_ID_INTEL_82965G_1_HB 0x2980 +#define PCI_DEVICE_ID_INTEL_82965Q_HB 0x2990 +#define PCI_DEVICE_ID_INTEL_82965G_HB 0x29A0 +#define PCI_DEVICE_ID_INTEL_82965GM_HB 0x2A00 +#define PCI_DEVICE_ID_INTEL_82965GME_HB 0x2A10 +#define PCI_DEVICE_ID_INTEL_82945GME_HB 0x27AC +#define PCI_DEVICE_ID_INTEL_G33_HB 0x29C0 +#define PCI_DEVICE_ID_INTEL_Q35_HB 0x29B0 +#define PCI_DEVICE_ID_INTEL_Q33_HB 0x29D0 + +#define IS_I965 (agp_dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \ + agp_dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \ + agp_dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \ + agp_dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ + agp_dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \ + agp_dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB) + +#define IS_G33 (agp_dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \ + agp_dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \ + agp_dev->device == PCI_DEVICE_ID_INTEL_Q33_HB) + +#define I915_IFPADDR 0x60 +#define I965_IFPADDR 0x70 + +static struct _intel_private_compat { + void __iomem *flush_page; + struct resource ifp_resource; +} intel_private; + +static void +intel_compat_align_resource(void *data, struct resource *res, + resource_size_t size, resource_size_t align) +{ + return; +} + + +static int intel_alloc_chipset_flush_resource(struct pci_dev *pdev) +{ + int ret; + ret = pci_bus_alloc_resource(pdev->bus, &intel_private.ifp_resource, PAGE_SIZE, + PAGE_SIZE, PCIBIOS_MIN_MEM, 0, + intel_compat_align_resource, pdev); + if (ret != 0) + return ret; + + return 0; +} + +static void intel_i915_setup_chipset_flush(struct pci_dev *pdev) +{ + int ret; + u32 temp; + + pci_read_config_dword(pdev, I915_IFPADDR, &temp); + if (!(temp & 0x1)) { + intel_alloc_chipset_flush_resource(pdev); + + pci_write_config_dword(pdev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); + } else { + temp &= ~1; + + intel_private.ifp_resource.start = temp; + intel_private.ifp_resource.end = temp + PAGE_SIZE; + ret = request_resource(&iomem_resource, &intel_private.ifp_resource); + if (ret) { + intel_private.ifp_resource.start = 0; + printk("Failed inserting resource into tree\n"); + } + } +} + +static void intel_i965_g33_setup_chipset_flush(struct pci_dev *pdev) +{ + u32 temp_hi, temp_lo; + int ret; + + pci_read_config_dword(pdev, I965_IFPADDR + 4, &temp_hi); + pci_read_config_dword(pdev, I965_IFPADDR, &temp_lo); + + if (!(temp_lo & 0x1)) { + + intel_alloc_chipset_flush_resource(pdev); + + pci_write_config_dword(pdev, I965_IFPADDR + 4, (intel_private.ifp_resource.start >> 32)); + pci_write_config_dword(pdev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); + intel_private.flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); + } else { + u64 l64; + + temp_lo &= ~0x1; + l64 = ((u64)temp_hi << 32) | temp_lo; + + intel_private.ifp_resource.start = l64; + intel_private.ifp_resource.end = l64 + PAGE_SIZE; + ret = request_resource(&iomem_resource, &intel_private.ifp_resource); + if (!ret) { + intel_private.ifp_resource.start = 0; + printk("Failed inserting resource into tree\n"); + } + } +} + +void intel_init_chipset_flush_compat(struct drm_device *dev) +{ + struct pci_dev *agp_dev = dev->agp->agp_info.device; + + intel_private.ifp_resource.name = "GMCH IFPBAR"; + intel_private.ifp_resource.flags = IORESOURCE_MEM; + + /* Setup chipset flush for 915 */ + if (IS_I965 || IS_G33) { + intel_i965_g33_setup_chipset_flush(agp_dev); + } else { + intel_i915_setup_chipset_flush(agp_dev); + } + + if (intel_private.ifp_resource.start) { + intel_private.flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); + if (!intel_private.flush_page) + printk("unable to ioremap flush page - no chipset flushing"); + } +} + +void intel_fini_chipset_flush_compat(struct drm_device *dev) +{ + iounmap(intel_private.flush_page); + release_resource(&intel_private.ifp_resource); +} + +void drm_agp_chipset_flush(struct drm_device *dev) +{ + if (intel_private.flush_page) + writel(1, intel_private.flush_page); +} +#endif -- cgit v1.2.3 From 17f0882d5080a2436e4351c2bf497b8e00bc8e74 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 31 Oct 2007 11:33:34 +1100 Subject: drm: add chipset flushing via agp support --- linux-core/drmP.h | 1 + linux-core/drm_agpsupport.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index ac3ca4d2..c014eddf 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1133,6 +1133,7 @@ extern int drm_agp_free_memory(DRM_AGP_MEM * handle); extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start); extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); extern struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev); +extern void drm_agp_chipset_flush(struct drm_device *dev); /* Stub support (drm_stub.h) */ extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index b68efc64..8c7f570e 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -650,4 +650,12 @@ struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev) } EXPORT_SYMBOL(drm_agp_init_ttm); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) +void drm_agp_flush_chipset(struct drm_device *dev) +{ + agp_flush_chipset(dev->agp->bridge); +} +EXPORT_SYMBOL(drm_agp_flush_chipset); +#endif + #endif /* __OS_HAS_AGP */ -- cgit v1.2.3 From 6b0b2546c29858866ae1986b3b7254551245967e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 1 Nov 2007 02:00:36 +1000 Subject: i915: fix compat code on 965/g33 --- linux-core/i915_compat.c | 1 - 1 file changed, 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/i915_compat.c b/linux-core/i915_compat.c index 86eb1e1c..969d5977 100644 --- a/linux-core/i915_compat.c +++ b/linux-core/i915_compat.c @@ -89,7 +89,6 @@ static void intel_i965_g33_setup_chipset_flush(struct pci_dev *pdev) pci_write_config_dword(pdev, I965_IFPADDR + 4, (intel_private.ifp_resource.start >> 32)); pci_write_config_dword(pdev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); - intel_private.flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); } else { u64 l64; -- cgit v1.2.3 From 61cbcb5dbe487c6d4eba04794cbaa0279ab807b0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 1 Nov 2007 10:34:11 +1100 Subject: drm/ttm: add support for cached un-snooped mappings. This mapping allows cached objects to be mapped in/out of the TT space with the appropriate flushing calls. It should put back the old CACHED functionality for snooped mappings --- linux-core/drm_agpsupport.c | 8 ++++++-- linux-core/drm_bo.c | 18 ++++++++---------- linux-core/drm_ttm.c | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 8c7f570e..7c50f411 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -541,11 +541,15 @@ static int drm_agp_bind_ttm(struct drm_ttm_backend *backend, container_of(backend, struct drm_agp_ttm_backend, backend); DRM_AGP_MEM *mem = agp_be->mem; int ret; + int snooped = (bo_mem->flags & DRM_BO_FLAG_CACHED) && !(bo_mem->flags & DRM_BO_FLAG_CACHED_MAPPED); DRM_DEBUG("drm_agp_bind_ttm\n"); mem->is_flushed = TRUE; - mem->type = (bo_mem->flags & DRM_BO_FLAG_CACHED) ? AGP_USER_CACHED_MEMORY : - AGP_USER_MEMORY; + mem->type = AGP_USER_MEMORY; + /* CACHED MAPPED implies not snooped memory */ + if (snooped) + mem->type = AGP_USER_CACHED_MEMORY; + ret = drm_agp_bind_memory(mem, bo_mem->mm_node->start); if (ret) { DRM_ERROR("AGP Bind memory failed\n"); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 16203c77..dc96e8aa 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -806,6 +806,9 @@ static int drm_bo_mt_compatible(struct drm_mem_type_manager * man, } flag_diff = (mask ^ cur_flags); + if (flag_diff & DRM_BO_FLAG_CACHED_MAPPED) + cur_flags |= DRM_BO_FLAG_CACHED_MAPPED; + if ((flag_diff & DRM_BO_FLAG_CACHED) && (!(mask & DRM_BO_FLAG_CACHED) || (mask & DRM_BO_FLAG_FORCE_CACHING))) @@ -1029,7 +1032,7 @@ static int drm_bo_busy(struct drm_buffer_object * bo) return 0; } -static int drm_bo_read_cached(struct drm_buffer_object * bo) +static int drm_bo_evict_cached(struct drm_buffer_object * bo) { int ret = 0; @@ -1177,15 +1180,11 @@ static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle, goto out; } - if ((map_flags & DRM_BO_FLAG_READ) && - (bo->mem.flags & DRM_BO_FLAG_READ_CACHED) && - (!(bo->mem.flags & DRM_BO_FLAG_CACHED))) { - drm_bo_read_cached(bo); - } + if (bo->mem.flags & DRM_BO_FLAG_CACHED_MAPPED) + drm_bo_evict_cached(bo); + break; - } else if ((map_flags & DRM_BO_FLAG_READ) && - (bo->mem.flags & DRM_BO_FLAG_READ_CACHED) && - (!(bo->mem.flags & DRM_BO_FLAG_CACHED))) { + } else if (bo->mem.flags & DRM_BO_FLAG_CACHED_MAPPED) { /* * We are already mapped with different flags. @@ -1666,7 +1665,6 @@ int drm_buffer_object_create(struct drm_device *dev, DRM_BO_FLAG_MAPPABLE; atomic_inc(&bm->count); ret = drm_bo_new_mask(bo, mask, hint); - if (ret) goto out_err; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index df9e7e44..fd03f6e8 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -329,7 +329,7 @@ int drm_bind_ttm(struct drm_ttm * ttm, struct drm_bo_mem_reg *bo_mem) if (ttm->state == ttm_unbound && !(bo_mem->flags & DRM_BO_FLAG_CACHED)) { drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); - } else if ((bo_mem->flags & DRM_BO_FLAG_CACHED) && + } else if ((bo_mem->flags & DRM_BO_FLAG_CACHED_MAPPED) && bo_driver->ttm_cache_flush) bo_driver->ttm_cache_flush(ttm); -- cgit v1.2.3 From 31847b4b62575739a164e019b33ced0531683403 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Wed, 31 Oct 2007 20:13:01 -0400 Subject: nouveau: ttm stubs --- linux-core/Makefile.kernel | 2 +- linux-core/nouveau_drv.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'linux-core') diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index f1ae28e6..bcbd78f2 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -22,7 +22,7 @@ i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ i915_buffer.o i915_compat.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o nouveau_notifier.o nouveau_swmthd.o \ - nouveau_sgdma.o nouveau_dma.o \ + nouveau_sgdma.o nouveau_dma.o nouveau_buffer.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o nv50_mc.o \ nv04_fb.o nv10_fb.o nv40_fb.o \ diff --git a/linux-core/nouveau_drv.c b/linux-core/nouveau_drv.c index 01de67de..9e6c8f41 100644 --- a/linux-core/nouveau_drv.c +++ b/linux-core/nouveau_drv.c @@ -41,6 +41,25 @@ static struct pci_device_id pciidlist[] = { } }; +#ifdef NOUVEAU_HAVE_BUFFER +static uint32_t nouveau_mem_prios[] = { DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL }; +static uint32_t nouveau_busy_prios[] = { DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL }; + +static struct drm_bo_driver nouveau_bo_driver = { + .mem_type_prio = nouveau_mem_prios, + .mem_busy_prio = nouveau_busy_prios, + .num_mem_type_prio = sizeof(nouveau_mem_prios)/sizeof(uint32_t), + .num_mem_busy_prio = sizeof(nouveau_busy_prios)/sizeof(uint32_t), + .create_ttm_backend_entry = nouveau_create_ttm_backend_entry, + .fence_type = nouveau_fence_types, + .invalidate_caches = nouveau_invalidate_caches, + .init_mem_type = nouveau_init_mem_type, + .evict_mask = nouveau_evict_mask, + .move = nouveau_move, + .ttm_cache_flush= nouveau_flush_ttm +}; +#endif + extern struct drm_ioctl_desc nouveau_ioctls[]; extern int nouveau_max_ioctl; @@ -80,6 +99,9 @@ static struct drm_driver driver = { .probe = probe, .remove = __devexit_p(drm_cleanup_pci), }, +#ifdef NOUVEAU_HAVE_BUFFER + .bo_driver = &nouveau_bo_driver, +#endif .name = DRIVER_NAME, .desc = DRIVER_DESC, -- cgit v1.2.3 From 1b176e76134224e2af94d24ff7b33c7b536eaeea Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Wed, 31 Oct 2007 21:27:00 -0400 Subject: nouveau: add missing file. --- linux-core/nouveau_buffer.c | 145 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 linux-core/nouveau_buffer.c (limited to 'linux-core') diff --git a/linux-core/nouveau_buffer.c b/linux-core/nouveau_buffer.c new file mode 100644 index 00000000..e9f09eb3 --- /dev/null +++ b/linux-core/nouveau_buffer.c @@ -0,0 +1,145 @@ +/* + * Copyright 2005 Stephane Marchesin. + * 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 + * VA LINUX SYSTEMS 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. + */ +/* + * Authors: Jeremy Kolb + */ + +#include "drmP.h" +#include "nouveau_drm.h" +#include "nouveau_drv.h" + +#ifdef NOUVEAU_HAVE_BUFFER + +struct drm_ttm_backend *nouveau_create_ttm_backend_entry(struct drm_device * dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + return drm_agp_init_ttm(dev); +} + +int nouveau_fence_types(struct drm_buffer_object *bo, + uint32_t *fclass, + uint32_t *type) +{ + *fclass = 0; + + if (bo->mem.mask & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) + *type = 3; + else + *type = 1; + return 0; + +} +int nouveau_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags) +{ + /* We'll do this from user space. */ + return 0; +} + +int nouveau_init_mem_type(struct drm_device *dev, + uint32_t type, + struct drm_mem_type_manager *man) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + switch (type) { + case DRM_BO_MEM_LOCAL: + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CACHED; + man->drm_bus_maptype = 0; + break; + + case DRM_BO_MEM_VRAM: + man->flags = _DRM_FLAG_MEMTYPE_FIXED | + _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_NEEDS_IOREMAP; + man->io_addr = NULL; + man->drm_bus_maptype = _DRM_FRAME_BUFFER; + man->io_offset = drm_get_resource_start(dev, 0); + man->io_size = drm_get_resource_len(dev, 0); + break; + + case DRM_BO_MEM_TT: + if (!(drm_core_has_AGP(dev) && dev->agp)) { + DRM_ERROR("AGP is not enabled for memory type %u\n", + (unsigned)type); + return -EINVAL; + } + + man->io_offset = dev->agp->agp_info.aper_base; + man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; + man->drm_bus_maptype = _DRM_AGP; + break; + + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + return -EINVAL; + } + return 0; +} + +uint32_t nouveau_evict_mask(struct drm_buffer_object *bo) +{ + switch (bo->mem.mem_type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return DRM_BO_FLAG_MEM_LOCAL; + case DRM_BO_MEM_VRAM: + if (bo->mem.num_pages > 128) + return DRM_BO_MEM_TT; + else + return DRM_BO_MEM_LOCAL; + default: + return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; + } + +} + +int nouveau_move(struct drm_buffer_object *bo, + int evict, + int no_wait, + struct drm_bo_mem_reg *new_mem) +{ + struct drm_bo_mem_reg *old_mem = &bo->mem; + + if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } + else { + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } + return 0; +} + +void nouveau_flush_ttm(struct drm_ttm *ttm) +{ + +} + +#endif -- cgit v1.2.3