diff options
34 files changed, 1628 insertions, 667 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4d350b5cbc71..4aa4180b106c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -1049,9 +1049,9 @@ config MTRR | |||
1049 | See <file:Documentation/mtrr.txt> for more information. | 1049 | See <file:Documentation/mtrr.txt> for more information. |
1050 | 1050 | ||
1051 | config X86_PAT | 1051 | config X86_PAT |
1052 | def_bool y | 1052 | bool |
1053 | prompt "x86 PAT support" | 1053 | prompt "x86 PAT support" |
1054 | depends on MTRR && NONPROMISC_DEVMEM | 1054 | depends on MTRR |
1055 | help | 1055 | help |
1056 | Use PAT attributes to setup page level cache control. | 1056 | Use PAT attributes to setup page level cache control. |
1057 | 1057 | ||
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index d28669992147..96bdb9296b07 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c | |||
@@ -436,8 +436,9 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, | |||
436 | system controller may experience noise due to strong drive strengths | 436 | system controller may experience noise due to strong drive strengths |
437 | */ | 437 | */ |
438 | if (agp_bridge->dev->device == PCI_DEVICE_ID_AMD_FE_GATE_7006) { | 438 | if (agp_bridge->dev->device == PCI_DEVICE_ID_AMD_FE_GATE_7006) { |
439 | u8 cap_ptr=0; | ||
440 | struct pci_dev *gfxcard=NULL; | 439 | struct pci_dev *gfxcard=NULL; |
440 | |||
441 | cap_ptr = 0; | ||
441 | while (!cap_ptr) { | 442 | while (!cap_ptr) { |
442 | gfxcard = pci_get_class(PCI_CLASS_DISPLAY_VGA<<8, gfxcard); | 443 | gfxcard = pci_get_class(PCI_CLASS_DISPLAY_VGA<<8, gfxcard); |
443 | if (!gfxcard) { | 444 | if (!gfxcard) { |
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 55d7a82bd071..857b26227d87 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c | |||
@@ -967,7 +967,7 @@ int agpioc_chipset_flush_wrap(struct agp_file_private *priv) | |||
967 | return 0; | 967 | return 0; |
968 | } | 968 | } |
969 | 969 | ||
970 | static int agp_ioctl(struct inode *inode, struct file *file, | 970 | static long agp_ioctl(struct file *file, |
971 | unsigned int cmd, unsigned long arg) | 971 | unsigned int cmd, unsigned long arg) |
972 | { | 972 | { |
973 | struct agp_file_private *curr_priv = file->private_data; | 973 | struct agp_file_private *curr_priv = file->private_data; |
@@ -1058,7 +1058,7 @@ static const struct file_operations agp_fops = | |||
1058 | .llseek = no_llseek, | 1058 | .llseek = no_llseek, |
1059 | .read = agp_read, | 1059 | .read = agp_read, |
1060 | .write = agp_write, | 1060 | .write = agp_write, |
1061 | .ioctl = agp_ioctl, | 1061 | .unlocked_ioctl = agp_ioctl, |
1062 | #ifdef CONFIG_COMPAT | 1062 | #ifdef CONFIG_COMPAT |
1063 | .compat_ioctl = compat_agp_ioctl, | 1063 | .compat_ioctl = compat_agp_ioctl, |
1064 | #endif | 1064 | #endif |
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index 141f4dfa0a11..b710426bab3e 100644 --- a/drivers/char/drm/ati_pcigart.c +++ b/drivers/char/drm/ati_pcigart.c | |||
@@ -167,13 +167,6 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga | |||
167 | page_base += ATI_PCIGART_PAGE_SIZE; | 167 | page_base += ATI_PCIGART_PAGE_SIZE; |
168 | } | 168 | } |
169 | } | 169 | } |
170 | |||
171 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) | ||
172 | dma_sync_single_for_device(&dev->pdev->dev, | ||
173 | bus_address, | ||
174 | max_pages * sizeof(u32), | ||
175 | PCI_DMA_TODEVICE); | ||
176 | |||
177 | ret = 1; | 170 | ret = 1; |
178 | 171 | ||
179 | #if defined(__i386__) || defined(__x86_64__) | 172 | #if defined(__i386__) || defined(__x86_64__) |
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index 3a05c6d5ebe1..6874f31ca8ca 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h | |||
@@ -471,6 +471,7 @@ struct drm_irq_busid { | |||
471 | enum drm_vblank_seq_type { | 471 | enum drm_vblank_seq_type { |
472 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ | 472 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ |
473 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ | 473 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ |
474 | _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ | ||
474 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ | 475 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ |
475 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ | 476 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ |
476 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ | 477 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ |
@@ -503,6 +504,21 @@ union drm_wait_vblank { | |||
503 | struct drm_wait_vblank_reply reply; | 504 | struct drm_wait_vblank_reply reply; |
504 | }; | 505 | }; |
505 | 506 | ||
507 | enum drm_modeset_ctl_cmd { | ||
508 | _DRM_PRE_MODESET = 1, | ||
509 | _DRM_POST_MODESET = 2, | ||
510 | }; | ||
511 | |||
512 | /** | ||
513 | * DRM_IOCTL_MODESET_CTL ioctl argument type | ||
514 | * | ||
515 | * \sa drmModesetCtl(). | ||
516 | */ | ||
517 | struct drm_modeset_ctl { | ||
518 | unsigned long arg; | ||
519 | enum drm_modeset_ctl_cmd cmd; | ||
520 | }; | ||
521 | |||
506 | /** | 522 | /** |
507 | * DRM_IOCTL_AGP_ENABLE ioctl argument type. | 523 | * DRM_IOCTL_AGP_ENABLE ioctl argument type. |
508 | * | 524 | * |
@@ -587,6 +603,7 @@ struct drm_set_version { | |||
587 | #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) | 603 | #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) |
588 | #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) | 604 | #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) |
589 | #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) | 605 | #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) |
606 | #define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) | ||
590 | 607 | ||
591 | #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) | 608 | #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) |
592 | #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) | 609 | #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) |
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 6540948d5176..ecee3547a13f 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h | |||
@@ -100,10 +100,8 @@ struct drm_device; | |||
100 | #define DRIVER_HAVE_DMA 0x20 | 100 | #define DRIVER_HAVE_DMA 0x20 |
101 | #define DRIVER_HAVE_IRQ 0x40 | 101 | #define DRIVER_HAVE_IRQ 0x40 |
102 | #define DRIVER_IRQ_SHARED 0x80 | 102 | #define DRIVER_IRQ_SHARED 0x80 |
103 | #define DRIVER_IRQ_VBL 0x100 | ||
104 | #define DRIVER_DMA_QUEUE 0x200 | 103 | #define DRIVER_DMA_QUEUE 0x200 |
105 | #define DRIVER_FB_DMA 0x400 | 104 | #define DRIVER_FB_DMA 0x400 |
106 | #define DRIVER_IRQ_VBL2 0x800 | ||
107 | 105 | ||
108 | /***********************************************************************/ | 106 | /***********************************************************************/ |
109 | /** \name Begin the DRM... */ | 107 | /** \name Begin the DRM... */ |
@@ -379,13 +377,12 @@ struct drm_buf_entry { | |||
379 | struct drm_file { | 377 | struct drm_file { |
380 | int authenticated; | 378 | int authenticated; |
381 | int master; | 379 | int master; |
382 | int minor; | ||
383 | pid_t pid; | 380 | pid_t pid; |
384 | uid_t uid; | 381 | uid_t uid; |
385 | drm_magic_t magic; | 382 | drm_magic_t magic; |
386 | unsigned long ioctl_count; | 383 | unsigned long ioctl_count; |
387 | struct list_head lhead; | 384 | struct list_head lhead; |
388 | struct drm_head *head; | 385 | struct drm_minor *minor; |
389 | int remove_auth_on_close; | 386 | int remove_auth_on_close; |
390 | unsigned long lock_count; | 387 | unsigned long lock_count; |
391 | struct file *filp; | 388 | struct file *filp; |
@@ -580,10 +577,52 @@ struct drm_driver { | |||
580 | int (*context_dtor) (struct drm_device *dev, int context); | 577 | int (*context_dtor) (struct drm_device *dev, int context); |
581 | int (*kernel_context_switch) (struct drm_device *dev, int old, | 578 | int (*kernel_context_switch) (struct drm_device *dev, int old, |
582 | int new); | 579 | int new); |
583 | void (*kernel_context_switch_unlock) (struct drm_device *dev); | 580 | void (*kernel_context_switch_unlock) (struct drm_device * dev); |
584 | int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence); | 581 | /** |
585 | int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence); | 582 | * get_vblank_counter - get raw hardware vblank counter |
586 | int (*dri_library_name) (struct drm_device *dev, char *buf); | 583 | * @dev: DRM device |
584 | * @crtc: counter to fetch | ||
585 | * | ||
586 | * Driver callback for fetching a raw hardware vblank counter | ||
587 | * for @crtc. If a device doesn't have a hardware counter, the | ||
588 | * driver can simply return the value of drm_vblank_count and | ||
589 | * make the enable_vblank() and disable_vblank() hooks into no-ops, | ||
590 | * leaving interrupts enabled at all times. | ||
591 | * | ||
592 | * Wraparound handling and loss of events due to modesetting is dealt | ||
593 | * with in the DRM core code. | ||
594 | * | ||
595 | * RETURNS | ||
596 | * Raw vblank counter value. | ||
597 | */ | ||
598 | u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); | ||
599 | |||
600 | /** | ||
601 | * enable_vblank - enable vblank interrupt events | ||
602 | * @dev: DRM device | ||
603 | * @crtc: which irq to enable | ||
604 | * | ||
605 | * Enable vblank interrupts for @crtc. If the device doesn't have | ||
606 | * a hardware vblank counter, this routine should be a no-op, since | ||
607 | * interrupts will have to stay on to keep the count accurate. | ||
608 | * | ||
609 | * RETURNS | ||
610 | * Zero on success, appropriate errno if the given @crtc's vblank | ||
611 | * interrupt cannot be enabled. | ||
612 | */ | ||
613 | int (*enable_vblank) (struct drm_device *dev, int crtc); | ||
614 | |||
615 | /** | ||
616 | * disable_vblank - disable vblank interrupt events | ||
617 | * @dev: DRM device | ||
618 | * @crtc: which irq to enable | ||
619 | * | ||
620 | * Disable vblank interrupts for @crtc. If the device doesn't have | ||
621 | * a hardware vblank counter, this routine should be a no-op, since | ||
622 | * interrupts will have to stay on to keep the count accurate. | ||
623 | */ | ||
624 | void (*disable_vblank) (struct drm_device *dev, int crtc); | ||
625 | int (*dri_library_name) (struct drm_device *dev, char * buf); | ||
587 | 626 | ||
588 | /** | 627 | /** |
589 | * Called by \c drm_device_is_agp. Typically used to determine if a | 628 | * Called by \c drm_device_is_agp. Typically used to determine if a |
@@ -602,7 +641,7 @@ struct drm_driver { | |||
602 | 641 | ||
603 | irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); | 642 | irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); |
604 | void (*irq_preinstall) (struct drm_device *dev); | 643 | void (*irq_preinstall) (struct drm_device *dev); |
605 | void (*irq_postinstall) (struct drm_device *dev); | 644 | int (*irq_postinstall) (struct drm_device *dev); |
606 | void (*irq_uninstall) (struct drm_device *dev); | 645 | void (*irq_uninstall) (struct drm_device *dev); |
607 | void (*reclaim_buffers) (struct drm_device *dev, | 646 | void (*reclaim_buffers) (struct drm_device *dev, |
608 | struct drm_file * file_priv); | 647 | struct drm_file * file_priv); |
@@ -630,16 +669,19 @@ struct drm_driver { | |||
630 | struct pci_driver pci_driver; | 669 | struct pci_driver pci_driver; |
631 | }; | 670 | }; |
632 | 671 | ||
672 | #define DRM_MINOR_UNASSIGNED 0 | ||
673 | #define DRM_MINOR_LEGACY 1 | ||
674 | |||
633 | /** | 675 | /** |
634 | * DRM head structure. This structure represent a video head on a card | 676 | * DRM minor structure. This structure represents a drm minor number. |
635 | * that may contain multiple heads. Embed one per head of these in the | ||
636 | * private drm_device structure. | ||
637 | */ | 677 | */ |
638 | struct drm_head { | 678 | struct drm_minor { |
639 | int minor; /**< Minor device number */ | 679 | int index; /**< Minor device number */ |
680 | int type; /**< Control or render */ | ||
681 | dev_t device; /**< Device number for mknod */ | ||
682 | struct device kdev; /**< Linux device */ | ||
640 | struct drm_device *dev; | 683 | struct drm_device *dev; |
641 | struct proc_dir_entry *dev_root; /**< proc directory entry */ | 684 | struct proc_dir_entry *dev_root; /**< proc directory entry */ |
642 | dev_t device; /**< Device number for mknod */ | ||
643 | }; | 685 | }; |
644 | 686 | ||
645 | /** | 687 | /** |
@@ -647,7 +689,6 @@ struct drm_head { | |||
647 | * may contain multiple heads. | 689 | * may contain multiple heads. |
648 | */ | 690 | */ |
649 | struct drm_device { | 691 | struct drm_device { |
650 | struct device dev; /**< Linux device */ | ||
651 | char *unique; /**< Unique identifier: e.g., busid */ | 692 | char *unique; /**< Unique identifier: e.g., busid */ |
652 | int unique_len; /**< Length of unique field */ | 693 | int unique_len; /**< Length of unique field */ |
653 | char *devname; /**< For /proc/interrupts */ | 694 | char *devname; /**< For /proc/interrupts */ |
@@ -729,13 +770,21 @@ struct drm_device { | |||
729 | /** \name VBLANK IRQ support */ | 770 | /** \name VBLANK IRQ support */ |
730 | /*@{ */ | 771 | /*@{ */ |
731 | 772 | ||
732 | wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ | 773 | wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ |
733 | atomic_t vbl_received; | 774 | atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ |
734 | atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ | ||
735 | spinlock_t vbl_lock; | 775 | spinlock_t vbl_lock; |
736 | struct list_head vbl_sigs; /**< signal list to send on VBLANK */ | 776 | struct list_head *vbl_sigs; /**< signal list to send on VBLANK */ |
737 | struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */ | 777 | atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ |
738 | unsigned int vbl_pending; | 778 | atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ |
779 | u32 *last_vblank; /* protected by dev->vbl_lock, used */ | ||
780 | /* for wraparound handling */ | ||
781 | u32 *vblank_offset; /* used to track how many vblanks */ | ||
782 | int *vblank_enabled; /* so we don't call enable more than | ||
783 | once per disable */ | ||
784 | u32 *vblank_premodeset; /* were lost during modeset */ | ||
785 | struct timer_list vblank_disable_timer; | ||
786 | |||
787 | unsigned long max_vblank_count; /**< size of vblank counter register */ | ||
739 | spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ | 788 | spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ |
740 | void (*locked_tasklet_func)(struct drm_device *dev); | 789 | void (*locked_tasklet_func)(struct drm_device *dev); |
741 | 790 | ||
@@ -755,6 +804,7 @@ struct drm_device { | |||
755 | #ifdef __alpha__ | 804 | #ifdef __alpha__ |
756 | struct pci_controller *hose; | 805 | struct pci_controller *hose; |
757 | #endif | 806 | #endif |
807 | int num_crtcs; /**< Number of CRTCs on this device */ | ||
758 | struct drm_sg_mem *sg; /**< Scatter gather memory */ | 808 | struct drm_sg_mem *sg; /**< Scatter gather memory */ |
759 | void *dev_private; /**< device private data */ | 809 | void *dev_private; /**< device private data */ |
760 | struct drm_sigdata sigdata; /**< For block_all_signals */ | 810 | struct drm_sigdata sigdata; /**< For block_all_signals */ |
@@ -763,7 +813,7 @@ struct drm_device { | |||
763 | struct drm_driver *driver; | 813 | struct drm_driver *driver; |
764 | drm_local_map_t *agp_buffer_map; | 814 | drm_local_map_t *agp_buffer_map; |
765 | unsigned int agp_buffer_token; | 815 | unsigned int agp_buffer_token; |
766 | struct drm_head primary; /**< primary screen head */ | 816 | struct drm_minor *primary; /**< render type primary screen head */ |
767 | 817 | ||
768 | /** \name Drawable information */ | 818 | /** \name Drawable information */ |
769 | /*@{ */ | 819 | /*@{ */ |
@@ -989,11 +1039,19 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev); | |||
989 | extern void drm_driver_irq_postinstall(struct drm_device *dev); | 1039 | extern void drm_driver_irq_postinstall(struct drm_device *dev); |
990 | extern void drm_driver_irq_uninstall(struct drm_device *dev); | 1040 | extern void drm_driver_irq_uninstall(struct drm_device *dev); |
991 | 1041 | ||
992 | extern int drm_wait_vblank(struct drm_device *dev, void *data, | 1042 | extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); |
993 | struct drm_file *file_priv); | 1043 | extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp); |
994 | extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); | 1044 | extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq); |
995 | extern void drm_vbl_send_signals(struct drm_device *dev); | ||
996 | extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); | 1045 | extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); |
1046 | extern u32 drm_vblank_count(struct drm_device *dev, int crtc); | ||
1047 | extern void drm_update_vblank_count(struct drm_device *dev, int crtc); | ||
1048 | extern void drm_handle_vblank(struct drm_device *dev, int crtc); | ||
1049 | extern int drm_vblank_get(struct drm_device *dev, int crtc); | ||
1050 | extern void drm_vblank_put(struct drm_device *dev, int crtc); | ||
1051 | |||
1052 | /* Modesetting support */ | ||
1053 | extern int drm_modeset_ctl(struct drm_device *dev, void *data, | ||
1054 | struct drm_file *file_priv); | ||
997 | 1055 | ||
998 | /* AGP/GART support (drm_agpsupport.h) */ | 1056 | /* AGP/GART support (drm_agpsupport.h) */ |
999 | extern struct drm_agp_head *drm_agp_init(struct drm_device *dev); | 1057 | extern struct drm_agp_head *drm_agp_init(struct drm_device *dev); |
@@ -1030,23 +1088,20 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); | |||
1030 | extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, | 1088 | extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, |
1031 | struct drm_driver *driver); | 1089 | struct drm_driver *driver); |
1032 | extern int drm_put_dev(struct drm_device *dev); | 1090 | extern int drm_put_dev(struct drm_device *dev); |
1033 | extern int drm_put_head(struct drm_head *head); | 1091 | extern int drm_put_minor(struct drm_minor **minor); |
1034 | extern unsigned int drm_debug; | 1092 | extern unsigned int drm_debug; |
1035 | extern unsigned int drm_cards_limit; | 1093 | |
1036 | extern struct drm_head **drm_heads; | ||
1037 | extern struct class *drm_class; | 1094 | extern struct class *drm_class; |
1038 | extern struct proc_dir_entry *drm_proc_root; | 1095 | extern struct proc_dir_entry *drm_proc_root; |
1039 | 1096 | ||
1097 | extern struct idr drm_minors_idr; | ||
1098 | |||
1040 | extern drm_local_map_t *drm_getsarea(struct drm_device *dev); | 1099 | extern drm_local_map_t *drm_getsarea(struct drm_device *dev); |
1041 | 1100 | ||
1042 | /* Proc support (drm_proc.h) */ | 1101 | /* Proc support (drm_proc.h) */ |
1043 | extern int drm_proc_init(struct drm_device *dev, | 1102 | extern int drm_proc_init(struct drm_minor *minor, int minor_id, |
1044 | int minor, | 1103 | struct proc_dir_entry *root); |
1045 | struct proc_dir_entry *root, | 1104 | extern int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root); |
1046 | struct proc_dir_entry **dev_root); | ||
1047 | extern int drm_proc_cleanup(int minor, | ||
1048 | struct proc_dir_entry *root, | ||
1049 | struct proc_dir_entry *dev_root); | ||
1050 | 1105 | ||
1051 | /* Scatter Gather Support (drm_scatter.h) */ | 1106 | /* Scatter Gather Support (drm_scatter.h) */ |
1052 | extern void drm_sg_cleanup(struct drm_sg_mem * entry); | 1107 | extern void drm_sg_cleanup(struct drm_sg_mem * entry); |
@@ -1071,8 +1126,8 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); | |||
1071 | struct drm_sysfs_class; | 1126 | struct drm_sysfs_class; |
1072 | extern struct class *drm_sysfs_create(struct module *owner, char *name); | 1127 | extern struct class *drm_sysfs_create(struct module *owner, char *name); |
1073 | extern void drm_sysfs_destroy(void); | 1128 | extern void drm_sysfs_destroy(void); |
1074 | extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head); | 1129 | extern int drm_sysfs_device_add(struct drm_minor *minor); |
1075 | extern void drm_sysfs_device_remove(struct drm_device *dev); | 1130 | extern void drm_sysfs_device_remove(struct drm_minor *minor); |
1076 | 1131 | ||
1077 | /* | 1132 | /* |
1078 | * Basic memory manager support (drm_mm.c) | 1133 | * Basic memory manager support (drm_mm.c) |
diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c index 9468c7889ff1..aefa5ac4c0b1 100644 --- a/drivers/char/drm/drm_agpsupport.c +++ b/drivers/char/drm/drm_agpsupport.c | |||
@@ -122,7 +122,7 @@ EXPORT_SYMBOL(drm_agp_acquire); | |||
122 | int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, | 122 | int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, |
123 | struct drm_file *file_priv) | 123 | struct drm_file *file_priv) |
124 | { | 124 | { |
125 | return drm_agp_acquire((struct drm_device *) file_priv->head->dev); | 125 | return drm_agp_acquire((struct drm_device *) file_priv->minor->dev); |
126 | } | 126 | } |
127 | 127 | ||
128 | /** | 128 | /** |
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index 0e7af53c87de..fc54140551a7 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c | |||
@@ -313,35 +313,36 @@ static void drm_cleanup(struct drm_device * dev) | |||
313 | drm_ht_remove(&dev->map_hash); | 313 | drm_ht_remove(&dev->map_hash); |
314 | drm_ctxbitmap_cleanup(dev); | 314 | drm_ctxbitmap_cleanup(dev); |
315 | 315 | ||
316 | drm_put_head(&dev->primary); | 316 | drm_put_minor(&dev->primary); |
317 | if (drm_put_dev(dev)) | 317 | if (drm_put_dev(dev)) |
318 | DRM_ERROR("Cannot unload module\n"); | 318 | DRM_ERROR("Cannot unload module\n"); |
319 | } | 319 | } |
320 | 320 | ||
321 | void drm_exit(struct drm_driver *driver) | 321 | int drm_minors_cleanup(int id, void *ptr, void *data) |
322 | { | 322 | { |
323 | int i; | 323 | struct drm_minor *minor = ptr; |
324 | struct drm_device *dev = NULL; | 324 | struct drm_device *dev; |
325 | struct drm_head *head; | 325 | struct drm_driver *driver = data; |
326 | |||
327 | dev = minor->dev; | ||
328 | if (minor->dev->driver != driver) | ||
329 | return 0; | ||
330 | |||
331 | if (minor->type != DRM_MINOR_LEGACY) | ||
332 | return 0; | ||
326 | 333 | ||
334 | if (dev) | ||
335 | pci_dev_put(dev->pdev); | ||
336 | drm_cleanup(dev); | ||
337 | return 1; | ||
338 | } | ||
339 | |||
340 | void drm_exit(struct drm_driver *driver) | ||
341 | { | ||
327 | DRM_DEBUG("\n"); | 342 | DRM_DEBUG("\n"); |
328 | 343 | ||
329 | for (i = 0; i < drm_cards_limit; i++) { | 344 | idr_for_each(&drm_minors_idr, &drm_minors_cleanup, driver); |
330 | head = drm_heads[i]; | 345 | |
331 | if (!head) | ||
332 | continue; | ||
333 | if (!head->dev) | ||
334 | continue; | ||
335 | if (head->dev->driver != driver) | ||
336 | continue; | ||
337 | dev = head->dev; | ||
338 | if (dev) { | ||
339 | /* release the pci driver */ | ||
340 | if (dev->pdev) | ||
341 | pci_dev_put(dev->pdev); | ||
342 | drm_cleanup(dev); | ||
343 | } | ||
344 | } | ||
345 | DRM_INFO("Module unloaded\n"); | 346 | DRM_INFO("Module unloaded\n"); |
346 | } | 347 | } |
347 | 348 | ||
@@ -357,13 +358,7 @@ static int __init drm_core_init(void) | |||
357 | { | 358 | { |
358 | int ret = -ENOMEM; | 359 | int ret = -ENOMEM; |
359 | 360 | ||
360 | drm_cards_limit = | 361 | idr_init(&drm_minors_idr); |
361 | (drm_cards_limit < | ||
362 | DRM_MAX_MINOR + 1 ? drm_cards_limit : DRM_MAX_MINOR + 1); | ||
363 | drm_heads = | ||
364 | drm_calloc(drm_cards_limit, sizeof(*drm_heads), DRM_MEM_STUB); | ||
365 | if (!drm_heads) | ||
366 | goto err_p1; | ||
367 | 362 | ||
368 | if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) | 363 | if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) |
369 | goto err_p1; | 364 | goto err_p1; |
@@ -391,7 +386,8 @@ err_p3: | |||
391 | drm_sysfs_destroy(); | 386 | drm_sysfs_destroy(); |
392 | err_p2: | 387 | err_p2: |
393 | unregister_chrdev(DRM_MAJOR, "drm"); | 388 | unregister_chrdev(DRM_MAJOR, "drm"); |
394 | drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); | 389 | |
390 | idr_destroy(&drm_minors_idr); | ||
395 | err_p1: | 391 | err_p1: |
396 | return ret; | 392 | return ret; |
397 | } | 393 | } |
@@ -403,7 +399,7 @@ static void __exit drm_core_exit(void) | |||
403 | 399 | ||
404 | unregister_chrdev(DRM_MAJOR, "drm"); | 400 | unregister_chrdev(DRM_MAJOR, "drm"); |
405 | 401 | ||
406 | drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); | 402 | idr_destroy(&drm_minors_idr); |
407 | } | 403 | } |
408 | 404 | ||
409 | module_init(drm_core_init); | 405 | module_init(drm_core_init); |
@@ -452,7 +448,7 @@ int drm_ioctl(struct inode *inode, struct file *filp, | |||
452 | unsigned int cmd, unsigned long arg) | 448 | unsigned int cmd, unsigned long arg) |
453 | { | 449 | { |
454 | struct drm_file *file_priv = filp->private_data; | 450 | struct drm_file *file_priv = filp->private_data; |
455 | struct drm_device *dev = file_priv->head->dev; | 451 | struct drm_device *dev = file_priv->minor->dev; |
456 | struct drm_ioctl_desc *ioctl; | 452 | struct drm_ioctl_desc *ioctl; |
457 | drm_ioctl_t *func; | 453 | drm_ioctl_t *func; |
458 | unsigned int nr = DRM_IOCTL_NR(cmd); | 454 | unsigned int nr = DRM_IOCTL_NR(cmd); |
@@ -465,7 +461,7 @@ int drm_ioctl(struct inode *inode, struct file *filp, | |||
465 | 461 | ||
466 | DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n", | 462 | DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n", |
467 | task_pid_nr(current), cmd, nr, | 463 | task_pid_nr(current), cmd, nr, |
468 | (long)old_encode_dev(file_priv->head->device), | 464 | (long)old_encode_dev(file_priv->minor->device), |
469 | file_priv->authenticated); | 465 | file_priv->authenticated); |
470 | 466 | ||
471 | if ((nr >= DRM_CORE_IOCTL_COUNT) && | 467 | if ((nr >= DRM_CORE_IOCTL_COUNT) && |
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index f09d4b5002b0..68f0da801ed8 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c | |||
@@ -129,16 +129,15 @@ static int drm_setup(struct drm_device * dev) | |||
129 | int drm_open(struct inode *inode, struct file *filp) | 129 | int drm_open(struct inode *inode, struct file *filp) |
130 | { | 130 | { |
131 | struct drm_device *dev = NULL; | 131 | struct drm_device *dev = NULL; |
132 | int minor = iminor(inode); | 132 | int minor_id = iminor(inode); |
133 | struct drm_minor *minor; | ||
133 | int retcode = 0; | 134 | int retcode = 0; |
134 | 135 | ||
135 | if (!((minor >= 0) && (minor < drm_cards_limit))) | 136 | minor = idr_find(&drm_minors_idr, minor_id); |
137 | if (!minor) | ||
136 | return -ENODEV; | 138 | return -ENODEV; |
137 | 139 | ||
138 | if (!drm_heads[minor]) | 140 | if (!(dev = minor->dev)) |
139 | return -ENODEV; | ||
140 | |||
141 | if (!(dev = drm_heads[minor]->dev)) | ||
142 | return -ENODEV; | 141 | return -ENODEV; |
143 | 142 | ||
144 | retcode = drm_open_helper(inode, filp, dev); | 143 | retcode = drm_open_helper(inode, filp, dev); |
@@ -168,19 +167,18 @@ EXPORT_SYMBOL(drm_open); | |||
168 | int drm_stub_open(struct inode *inode, struct file *filp) | 167 | int drm_stub_open(struct inode *inode, struct file *filp) |
169 | { | 168 | { |
170 | struct drm_device *dev = NULL; | 169 | struct drm_device *dev = NULL; |
171 | int minor = iminor(inode); | 170 | struct drm_minor *minor; |
171 | int minor_id = iminor(inode); | ||
172 | int err = -ENODEV; | 172 | int err = -ENODEV; |
173 | const struct file_operations *old_fops; | 173 | const struct file_operations *old_fops; |
174 | 174 | ||
175 | DRM_DEBUG("\n"); | 175 | DRM_DEBUG("\n"); |
176 | 176 | ||
177 | if (!((minor >= 0) && (minor < drm_cards_limit))) | 177 | minor = idr_find(&drm_minors_idr, minor_id); |
178 | return -ENODEV; | 178 | if (!minor) |
179 | |||
180 | if (!drm_heads[minor]) | ||
181 | return -ENODEV; | 179 | return -ENODEV; |
182 | 180 | ||
183 | if (!(dev = drm_heads[minor]->dev)) | 181 | if (!(dev = minor->dev)) |
184 | return -ENODEV; | 182 | return -ENODEV; |
185 | 183 | ||
186 | old_fops = filp->f_op; | 184 | old_fops = filp->f_op; |
@@ -225,7 +223,7 @@ static int drm_cpu_valid(void) | |||
225 | static int drm_open_helper(struct inode *inode, struct file *filp, | 223 | static int drm_open_helper(struct inode *inode, struct file *filp, |
226 | struct drm_device * dev) | 224 | struct drm_device * dev) |
227 | { | 225 | { |
228 | int minor = iminor(inode); | 226 | int minor_id = iminor(inode); |
229 | struct drm_file *priv; | 227 | struct drm_file *priv; |
230 | int ret; | 228 | int ret; |
231 | 229 | ||
@@ -234,7 +232,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
234 | if (!drm_cpu_valid()) | 232 | if (!drm_cpu_valid()) |
235 | return -EINVAL; | 233 | return -EINVAL; |
236 | 234 | ||
237 | DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor); | 235 | DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); |
238 | 236 | ||
239 | priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); | 237 | priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); |
240 | if (!priv) | 238 | if (!priv) |
@@ -245,8 +243,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
245 | priv->filp = filp; | 243 | priv->filp = filp; |
246 | priv->uid = current->euid; | 244 | priv->uid = current->euid; |
247 | priv->pid = task_pid_nr(current); | 245 | priv->pid = task_pid_nr(current); |
248 | priv->minor = minor; | 246 | priv->minor = idr_find(&drm_minors_idr, minor_id); |
249 | priv->head = drm_heads[minor]; | ||
250 | priv->ioctl_count = 0; | 247 | priv->ioctl_count = 0; |
251 | /* for compatibility root is always authenticated */ | 248 | /* for compatibility root is always authenticated */ |
252 | priv->authenticated = capable(CAP_SYS_ADMIN); | 249 | priv->authenticated = capable(CAP_SYS_ADMIN); |
@@ -297,11 +294,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
297 | int drm_fasync(int fd, struct file *filp, int on) | 294 | int drm_fasync(int fd, struct file *filp, int on) |
298 | { | 295 | { |
299 | struct drm_file *priv = filp->private_data; | 296 | struct drm_file *priv = filp->private_data; |
300 | struct drm_device *dev = priv->head->dev; | 297 | struct drm_device *dev = priv->minor->dev; |
301 | int retcode; | 298 | int retcode; |
302 | 299 | ||
303 | DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, | 300 | DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, |
304 | (long)old_encode_dev(priv->head->device)); | 301 | (long)old_encode_dev(priv->minor->device)); |
305 | retcode = fasync_helper(fd, filp, on, &dev->buf_async); | 302 | retcode = fasync_helper(fd, filp, on, &dev->buf_async); |
306 | if (retcode < 0) | 303 | if (retcode < 0) |
307 | return retcode; | 304 | return retcode; |
@@ -324,7 +321,7 @@ EXPORT_SYMBOL(drm_fasync); | |||
324 | int drm_release(struct inode *inode, struct file *filp) | 321 | int drm_release(struct inode *inode, struct file *filp) |
325 | { | 322 | { |
326 | struct drm_file *file_priv = filp->private_data; | 323 | struct drm_file *file_priv = filp->private_data; |
327 | struct drm_device *dev = file_priv->head->dev; | 324 | struct drm_device *dev = file_priv->minor->dev; |
328 | int retcode = 0; | 325 | int retcode = 0; |
329 | unsigned long irqflags; | 326 | unsigned long irqflags; |
330 | 327 | ||
@@ -341,14 +338,14 @@ int drm_release(struct inode *inode, struct file *filp) | |||
341 | 338 | ||
342 | DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", | 339 | DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", |
343 | task_pid_nr(current), | 340 | task_pid_nr(current), |
344 | (long)old_encode_dev(file_priv->head->device), | 341 | (long)old_encode_dev(file_priv->minor->device), |
345 | dev->open_count); | 342 | dev->open_count); |
346 | 343 | ||
347 | if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { | 344 | if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { |
348 | if (drm_i_have_hw_lock(dev, file_priv)) { | 345 | if (drm_i_have_hw_lock(dev, file_priv)) { |
349 | dev->driver->reclaim_buffers_locked(dev, file_priv); | 346 | dev->driver->reclaim_buffers_locked(dev, file_priv); |
350 | } else { | 347 | } else { |
351 | unsigned long _end=jiffies + 3*DRM_HZ; | 348 | unsigned long endtime = jiffies + 3 * DRM_HZ; |
352 | int locked = 0; | 349 | int locked = 0; |
353 | 350 | ||
354 | drm_idlelock_take(&dev->lock); | 351 | drm_idlelock_take(&dev->lock); |
@@ -366,7 +363,7 @@ int drm_release(struct inode *inode, struct file *filp) | |||
366 | if (locked) | 363 | if (locked) |
367 | break; | 364 | break; |
368 | schedule(); | 365 | schedule(); |
369 | } while (!time_after_eq(jiffies, _end)); | 366 | } while (!time_after_eq(jiffies, endtime)); |
370 | 367 | ||
371 | if (!locked) { | 368 | if (!locked) { |
372 | DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" | 369 | DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" |
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c index 089c015c01d1..286f9d61e7d5 100644 --- a/drivers/char/drm/drm_irq.c +++ b/drivers/char/drm/drm_irq.c | |||
@@ -71,6 +71,117 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, | |||
71 | return 0; | 71 | return 0; |
72 | } | 72 | } |
73 | 73 | ||
74 | static void vblank_disable_fn(unsigned long arg) | ||
75 | { | ||
76 | struct drm_device *dev = (struct drm_device *)arg; | ||
77 | unsigned long irqflags; | ||
78 | int i; | ||
79 | |||
80 | for (i = 0; i < dev->num_crtcs; i++) { | ||
81 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
82 | if (atomic_read(&dev->vblank_refcount[i]) == 0 && | ||
83 | dev->vblank_enabled[i]) { | ||
84 | dev->driver->disable_vblank(dev, i); | ||
85 | dev->vblank_enabled[i] = 0; | ||
86 | } | ||
87 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static void drm_vblank_cleanup(struct drm_device *dev) | ||
92 | { | ||
93 | /* Bail if the driver didn't call drm_vblank_init() */ | ||
94 | if (dev->num_crtcs == 0) | ||
95 | return; | ||
96 | |||
97 | del_timer(&dev->vblank_disable_timer); | ||
98 | |||
99 | vblank_disable_fn((unsigned long)dev); | ||
100 | |||
101 | drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, | ||
102 | DRM_MEM_DRIVER); | ||
103 | drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, | ||
104 | DRM_MEM_DRIVER); | ||
105 | drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * | ||
106 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
107 | drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * | ||
108 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
109 | drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * | ||
110 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
111 | drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, | ||
112 | DRM_MEM_DRIVER); | ||
113 | drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * | ||
114 | dev->num_crtcs, DRM_MEM_DRIVER); | ||
115 | drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, | ||
116 | DRM_MEM_DRIVER); | ||
117 | |||
118 | dev->num_crtcs = 0; | ||
119 | } | ||
120 | |||
121 | int drm_vblank_init(struct drm_device *dev, int num_crtcs) | ||
122 | { | ||
123 | int i, ret = -ENOMEM; | ||
124 | |||
125 | setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, | ||
126 | (unsigned long)dev); | ||
127 | spin_lock_init(&dev->vbl_lock); | ||
128 | atomic_set(&dev->vbl_signal_pending, 0); | ||
129 | dev->num_crtcs = num_crtcs; | ||
130 | |||
131 | dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, | ||
132 | DRM_MEM_DRIVER); | ||
133 | if (!dev->vbl_queue) | ||
134 | goto err; | ||
135 | |||
136 | dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs, | ||
137 | DRM_MEM_DRIVER); | ||
138 | if (!dev->vbl_sigs) | ||
139 | goto err; | ||
140 | |||
141 | dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, | ||
142 | DRM_MEM_DRIVER); | ||
143 | if (!dev->_vblank_count) | ||
144 | goto err; | ||
145 | |||
146 | dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, | ||
147 | DRM_MEM_DRIVER); | ||
148 | if (!dev->vblank_refcount) | ||
149 | goto err; | ||
150 | |||
151 | dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), | ||
152 | DRM_MEM_DRIVER); | ||
153 | if (!dev->vblank_enabled) | ||
154 | goto err; | ||
155 | |||
156 | dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); | ||
157 | if (!dev->last_vblank) | ||
158 | goto err; | ||
159 | |||
160 | dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), | ||
161 | DRM_MEM_DRIVER); | ||
162 | if (!dev->vblank_premodeset) | ||
163 | goto err; | ||
164 | |||
165 | dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); | ||
166 | if (!dev->vblank_offset) | ||
167 | goto err; | ||
168 | |||
169 | /* Zero per-crtc vblank stuff */ | ||
170 | for (i = 0; i < num_crtcs; i++) { | ||
171 | init_waitqueue_head(&dev->vbl_queue[i]); | ||
172 | INIT_LIST_HEAD(&dev->vbl_sigs[i]); | ||
173 | atomic_set(&dev->_vblank_count[i], 0); | ||
174 | atomic_set(&dev->vblank_refcount[i], 0); | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | |||
179 | err: | ||
180 | drm_vblank_cleanup(dev); | ||
181 | return ret; | ||
182 | } | ||
183 | EXPORT_SYMBOL(drm_vblank_init); | ||
184 | |||
74 | /** | 185 | /** |
75 | * Install IRQ handler. | 186 | * Install IRQ handler. |
76 | * | 187 | * |
@@ -109,17 +220,6 @@ static int drm_irq_install(struct drm_device * dev) | |||
109 | 220 | ||
110 | DRM_DEBUG("irq=%d\n", dev->irq); | 221 | DRM_DEBUG("irq=%d\n", dev->irq); |
111 | 222 | ||
112 | if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) { | ||
113 | init_waitqueue_head(&dev->vbl_queue); | ||
114 | |||
115 | spin_lock_init(&dev->vbl_lock); | ||
116 | |||
117 | INIT_LIST_HEAD(&dev->vbl_sigs); | ||
118 | INIT_LIST_HEAD(&dev->vbl_sigs2); | ||
119 | |||
120 | dev->vbl_pending = 0; | ||
121 | } | ||
122 | |||
123 | /* Before installing handler */ | 223 | /* Before installing handler */ |
124 | dev->driver->irq_preinstall(dev); | 224 | dev->driver->irq_preinstall(dev); |
125 | 225 | ||
@@ -137,9 +237,14 @@ static int drm_irq_install(struct drm_device * dev) | |||
137 | } | 237 | } |
138 | 238 | ||
139 | /* After installing handler */ | 239 | /* After installing handler */ |
140 | dev->driver->irq_postinstall(dev); | 240 | ret = dev->driver->irq_postinstall(dev); |
241 | if (ret < 0) { | ||
242 | mutex_lock(&dev->struct_mutex); | ||
243 | dev->irq_enabled = 0; | ||
244 | mutex_unlock(&dev->struct_mutex); | ||
245 | } | ||
141 | 246 | ||
142 | return 0; | 247 | return ret; |
143 | } | 248 | } |
144 | 249 | ||
145 | /** | 250 | /** |
@@ -170,6 +275,8 @@ int drm_irq_uninstall(struct drm_device * dev) | |||
170 | 275 | ||
171 | free_irq(dev->irq, dev); | 276 | free_irq(dev->irq, dev); |
172 | 277 | ||
278 | drm_vblank_cleanup(dev); | ||
279 | |||
173 | dev->locked_tasklet_func = NULL; | 280 | dev->locked_tasklet_func = NULL; |
174 | 281 | ||
175 | return 0; | 282 | return 0; |
@@ -214,6 +321,148 @@ int drm_control(struct drm_device *dev, void *data, | |||
214 | } | 321 | } |
215 | 322 | ||
216 | /** | 323 | /** |
324 | * drm_vblank_count - retrieve "cooked" vblank counter value | ||
325 | * @dev: DRM device | ||
326 | * @crtc: which counter to retrieve | ||
327 | * | ||
328 | * Fetches the "cooked" vblank count value that represents the number of | ||
329 | * vblank events since the system was booted, including lost events due to | ||
330 | * modesetting activity. | ||
331 | */ | ||
332 | u32 drm_vblank_count(struct drm_device *dev, int crtc) | ||
333 | { | ||
334 | return atomic_read(&dev->_vblank_count[crtc]) + | ||
335 | dev->vblank_offset[crtc]; | ||
336 | } | ||
337 | EXPORT_SYMBOL(drm_vblank_count); | ||
338 | |||
339 | /** | ||
340 | * drm_update_vblank_count - update the master vblank counter | ||
341 | * @dev: DRM device | ||
342 | * @crtc: counter to update | ||
343 | * | ||
344 | * Call back into the driver to update the appropriate vblank counter | ||
345 | * (specified by @crtc). Deal with wraparound, if it occurred, and | ||
346 | * update the last read value so we can deal with wraparound on the next | ||
347 | * call if necessary. | ||
348 | */ | ||
349 | void drm_update_vblank_count(struct drm_device *dev, int crtc) | ||
350 | { | ||
351 | unsigned long irqflags; | ||
352 | u32 cur_vblank, diff; | ||
353 | |||
354 | /* | ||
355 | * Interrupts were disabled prior to this call, so deal with counter | ||
356 | * wrap if needed. | ||
357 | * NOTE! It's possible we lost a full dev->max_vblank_count events | ||
358 | * here if the register is small or we had vblank interrupts off for | ||
359 | * a long time. | ||
360 | */ | ||
361 | cur_vblank = dev->driver->get_vblank_counter(dev, crtc); | ||
362 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
363 | if (cur_vblank < dev->last_vblank[crtc]) { | ||
364 | diff = dev->max_vblank_count - | ||
365 | dev->last_vblank[crtc]; | ||
366 | diff += cur_vblank; | ||
367 | } else { | ||
368 | diff = cur_vblank - dev->last_vblank[crtc]; | ||
369 | } | ||
370 | dev->last_vblank[crtc] = cur_vblank; | ||
371 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
372 | |||
373 | atomic_add(diff, &dev->_vblank_count[crtc]); | ||
374 | } | ||
375 | EXPORT_SYMBOL(drm_update_vblank_count); | ||
376 | |||
377 | /** | ||
378 | * drm_vblank_get - get a reference count on vblank events | ||
379 | * @dev: DRM device | ||
380 | * @crtc: which CRTC to own | ||
381 | * | ||
382 | * Acquire a reference count on vblank events to avoid having them disabled | ||
383 | * while in use. Note callers will probably want to update the master counter | ||
384 | * using drm_update_vblank_count() above before calling this routine so that | ||
385 | * wakeups occur on the right vblank event. | ||
386 | * | ||
387 | * RETURNS | ||
388 | * Zero on success, nonzero on failure. | ||
389 | */ | ||
390 | int drm_vblank_get(struct drm_device *dev, int crtc) | ||
391 | { | ||
392 | unsigned long irqflags; | ||
393 | int ret = 0; | ||
394 | |||
395 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
396 | /* Going from 0->1 means we have to enable interrupts again */ | ||
397 | if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && | ||
398 | !dev->vblank_enabled[crtc]) { | ||
399 | ret = dev->driver->enable_vblank(dev, crtc); | ||
400 | if (ret) | ||
401 | atomic_dec(&dev->vblank_refcount[crtc]); | ||
402 | else | ||
403 | dev->vblank_enabled[crtc] = 1; | ||
404 | } | ||
405 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
406 | |||
407 | return ret; | ||
408 | } | ||
409 | EXPORT_SYMBOL(drm_vblank_get); | ||
410 | |||
411 | /** | ||
412 | * drm_vblank_put - give up ownership of vblank events | ||
413 | * @dev: DRM device | ||
414 | * @crtc: which counter to give up | ||
415 | * | ||
416 | * Release ownership of a given vblank counter, turning off interrupts | ||
417 | * if possible. | ||
418 | */ | ||
419 | void drm_vblank_put(struct drm_device *dev, int crtc) | ||
420 | { | ||
421 | /* Last user schedules interrupt disable */ | ||
422 | if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) | ||
423 | mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); | ||
424 | } | ||
425 | EXPORT_SYMBOL(drm_vblank_put); | ||
426 | |||
427 | /** | ||
428 | * drm_modeset_ctl - handle vblank event counter changes across mode switch | ||
429 | * @DRM_IOCTL_ARGS: standard ioctl arguments | ||
430 | * | ||
431 | * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET | ||
432 | * ioctls around modesetting so that any lost vblank events are accounted for. | ||
433 | */ | ||
434 | int drm_modeset_ctl(struct drm_device *dev, void *data, | ||
435 | struct drm_file *file_priv) | ||
436 | { | ||
437 | struct drm_modeset_ctl *modeset = data; | ||
438 | int crtc, ret = 0; | ||
439 | u32 new; | ||
440 | |||
441 | crtc = modeset->arg; | ||
442 | if (crtc >= dev->num_crtcs) { | ||
443 | ret = -EINVAL; | ||
444 | goto out; | ||
445 | } | ||
446 | |||
447 | switch (modeset->cmd) { | ||
448 | case _DRM_PRE_MODESET: | ||
449 | dev->vblank_premodeset[crtc] = | ||
450 | dev->driver->get_vblank_counter(dev, crtc); | ||
451 | break; | ||
452 | case _DRM_POST_MODESET: | ||
453 | new = dev->driver->get_vblank_counter(dev, crtc); | ||
454 | dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new; | ||
455 | break; | ||
456 | default: | ||
457 | ret = -EINVAL; | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | out: | ||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | /** | ||
217 | * Wait for VBLANK. | 466 | * Wait for VBLANK. |
218 | * | 467 | * |
219 | * \param inode device inode. | 468 | * \param inode device inode. |
@@ -232,12 +481,13 @@ int drm_control(struct drm_device *dev, void *data, | |||
232 | * | 481 | * |
233 | * If a signal is not requested, then calls vblank_wait(). | 482 | * If a signal is not requested, then calls vblank_wait(). |
234 | */ | 483 | */ |
235 | int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) | 484 | int drm_wait_vblank(struct drm_device *dev, void *data, |
485 | struct drm_file *file_priv) | ||
236 | { | 486 | { |
237 | union drm_wait_vblank *vblwait = data; | 487 | union drm_wait_vblank *vblwait = data; |
238 | struct timeval now; | 488 | struct timeval now; |
239 | int ret = 0; | 489 | int ret = 0; |
240 | unsigned int flags, seq; | 490 | unsigned int flags, seq, crtc; |
241 | 491 | ||
242 | if ((!dev->irq) || (!dev->irq_enabled)) | 492 | if ((!dev->irq) || (!dev->irq_enabled)) |
243 | return -EINVAL; | 493 | return -EINVAL; |
@@ -251,13 +501,13 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
251 | } | 501 | } |
252 | 502 | ||
253 | flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; | 503 | flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; |
504 | crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; | ||
254 | 505 | ||
255 | if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? | 506 | if (crtc >= dev->num_crtcs) |
256 | DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) | ||
257 | return -EINVAL; | 507 | return -EINVAL; |
258 | 508 | ||
259 | seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 | 509 | drm_update_vblank_count(dev, crtc); |
260 | : &dev->vbl_received); | 510 | seq = drm_vblank_count(dev, crtc); |
261 | 511 | ||
262 | switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { | 512 | switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { |
263 | case _DRM_VBLANK_RELATIVE: | 513 | case _DRM_VBLANK_RELATIVE: |
@@ -276,8 +526,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
276 | 526 | ||
277 | if (flags & _DRM_VBLANK_SIGNAL) { | 527 | if (flags & _DRM_VBLANK_SIGNAL) { |
278 | unsigned long irqflags; | 528 | unsigned long irqflags; |
279 | struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) | 529 | struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; |
280 | ? &dev->vbl_sigs2 : &dev->vbl_sigs; | ||
281 | struct drm_vbl_sig *vbl_sig; | 530 | struct drm_vbl_sig *vbl_sig; |
282 | 531 | ||
283 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 532 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
@@ -298,22 +547,26 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
298 | } | 547 | } |
299 | } | 548 | } |
300 | 549 | ||
301 | if (dev->vbl_pending >= 100) { | 550 | if (atomic_read(&dev->vbl_signal_pending) >= 100) { |
302 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 551 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
303 | return -EBUSY; | 552 | return -EBUSY; |
304 | } | 553 | } |
305 | 554 | ||
306 | dev->vbl_pending++; | ||
307 | |||
308 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 555 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
309 | 556 | ||
310 | if (! | 557 | vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), |
311 | (vbl_sig = | 558 | DRM_MEM_DRIVER); |
312 | drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) { | 559 | if (!vbl_sig) |
313 | return -ENOMEM; | 560 | return -ENOMEM; |
561 | |||
562 | ret = drm_vblank_get(dev, crtc); | ||
563 | if (ret) { | ||
564 | drm_free(vbl_sig, sizeof(struct drm_vbl_sig), | ||
565 | DRM_MEM_DRIVER); | ||
566 | return ret; | ||
314 | } | 567 | } |
315 | 568 | ||
316 | memset((void *)vbl_sig, 0, sizeof(*vbl_sig)); | 569 | atomic_inc(&dev->vbl_signal_pending); |
317 | 570 | ||
318 | vbl_sig->sequence = vblwait->request.sequence; | 571 | vbl_sig->sequence = vblwait->request.sequence; |
319 | vbl_sig->info.si_signo = vblwait->request.signal; | 572 | vbl_sig->info.si_signo = vblwait->request.signal; |
@@ -327,17 +580,20 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
327 | 580 | ||
328 | vblwait->reply.sequence = seq; | 581 | vblwait->reply.sequence = seq; |
329 | } else { | 582 | } else { |
330 | if (flags & _DRM_VBLANK_SECONDARY) { | 583 | unsigned long cur_vblank; |
331 | if (dev->driver->vblank_wait2) | 584 | |
332 | ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence); | 585 | ret = drm_vblank_get(dev, crtc); |
333 | } else if (dev->driver->vblank_wait) | 586 | if (ret) |
334 | ret = | 587 | return ret; |
335 | dev->driver->vblank_wait(dev, | 588 | DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, |
336 | &vblwait->request.sequence); | 589 | (((cur_vblank = drm_vblank_count(dev, crtc)) |
337 | 590 | - vblwait->request.sequence) <= (1 << 23))); | |
591 | drm_vblank_put(dev, crtc); | ||
338 | do_gettimeofday(&now); | 592 | do_gettimeofday(&now); |
593 | |||
339 | vblwait->reply.tval_sec = now.tv_sec; | 594 | vblwait->reply.tval_sec = now.tv_sec; |
340 | vblwait->reply.tval_usec = now.tv_usec; | 595 | vblwait->reply.tval_usec = now.tv_usec; |
596 | vblwait->reply.sequence = cur_vblank; | ||
341 | } | 597 | } |
342 | 598 | ||
343 | done: | 599 | done: |
@@ -348,44 +604,57 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
348 | * Send the VBLANK signals. | 604 | * Send the VBLANK signals. |
349 | * | 605 | * |
350 | * \param dev DRM device. | 606 | * \param dev DRM device. |
607 | * \param crtc CRTC where the vblank event occurred | ||
351 | * | 608 | * |
352 | * Sends a signal for each task in drm_device::vbl_sigs and empties the list. | 609 | * Sends a signal for each task in drm_device::vbl_sigs and empties the list. |
353 | * | 610 | * |
354 | * If a signal is not requested, then calls vblank_wait(). | 611 | * If a signal is not requested, then calls vblank_wait(). |
355 | */ | 612 | */ |
356 | void drm_vbl_send_signals(struct drm_device * dev) | 613 | static void drm_vbl_send_signals(struct drm_device * dev, int crtc) |
357 | { | 614 | { |
615 | struct drm_vbl_sig *vbl_sig, *tmp; | ||
616 | struct list_head *vbl_sigs; | ||
617 | unsigned int vbl_seq; | ||
358 | unsigned long flags; | 618 | unsigned long flags; |
359 | int i; | ||
360 | 619 | ||
361 | spin_lock_irqsave(&dev->vbl_lock, flags); | 620 | spin_lock_irqsave(&dev->vbl_lock, flags); |
362 | 621 | ||
363 | for (i = 0; i < 2; i++) { | 622 | vbl_sigs = &dev->vbl_sigs[crtc]; |
364 | struct drm_vbl_sig *vbl_sig, *tmp; | 623 | vbl_seq = drm_vblank_count(dev, crtc); |
365 | struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; | ||
366 | unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : | ||
367 | &dev->vbl_received); | ||
368 | 624 | ||
369 | list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { | 625 | list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { |
370 | if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { | 626 | if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { |
371 | vbl_sig->info.si_code = vbl_seq; | 627 | vbl_sig->info.si_code = vbl_seq; |
372 | send_sig_info(vbl_sig->info.si_signo, | 628 | send_sig_info(vbl_sig->info.si_signo, |
373 | &vbl_sig->info, vbl_sig->task); | 629 | &vbl_sig->info, vbl_sig->task); |
374 | 630 | ||
375 | list_del(&vbl_sig->head); | 631 | list_del(&vbl_sig->head); |
376 | 632 | ||
377 | drm_free(vbl_sig, sizeof(*vbl_sig), | 633 | drm_free(vbl_sig, sizeof(*vbl_sig), |
378 | DRM_MEM_DRIVER); | 634 | DRM_MEM_DRIVER); |
379 | 635 | atomic_dec(&dev->vbl_signal_pending); | |
380 | dev->vbl_pending--; | 636 | drm_vblank_put(dev, crtc); |
381 | } | 637 | } |
382 | } | ||
383 | } | 638 | } |
384 | 639 | ||
385 | spin_unlock_irqrestore(&dev->vbl_lock, flags); | 640 | spin_unlock_irqrestore(&dev->vbl_lock, flags); |
386 | } | 641 | } |
387 | 642 | ||
388 | EXPORT_SYMBOL(drm_vbl_send_signals); | 643 | /** |
644 | * drm_handle_vblank - handle a vblank event | ||
645 | * @dev: DRM device | ||
646 | * @crtc: where this event occurred | ||
647 | * | ||
648 | * Drivers should call this routine in their vblank interrupt handlers to | ||
649 | * update the vblank counter and send any signals that may be pending. | ||
650 | */ | ||
651 | void drm_handle_vblank(struct drm_device *dev, int crtc) | ||
652 | { | ||
653 | drm_update_vblank_count(dev, crtc); | ||
654 | DRM_WAKEUP(&dev->vbl_queue[crtc]); | ||
655 | drm_vbl_send_signals(dev, crtc); | ||
656 | } | ||
657 | EXPORT_SYMBOL(drm_handle_vblank); | ||
389 | 658 | ||
390 | /** | 659 | /** |
391 | * Tasklet wrapper function. | 660 | * Tasklet wrapper function. |
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c index d9b560fe9bbe..93b1e0475c93 100644 --- a/drivers/char/drm/drm_proc.c +++ b/drivers/char/drm/drm_proc.c | |||
@@ -87,34 +87,35 @@ static struct drm_proc_list { | |||
87 | * "/proc/dri/%minor%/", and each entry in proc_list as | 87 | * "/proc/dri/%minor%/", and each entry in proc_list as |
88 | * "/proc/dri/%minor%/%name%". | 88 | * "/proc/dri/%minor%/%name%". |
89 | */ | 89 | */ |
90 | int drm_proc_init(struct drm_device * dev, int minor, | 90 | int drm_proc_init(struct drm_minor *minor, int minor_id, |
91 | struct proc_dir_entry *root, struct proc_dir_entry **dev_root) | 91 | struct proc_dir_entry *root) |
92 | { | 92 | { |
93 | struct proc_dir_entry *ent; | 93 | struct proc_dir_entry *ent; |
94 | int i, j; | 94 | int i, j; |
95 | char name[64]; | 95 | char name[64]; |
96 | 96 | ||
97 | sprintf(name, "%d", minor); | 97 | sprintf(name, "%d", minor_id); |
98 | *dev_root = proc_mkdir(name, root); | 98 | minor->dev_root = proc_mkdir(name, root); |
99 | if (!*dev_root) { | 99 | if (!minor->dev_root) { |
100 | DRM_ERROR("Cannot create /proc/dri/%s\n", name); | 100 | DRM_ERROR("Cannot create /proc/dri/%s\n", name); |
101 | return -1; | 101 | return -1; |
102 | } | 102 | } |
103 | 103 | ||
104 | for (i = 0; i < DRM_PROC_ENTRIES; i++) { | 104 | for (i = 0; i < DRM_PROC_ENTRIES; i++) { |
105 | ent = create_proc_entry(drm_proc_list[i].name, | 105 | ent = create_proc_entry(drm_proc_list[i].name, |
106 | S_IFREG | S_IRUGO, *dev_root); | 106 | S_IFREG | S_IRUGO, minor->dev_root); |
107 | if (!ent) { | 107 | if (!ent) { |
108 | DRM_ERROR("Cannot create /proc/dri/%s/%s\n", | 108 | DRM_ERROR("Cannot create /proc/dri/%s/%s\n", |
109 | name, drm_proc_list[i].name); | 109 | name, drm_proc_list[i].name); |
110 | for (j = 0; j < i; j++) | 110 | for (j = 0; j < i; j++) |
111 | remove_proc_entry(drm_proc_list[i].name, | 111 | remove_proc_entry(drm_proc_list[i].name, |
112 | *dev_root); | 112 | minor->dev_root); |
113 | remove_proc_entry(name, root); | 113 | remove_proc_entry(name, root); |
114 | minor->dev_root = NULL; | ||
114 | return -1; | 115 | return -1; |
115 | } | 116 | } |
116 | ent->read_proc = drm_proc_list[i].f; | 117 | ent->read_proc = drm_proc_list[i].f; |
117 | ent->data = dev; | 118 | ent->data = minor; |
118 | } | 119 | } |
119 | 120 | ||
120 | return 0; | 121 | return 0; |
@@ -130,18 +131,17 @@ int drm_proc_init(struct drm_device * dev, int minor, | |||
130 | * | 131 | * |
131 | * Remove all proc entries created by proc_init(). | 132 | * Remove all proc entries created by proc_init(). |
132 | */ | 133 | */ |
133 | int drm_proc_cleanup(int minor, struct proc_dir_entry *root, | 134 | int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) |
134 | struct proc_dir_entry *dev_root) | ||
135 | { | 135 | { |
136 | int i; | 136 | int i; |
137 | char name[64]; | 137 | char name[64]; |
138 | 138 | ||
139 | if (!root || !dev_root) | 139 | if (!root || !minor->dev_root) |
140 | return 0; | 140 | return 0; |
141 | 141 | ||
142 | for (i = 0; i < DRM_PROC_ENTRIES; i++) | 142 | for (i = 0; i < DRM_PROC_ENTRIES; i++) |
143 | remove_proc_entry(drm_proc_list[i].name, dev_root); | 143 | remove_proc_entry(drm_proc_list[i].name, minor->dev_root); |
144 | sprintf(name, "%d", minor); | 144 | sprintf(name, "%d", minor->index); |
145 | remove_proc_entry(name, root); | 145 | remove_proc_entry(name, root); |
146 | 146 | ||
147 | return 0; | 147 | return 0; |
@@ -163,7 +163,8 @@ int drm_proc_cleanup(int minor, struct proc_dir_entry *root, | |||
163 | static int drm_name_info(char *buf, char **start, off_t offset, int request, | 163 | static int drm_name_info(char *buf, char **start, off_t offset, int request, |
164 | int *eof, void *data) | 164 | int *eof, void *data) |
165 | { | 165 | { |
166 | struct drm_device *dev = (struct drm_device *) data; | 166 | struct drm_minor *minor = (struct drm_minor *) data; |
167 | struct drm_device *dev = minor->dev; | ||
167 | int len = 0; | 168 | int len = 0; |
168 | 169 | ||
169 | if (offset > DRM_PROC_LIMIT) { | 170 | if (offset > DRM_PROC_LIMIT) { |
@@ -205,7 +206,8 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, | |||
205 | static int drm__vm_info(char *buf, char **start, off_t offset, int request, | 206 | static int drm__vm_info(char *buf, char **start, off_t offset, int request, |
206 | int *eof, void *data) | 207 | int *eof, void *data) |
207 | { | 208 | { |
208 | struct drm_device *dev = (struct drm_device *) data; | 209 | struct drm_minor *minor = (struct drm_minor *) data; |
210 | struct drm_device *dev = minor->dev; | ||
209 | int len = 0; | 211 | int len = 0; |
210 | struct drm_map *map; | 212 | struct drm_map *map; |
211 | struct drm_map_list *r_list; | 213 | struct drm_map_list *r_list; |
@@ -261,7 +263,8 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, | |||
261 | static int drm_vm_info(char *buf, char **start, off_t offset, int request, | 263 | static int drm_vm_info(char *buf, char **start, off_t offset, int request, |
262 | int *eof, void *data) | 264 | int *eof, void *data) |
263 | { | 265 | { |
264 | struct drm_device *dev = (struct drm_device *) data; | 266 | struct drm_minor *minor = (struct drm_minor *) data; |
267 | struct drm_device *dev = minor->dev; | ||
265 | int ret; | 268 | int ret; |
266 | 269 | ||
267 | mutex_lock(&dev->struct_mutex); | 270 | mutex_lock(&dev->struct_mutex); |
@@ -284,7 +287,8 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request, | |||
284 | static int drm__queues_info(char *buf, char **start, off_t offset, | 287 | static int drm__queues_info(char *buf, char **start, off_t offset, |
285 | int request, int *eof, void *data) | 288 | int request, int *eof, void *data) |
286 | { | 289 | { |
287 | struct drm_device *dev = (struct drm_device *) data; | 290 | struct drm_minor *minor = (struct drm_minor *) data; |
291 | struct drm_device *dev = minor->dev; | ||
288 | int len = 0; | 292 | int len = 0; |
289 | int i; | 293 | int i; |
290 | struct drm_queue *q; | 294 | struct drm_queue *q; |
@@ -334,7 +338,8 @@ static int drm__queues_info(char *buf, char **start, off_t offset, | |||
334 | static int drm_queues_info(char *buf, char **start, off_t offset, int request, | 338 | static int drm_queues_info(char *buf, char **start, off_t offset, int request, |
335 | int *eof, void *data) | 339 | int *eof, void *data) |
336 | { | 340 | { |
337 | struct drm_device *dev = (struct drm_device *) data; | 341 | struct drm_minor *minor = (struct drm_minor *) data; |
342 | struct drm_device *dev = minor->dev; | ||
338 | int ret; | 343 | int ret; |
339 | 344 | ||
340 | mutex_lock(&dev->struct_mutex); | 345 | mutex_lock(&dev->struct_mutex); |
@@ -357,7 +362,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request, | |||
357 | static int drm__bufs_info(char *buf, char **start, off_t offset, int request, | 362 | static int drm__bufs_info(char *buf, char **start, off_t offset, int request, |
358 | int *eof, void *data) | 363 | int *eof, void *data) |
359 | { | 364 | { |
360 | struct drm_device *dev = (struct drm_device *) data; | 365 | struct drm_minor *minor = (struct drm_minor *) data; |
366 | struct drm_device *dev = minor->dev; | ||
361 | int len = 0; | 367 | int len = 0; |
362 | struct drm_device_dma *dma = dev->dma; | 368 | struct drm_device_dma *dma = dev->dma; |
363 | int i; | 369 | int i; |
@@ -406,7 +412,8 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request, | |||
406 | static int drm_bufs_info(char *buf, char **start, off_t offset, int request, | 412 | static int drm_bufs_info(char *buf, char **start, off_t offset, int request, |
407 | int *eof, void *data) | 413 | int *eof, void *data) |
408 | { | 414 | { |
409 | struct drm_device *dev = (struct drm_device *) data; | 415 | struct drm_minor *minor = (struct drm_minor *) data; |
416 | struct drm_device *dev = minor->dev; | ||
410 | int ret; | 417 | int ret; |
411 | 418 | ||
412 | mutex_lock(&dev->struct_mutex); | 419 | mutex_lock(&dev->struct_mutex); |
@@ -429,7 +436,8 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, | |||
429 | static int drm__clients_info(char *buf, char **start, off_t offset, | 436 | static int drm__clients_info(char *buf, char **start, off_t offset, |
430 | int request, int *eof, void *data) | 437 | int request, int *eof, void *data) |
431 | { | 438 | { |
432 | struct drm_device *dev = (struct drm_device *) data; | 439 | struct drm_minor *minor = (struct drm_minor *) data; |
440 | struct drm_device *dev = minor->dev; | ||
433 | int len = 0; | 441 | int len = 0; |
434 | struct drm_file *priv; | 442 | struct drm_file *priv; |
435 | 443 | ||
@@ -445,7 +453,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset, | |||
445 | list_for_each_entry(priv, &dev->filelist, lhead) { | 453 | list_for_each_entry(priv, &dev->filelist, lhead) { |
446 | DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", | 454 | DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", |
447 | priv->authenticated ? 'y' : 'n', | 455 | priv->authenticated ? 'y' : 'n', |
448 | priv->minor, | 456 | priv->minor->index, |
449 | priv->pid, | 457 | priv->pid, |
450 | priv->uid, priv->magic, priv->ioctl_count); | 458 | priv->uid, priv->magic, priv->ioctl_count); |
451 | } | 459 | } |
@@ -462,7 +470,8 @@ static int drm__clients_info(char *buf, char **start, off_t offset, | |||
462 | static int drm_clients_info(char *buf, char **start, off_t offset, | 470 | static int drm_clients_info(char *buf, char **start, off_t offset, |
463 | int request, int *eof, void *data) | 471 | int request, int *eof, void *data) |
464 | { | 472 | { |
465 | struct drm_device *dev = (struct drm_device *) data; | 473 | struct drm_minor *minor = (struct drm_minor *) data; |
474 | struct drm_device *dev = minor->dev; | ||
466 | int ret; | 475 | int ret; |
467 | 476 | ||
468 | mutex_lock(&dev->struct_mutex); | 477 | mutex_lock(&dev->struct_mutex); |
@@ -476,7 +485,8 @@ static int drm_clients_info(char *buf, char **start, off_t offset, | |||
476 | static int drm__vma_info(char *buf, char **start, off_t offset, int request, | 485 | static int drm__vma_info(char *buf, char **start, off_t offset, int request, |
477 | int *eof, void *data) | 486 | int *eof, void *data) |
478 | { | 487 | { |
479 | struct drm_device *dev = (struct drm_device *) data; | 488 | struct drm_minor *minor = (struct drm_minor *) data; |
489 | struct drm_device *dev = minor->dev; | ||
480 | int len = 0; | 490 | int len = 0; |
481 | struct drm_vma_entry *pt; | 491 | struct drm_vma_entry *pt; |
482 | struct vm_area_struct *vma; | 492 | struct vm_area_struct *vma; |
@@ -535,7 +545,8 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request, | |||
535 | static int drm_vma_info(char *buf, char **start, off_t offset, int request, | 545 | static int drm_vma_info(char *buf, char **start, off_t offset, int request, |
536 | int *eof, void *data) | 546 | int *eof, void *data) |
537 | { | 547 | { |
538 | struct drm_device *dev = (struct drm_device *) data; | 548 | struct drm_minor *minor = (struct drm_minor *) data; |
549 | struct drm_device *dev = minor->dev; | ||
539 | int ret; | 550 | int ret; |
540 | 551 | ||
541 | mutex_lock(&dev->struct_mutex); | 552 | mutex_lock(&dev->struct_mutex); |
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index d93a217f856a..c2f584f3b46c 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c | |||
@@ -36,23 +36,49 @@ | |||
36 | #include "drmP.h" | 36 | #include "drmP.h" |
37 | #include "drm_core.h" | 37 | #include "drm_core.h" |
38 | 38 | ||
39 | unsigned int drm_cards_limit = 16; /* Enough for one machine */ | ||
40 | unsigned int drm_debug = 0; /* 1 to enable debug output */ | 39 | unsigned int drm_debug = 0; /* 1 to enable debug output */ |
41 | EXPORT_SYMBOL(drm_debug); | 40 | EXPORT_SYMBOL(drm_debug); |
42 | 41 | ||
43 | MODULE_AUTHOR(CORE_AUTHOR); | 42 | MODULE_AUTHOR(CORE_AUTHOR); |
44 | MODULE_DESCRIPTION(CORE_DESC); | 43 | MODULE_DESCRIPTION(CORE_DESC); |
45 | MODULE_LICENSE("GPL and additional rights"); | 44 | MODULE_LICENSE("GPL and additional rights"); |
46 | MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards"); | ||
47 | MODULE_PARM_DESC(debug, "Enable debug output"); | 45 | MODULE_PARM_DESC(debug, "Enable debug output"); |
48 | 46 | ||
49 | module_param_named(cards_limit, drm_cards_limit, int, 0444); | ||
50 | module_param_named(debug, drm_debug, int, 0600); | 47 | module_param_named(debug, drm_debug, int, 0600); |
51 | 48 | ||
52 | struct drm_head **drm_heads; | 49 | struct idr drm_minors_idr; |
50 | |||
53 | struct class *drm_class; | 51 | struct class *drm_class; |
54 | struct proc_dir_entry *drm_proc_root; | 52 | struct proc_dir_entry *drm_proc_root; |
55 | 53 | ||
54 | static int drm_minor_get_id(struct drm_device *dev, int type) | ||
55 | { | ||
56 | int new_id; | ||
57 | int ret; | ||
58 | int base = 0, limit = 63; | ||
59 | |||
60 | again: | ||
61 | if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) { | ||
62 | DRM_ERROR("Out of memory expanding drawable idr\n"); | ||
63 | return -ENOMEM; | ||
64 | } | ||
65 | mutex_lock(&dev->struct_mutex); | ||
66 | ret = idr_get_new_above(&drm_minors_idr, NULL, | ||
67 | base, &new_id); | ||
68 | mutex_unlock(&dev->struct_mutex); | ||
69 | if (ret == -EAGAIN) { | ||
70 | goto again; | ||
71 | } else if (ret) { | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | if (new_id >= limit) { | ||
76 | idr_remove(&drm_minors_idr, new_id); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | return new_id; | ||
80 | } | ||
81 | |||
56 | static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, | 82 | static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, |
57 | const struct pci_device_id *ent, | 83 | const struct pci_device_id *ent, |
58 | struct drm_driver *driver) | 84 | struct drm_driver *driver) |
@@ -145,48 +171,60 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, | |||
145 | * create the proc init entry via proc_init(). This routines assigns | 171 | * create the proc init entry via proc_init(). This routines assigns |
146 | * minor numbers to secondary heads of multi-headed cards | 172 | * minor numbers to secondary heads of multi-headed cards |
147 | */ | 173 | */ |
148 | static int drm_get_head(struct drm_device * dev, struct drm_head * head) | 174 | static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) |
149 | { | 175 | { |
150 | struct drm_head **heads = drm_heads; | 176 | struct drm_minor *new_minor; |
151 | int ret; | 177 | int ret; |
152 | int minor; | 178 | int minor_id; |
153 | 179 | ||
154 | DRM_DEBUG("\n"); | 180 | DRM_DEBUG("\n"); |
155 | 181 | ||
156 | for (minor = 0; minor < drm_cards_limit; minor++, heads++) { | 182 | minor_id = drm_minor_get_id(dev, type); |
157 | if (!*heads) { | 183 | if (minor_id < 0) |
158 | 184 | return minor_id; | |
159 | *head = (struct drm_head) { | 185 | |
160 | .dev = dev,.device = | 186 | new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); |
161 | MKDEV(DRM_MAJOR, minor),.minor = minor,}; | 187 | if (!new_minor) { |
162 | 188 | ret = -ENOMEM; | |
163 | if ((ret = | 189 | goto err_idr; |
164 | drm_proc_init(dev, minor, drm_proc_root, | 190 | } |
165 | &head->dev_root))) { | 191 | |
166 | printk(KERN_ERR | 192 | new_minor->type = type; |
167 | "DRM: Failed to initialize /proc/dri.\n"); | 193 | new_minor->device = MKDEV(DRM_MAJOR, minor_id); |
168 | goto err_g1; | 194 | new_minor->dev = dev; |
169 | } | 195 | new_minor->index = minor_id; |
170 | 196 | ||
171 | ret = drm_sysfs_device_add(dev, head); | 197 | idr_replace(&drm_minors_idr, new_minor, minor_id); |
172 | if (ret) { | 198 | |
173 | printk(KERN_ERR | 199 | if (type == DRM_MINOR_LEGACY) { |
174 | "DRM: Error sysfs_device_add.\n"); | 200 | ret = drm_proc_init(new_minor, minor_id, drm_proc_root); |
175 | goto err_g2; | 201 | if (ret) { |
176 | } | 202 | DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); |
177 | *heads = head; | 203 | goto err_mem; |
178 | |||
179 | DRM_DEBUG("new minor assigned %d\n", minor); | ||
180 | return 0; | ||
181 | } | 204 | } |
205 | } else | ||
206 | new_minor->dev_root = NULL; | ||
207 | |||
208 | ret = drm_sysfs_device_add(new_minor); | ||
209 | if (ret) { | ||
210 | printk(KERN_ERR | ||
211 | "DRM: Error sysfs_device_add.\n"); | ||
212 | goto err_g2; | ||
182 | } | 213 | } |
183 | DRM_ERROR("out of minors\n"); | 214 | *minor = new_minor; |
184 | return -ENOMEM; | 215 | |
185 | err_g2: | 216 | DRM_DEBUG("new minor assigned %d\n", minor_id); |
186 | drm_proc_cleanup(minor, drm_proc_root, head->dev_root); | 217 | return 0; |
187 | err_g1: | 218 | |
188 | *head = (struct drm_head) { | 219 | |
189 | .dev = NULL}; | 220 | err_g2: |
221 | if (new_minor->type == DRM_MINOR_LEGACY) | ||
222 | drm_proc_cleanup(new_minor, drm_proc_root); | ||
223 | err_mem: | ||
224 | kfree(new_minor); | ||
225 | err_idr: | ||
226 | idr_remove(&drm_minors_idr, minor_id); | ||
227 | *minor = NULL; | ||
190 | return ret; | 228 | return ret; |
191 | } | 229 | } |
192 | 230 | ||
@@ -222,12 +260,12 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, | |||
222 | printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); | 260 | printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); |
223 | goto err_g2; | 261 | goto err_g2; |
224 | } | 262 | } |
225 | if ((ret = drm_get_head(dev, &dev->primary))) | 263 | if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) |
226 | goto err_g2; | 264 | goto err_g2; |
227 | 265 | ||
228 | DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", | 266 | DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", |
229 | driver->name, driver->major, driver->minor, driver->patchlevel, | 267 | driver->name, driver->major, driver->minor, driver->patchlevel, |
230 | driver->date, dev->primary.minor); | 268 | driver->date, dev->primary->index); |
231 | 269 | ||
232 | return 0; | 270 | return 0; |
233 | 271 | ||
@@ -276,18 +314,18 @@ int drm_put_dev(struct drm_device * dev) | |||
276 | * last minor released. | 314 | * last minor released. |
277 | * | 315 | * |
278 | */ | 316 | */ |
279 | int drm_put_head(struct drm_head * head) | 317 | int drm_put_minor(struct drm_minor **minor_p) |
280 | { | 318 | { |
281 | int minor = head->minor; | 319 | struct drm_minor *minor = *minor_p; |
282 | 320 | DRM_DEBUG("release secondary minor %d\n", minor->index); | |
283 | DRM_DEBUG("release secondary minor %d\n", minor); | ||
284 | |||
285 | drm_proc_cleanup(minor, drm_proc_root, head->dev_root); | ||
286 | drm_sysfs_device_remove(head->dev); | ||
287 | 321 | ||
288 | *head = (struct drm_head) {.dev = NULL}; | 322 | if (minor->type == DRM_MINOR_LEGACY) |
323 | drm_proc_cleanup(minor, drm_proc_root); | ||
324 | drm_sysfs_device_remove(minor); | ||
289 | 325 | ||
290 | drm_heads[minor] = NULL; | 326 | idr_remove(&drm_minors_idr, minor->index); |
291 | 327 | ||
328 | kfree(minor); | ||
329 | *minor_p = NULL; | ||
292 | return 0; | 330 | return 0; |
293 | } | 331 | } |
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index 05ed5043254f..7a1d9a782ddb 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include "drm_core.h" | 19 | #include "drm_core.h" |
20 | #include "drmP.h" | 20 | #include "drmP.h" |
21 | 21 | ||
22 | #define to_drm_device(d) container_of(d, struct drm_device, dev) | 22 | #define to_drm_minor(d) container_of(d, struct drm_minor, kdev) |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * drm_sysfs_suspend - DRM class suspend hook | 25 | * drm_sysfs_suspend - DRM class suspend hook |
@@ -31,7 +31,8 @@ | |||
31 | */ | 31 | */ |
32 | static int drm_sysfs_suspend(struct device *dev, pm_message_t state) | 32 | static int drm_sysfs_suspend(struct device *dev, pm_message_t state) |
33 | { | 33 | { |
34 | struct drm_device *drm_dev = to_drm_device(dev); | 34 | struct drm_minor *drm_minor = to_drm_minor(dev); |
35 | struct drm_device *drm_dev = drm_minor->dev; | ||
35 | 36 | ||
36 | printk(KERN_ERR "%s\n", __FUNCTION__); | 37 | printk(KERN_ERR "%s\n", __FUNCTION__); |
37 | 38 | ||
@@ -50,7 +51,8 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) | |||
50 | */ | 51 | */ |
51 | static int drm_sysfs_resume(struct device *dev) | 52 | static int drm_sysfs_resume(struct device *dev) |
52 | { | 53 | { |
53 | struct drm_device *drm_dev = to_drm_device(dev); | 54 | struct drm_minor *drm_minor = to_drm_minor(dev); |
55 | struct drm_device *drm_dev = drm_minor->dev; | ||
54 | 56 | ||
55 | if (drm_dev->driver->resume) | 57 | if (drm_dev->driver->resume) |
56 | return drm_dev->driver->resume(drm_dev); | 58 | return drm_dev->driver->resume(drm_dev); |
@@ -120,10 +122,11 @@ void drm_sysfs_destroy(void) | |||
120 | static ssize_t show_dri(struct device *device, struct device_attribute *attr, | 122 | static ssize_t show_dri(struct device *device, struct device_attribute *attr, |
121 | char *buf) | 123 | char *buf) |
122 | { | 124 | { |
123 | struct drm_device *dev = to_drm_device(device); | 125 | struct drm_minor *drm_minor = to_drm_minor(device); |
124 | if (dev->driver->dri_library_name) | 126 | struct drm_device *drm_dev = drm_minor->dev; |
125 | return dev->driver->dri_library_name(dev, buf); | 127 | if (drm_dev->driver->dri_library_name) |
126 | return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); | 128 | return drm_dev->driver->dri_library_name(drm_dev, buf); |
129 | return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name); | ||
127 | } | 130 | } |
128 | 131 | ||
129 | static struct device_attribute device_attrs[] = { | 132 | static struct device_attribute device_attrs[] = { |
@@ -152,25 +155,28 @@ static void drm_sysfs_device_release(struct device *dev) | |||
152 | * as the parent for the Linux device, and make sure it has a file containing | 155 | * as the parent for the Linux device, and make sure it has a file containing |
153 | * the driver we're using (for userspace compatibility). | 156 | * the driver we're using (for userspace compatibility). |
154 | */ | 157 | */ |
155 | int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) | 158 | int drm_sysfs_device_add(struct drm_minor *minor) |
156 | { | 159 | { |
157 | int err; | 160 | int err; |
158 | int i, j; | 161 | int i, j; |
162 | char *minor_str; | ||
159 | 163 | ||
160 | dev->dev.parent = &dev->pdev->dev; | 164 | minor->kdev.parent = &minor->dev->pdev->dev; |
161 | dev->dev.class = drm_class; | 165 | minor->kdev.class = drm_class; |
162 | dev->dev.release = drm_sysfs_device_release; | 166 | minor->kdev.release = drm_sysfs_device_release; |
163 | dev->dev.devt = head->device; | 167 | minor->kdev.devt = minor->device; |
164 | snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor); | 168 | minor_str = "card%d"; |
165 | 169 | ||
166 | err = device_register(&dev->dev); | 170 | snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); |
171 | |||
172 | err = device_register(&minor->kdev); | ||
167 | if (err) { | 173 | if (err) { |
168 | DRM_ERROR("device add failed: %d\n", err); | 174 | DRM_ERROR("device add failed: %d\n", err); |
169 | goto err_out; | 175 | goto err_out; |
170 | } | 176 | } |
171 | 177 | ||
172 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { | 178 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { |
173 | err = device_create_file(&dev->dev, &device_attrs[i]); | 179 | err = device_create_file(&minor->kdev, &device_attrs[i]); |
174 | if (err) | 180 | if (err) |
175 | goto err_out_files; | 181 | goto err_out_files; |
176 | } | 182 | } |
@@ -180,8 +186,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) | |||
180 | err_out_files: | 186 | err_out_files: |
181 | if (i > 0) | 187 | if (i > 0) |
182 | for (j = 0; j < i; j++) | 188 | for (j = 0; j < i; j++) |
183 | device_remove_file(&dev->dev, &device_attrs[i]); | 189 | device_remove_file(&minor->kdev, &device_attrs[i]); |
184 | device_unregister(&dev->dev); | 190 | device_unregister(&minor->kdev); |
185 | err_out: | 191 | err_out: |
186 | 192 | ||
187 | return err; | 193 | return err; |
@@ -194,11 +200,11 @@ err_out: | |||
194 | * This call unregisters and cleans up a class device that was created with a | 200 | * This call unregisters and cleans up a class device that was created with a |
195 | * call to drm_sysfs_device_add() | 201 | * call to drm_sysfs_device_add() |
196 | */ | 202 | */ |
197 | void drm_sysfs_device_remove(struct drm_device *dev) | 203 | void drm_sysfs_device_remove(struct drm_minor *minor) |
198 | { | 204 | { |
199 | int i; | 205 | int i; |
200 | 206 | ||
201 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) | 207 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) |
202 | device_remove_file(&dev->dev, &device_attrs[i]); | 208 | device_remove_file(&minor->kdev, &device_attrs[i]); |
203 | device_unregister(&dev->dev); | 209 | device_unregister(&minor->kdev); |
204 | } | 210 | } |
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index 945df72a51a9..c234c6f24a8d 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c | |||
@@ -90,7 +90,7 @@ static pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma) | |||
90 | static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 90 | static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
91 | { | 91 | { |
92 | struct drm_file *priv = vma->vm_file->private_data; | 92 | struct drm_file *priv = vma->vm_file->private_data; |
93 | struct drm_device *dev = priv->head->dev; | 93 | struct drm_device *dev = priv->minor->dev; |
94 | struct drm_map *map = NULL; | 94 | struct drm_map *map = NULL; |
95 | struct drm_map_list *r_list; | 95 | struct drm_map_list *r_list; |
96 | struct drm_hash_item *hash; | 96 | struct drm_hash_item *hash; |
@@ -207,7 +207,7 @@ static int drm_do_vm_shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
207 | static void drm_vm_shm_close(struct vm_area_struct *vma) | 207 | static void drm_vm_shm_close(struct vm_area_struct *vma) |
208 | { | 208 | { |
209 | struct drm_file *priv = vma->vm_file->private_data; | 209 | struct drm_file *priv = vma->vm_file->private_data; |
210 | struct drm_device *dev = priv->head->dev; | 210 | struct drm_device *dev = priv->minor->dev; |
211 | struct drm_vma_entry *pt, *temp; | 211 | struct drm_vma_entry *pt, *temp; |
212 | struct drm_map *map; | 212 | struct drm_map *map; |
213 | struct drm_map_list *r_list; | 213 | struct drm_map_list *r_list; |
@@ -286,7 +286,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) | |||
286 | static int drm_do_vm_dma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 286 | static int drm_do_vm_dma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
287 | { | 287 | { |
288 | struct drm_file *priv = vma->vm_file->private_data; | 288 | struct drm_file *priv = vma->vm_file->private_data; |
289 | struct drm_device *dev = priv->head->dev; | 289 | struct drm_device *dev = priv->minor->dev; |
290 | struct drm_device_dma *dma = dev->dma; | 290 | struct drm_device_dma *dma = dev->dma; |
291 | unsigned long offset; | 291 | unsigned long offset; |
292 | unsigned long page_nr; | 292 | unsigned long page_nr; |
@@ -321,7 +321,7 @@ static int drm_do_vm_sg_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
321 | { | 321 | { |
322 | struct drm_map *map = (struct drm_map *) vma->vm_private_data; | 322 | struct drm_map *map = (struct drm_map *) vma->vm_private_data; |
323 | struct drm_file *priv = vma->vm_file->private_data; | 323 | struct drm_file *priv = vma->vm_file->private_data; |
324 | struct drm_device *dev = priv->head->dev; | 324 | struct drm_device *dev = priv->minor->dev; |
325 | struct drm_sg_mem *entry = dev->sg; | 325 | struct drm_sg_mem *entry = dev->sg; |
326 | unsigned long offset; | 326 | unsigned long offset; |
327 | unsigned long map_offset; | 327 | unsigned long map_offset; |
@@ -402,7 +402,7 @@ static struct vm_operations_struct drm_vm_sg_ops = { | |||
402 | static void drm_vm_open_locked(struct vm_area_struct *vma) | 402 | static void drm_vm_open_locked(struct vm_area_struct *vma) |
403 | { | 403 | { |
404 | struct drm_file *priv = vma->vm_file->private_data; | 404 | struct drm_file *priv = vma->vm_file->private_data; |
405 | struct drm_device *dev = priv->head->dev; | 405 | struct drm_device *dev = priv->minor->dev; |
406 | struct drm_vma_entry *vma_entry; | 406 | struct drm_vma_entry *vma_entry; |
407 | 407 | ||
408 | DRM_DEBUG("0x%08lx,0x%08lx\n", | 408 | DRM_DEBUG("0x%08lx,0x%08lx\n", |
@@ -420,7 +420,7 @@ static void drm_vm_open_locked(struct vm_area_struct *vma) | |||
420 | static void drm_vm_open(struct vm_area_struct *vma) | 420 | static void drm_vm_open(struct vm_area_struct *vma) |
421 | { | 421 | { |
422 | struct drm_file *priv = vma->vm_file->private_data; | 422 | struct drm_file *priv = vma->vm_file->private_data; |
423 | struct drm_device *dev = priv->head->dev; | 423 | struct drm_device *dev = priv->minor->dev; |
424 | 424 | ||
425 | mutex_lock(&dev->struct_mutex); | 425 | mutex_lock(&dev->struct_mutex); |
426 | drm_vm_open_locked(vma); | 426 | drm_vm_open_locked(vma); |
@@ -438,7 +438,7 @@ static void drm_vm_open(struct vm_area_struct *vma) | |||
438 | static void drm_vm_close(struct vm_area_struct *vma) | 438 | static void drm_vm_close(struct vm_area_struct *vma) |
439 | { | 439 | { |
440 | struct drm_file *priv = vma->vm_file->private_data; | 440 | struct drm_file *priv = vma->vm_file->private_data; |
441 | struct drm_device *dev = priv->head->dev; | 441 | struct drm_device *dev = priv->minor->dev; |
442 | struct drm_vma_entry *pt, *temp; | 442 | struct drm_vma_entry *pt, *temp; |
443 | 443 | ||
444 | DRM_DEBUG("0x%08lx,0x%08lx\n", | 444 | DRM_DEBUG("0x%08lx,0x%08lx\n", |
@@ -473,7 +473,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) | |||
473 | struct drm_device_dma *dma; | 473 | struct drm_device_dma *dma; |
474 | unsigned long length = vma->vm_end - vma->vm_start; | 474 | unsigned long length = vma->vm_end - vma->vm_start; |
475 | 475 | ||
476 | dev = priv->head->dev; | 476 | dev = priv->minor->dev; |
477 | dma = dev->dma; | 477 | dma = dev->dma; |
478 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", | 478 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", |
479 | vma->vm_start, vma->vm_end, vma->vm_pgoff); | 479 | vma->vm_start, vma->vm_end, vma->vm_pgoff); |
@@ -543,7 +543,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs); | |||
543 | static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) | 543 | static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) |
544 | { | 544 | { |
545 | struct drm_file *priv = filp->private_data; | 545 | struct drm_file *priv = filp->private_data; |
546 | struct drm_device *dev = priv->head->dev; | 546 | struct drm_device *dev = priv->minor->dev; |
547 | struct drm_map *map = NULL; | 547 | struct drm_map *map = NULL; |
548 | unsigned long offset = 0; | 548 | unsigned long offset = 0; |
549 | struct drm_hash_item *hash; | 549 | struct drm_hash_item *hash; |
@@ -640,12 +640,12 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) | |||
640 | /* Don't let this area swap. Change when | 640 | /* Don't let this area swap. Change when |
641 | DRM_KERNEL advisory is supported. */ | 641 | DRM_KERNEL advisory is supported. */ |
642 | vma->vm_flags |= VM_RESERVED; | 642 | vma->vm_flags |= VM_RESERVED; |
643 | vma->vm_page_prot = drm_dma_prot(map->type, vma); | ||
644 | break; | 643 | break; |
645 | case _DRM_SCATTER_GATHER: | 644 | case _DRM_SCATTER_GATHER: |
646 | vma->vm_ops = &drm_vm_sg_ops; | 645 | vma->vm_ops = &drm_vm_sg_ops; |
647 | vma->vm_private_data = (void *)map; | 646 | vma->vm_private_data = (void *)map; |
648 | vma->vm_flags |= VM_RESERVED; | 647 | vma->vm_flags |= VM_RESERVED; |
648 | vma->vm_page_prot = drm_dma_prot(map->type, vma); | ||
649 | break; | 649 | break; |
650 | default: | 650 | default: |
651 | return -EINVAL; /* This should never happen. */ | 651 | return -EINVAL; /* This should never happen. */ |
@@ -661,7 +661,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) | |||
661 | int drm_mmap(struct file *filp, struct vm_area_struct *vma) | 661 | int drm_mmap(struct file *filp, struct vm_area_struct *vma) |
662 | { | 662 | { |
663 | struct drm_file *priv = filp->private_data; | 663 | struct drm_file *priv = filp->private_data; |
664 | struct drm_device *dev = priv->head->dev; | 664 | struct drm_device *dev = priv->minor->dev; |
665 | int ret; | 665 | int ret; |
666 | 666 | ||
667 | mutex_lock(&dev->struct_mutex); | 667 | mutex_lock(&dev->struct_mutex); |
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index 8d7ea81c4b66..e5de8ea41544 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c | |||
@@ -94,7 +94,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) | |||
94 | drm_i810_buf_priv_t *buf_priv; | 94 | drm_i810_buf_priv_t *buf_priv; |
95 | 95 | ||
96 | lock_kernel(); | 96 | lock_kernel(); |
97 | dev = priv->head->dev; | 97 | dev = priv->minor->dev; |
98 | dev_priv = dev->dev_private; | 98 | dev_priv = dev->dev_private; |
99 | buf = dev_priv->mmap_buffer; | 99 | buf = dev_priv->mmap_buffer; |
100 | buf_priv = buf->dev_private; | 100 | buf_priv = buf->dev_private; |
@@ -122,7 +122,7 @@ static const struct file_operations i810_buffer_fops = { | |||
122 | 122 | ||
123 | static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) | 123 | static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) |
124 | { | 124 | { |
125 | struct drm_device *dev = file_priv->head->dev; | 125 | struct drm_device *dev = file_priv->minor->dev; |
126 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 126 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; |
127 | drm_i810_private_t *dev_priv = dev->dev_private; | 127 | drm_i810_private_t *dev_priv = dev->dev_private; |
128 | const struct file_operations *old_fops; | 128 | const struct file_operations *old_fops; |
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 9df08105f4f3..60c9376be486 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c | |||
@@ -96,7 +96,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma) | |||
96 | drm_i830_buf_priv_t *buf_priv; | 96 | drm_i830_buf_priv_t *buf_priv; |
97 | 97 | ||
98 | lock_kernel(); | 98 | lock_kernel(); |
99 | dev = priv->head->dev; | 99 | dev = priv->minor->dev; |
100 | dev_priv = dev->dev_private; | 100 | dev_priv = dev->dev_private; |
101 | buf = dev_priv->mmap_buffer; | 101 | buf = dev_priv->mmap_buffer; |
102 | buf_priv = buf->dev_private; | 102 | buf_priv = buf->dev_private; |
@@ -124,7 +124,7 @@ static const struct file_operations i830_buffer_fops = { | |||
124 | 124 | ||
125 | static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) | 125 | static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) |
126 | { | 126 | { |
127 | struct drm_device *dev = file_priv->head->dev; | 127 | struct drm_device *dev = file_priv->minor->dev; |
128 | drm_i830_buf_priv_t *buf_priv = buf->dev_private; | 128 | drm_i830_buf_priv_t *buf_priv = buf->dev_private; |
129 | drm_i830_private_t *dev_priv = dev->dev_private; | 129 | drm_i830_private_t *dev_priv = dev->dev_private; |
130 | const struct file_operations *old_fops; | 130 | const struct file_operations *old_fops; |
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index a043bb12301a..ef7bf143a80c 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c | |||
@@ -415,10 +415,13 @@ static void i915_emit_breadcrumb(struct drm_device *dev) | |||
415 | drm_i915_private_t *dev_priv = dev->dev_private; | 415 | drm_i915_private_t *dev_priv = dev->dev_private; |
416 | RING_LOCALS; | 416 | RING_LOCALS; |
417 | 417 | ||
418 | dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; | 418 | if (++dev_priv->counter > BREADCRUMB_MASK) { |
419 | dev_priv->counter = 1; | ||
420 | DRM_DEBUG("Breadcrumb counter wrapped around\n"); | ||
421 | } | ||
419 | 422 | ||
420 | if (dev_priv->counter > 0x7FFFFFFFUL) | 423 | if (dev_priv->sarea_priv) |
421 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; | 424 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter; |
422 | 425 | ||
423 | BEGIN_LP_RING(4); | 426 | BEGIN_LP_RING(4); |
424 | OUT_RING(CMD_STORE_DWORD_IDX); | 427 | OUT_RING(CMD_STORE_DWORD_IDX); |
@@ -428,6 +431,26 @@ static void i915_emit_breadcrumb(struct drm_device *dev) | |||
428 | ADVANCE_LP_RING(); | 431 | ADVANCE_LP_RING(); |
429 | } | 432 | } |
430 | 433 | ||
434 | int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush) | ||
435 | { | ||
436 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
437 | uint32_t flush_cmd = CMD_MI_FLUSH; | ||
438 | RING_LOCALS; | ||
439 | |||
440 | flush_cmd |= flush; | ||
441 | |||
442 | i915_kernel_lost_context(dev); | ||
443 | |||
444 | BEGIN_LP_RING(4); | ||
445 | OUT_RING(flush_cmd); | ||
446 | OUT_RING(0); | ||
447 | OUT_RING(0); | ||
448 | OUT_RING(0); | ||
449 | ADVANCE_LP_RING(); | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
431 | static int i915_dispatch_cmdbuffer(struct drm_device * dev, | 454 | static int i915_dispatch_cmdbuffer(struct drm_device * dev, |
432 | drm_i915_cmdbuffer_t * cmd) | 455 | drm_i915_cmdbuffer_t * cmd) |
433 | { | 456 | { |
@@ -511,52 +534,74 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, | |||
511 | return 0; | 534 | return 0; |
512 | } | 535 | } |
513 | 536 | ||
514 | static int i915_dispatch_flip(struct drm_device * dev) | 537 | static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) |
515 | { | 538 | { |
516 | drm_i915_private_t *dev_priv = dev->dev_private; | 539 | drm_i915_private_t *dev_priv = dev->dev_private; |
540 | u32 num_pages, current_page, next_page, dspbase; | ||
541 | int shift = 2 * plane, x, y; | ||
517 | RING_LOCALS; | 542 | RING_LOCALS; |
518 | 543 | ||
519 | DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", | 544 | /* Calculate display base offset */ |
520 | __FUNCTION__, | 545 | num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; |
521 | dev_priv->current_page, | 546 | current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3; |
522 | dev_priv->sarea_priv->pf_current_page); | 547 | next_page = (current_page + 1) % num_pages; |
523 | 548 | ||
524 | i915_kernel_lost_context(dev); | 549 | switch (next_page) { |
525 | 550 | default: | |
526 | BEGIN_LP_RING(2); | 551 | case 0: |
527 | OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE); | 552 | dspbase = dev_priv->sarea_priv->front_offset; |
528 | OUT_RING(0); | 553 | break; |
529 | ADVANCE_LP_RING(); | 554 | case 1: |
555 | dspbase = dev_priv->sarea_priv->back_offset; | ||
556 | break; | ||
557 | case 2: | ||
558 | dspbase = dev_priv->sarea_priv->third_offset; | ||
559 | break; | ||
560 | } | ||
530 | 561 | ||
531 | BEGIN_LP_RING(6); | 562 | if (plane == 0) { |
532 | OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP); | 563 | x = dev_priv->sarea_priv->planeA_x; |
533 | OUT_RING(0); | 564 | y = dev_priv->sarea_priv->planeA_y; |
534 | if (dev_priv->current_page == 0) { | ||
535 | OUT_RING(dev_priv->back_offset); | ||
536 | dev_priv->current_page = 1; | ||
537 | } else { | 565 | } else { |
538 | OUT_RING(dev_priv->front_offset); | 566 | x = dev_priv->sarea_priv->planeB_x; |
539 | dev_priv->current_page = 0; | 567 | y = dev_priv->sarea_priv->planeB_y; |
540 | } | 568 | } |
541 | OUT_RING(0); | ||
542 | ADVANCE_LP_RING(); | ||
543 | 569 | ||
544 | BEGIN_LP_RING(2); | 570 | dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; |
545 | OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP); | ||
546 | OUT_RING(0); | ||
547 | ADVANCE_LP_RING(); | ||
548 | 571 | ||
549 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; | 572 | DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page, |
573 | dspbase); | ||
550 | 574 | ||
551 | BEGIN_LP_RING(4); | 575 | BEGIN_LP_RING(4); |
552 | OUT_RING(CMD_STORE_DWORD_IDX); | 576 | OUT_RING(sync ? 0 : |
553 | OUT_RING(20); | 577 | (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP : |
554 | OUT_RING(dev_priv->counter); | 578 | MI_WAIT_FOR_PLANE_A_FLIP))); |
555 | OUT_RING(0); | 579 | OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | |
580 | (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); | ||
581 | OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); | ||
582 | OUT_RING(dspbase); | ||
556 | ADVANCE_LP_RING(); | 583 | ADVANCE_LP_RING(); |
557 | 584 | ||
558 | dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; | 585 | dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); |
559 | return 0; | 586 | dev_priv->sarea_priv->pf_current_page |= next_page << shift; |
587 | } | ||
588 | |||
589 | void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) | ||
590 | { | ||
591 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
592 | int i; | ||
593 | |||
594 | DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n", | ||
595 | planes, dev_priv->sarea_priv->pf_current_page); | ||
596 | |||
597 | i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); | ||
598 | |||
599 | for (i = 0; i < 2; i++) | ||
600 | if (planes & (1 << i)) | ||
601 | i915_do_dispatch_flip(dev, i, sync); | ||
602 | |||
603 | i915_emit_breadcrumb(dev); | ||
604 | |||
560 | } | 605 | } |
561 | 606 | ||
562 | static int i915_quiescent(struct drm_device * dev) | 607 | static int i915_quiescent(struct drm_device * dev) |
@@ -579,7 +624,6 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, | |||
579 | struct drm_file *file_priv) | 624 | struct drm_file *file_priv) |
580 | { | 625 | { |
581 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 626 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
582 | u32 *hw_status = dev_priv->hw_status_page; | ||
583 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) | 627 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) |
584 | dev_priv->sarea_priv; | 628 | dev_priv->sarea_priv; |
585 | drm_i915_batchbuffer_t *batch = data; | 629 | drm_i915_batchbuffer_t *batch = data; |
@@ -602,7 +646,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, | |||
602 | 646 | ||
603 | ret = i915_dispatch_batchbuffer(dev, batch); | 647 | ret = i915_dispatch_batchbuffer(dev, batch); |
604 | 648 | ||
605 | sarea_priv->last_dispatch = (int)hw_status[5]; | 649 | sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
606 | return ret; | 650 | return ret; |
607 | } | 651 | } |
608 | 652 | ||
@@ -610,7 +654,6 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, | |||
610 | struct drm_file *file_priv) | 654 | struct drm_file *file_priv) |
611 | { | 655 | { |
612 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 656 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
613 | u32 *hw_status = dev_priv->hw_status_page; | ||
614 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) | 657 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) |
615 | dev_priv->sarea_priv; | 658 | dev_priv->sarea_priv; |
616 | drm_i915_cmdbuffer_t *cmdbuf = data; | 659 | drm_i915_cmdbuffer_t *cmdbuf = data; |
@@ -635,18 +678,51 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, | |||
635 | return ret; | 678 | return ret; |
636 | } | 679 | } |
637 | 680 | ||
638 | sarea_priv->last_dispatch = (int)hw_status[5]; | 681 | sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static int i915_do_cleanup_pageflip(struct drm_device * dev) | ||
686 | { | ||
687 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
688 | int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; | ||
689 | |||
690 | DRM_DEBUG("\n"); | ||
691 | |||
692 | for (i = 0, planes = 0; i < 2; i++) | ||
693 | if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { | ||
694 | dev_priv->sarea_priv->pf_current_page = | ||
695 | (dev_priv->sarea_priv->pf_current_page & | ||
696 | ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i)); | ||
697 | |||
698 | planes |= 1 << i; | ||
699 | } | ||
700 | |||
701 | if (planes) | ||
702 | i915_dispatch_flip(dev, planes, 0); | ||
703 | |||
639 | return 0; | 704 | return 0; |
640 | } | 705 | } |
641 | 706 | ||
642 | static int i915_flip_bufs(struct drm_device *dev, void *data, | 707 | static int i915_flip_bufs(struct drm_device *dev, void *data, |
643 | struct drm_file *file_priv) | 708 | struct drm_file *file_priv) |
644 | { | 709 | { |
645 | DRM_DEBUG("%s\n", __FUNCTION__); | 710 | drm_i915_flip_t *param = data; |
711 | |||
712 | DRM_DEBUG("\n"); | ||
646 | 713 | ||
647 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 714 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
648 | 715 | ||
649 | return i915_dispatch_flip(dev); | 716 | /* This is really planes */ |
717 | if (param->pipes & ~0x3) { | ||
718 | DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n", | ||
719 | param->pipes); | ||
720 | return -EINVAL; | ||
721 | } | ||
722 | |||
723 | i915_dispatch_flip(dev, param->pipes, 0); | ||
724 | |||
725 | return 0; | ||
650 | } | 726 | } |
651 | 727 | ||
652 | static int i915_getparam(struct drm_device *dev, void *data, | 728 | static int i915_getparam(struct drm_device *dev, void *data, |
@@ -807,6 +883,8 @@ void i915_driver_lastclose(struct drm_device * dev) | |||
807 | if (!dev_priv) | 883 | if (!dev_priv) |
808 | return; | 884 | return; |
809 | 885 | ||
886 | if (drm_getsarea(dev) && dev_priv->sarea_priv) | ||
887 | i915_do_cleanup_pageflip(dev); | ||
810 | if (dev_priv->agp_heap) | 888 | if (dev_priv->agp_heap) |
811 | i915_mem_takedown(&(dev_priv->agp_heap)); | 889 | i915_mem_takedown(&(dev_priv->agp_heap)); |
812 | 890 | ||
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h index 05c66cf03a9e..0431c00e2289 100644 --- a/drivers/char/drm/i915_drm.h +++ b/drivers/char/drm/i915_drm.h | |||
@@ -105,14 +105,29 @@ typedef struct _drm_i915_sarea { | |||
105 | unsigned int rotated_tiled; | 105 | unsigned int rotated_tiled; |
106 | unsigned int rotated2_tiled; | 106 | unsigned int rotated2_tiled; |
107 | 107 | ||
108 | int pipeA_x; | 108 | int planeA_x; |
109 | int pipeA_y; | 109 | int planeA_y; |
110 | int pipeA_w; | 110 | int planeA_w; |
111 | int pipeA_h; | 111 | int planeA_h; |
112 | int pipeB_x; | 112 | int planeB_x; |
113 | int pipeB_y; | 113 | int planeB_y; |
114 | int pipeB_w; | 114 | int planeB_w; |
115 | int pipeB_h; | 115 | int planeB_h; |
116 | |||
117 | /* Triple buffering */ | ||
118 | drm_handle_t third_handle; | ||
119 | int third_offset; | ||
120 | int third_size; | ||
121 | unsigned int third_tiled; | ||
122 | |||
123 | /* buffer object handles for the static buffers. May change | ||
124 | * over the lifetime of the client, though it doesn't in our current | ||
125 | * implementation. | ||
126 | */ | ||
127 | unsigned int front_bo_handle; | ||
128 | unsigned int back_bo_handle; | ||
129 | unsigned int third_bo_handle; | ||
130 | unsigned int depth_bo_handle; | ||
116 | } drm_i915_sarea_t; | 131 | } drm_i915_sarea_t; |
117 | 132 | ||
118 | /* Flags for perf_boxes | 133 | /* Flags for perf_boxes |
@@ -146,7 +161,7 @@ typedef struct _drm_i915_sarea { | |||
146 | 161 | ||
147 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) | 162 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) |
148 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) | 163 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) |
149 | #define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP) | 164 | #define DRM_IOCTL_I915_FLIP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FLIP, drm_i915_flip_t) |
150 | #define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t) | 165 | #define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t) |
151 | #define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t) | 166 | #define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t) |
152 | #define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t) | 167 | #define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t) |
@@ -161,6 +176,18 @@ typedef struct _drm_i915_sarea { | |||
161 | #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) | 176 | #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) |
162 | #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) | 177 | #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) |
163 | 178 | ||
179 | /* Asynchronous page flipping: | ||
180 | */ | ||
181 | typedef struct drm_i915_flip { | ||
182 | /* | ||
183 | * This is really talking about planes, and we could rename it | ||
184 | * except for the fact that some of the duplicated i915_drm.h files | ||
185 | * out there check for HAVE_I915_FLIP and so might pick up this | ||
186 | * version. | ||
187 | */ | ||
188 | int pipes; | ||
189 | } drm_i915_flip_t; | ||
190 | |||
164 | /* Allow drivers to submit batchbuffers directly to hardware, relying | 191 | /* Allow drivers to submit batchbuffers directly to hardware, relying |
165 | * on the security mechanisms provided by hardware. | 192 | * on the security mechanisms provided by hardware. |
166 | */ | 193 | */ |
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index b2b451dc4460..bb8f1b2fb383 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c | |||
@@ -533,8 +533,7 @@ static struct drm_driver driver = { | |||
533 | */ | 533 | */ |
534 | .driver_features = | 534 | .driver_features = |
535 | DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ | 535 | DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ |
536 | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | | 536 | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, |
537 | DRIVER_IRQ_VBL2, | ||
538 | .load = i915_driver_load, | 537 | .load = i915_driver_load, |
539 | .unload = i915_driver_unload, | 538 | .unload = i915_driver_unload, |
540 | .lastclose = i915_driver_lastclose, | 539 | .lastclose = i915_driver_lastclose, |
@@ -542,8 +541,9 @@ static struct drm_driver driver = { | |||
542 | .suspend = i915_suspend, | 541 | .suspend = i915_suspend, |
543 | .resume = i915_resume, | 542 | .resume = i915_resume, |
544 | .device_is_agp = i915_driver_device_is_agp, | 543 | .device_is_agp = i915_driver_device_is_agp, |
545 | .vblank_wait = i915_driver_vblank_wait, | 544 | .get_vblank_counter = i915_get_vblank_counter, |
546 | .vblank_wait2 = i915_driver_vblank_wait2, | 545 | .enable_vblank = i915_enable_vblank, |
546 | .disable_vblank = i915_disable_vblank, | ||
547 | .irq_preinstall = i915_driver_irq_preinstall, | 547 | .irq_preinstall = i915_driver_irq_preinstall, |
548 | .irq_postinstall = i915_driver_irq_postinstall, | 548 | .irq_postinstall = i915_driver_irq_postinstall, |
549 | .irq_uninstall = i915_driver_irq_uninstall, | 549 | .irq_uninstall = i915_driver_irq_uninstall, |
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index 675d88bda066..c614d78b3dfd 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h | |||
@@ -76,8 +76,9 @@ struct mem_block { | |||
76 | typedef struct _drm_i915_vbl_swap { | 76 | typedef struct _drm_i915_vbl_swap { |
77 | struct list_head head; | 77 | struct list_head head; |
78 | drm_drawable_t drw_id; | 78 | drm_drawable_t drw_id; |
79 | unsigned int pipe; | 79 | unsigned int plane; |
80 | unsigned int sequence; | 80 | unsigned int sequence; |
81 | int flip; | ||
81 | } drm_i915_vbl_swap_t; | 82 | } drm_i915_vbl_swap_t; |
82 | 83 | ||
83 | typedef struct drm_i915_private { | 84 | typedef struct drm_i915_private { |
@@ -90,7 +91,7 @@ typedef struct drm_i915_private { | |||
90 | drm_dma_handle_t *status_page_dmah; | 91 | drm_dma_handle_t *status_page_dmah; |
91 | void *hw_status_page; | 92 | void *hw_status_page; |
92 | dma_addr_t dma_status_page; | 93 | dma_addr_t dma_status_page; |
93 | unsigned long counter; | 94 | uint32_t counter; |
94 | unsigned int status_gfx_addr; | 95 | unsigned int status_gfx_addr; |
95 | drm_local_map_t hws_map; | 96 | drm_local_map_t hws_map; |
96 | 97 | ||
@@ -103,13 +104,18 @@ typedef struct drm_i915_private { | |||
103 | 104 | ||
104 | wait_queue_head_t irq_queue; | 105 | wait_queue_head_t irq_queue; |
105 | atomic_t irq_received; | 106 | atomic_t irq_received; |
106 | atomic_t irq_emitted; | 107 | atomic_t irq_emited; |
107 | 108 | ||
108 | int tex_lru_log_granularity; | 109 | int tex_lru_log_granularity; |
109 | int allow_batchbuffer; | 110 | int allow_batchbuffer; |
110 | struct mem_block *agp_heap; | 111 | struct mem_block *agp_heap; |
111 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; | 112 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; |
112 | int vblank_pipe; | 113 | int vblank_pipe; |
114 | spinlock_t user_irq_lock; | ||
115 | int user_irq_refcount; | ||
116 | int fence_irq_on; | ||
117 | uint32_t irq_enable_reg; | ||
118 | int irq_enabled; | ||
113 | 119 | ||
114 | spinlock_t swaps_lock; | 120 | spinlock_t swaps_lock; |
115 | drm_i915_vbl_swap_t vbl_swaps; | 121 | drm_i915_vbl_swap_t vbl_swaps; |
@@ -216,7 +222,7 @@ extern void i915_driver_preclose(struct drm_device *dev, | |||
216 | extern int i915_driver_device_is_agp(struct drm_device * dev); | 222 | extern int i915_driver_device_is_agp(struct drm_device * dev); |
217 | extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, | 223 | extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, |
218 | unsigned long arg); | 224 | unsigned long arg); |
219 | 225 | extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync); | |
220 | /* i915_irq.c */ | 226 | /* i915_irq.c */ |
221 | extern int i915_irq_emit(struct drm_device *dev, void *data, | 227 | extern int i915_irq_emit(struct drm_device *dev, void *data, |
222 | struct drm_file *file_priv); | 228 | struct drm_file *file_priv); |
@@ -227,7 +233,7 @@ extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequenc | |||
227 | extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence); | 233 | extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence); |
228 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); | 234 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); |
229 | extern void i915_driver_irq_preinstall(struct drm_device * dev); | 235 | extern void i915_driver_irq_preinstall(struct drm_device * dev); |
230 | extern void i915_driver_irq_postinstall(struct drm_device * dev); | 236 | extern int i915_driver_irq_postinstall(struct drm_device * dev); |
231 | extern void i915_driver_irq_uninstall(struct drm_device * dev); | 237 | extern void i915_driver_irq_uninstall(struct drm_device * dev); |
232 | extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, | 238 | extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, |
233 | struct drm_file *file_priv); | 239 | struct drm_file *file_priv); |
@@ -235,6 +241,9 @@ extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, | |||
235 | struct drm_file *file_priv); | 241 | struct drm_file *file_priv); |
236 | extern int i915_vblank_swap(struct drm_device *dev, void *data, | 242 | extern int i915_vblank_swap(struct drm_device *dev, void *data, |
237 | struct drm_file *file_priv); | 243 | struct drm_file *file_priv); |
244 | extern int i915_enable_vblank(struct drm_device *dev, int crtc); | ||
245 | extern void i915_disable_vblank(struct drm_device *dev, int crtc); | ||
246 | extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); | ||
238 | 247 | ||
239 | /* i915_mem.c */ | 248 | /* i915_mem.c */ |
240 | extern int i915_mem_alloc(struct drm_device *dev, void *data, | 249 | extern int i915_mem_alloc(struct drm_device *dev, void *data, |
@@ -379,21 +388,91 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | |||
379 | 388 | ||
380 | /* Interrupt bits: | 389 | /* Interrupt bits: |
381 | */ | 390 | */ |
382 | #define USER_INT_FLAG (1<<1) | 391 | #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) |
383 | #define VSYNC_PIPEB_FLAG (1<<5) | 392 | #define I915_DISPLAY_PORT_INTERRUPT (1<<17) |
384 | #define VSYNC_PIPEA_FLAG (1<<7) | 393 | #define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) |
385 | #define HWB_OOM_FLAG (1<<13) /* binner out of memory */ | 394 | #define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) |
395 | #define I915_HWB_OOM_INTERRUPT (1<<13) /* binner out of memory */ | ||
396 | #define I915_SYNC_STATUS_INTERRUPT (1<<12) | ||
397 | #define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) | ||
398 | #define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) | ||
399 | #define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) | ||
400 | #define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) | ||
401 | #define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) | ||
402 | #define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) | ||
403 | #define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) | ||
404 | #define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) | ||
405 | #define I915_DEBUG_INTERRUPT (1<<2) | ||
406 | #define I915_USER_INTERRUPT (1<<1) | ||
407 | |||
386 | 408 | ||
387 | #define I915REG_HWSTAM 0x02098 | 409 | #define I915REG_HWSTAM 0x02098 |
388 | #define I915REG_INT_IDENTITY_R 0x020a4 | 410 | #define I915REG_INT_IDENTITY_R 0x020a4 |
389 | #define I915REG_INT_MASK_R 0x020a8 | 411 | #define I915REG_INT_MASK_R 0x020a8 |
390 | #define I915REG_INT_ENABLE_R 0x020a0 | 412 | #define I915REG_INT_ENABLE_R 0x020a0 |
413 | #define I915REG_INSTPM 0x020c0 | ||
414 | |||
415 | #define PIPEADSL 0x70000 | ||
416 | #define PIPEBDSL 0x71000 | ||
391 | 417 | ||
392 | #define I915REG_PIPEASTAT 0x70024 | 418 | #define I915REG_PIPEASTAT 0x70024 |
393 | #define I915REG_PIPEBSTAT 0x71024 | 419 | #define I915REG_PIPEBSTAT 0x71024 |
420 | /* | ||
421 | * The two pipe frame counter registers are not synchronized, so | ||
422 | * reading a stable value is somewhat tricky. The following code | ||
423 | * should work: | ||
424 | * | ||
425 | * do { | ||
426 | * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> | ||
427 | * PIPE_FRAME_HIGH_SHIFT; | ||
428 | * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> | ||
429 | * PIPE_FRAME_LOW_SHIFT); | ||
430 | * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> | ||
431 | * PIPE_FRAME_HIGH_SHIFT); | ||
432 | * } while (high1 != high2); | ||
433 | * frame = (high1 << 8) | low1; | ||
434 | */ | ||
435 | #define PIPEAFRAMEHIGH 0x70040 | ||
436 | #define PIPEBFRAMEHIGH 0x71040 | ||
437 | #define PIPE_FRAME_HIGH_MASK 0x0000ffff | ||
438 | #define PIPE_FRAME_HIGH_SHIFT 0 | ||
439 | #define PIPEAFRAMEPIXEL 0x70044 | ||
440 | #define PIPEBFRAMEPIXEL 0x71044 | ||
394 | 441 | ||
395 | #define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) | 442 | #define PIPE_FRAME_LOW_MASK 0xff000000 |
396 | #define I915_VBLANK_CLEAR (1UL<<1) | 443 | #define PIPE_FRAME_LOW_SHIFT 24 |
444 | /* | ||
445 | * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register | ||
446 | * and is 24 bits wide. | ||
447 | */ | ||
448 | #define PIPE_PIXEL_MASK 0x00ffffff | ||
449 | #define PIPE_PIXEL_SHIFT 0 | ||
450 | |||
451 | #define I915_FIFO_UNDERRUN_STATUS (1UL<<31) | ||
452 | #define I915_CRC_ERROR_ENABLE (1UL<<29) | ||
453 | #define I915_CRC_DONE_ENABLE (1UL<<28) | ||
454 | #define I915_GMBUS_EVENT_ENABLE (1UL<<27) | ||
455 | #define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25) | ||
456 | #define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) | ||
457 | #define I915_DPST_EVENT_ENABLE (1UL<<23) | ||
458 | #define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22) | ||
459 | #define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) | ||
460 | #define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) | ||
461 | #define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ | ||
462 | #define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) | ||
463 | #define I915_OVERLAY_UPDATED_ENABLE (1UL<<16) | ||
464 | #define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) | ||
465 | #define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12) | ||
466 | #define I915_GMBUS_INTERRUPT_STATUS (1UL<<11) | ||
467 | #define I915_VSYNC_INTERRUPT_STATUS (1UL<<9) | ||
468 | #define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) | ||
469 | #define I915_DPST_EVENT_STATUS (1UL<<7) | ||
470 | #define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6) | ||
471 | #define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) | ||
472 | #define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) | ||
473 | #define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ | ||
474 | #define I915_VBLANK_INTERRUPT_STATUS (1UL<<1) | ||
475 | #define I915_OVERLAY_UPDATED_STATUS (1UL<<0) | ||
397 | 476 | ||
398 | #define SRX_INDEX 0x3c4 | 477 | #define SRX_INDEX 0x3c4 |
399 | #define SRX_DATA 0x3c5 | 478 | #define SRX_DATA 0x3c5 |
@@ -566,6 +645,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | |||
566 | #define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) | 645 | #define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) |
567 | #define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) | 646 | #define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) |
568 | #define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) | 647 | #define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) |
648 | #define XY_SRC_COPY_BLT_SRC_TILED (1<<15) | ||
649 | #define XY_SRC_COPY_BLT_DST_TILED (1<<11) | ||
569 | 650 | ||
570 | #define MI_BATCH_BUFFER ((0x30<<23)|1) | 651 | #define MI_BATCH_BUFFER ((0x30<<23)|1) |
571 | #define MI_BATCH_BUFFER_START (0x31<<23) | 652 | #define MI_BATCH_BUFFER_START (0x31<<23) |
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 92653b38e64c..023ce66ef3ab 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c | |||
@@ -38,6 +38,109 @@ | |||
38 | #define MAX_NOPID ((u32)~0) | 38 | #define MAX_NOPID ((u32)~0) |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * i915_get_pipe - return the the pipe associated with a given plane | ||
42 | * @dev: DRM device | ||
43 | * @plane: plane to look for | ||
44 | * | ||
45 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
46 | * rather than a pipe number, since they may not always be equal. This routine | ||
47 | * maps the given @plane back to a pipe number. | ||
48 | */ | ||
49 | static int | ||
50 | i915_get_pipe(struct drm_device *dev, int plane) | ||
51 | { | ||
52 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
53 | u32 dspcntr; | ||
54 | |||
55 | dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); | ||
56 | |||
57 | return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * i915_get_plane - return the the plane associated with a given pipe | ||
62 | * @dev: DRM device | ||
63 | * @pipe: pipe to look for | ||
64 | * | ||
65 | * The Intel Mesa & 2D drivers call the vblank routines with a plane number | ||
66 | * rather than a plane number, since they may not always be equal. This routine | ||
67 | * maps the given @pipe back to a plane number. | ||
68 | */ | ||
69 | static int | ||
70 | i915_get_plane(struct drm_device *dev, int pipe) | ||
71 | { | ||
72 | if (i915_get_pipe(dev, 0) == pipe) | ||
73 | return 0; | ||
74 | return 1; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * i915_pipe_enabled - check if a pipe is enabled | ||
79 | * @dev: DRM device | ||
80 | * @pipe: pipe to check | ||
81 | * | ||
82 | * Reading certain registers when the pipe is disabled can hang the chip. | ||
83 | * Use this routine to make sure the PLL is running and the pipe is active | ||
84 | * before reading such registers if unsure. | ||
85 | */ | ||
86 | static int | ||
87 | i915_pipe_enabled(struct drm_device *dev, int pipe) | ||
88 | { | ||
89 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
90 | unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; | ||
91 | |||
92 | if (I915_READ(pipeconf) & PIPEACONF_ENABLE) | ||
93 | return 1; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * Emit a synchronous flip. | ||
100 | * | ||
101 | * This function must be called with the drawable spinlock held. | ||
102 | */ | ||
103 | static void | ||
104 | i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, | ||
105 | int plane) | ||
106 | { | ||
107 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
108 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | ||
109 | u16 x1, y1, x2, y2; | ||
110 | int pf_planes = 1 << plane; | ||
111 | |||
112 | /* If the window is visible on the other plane, we have to flip on that | ||
113 | * plane as well. | ||
114 | */ | ||
115 | if (plane == 1) { | ||
116 | x1 = sarea_priv->planeA_x; | ||
117 | y1 = sarea_priv->planeA_y; | ||
118 | x2 = x1 + sarea_priv->planeA_w; | ||
119 | y2 = y1 + sarea_priv->planeA_h; | ||
120 | } else { | ||
121 | x1 = sarea_priv->planeB_x; | ||
122 | y1 = sarea_priv->planeB_y; | ||
123 | x2 = x1 + sarea_priv->planeB_w; | ||
124 | y2 = y1 + sarea_priv->planeB_h; | ||
125 | } | ||
126 | |||
127 | if (x2 > 0 && y2 > 0) { | ||
128 | int i, num_rects = drw->num_rects; | ||
129 | struct drm_clip_rect *rect = drw->rects; | ||
130 | |||
131 | for (i = 0; i < num_rects; i++) | ||
132 | if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 || | ||
133 | rect[i].x2 <= x1 || rect[i].y2 <= y1)) { | ||
134 | pf_planes = 0x3; | ||
135 | |||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | i915_dispatch_flip(dev, pf_planes, 1); | ||
141 | } | ||
142 | |||
143 | /** | ||
41 | * Emit blits for scheduled buffer swaps. | 144 | * Emit blits for scheduled buffer swaps. |
42 | * | 145 | * |
43 | * This function will be called with the HW lock held. | 146 | * This function will be called with the HW lock held. |
@@ -45,40 +148,59 @@ | |||
45 | static void i915_vblank_tasklet(struct drm_device *dev) | 148 | static void i915_vblank_tasklet(struct drm_device *dev) |
46 | { | 149 | { |
47 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 150 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
48 | unsigned long irqflags; | ||
49 | struct list_head *list, *tmp, hits, *hit; | 151 | struct list_head *list, *tmp, hits, *hit; |
50 | int nhits, nrects, slice[2], upper[2], lower[2], i; | 152 | int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; |
51 | unsigned counter[2] = { atomic_read(&dev->vbl_received), | 153 | unsigned counter[2]; |
52 | atomic_read(&dev->vbl_received2) }; | ||
53 | struct drm_drawable_info *drw; | 154 | struct drm_drawable_info *drw; |
54 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | 155 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; |
55 | u32 cpp = dev_priv->cpp; | 156 | u32 cpp = dev_priv->cpp, offsets[3]; |
56 | u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | | 157 | u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | |
57 | XY_SRC_COPY_BLT_WRITE_ALPHA | | 158 | XY_SRC_COPY_BLT_WRITE_ALPHA | |
58 | XY_SRC_COPY_BLT_WRITE_RGB) | 159 | XY_SRC_COPY_BLT_WRITE_RGB) |
59 | : XY_SRC_COPY_BLT_CMD; | 160 | : XY_SRC_COPY_BLT_CMD; |
60 | u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | | 161 | u32 src_pitch = sarea_priv->pitch * cpp; |
61 | (cpp << 23) | (1 << 24); | 162 | u32 dst_pitch = sarea_priv->pitch * cpp; |
163 | /* COPY rop (0xcc), map cpp to magic color depth constants */ | ||
164 | u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); | ||
62 | RING_LOCALS; | 165 | RING_LOCALS; |
63 | 166 | ||
167 | if (sarea_priv->front_tiled) { | ||
168 | cmd |= XY_SRC_COPY_BLT_DST_TILED; | ||
169 | dst_pitch >>= 2; | ||
170 | } | ||
171 | if (sarea_priv->back_tiled) { | ||
172 | cmd |= XY_SRC_COPY_BLT_SRC_TILED; | ||
173 | src_pitch >>= 2; | ||
174 | } | ||
175 | |||
176 | counter[0] = drm_vblank_count(dev, 0); | ||
177 | counter[1] = drm_vblank_count(dev, 1); | ||
178 | |||
64 | DRM_DEBUG("\n"); | 179 | DRM_DEBUG("\n"); |
65 | 180 | ||
66 | INIT_LIST_HEAD(&hits); | 181 | INIT_LIST_HEAD(&hits); |
67 | 182 | ||
68 | nhits = nrects = 0; | 183 | nhits = nrects = 0; |
69 | 184 | ||
70 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 185 | /* No irqsave/restore necessary. This tasklet may be run in an |
186 | * interrupt context or normal context, but we don't have to worry | ||
187 | * about getting interrupted by something acquiring the lock, because | ||
188 | * we are the interrupt context thing that acquires the lock. | ||
189 | */ | ||
190 | spin_lock(&dev_priv->swaps_lock); | ||
71 | 191 | ||
72 | /* Find buffer swaps scheduled for this vertical blank */ | 192 | /* Find buffer swaps scheduled for this vertical blank */ |
73 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { | 193 | list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { |
74 | drm_i915_vbl_swap_t *vbl_swap = | 194 | drm_i915_vbl_swap_t *vbl_swap = |
75 | list_entry(list, drm_i915_vbl_swap_t, head); | 195 | list_entry(list, drm_i915_vbl_swap_t, head); |
196 | int pipe = i915_get_pipe(dev, vbl_swap->plane); | ||
76 | 197 | ||
77 | if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23)) | 198 | if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) |
78 | continue; | 199 | continue; |
79 | 200 | ||
80 | list_del(list); | 201 | list_del(list); |
81 | dev_priv->swaps_pending--; | 202 | dev_priv->swaps_pending--; |
203 | drm_vblank_put(dev, pipe); | ||
82 | 204 | ||
83 | spin_unlock(&dev_priv->swaps_lock); | 205 | spin_unlock(&dev_priv->swaps_lock); |
84 | spin_lock(&dev->drw_lock); | 206 | spin_lock(&dev->drw_lock); |
@@ -116,33 +238,23 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
116 | spin_lock(&dev_priv->swaps_lock); | 238 | spin_lock(&dev_priv->swaps_lock); |
117 | } | 239 | } |
118 | 240 | ||
119 | if (nhits == 0) { | ||
120 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | ||
121 | return; | ||
122 | } | ||
123 | |||
124 | spin_unlock(&dev_priv->swaps_lock); | 241 | spin_unlock(&dev_priv->swaps_lock); |
125 | 242 | ||
126 | i915_kernel_lost_context(dev); | 243 | if (nhits == 0) |
127 | 244 | return; | |
128 | BEGIN_LP_RING(6); | ||
129 | |||
130 | OUT_RING(GFX_OP_DRAWRECT_INFO); | ||
131 | OUT_RING(0); | ||
132 | OUT_RING(0); | ||
133 | OUT_RING(sarea_priv->width | sarea_priv->height << 16); | ||
134 | OUT_RING(sarea_priv->width | sarea_priv->height << 16); | ||
135 | OUT_RING(0); | ||
136 | |||
137 | ADVANCE_LP_RING(); | ||
138 | 245 | ||
139 | sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; | 246 | i915_kernel_lost_context(dev); |
140 | 247 | ||
141 | upper[0] = upper[1] = 0; | 248 | upper[0] = upper[1] = 0; |
142 | slice[0] = max(sarea_priv->pipeA_h / nhits, 1); | 249 | slice[0] = max(sarea_priv->planeA_h / nhits, 1); |
143 | slice[1] = max(sarea_priv->pipeB_h / nhits, 1); | 250 | slice[1] = max(sarea_priv->planeB_h / nhits, 1); |
144 | lower[0] = sarea_priv->pipeA_y + slice[0]; | 251 | lower[0] = sarea_priv->planeA_y + slice[0]; |
145 | lower[1] = sarea_priv->pipeB_y + slice[0]; | 252 | lower[1] = sarea_priv->planeB_y + slice[0]; |
253 | |||
254 | offsets[0] = sarea_priv->front_offset; | ||
255 | offsets[1] = sarea_priv->back_offset; | ||
256 | offsets[2] = sarea_priv->third_offset; | ||
257 | num_pages = sarea_priv->third_handle ? 3 : 2; | ||
146 | 258 | ||
147 | spin_lock(&dev->drw_lock); | 259 | spin_lock(&dev->drw_lock); |
148 | 260 | ||
@@ -154,6 +266,8 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
154 | for (i = 0; i++ < nhits; | 266 | for (i = 0; i++ < nhits; |
155 | upper[0] = lower[0], lower[0] += slice[0], | 267 | upper[0] = lower[0], lower[0] += slice[0], |
156 | upper[1] = lower[1], lower[1] += slice[1]) { | 268 | upper[1] = lower[1], lower[1] += slice[1]) { |
269 | int init_drawrect = 1; | ||
270 | |||
157 | if (i == nhits) | 271 | if (i == nhits) |
158 | lower[0] = lower[1] = sarea_priv->height; | 272 | lower[0] = lower[1] = sarea_priv->height; |
159 | 273 | ||
@@ -161,7 +275,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
161 | drm_i915_vbl_swap_t *swap_hit = | 275 | drm_i915_vbl_swap_t *swap_hit = |
162 | list_entry(hit, drm_i915_vbl_swap_t, head); | 276 | list_entry(hit, drm_i915_vbl_swap_t, head); |
163 | struct drm_clip_rect *rect; | 277 | struct drm_clip_rect *rect; |
164 | int num_rects, pipe; | 278 | int num_rects, plane, front, back; |
165 | unsigned short top, bottom; | 279 | unsigned short top, bottom; |
166 | 280 | ||
167 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); | 281 | drw = drm_get_drawable_info(dev, swap_hit->drw_id); |
@@ -169,10 +283,50 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
169 | if (!drw) | 283 | if (!drw) |
170 | continue; | 284 | continue; |
171 | 285 | ||
286 | plane = swap_hit->plane; | ||
287 | |||
288 | if (swap_hit->flip) { | ||
289 | i915_dispatch_vsync_flip(dev, drw, plane); | ||
290 | continue; | ||
291 | } | ||
292 | |||
293 | if (init_drawrect) { | ||
294 | int width = sarea_priv->width; | ||
295 | int height = sarea_priv->height; | ||
296 | if (IS_I965G(dev)) { | ||
297 | BEGIN_LP_RING(4); | ||
298 | |||
299 | OUT_RING(GFX_OP_DRAWRECT_INFO_I965); | ||
300 | OUT_RING(0); | ||
301 | OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); | ||
302 | OUT_RING(0); | ||
303 | |||
304 | ADVANCE_LP_RING(); | ||
305 | } else { | ||
306 | BEGIN_LP_RING(6); | ||
307 | |||
308 | OUT_RING(GFX_OP_DRAWRECT_INFO); | ||
309 | OUT_RING(0); | ||
310 | OUT_RING(0); | ||
311 | OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); | ||
312 | OUT_RING(0); | ||
313 | OUT_RING(0); | ||
314 | |||
315 | ADVANCE_LP_RING(); | ||
316 | } | ||
317 | |||
318 | sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; | ||
319 | |||
320 | init_drawrect = 0; | ||
321 | } | ||
322 | |||
172 | rect = drw->rects; | 323 | rect = drw->rects; |
173 | pipe = swap_hit->pipe; | 324 | top = upper[plane]; |
174 | top = upper[pipe]; | 325 | bottom = lower[plane]; |
175 | bottom = lower[pipe]; | 326 | |
327 | front = (dev_priv->sarea_priv->pf_current_page >> | ||
328 | (2 * plane)) & 0x3; | ||
329 | back = (front + 1) % num_pages; | ||
176 | 330 | ||
177 | for (num_rects = drw->num_rects; num_rects--; rect++) { | 331 | for (num_rects = drw->num_rects; num_rects--; rect++) { |
178 | int y1 = max(rect->y1, top); | 332 | int y1 = max(rect->y1, top); |
@@ -184,20 +338,20 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
184 | BEGIN_LP_RING(8); | 338 | BEGIN_LP_RING(8); |
185 | 339 | ||
186 | OUT_RING(cmd); | 340 | OUT_RING(cmd); |
187 | OUT_RING(pitchropcpp); | 341 | OUT_RING(ropcpp | dst_pitch); |
188 | OUT_RING((y1 << 16) | rect->x1); | 342 | OUT_RING((y1 << 16) | rect->x1); |
189 | OUT_RING((y2 << 16) | rect->x2); | 343 | OUT_RING((y2 << 16) | rect->x2); |
190 | OUT_RING(sarea_priv->front_offset); | 344 | OUT_RING(offsets[front]); |
191 | OUT_RING((y1 << 16) | rect->x1); | 345 | OUT_RING((y1 << 16) | rect->x1); |
192 | OUT_RING(pitchropcpp & 0xffff); | 346 | OUT_RING(src_pitch); |
193 | OUT_RING(sarea_priv->back_offset); | 347 | OUT_RING(offsets[back]); |
194 | 348 | ||
195 | ADVANCE_LP_RING(); | 349 | ADVANCE_LP_RING(); |
196 | } | 350 | } |
197 | } | 351 | } |
198 | } | 352 | } |
199 | 353 | ||
200 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 354 | spin_unlock(&dev->drw_lock); |
201 | 355 | ||
202 | list_for_each_safe(hit, tmp, &hits) { | 356 | list_for_each_safe(hit, tmp, &hits) { |
203 | drm_i915_vbl_swap_t *swap_hit = | 357 | drm_i915_vbl_swap_t *swap_hit = |
@@ -209,67 +363,112 @@ static void i915_vblank_tasklet(struct drm_device *dev) | |||
209 | } | 363 | } |
210 | } | 364 | } |
211 | 365 | ||
366 | u32 i915_get_vblank_counter(struct drm_device *dev, int plane) | ||
367 | { | ||
368 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
369 | unsigned long high_frame; | ||
370 | unsigned long low_frame; | ||
371 | u32 high1, high2, low, count; | ||
372 | int pipe; | ||
373 | |||
374 | pipe = i915_get_pipe(dev, plane); | ||
375 | high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; | ||
376 | low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; | ||
377 | |||
378 | if (!i915_pipe_enabled(dev, pipe)) { | ||
379 | printk(KERN_ERR "trying to get vblank count for disabled " | ||
380 | "pipe %d\n", pipe); | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * High & low register fields aren't synchronized, so make sure | ||
386 | * we get a low value that's stable across two reads of the high | ||
387 | * register. | ||
388 | */ | ||
389 | do { | ||
390 | high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
391 | PIPE_FRAME_HIGH_SHIFT); | ||
392 | low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> | ||
393 | PIPE_FRAME_LOW_SHIFT); | ||
394 | high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> | ||
395 | PIPE_FRAME_HIGH_SHIFT); | ||
396 | } while (high1 != high2); | ||
397 | |||
398 | count = (high1 << 8) | low; | ||
399 | |||
400 | /* count may be reset by other driver(e.g. 2D driver), | ||
401 | we have no way to know if it is wrapped or resetted | ||
402 | when count is zero. do a rough guess. | ||
403 | */ | ||
404 | if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2) | ||
405 | dev->last_vblank[pipe] = 0; | ||
406 | |||
407 | return count; | ||
408 | } | ||
409 | |||
212 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 410 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) |
213 | { | 411 | { |
214 | struct drm_device *dev = (struct drm_device *) arg; | 412 | struct drm_device *dev = (struct drm_device *) arg; |
215 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 413 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
216 | u16 temp; | 414 | u32 iir; |
217 | u32 pipea_stats, pipeb_stats; | 415 | u32 pipea_stats, pipeb_stats; |
218 | 416 | int vblank = 0; | |
219 | pipea_stats = I915_READ(I915REG_PIPEASTAT); | 417 | |
220 | pipeb_stats = I915_READ(I915REG_PIPEBSTAT); | 418 | iir = I915_READ(I915REG_INT_IDENTITY_R); |
221 | 419 | if (iir == 0) { | |
222 | temp = I915_READ16(I915REG_INT_IDENTITY_R); | 420 | DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", |
223 | 421 | iir, | |
224 | temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); | 422 | I915_READ(I915REG_INT_MASK_R), |
225 | 423 | I915_READ(I915REG_INT_ENABLE_R), | |
226 | DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); | 424 | I915_READ(I915REG_PIPEASTAT), |
227 | 425 | I915_READ(I915REG_PIPEBSTAT)); | |
228 | if (temp == 0) | ||
229 | return IRQ_NONE; | 426 | return IRQ_NONE; |
427 | } | ||
230 | 428 | ||
231 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); | 429 | /* |
232 | (void) I915_READ16(I915REG_INT_IDENTITY_R); | 430 | * Clear the PIPE(A|B)STAT regs before the IIR otherwise |
233 | DRM_READMEMORYBARRIER(); | 431 | * we may get extra interrupts. |
234 | 432 | */ | |
235 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 433 | if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { |
434 | pipea_stats = I915_READ(I915REG_PIPEASTAT); | ||
435 | if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| | ||
436 | I915_VBLANK_INTERRUPT_STATUS)) | ||
437 | { | ||
438 | vblank++; | ||
439 | drm_handle_vblank(dev, i915_get_plane(dev, 0)); | ||
440 | } | ||
441 | I915_WRITE(I915REG_PIPEASTAT, pipea_stats); | ||
442 | } | ||
443 | if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { | ||
444 | pipeb_stats = I915_READ(I915REG_PIPEBSTAT); | ||
445 | if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| | ||
446 | I915_VBLANK_INTERRUPT_STATUS)) | ||
447 | { | ||
448 | vblank++; | ||
449 | drm_handle_vblank(dev, i915_get_plane(dev, 1)); | ||
450 | } | ||
451 | I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); | ||
452 | } | ||
236 | 453 | ||
237 | if (temp & USER_INT_FLAG) | 454 | if (dev_priv->sarea_priv) |
238 | DRM_WAKEUP(&dev_priv->irq_queue); | 455 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
239 | 456 | ||
240 | if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { | 457 | I915_WRITE(I915REG_INT_IDENTITY_R, iir); |
241 | int vblank_pipe = dev_priv->vblank_pipe; | 458 | (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */ |
242 | |||
243 | if ((vblank_pipe & | ||
244 | (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) | ||
245 | == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { | ||
246 | if (temp & VSYNC_PIPEA_FLAG) | ||
247 | atomic_inc(&dev->vbl_received); | ||
248 | if (temp & VSYNC_PIPEB_FLAG) | ||
249 | atomic_inc(&dev->vbl_received2); | ||
250 | } else if (((temp & VSYNC_PIPEA_FLAG) && | ||
251 | (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || | ||
252 | ((temp & VSYNC_PIPEB_FLAG) && | ||
253 | (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) | ||
254 | atomic_inc(&dev->vbl_received); | ||
255 | |||
256 | DRM_WAKEUP(&dev->vbl_queue); | ||
257 | drm_vbl_send_signals(dev); | ||
258 | 459 | ||
460 | if (iir & I915_USER_INTERRUPT) { | ||
461 | DRM_WAKEUP(&dev_priv->irq_queue); | ||
462 | } | ||
463 | if (vblank) { | ||
259 | if (dev_priv->swaps_pending > 0) | 464 | if (dev_priv->swaps_pending > 0) |
260 | drm_locked_tasklet(dev, i915_vblank_tasklet); | 465 | drm_locked_tasklet(dev, i915_vblank_tasklet); |
261 | I915_WRITE(I915REG_PIPEASTAT, | ||
262 | pipea_stats|I915_VBLANK_INTERRUPT_ENABLE| | ||
263 | I915_VBLANK_CLEAR); | ||
264 | I915_WRITE(I915REG_PIPEBSTAT, | ||
265 | pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE| | ||
266 | I915_VBLANK_CLEAR); | ||
267 | } | 466 | } |
268 | 467 | ||
269 | return IRQ_HANDLED; | 468 | return IRQ_HANDLED; |
270 | } | 469 | } |
271 | 470 | ||
272 | static int i915_emit_irq(struct drm_device * dev) | 471 | static int i915_emit_irq(struct drm_device *dev) |
273 | { | 472 | { |
274 | drm_i915_private_t *dev_priv = dev->dev_private; | 473 | drm_i915_private_t *dev_priv = dev->dev_private; |
275 | RING_LOCALS; | 474 | RING_LOCALS; |
@@ -316,42 +515,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) | |||
316 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); | 515 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); |
317 | } | 516 | } |
318 | 517 | ||
319 | dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); | 518 | if (dev_priv->sarea_priv) |
320 | return ret; | 519 | dev_priv->sarea_priv->last_dispatch = |
321 | } | 520 | READ_BREADCRUMB(dev_priv); |
322 | |||
323 | static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence, | ||
324 | atomic_t *counter) | ||
325 | { | ||
326 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
327 | unsigned int cur_vblank; | ||
328 | int ret = 0; | ||
329 | |||
330 | if (!dev_priv) { | ||
331 | DRM_ERROR("called with no initialization\n"); | ||
332 | return -EINVAL; | ||
333 | } | ||
334 | |||
335 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
336 | (((cur_vblank = atomic_read(counter)) | ||
337 | - *sequence) <= (1<<23))); | ||
338 | |||
339 | *sequence = cur_vblank; | ||
340 | |||
341 | return ret; | 521 | return ret; |
342 | } | 522 | } |
343 | 523 | ||
344 | |||
345 | int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) | ||
346 | { | ||
347 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); | ||
348 | } | ||
349 | |||
350 | int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) | ||
351 | { | ||
352 | return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); | ||
353 | } | ||
354 | |||
355 | /* Needs the lock as it touches the ring. | 524 | /* Needs the lock as it touches the ring. |
356 | */ | 525 | */ |
357 | int i915_irq_emit(struct drm_device *dev, void *data, | 526 | int i915_irq_emit(struct drm_device *dev, void *data, |
@@ -394,18 +563,96 @@ int i915_irq_wait(struct drm_device *dev, void *data, | |||
394 | return i915_wait_irq(dev, irqwait->irq_seq); | 563 | return i915_wait_irq(dev, irqwait->irq_seq); |
395 | } | 564 | } |
396 | 565 | ||
566 | int i915_enable_vblank(struct drm_device *dev, int plane) | ||
567 | { | ||
568 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
569 | int pipe = i915_get_pipe(dev, plane); | ||
570 | u32 pipestat_reg = 0; | ||
571 | u32 pipestat; | ||
572 | |||
573 | switch (pipe) { | ||
574 | case 0: | ||
575 | pipestat_reg = I915REG_PIPEASTAT; | ||
576 | dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; | ||
577 | break; | ||
578 | case 1: | ||
579 | pipestat_reg = I915REG_PIPEBSTAT; | ||
580 | dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; | ||
581 | break; | ||
582 | default: | ||
583 | DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", | ||
584 | pipe); | ||
585 | break; | ||
586 | } | ||
587 | |||
588 | if (pipestat_reg) | ||
589 | { | ||
590 | pipestat = I915_READ (pipestat_reg); | ||
591 | /* | ||
592 | * Older chips didn't have the start vblank interrupt, | ||
593 | * but | ||
594 | */ | ||
595 | if (IS_I965G (dev)) | ||
596 | pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE; | ||
597 | else | ||
598 | pipestat |= I915_VBLANK_INTERRUPT_ENABLE; | ||
599 | /* | ||
600 | * Clear any pending status | ||
601 | */ | ||
602 | pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | | ||
603 | I915_VBLANK_INTERRUPT_STATUS); | ||
604 | I915_WRITE(pipestat_reg, pipestat); | ||
605 | } | ||
606 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | void i915_disable_vblank(struct drm_device *dev, int plane) | ||
612 | { | ||
613 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | ||
614 | int pipe = i915_get_pipe(dev, plane); | ||
615 | u32 pipestat_reg = 0; | ||
616 | u32 pipestat; | ||
617 | |||
618 | switch (pipe) { | ||
619 | case 0: | ||
620 | pipestat_reg = I915REG_PIPEASTAT; | ||
621 | dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; | ||
622 | break; | ||
623 | case 1: | ||
624 | pipestat_reg = I915REG_PIPEBSTAT; | ||
625 | dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; | ||
626 | break; | ||
627 | default: | ||
628 | DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", | ||
629 | pipe); | ||
630 | break; | ||
631 | } | ||
632 | |||
633 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); | ||
634 | if (pipestat_reg) | ||
635 | { | ||
636 | pipestat = I915_READ (pipestat_reg); | ||
637 | pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE | | ||
638 | I915_VBLANK_INTERRUPT_ENABLE); | ||
639 | /* | ||
640 | * Clear any pending status | ||
641 | */ | ||
642 | pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | | ||
643 | I915_VBLANK_INTERRUPT_STATUS); | ||
644 | I915_WRITE(pipestat_reg, pipestat); | ||
645 | } | ||
646 | } | ||
647 | |||
397 | static void i915_enable_interrupt (struct drm_device *dev) | 648 | static void i915_enable_interrupt (struct drm_device *dev) |
398 | { | 649 | { |
399 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 650 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
400 | u16 flag; | ||
401 | 651 | ||
402 | flag = 0; | 652 | dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; |
403 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) | ||
404 | flag |= VSYNC_PIPEA_FLAG; | ||
405 | if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) | ||
406 | flag |= VSYNC_PIPEB_FLAG; | ||
407 | 653 | ||
408 | I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); | 654 | I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); |
655 | dev_priv->irq_enabled = 1; | ||
409 | } | 656 | } |
410 | 657 | ||
411 | /* Set the vblank monitor pipe | 658 | /* Set the vblank monitor pipe |
@@ -428,8 +675,6 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data, | |||
428 | 675 | ||
429 | dev_priv->vblank_pipe = pipe->pipe; | 676 | dev_priv->vblank_pipe = pipe->pipe; |
430 | 677 | ||
431 | i915_enable_interrupt (dev); | ||
432 | |||
433 | return 0; | 678 | return 0; |
434 | } | 679 | } |
435 | 680 | ||
@@ -447,9 +692,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, | |||
447 | 692 | ||
448 | flag = I915_READ(I915REG_INT_ENABLE_R); | 693 | flag = I915_READ(I915REG_INT_ENABLE_R); |
449 | pipe->pipe = 0; | 694 | pipe->pipe = 0; |
450 | if (flag & VSYNC_PIPEA_FLAG) | 695 | if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) |
451 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; | 696 | pipe->pipe |= DRM_I915_VBLANK_PIPE_A; |
452 | if (flag & VSYNC_PIPEB_FLAG) | 697 | if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) |
453 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; | 698 | pipe->pipe |= DRM_I915_VBLANK_PIPE_B; |
454 | 699 | ||
455 | return 0; | 700 | return 0; |
@@ -464,27 +709,30 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
464 | drm_i915_private_t *dev_priv = dev->dev_private; | 709 | drm_i915_private_t *dev_priv = dev->dev_private; |
465 | drm_i915_vblank_swap_t *swap = data; | 710 | drm_i915_vblank_swap_t *swap = data; |
466 | drm_i915_vbl_swap_t *vbl_swap; | 711 | drm_i915_vbl_swap_t *vbl_swap; |
467 | unsigned int pipe, seqtype, curseq; | 712 | unsigned int pipe, seqtype, curseq, plane; |
468 | unsigned long irqflags; | 713 | unsigned long irqflags; |
469 | struct list_head *list; | 714 | struct list_head *list; |
715 | int ret; | ||
470 | 716 | ||
471 | if (!dev_priv) { | 717 | if (!dev_priv) { |
472 | DRM_ERROR("%s called with no initialization\n", __func__); | 718 | DRM_ERROR("%s called with no initialization\n", __func__); |
473 | return -EINVAL; | 719 | return -EINVAL; |
474 | } | 720 | } |
475 | 721 | ||
476 | if (dev_priv->sarea_priv->rotation) { | 722 | if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { |
477 | DRM_DEBUG("Rotation not supported\n"); | 723 | DRM_DEBUG("Rotation not supported\n"); |
478 | return -EINVAL; | 724 | return -EINVAL; |
479 | } | 725 | } |
480 | 726 | ||
481 | if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | | 727 | if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | |
482 | _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { | 728 | _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS | |
729 | _DRM_VBLANK_FLIP)) { | ||
483 | DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); | 730 | DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); |
484 | return -EINVAL; | 731 | return -EINVAL; |
485 | } | 732 | } |
486 | 733 | ||
487 | pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; | 734 | plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; |
735 | pipe = i915_get_pipe(dev, plane); | ||
488 | 736 | ||
489 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); | 737 | seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); |
490 | 738 | ||
@@ -495,6 +743,11 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
495 | 743 | ||
496 | spin_lock_irqsave(&dev->drw_lock, irqflags); | 744 | spin_lock_irqsave(&dev->drw_lock, irqflags); |
497 | 745 | ||
746 | /* It makes no sense to schedule a swap for a drawable that doesn't have | ||
747 | * valid information at this point. E.g. this could mean that the X | ||
748 | * server is too old to push drawable information to the DRM, in which | ||
749 | * case all such swaps would become ineffective. | ||
750 | */ | ||
498 | if (!drm_get_drawable_info(dev, swap->drawable)) { | 751 | if (!drm_get_drawable_info(dev, swap->drawable)) { |
499 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 752 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
500 | DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); | 753 | DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); |
@@ -503,7 +756,8 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
503 | 756 | ||
504 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | 757 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); |
505 | 758 | ||
506 | curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); | 759 | drm_update_vblank_count(dev, pipe); |
760 | curseq = drm_vblank_count(dev, pipe); | ||
507 | 761 | ||
508 | if (seqtype == _DRM_VBLANK_RELATIVE) | 762 | if (seqtype == _DRM_VBLANK_RELATIVE) |
509 | swap->sequence += curseq; | 763 | swap->sequence += curseq; |
@@ -517,14 +771,43 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
517 | } | 771 | } |
518 | } | 772 | } |
519 | 773 | ||
774 | if (swap->seqtype & _DRM_VBLANK_FLIP) { | ||
775 | swap->sequence--; | ||
776 | |||
777 | if ((curseq - swap->sequence) <= (1<<23)) { | ||
778 | struct drm_drawable_info *drw; | ||
779 | |||
780 | LOCK_TEST_WITH_RETURN(dev, file_priv); | ||
781 | |||
782 | spin_lock_irqsave(&dev->drw_lock, irqflags); | ||
783 | |||
784 | drw = drm_get_drawable_info(dev, swap->drawable); | ||
785 | |||
786 | if (!drw) { | ||
787 | spin_unlock_irqrestore(&dev->drw_lock, | ||
788 | irqflags); | ||
789 | DRM_DEBUG("Invalid drawable ID %d\n", | ||
790 | swap->drawable); | ||
791 | return -EINVAL; | ||
792 | } | ||
793 | |||
794 | i915_dispatch_vsync_flip(dev, drw, plane); | ||
795 | |||
796 | spin_unlock_irqrestore(&dev->drw_lock, irqflags); | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | } | ||
801 | |||
520 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 802 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
521 | 803 | ||
522 | list_for_each(list, &dev_priv->vbl_swaps.head) { | 804 | list_for_each(list, &dev_priv->vbl_swaps.head) { |
523 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); | 805 | vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); |
524 | 806 | ||
525 | if (vbl_swap->drw_id == swap->drawable && | 807 | if (vbl_swap->drw_id == swap->drawable && |
526 | vbl_swap->pipe == pipe && | 808 | vbl_swap->plane == plane && |
527 | vbl_swap->sequence == swap->sequence) { | 809 | vbl_swap->sequence == swap->sequence) { |
810 | vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); | ||
528 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); | 811 | spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); |
529 | DRM_DEBUG("Already scheduled\n"); | 812 | DRM_DEBUG("Already scheduled\n"); |
530 | return 0; | 813 | return 0; |
@@ -547,9 +830,19 @@ int i915_vblank_swap(struct drm_device *dev, void *data, | |||
547 | 830 | ||
548 | DRM_DEBUG("\n"); | 831 | DRM_DEBUG("\n"); |
549 | 832 | ||
833 | ret = drm_vblank_get(dev, pipe); | ||
834 | if (ret) { | ||
835 | drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); | ||
836 | return ret; | ||
837 | } | ||
838 | |||
550 | vbl_swap->drw_id = swap->drawable; | 839 | vbl_swap->drw_id = swap->drawable; |
551 | vbl_swap->pipe = pipe; | 840 | vbl_swap->plane = plane; |
552 | vbl_swap->sequence = swap->sequence; | 841 | vbl_swap->sequence = swap->sequence; |
842 | vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); | ||
843 | |||
844 | if (vbl_swap->flip) | ||
845 | swap->sequence++; | ||
553 | 846 | ||
554 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); | 847 | spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); |
555 | 848 | ||
@@ -567,37 +860,57 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
567 | { | 860 | { |
568 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 861 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
569 | 862 | ||
570 | I915_WRITE16(I915REG_HWSTAM, 0xfffe); | 863 | I915_WRITE16(I915REG_HWSTAM, 0xeffe); |
571 | I915_WRITE16(I915REG_INT_MASK_R, 0x0); | 864 | I915_WRITE16(I915REG_INT_MASK_R, 0x0); |
572 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); | 865 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); |
573 | } | 866 | } |
574 | 867 | ||
575 | void i915_driver_irq_postinstall(struct drm_device * dev) | 868 | int i915_driver_irq_postinstall(struct drm_device * dev) |
576 | { | 869 | { |
577 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 870 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
871 | int ret, num_pipes = 2; | ||
578 | 872 | ||
579 | spin_lock_init(&dev_priv->swaps_lock); | 873 | spin_lock_init(&dev_priv->swaps_lock); |
580 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); | 874 | INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); |
581 | dev_priv->swaps_pending = 0; | 875 | dev_priv->swaps_pending = 0; |
582 | 876 | ||
583 | if (!dev_priv->vblank_pipe) | 877 | dev_priv->user_irq_refcount = 0; |
584 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; | 878 | dev_priv->irq_enable_reg = 0; |
879 | |||
880 | ret = drm_vblank_init(dev, num_pipes); | ||
881 | if (ret) | ||
882 | return ret; | ||
883 | |||
884 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ | ||
885 | |||
585 | i915_enable_interrupt(dev); | 886 | i915_enable_interrupt(dev); |
586 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); | 887 | DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); |
888 | |||
889 | /* | ||
890 | * Initialize the hardware status page IRQ location. | ||
891 | */ | ||
892 | |||
893 | I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); | ||
894 | return 0; | ||
587 | } | 895 | } |
588 | 896 | ||
589 | void i915_driver_irq_uninstall(struct drm_device * dev) | 897 | void i915_driver_irq_uninstall(struct drm_device * dev) |
590 | { | 898 | { |
591 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 899 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
592 | u16 temp; | 900 | u32 temp; |
593 | 901 | ||
594 | if (!dev_priv) | 902 | if (!dev_priv) |
595 | return; | 903 | return; |
596 | 904 | ||
597 | I915_WRITE16(I915REG_HWSTAM, 0xffff); | 905 | dev_priv->irq_enabled = 0; |
598 | I915_WRITE16(I915REG_INT_MASK_R, 0xffff); | 906 | I915_WRITE(I915REG_HWSTAM, 0xffffffff); |
599 | I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); | 907 | I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); |
600 | 908 | I915_WRITE(I915REG_INT_ENABLE_R, 0x0); | |
601 | temp = I915_READ16(I915REG_INT_IDENTITY_R); | 909 | |
602 | I915_WRITE16(I915REG_INT_IDENTITY_R, temp); | 910 | temp = I915_READ(I915REG_PIPEASTAT); |
911 | I915_WRITE(I915REG_PIPEASTAT, temp); | ||
912 | temp = I915_READ(I915REG_PIPEBSTAT); | ||
913 | I915_WRITE(I915REG_PIPEBSTAT, temp); | ||
914 | temp = I915_READ(I915REG_INT_IDENTITY_R); | ||
915 | I915_WRITE(I915REG_INT_IDENTITY_R, temp); | ||
603 | } | 916 | } |
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index 5572939fc7d1..6b3790939e76 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c | |||
@@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = { | |||
45 | static struct drm_driver driver = { | 45 | static struct drm_driver driver = { |
46 | .driver_features = | 46 | .driver_features = |
47 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | | 47 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | |
48 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | | 48 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, |
49 | DRIVER_IRQ_VBL, | ||
50 | .dev_priv_size = sizeof(drm_mga_buf_priv_t), | 49 | .dev_priv_size = sizeof(drm_mga_buf_priv_t), |
51 | .load = mga_driver_load, | 50 | .load = mga_driver_load, |
52 | .unload = mga_driver_unload, | 51 | .unload = mga_driver_unload, |
53 | .lastclose = mga_driver_lastclose, | 52 | .lastclose = mga_driver_lastclose, |
54 | .dma_quiescent = mga_driver_dma_quiescent, | 53 | .dma_quiescent = mga_driver_dma_quiescent, |
55 | .device_is_agp = mga_driver_device_is_agp, | 54 | .device_is_agp = mga_driver_device_is_agp, |
56 | .vblank_wait = mga_driver_vblank_wait, | 55 | .get_vblank_counter = mga_get_vblank_counter, |
56 | .enable_vblank = mga_enable_vblank, | ||
57 | .disable_vblank = mga_disable_vblank, | ||
57 | .irq_preinstall = mga_driver_irq_preinstall, | 58 | .irq_preinstall = mga_driver_irq_preinstall, |
58 | .irq_postinstall = mga_driver_irq_postinstall, | 59 | .irq_postinstall = mga_driver_irq_postinstall, |
59 | .irq_uninstall = mga_driver_irq_uninstall, | 60 | .irq_uninstall = mga_driver_irq_uninstall, |
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index f6ebd24bd587..8f7291f36363 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h | |||
@@ -120,6 +120,7 @@ typedef struct drm_mga_private { | |||
120 | u32 clear_cmd; | 120 | u32 clear_cmd; |
121 | u32 maccess; | 121 | u32 maccess; |
122 | 122 | ||
123 | atomic_t vbl_received; /**< Number of vblanks received. */ | ||
123 | wait_queue_head_t fence_queue; | 124 | wait_queue_head_t fence_queue; |
124 | atomic_t last_fence_retired; | 125 | atomic_t last_fence_retired; |
125 | u32 next_fence_to_post; | 126 | u32 next_fence_to_post; |
@@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); | |||
181 | extern int mga_warp_init(drm_mga_private_t * dev_priv); | 182 | extern int mga_warp_init(drm_mga_private_t * dev_priv); |
182 | 183 | ||
183 | /* mga_irq.c */ | 184 | /* mga_irq.c */ |
185 | extern int mga_enable_vblank(struct drm_device *dev, int crtc); | ||
186 | extern void mga_disable_vblank(struct drm_device *dev, int crtc); | ||
187 | extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc); | ||
184 | extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); | 188 | extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); |
185 | extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); | 189 | extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); |
186 | extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); | 190 | extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); |
187 | extern void mga_driver_irq_preinstall(struct drm_device * dev); | 191 | extern void mga_driver_irq_preinstall(struct drm_device * dev); |
188 | extern void mga_driver_irq_postinstall(struct drm_device * dev); | 192 | extern int mga_driver_irq_postinstall(struct drm_device * dev); |
189 | extern void mga_driver_irq_uninstall(struct drm_device * dev); | 193 | extern void mga_driver_irq_uninstall(struct drm_device * dev); |
190 | extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, | 194 | extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, |
191 | unsigned long arg); | 195 | unsigned long arg); |
diff --git a/drivers/char/drm/mga_irq.c b/drivers/char/drm/mga_irq.c index 9302cb8f0f83..06852fb4b278 100644 --- a/drivers/char/drm/mga_irq.c +++ b/drivers/char/drm/mga_irq.c | |||
@@ -35,6 +35,20 @@ | |||
35 | #include "mga_drm.h" | 35 | #include "mga_drm.h" |
36 | #include "mga_drv.h" | 36 | #include "mga_drv.h" |
37 | 37 | ||
38 | u32 mga_get_vblank_counter(struct drm_device *dev, int crtc) | ||
39 | { | ||
40 | const drm_mga_private_t *const dev_priv = | ||
41 | (drm_mga_private_t *) dev->dev_private; | ||
42 | |||
43 | if (crtc != 0) { | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | |||
48 | return atomic_read(&dev_priv->vbl_received); | ||
49 | } | ||
50 | |||
51 | |||
38 | irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | 52 | irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) |
39 | { | 53 | { |
40 | struct drm_device *dev = (struct drm_device *) arg; | 54 | struct drm_device *dev = (struct drm_device *) arg; |
@@ -47,9 +61,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | |||
47 | /* VBLANK interrupt */ | 61 | /* VBLANK interrupt */ |
48 | if (status & MGA_VLINEPEN) { | 62 | if (status & MGA_VLINEPEN) { |
49 | MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); | 63 | MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); |
50 | atomic_inc(&dev->vbl_received); | 64 | atomic_inc(&dev_priv->vbl_received); |
51 | DRM_WAKEUP(&dev->vbl_queue); | 65 | drm_handle_vblank(dev, 0); |
52 | drm_vbl_send_signals(dev); | ||
53 | handled = 1; | 66 | handled = 1; |
54 | } | 67 | } |
55 | 68 | ||
@@ -78,22 +91,34 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) | |||
78 | return IRQ_NONE; | 91 | return IRQ_NONE; |
79 | } | 92 | } |
80 | 93 | ||
81 | int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) | 94 | int mga_enable_vblank(struct drm_device *dev, int crtc) |
82 | { | 95 | { |
83 | unsigned int cur_vblank; | 96 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; |
84 | int ret = 0; | ||
85 | 97 | ||
86 | /* Assume that the user has missed the current sequence number | 98 | if (crtc != 0) { |
87 | * by about a day rather than she wants to wait for years | 99 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", |
88 | * using vertical blanks... | 100 | crtc); |
89 | */ | 101 | return 0; |
90 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | 102 | } |
91 | (((cur_vblank = atomic_read(&dev->vbl_received)) | ||
92 | - *sequence) <= (1 << 23))); | ||
93 | 103 | ||
94 | *sequence = cur_vblank; | 104 | MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); |
105 | return 0; | ||
106 | } | ||
95 | 107 | ||
96 | return ret; | 108 | |
109 | void mga_disable_vblank(struct drm_device *dev, int crtc) | ||
110 | { | ||
111 | if (crtc != 0) { | ||
112 | DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", | ||
113 | crtc); | ||
114 | } | ||
115 | |||
116 | /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have | ||
117 | * a nice hardware counter that tracks the number of refreshes when | ||
118 | * the interrupt is disabled, and the kernel doesn't know the refresh | ||
119 | * rate to calculate an estimate. | ||
120 | */ | ||
121 | /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */ | ||
97 | } | 122 | } |
98 | 123 | ||
99 | int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) | 124 | int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) |
@@ -125,14 +150,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev) | |||
125 | MGA_WRITE(MGA_ICLEAR, ~0); | 150 | MGA_WRITE(MGA_ICLEAR, ~0); |
126 | } | 151 | } |
127 | 152 | ||
128 | void mga_driver_irq_postinstall(struct drm_device * dev) | 153 | int mga_driver_irq_postinstall(struct drm_device * dev) |
129 | { | 154 | { |
130 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; | 155 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; |
156 | int ret; | ||
157 | |||
158 | ret = drm_vblank_init(dev, 1); | ||
159 | if (ret) | ||
160 | return ret; | ||
131 | 161 | ||
132 | DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); | 162 | DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); |
133 | 163 | ||
134 | /* Turn on vertical blank interrupt and soft trap interrupt. */ | 164 | /* Turn on soft trap interrupt. Vertical blank interrupts are enabled |
135 | MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); | 165 | * in mga_enable_vblank. |
166 | */ | ||
167 | MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN); | ||
168 | return 0; | ||
136 | } | 169 | } |
137 | 170 | ||
138 | void mga_driver_irq_uninstall(struct drm_device * dev) | 171 | void mga_driver_irq_uninstall(struct drm_device * dev) |
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c index 6108e7587e12..2888aa01ebc7 100644 --- a/drivers/char/drm/r128_drv.c +++ b/drivers/char/drm/r128_drv.c | |||
@@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = { | |||
43 | static struct drm_driver driver = { | 43 | static struct drm_driver driver = { |
44 | .driver_features = | 44 | .driver_features = |
45 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | | 45 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | |
46 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | | 46 | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, |
47 | DRIVER_IRQ_VBL, | ||
48 | .dev_priv_size = sizeof(drm_r128_buf_priv_t), | 47 | .dev_priv_size = sizeof(drm_r128_buf_priv_t), |
49 | .preclose = r128_driver_preclose, | 48 | .preclose = r128_driver_preclose, |
50 | .lastclose = r128_driver_lastclose, | 49 | .lastclose = r128_driver_lastclose, |
51 | .vblank_wait = r128_driver_vblank_wait, | 50 | .get_vblank_counter = r128_get_vblank_counter, |
51 | .enable_vblank = r128_enable_vblank, | ||
52 | .disable_vblank = r128_disable_vblank, | ||
52 | .irq_preinstall = r128_driver_irq_preinstall, | 53 | .irq_preinstall = r128_driver_irq_preinstall, |
53 | .irq_postinstall = r128_driver_irq_postinstall, | 54 | .irq_postinstall = r128_driver_irq_postinstall, |
54 | .irq_uninstall = r128_driver_irq_uninstall, | 55 | .irq_uninstall = r128_driver_irq_uninstall, |
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index 011105e51ac6..80af9e09e75d 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h | |||
@@ -97,6 +97,8 @@ typedef struct drm_r128_private { | |||
97 | u32 crtc_offset; | 97 | u32 crtc_offset; |
98 | u32 crtc_offset_cntl; | 98 | u32 crtc_offset_cntl; |
99 | 99 | ||
100 | atomic_t vbl_received; | ||
101 | |||
100 | u32 color_fmt; | 102 | u32 color_fmt; |
101 | unsigned int front_offset; | 103 | unsigned int front_offset; |
102 | unsigned int front_pitch; | 104 | unsigned int front_pitch; |
@@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n); | |||
149 | extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); | 151 | extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); |
150 | extern int r128_do_cleanup_cce(struct drm_device * dev); | 152 | extern int r128_do_cleanup_cce(struct drm_device * dev); |
151 | 153 | ||
152 | extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); | 154 | extern int r128_enable_vblank(struct drm_device *dev, int crtc); |
153 | 155 | extern void r128_disable_vblank(struct drm_device *dev, int crtc); | |
156 | extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc); | ||
154 | extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); | 157 | extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); |
155 | extern void r128_driver_irq_preinstall(struct drm_device * dev); | 158 | extern void r128_driver_irq_preinstall(struct drm_device * dev); |
156 | extern void r128_driver_irq_postinstall(struct drm_device * dev); | 159 | extern int r128_driver_irq_postinstall(struct drm_device * dev); |
157 | extern void r128_driver_irq_uninstall(struct drm_device * dev); | 160 | extern void r128_driver_irq_uninstall(struct drm_device * dev); |
158 | extern void r128_driver_lastclose(struct drm_device * dev); | 161 | extern void r128_driver_lastclose(struct drm_device * dev); |
159 | extern void r128_driver_preclose(struct drm_device * dev, | 162 | extern void r128_driver_preclose(struct drm_device * dev, |
diff --git a/drivers/char/drm/r128_irq.c b/drivers/char/drm/r128_irq.c index c76fdca7662d..5b95bd898f95 100644 --- a/drivers/char/drm/r128_irq.c +++ b/drivers/char/drm/r128_irq.c | |||
@@ -35,6 +35,16 @@ | |||
35 | #include "r128_drm.h" | 35 | #include "r128_drm.h" |
36 | #include "r128_drv.h" | 36 | #include "r128_drv.h" |
37 | 37 | ||
38 | u32 r128_get_vblank_counter(struct drm_device *dev, int crtc) | ||
39 | { | ||
40 | const drm_r128_private_t *dev_priv = dev->dev_private; | ||
41 | |||
42 | if (crtc != 0) | ||
43 | return 0; | ||
44 | |||
45 | return atomic_read(&dev_priv->vbl_received); | ||
46 | } | ||
47 | |||
38 | irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) | 48 | irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) |
39 | { | 49 | { |
40 | struct drm_device *dev = (struct drm_device *) arg; | 50 | struct drm_device *dev = (struct drm_device *) arg; |
@@ -46,30 +56,38 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS) | |||
46 | /* VBLANK interrupt */ | 56 | /* VBLANK interrupt */ |
47 | if (status & R128_CRTC_VBLANK_INT) { | 57 | if (status & R128_CRTC_VBLANK_INT) { |
48 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); | 58 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); |
49 | atomic_inc(&dev->vbl_received); | 59 | atomic_inc(&dev_priv->vbl_received); |
50 | DRM_WAKEUP(&dev->vbl_queue); | 60 | drm_handle_vblank(dev, 0); |
51 | drm_vbl_send_signals(dev); | ||
52 | return IRQ_HANDLED; | 61 | return IRQ_HANDLED; |
53 | } | 62 | } |
54 | return IRQ_NONE; | 63 | return IRQ_NONE; |
55 | } | 64 | } |
56 | 65 | ||
57 | int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) | 66 | int r128_enable_vblank(struct drm_device *dev, int crtc) |
58 | { | 67 | { |
59 | unsigned int cur_vblank; | 68 | drm_r128_private_t *dev_priv = dev->dev_private; |
60 | int ret = 0; | ||
61 | 69 | ||
62 | /* Assume that the user has missed the current sequence number | 70 | if (crtc != 0) { |
63 | * by about a day rather than she wants to wait for years | 71 | DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); |
64 | * using vertical blanks... | 72 | return -EINVAL; |
65 | */ | 73 | } |
66 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
67 | (((cur_vblank = atomic_read(&dev->vbl_received)) | ||
68 | - *sequence) <= (1 << 23))); | ||
69 | 74 | ||
70 | *sequence = cur_vblank; | 75 | R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN); |
76 | return 0; | ||
77 | } | ||
78 | |||
79 | void r128_disable_vblank(struct drm_device *dev, int crtc) | ||
80 | { | ||
81 | if (crtc != 0) | ||
82 | DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); | ||
71 | 83 | ||
72 | return ret; | 84 | /* |
85 | * FIXME: implement proper interrupt disable by using the vblank | ||
86 | * counter register (if available) | ||
87 | * | ||
88 | * R128_WRITE(R128_GEN_INT_CNTL, | ||
89 | * R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN); | ||
90 | */ | ||
73 | } | 91 | } |
74 | 92 | ||
75 | void r128_driver_irq_preinstall(struct drm_device * dev) | 93 | void r128_driver_irq_preinstall(struct drm_device * dev) |
@@ -82,12 +100,9 @@ void r128_driver_irq_preinstall(struct drm_device * dev) | |||
82 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); | 100 | R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK); |
83 | } | 101 | } |
84 | 102 | ||
85 | void r128_driver_irq_postinstall(struct drm_device * dev) | 103 | int r128_driver_irq_postinstall(struct drm_device * dev) |
86 | { | 104 | { |
87 | drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private; | 105 | return drm_vblank_init(dev, 1); |
88 | |||
89 | /* Turn on VBL interrupt */ | ||
90 | R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN); | ||
91 | } | 106 | } |
92 | 107 | ||
93 | void r128_driver_irq_uninstall(struct drm_device * dev) | 108 | void r128_driver_irq_uninstall(struct drm_device * dev) |
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c index 349ac3d3b848..a2610319624d 100644 --- a/drivers/char/drm/radeon_drv.c +++ b/drivers/char/drm/radeon_drv.c | |||
@@ -59,8 +59,7 @@ static struct pci_device_id pciidlist[] = { | |||
59 | static struct drm_driver driver = { | 59 | static struct drm_driver driver = { |
60 | .driver_features = | 60 | .driver_features = |
61 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | | 61 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | |
62 | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | | 62 | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED, |
63 | DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, | ||
64 | .dev_priv_size = sizeof(drm_radeon_buf_priv_t), | 63 | .dev_priv_size = sizeof(drm_radeon_buf_priv_t), |
65 | .load = radeon_driver_load, | 64 | .load = radeon_driver_load, |
66 | .firstopen = radeon_driver_firstopen, | 65 | .firstopen = radeon_driver_firstopen, |
@@ -69,8 +68,9 @@ static struct drm_driver driver = { | |||
69 | .postclose = radeon_driver_postclose, | 68 | .postclose = radeon_driver_postclose, |
70 | .lastclose = radeon_driver_lastclose, | 69 | .lastclose = radeon_driver_lastclose, |
71 | .unload = radeon_driver_unload, | 70 | .unload = radeon_driver_unload, |
72 | .vblank_wait = radeon_driver_vblank_wait, | 71 | .get_vblank_counter = radeon_get_vblank_counter, |
73 | .vblank_wait2 = radeon_driver_vblank_wait2, | 72 | .enable_vblank = radeon_enable_vblank, |
73 | .disable_vblank = radeon_disable_vblank, | ||
74 | .dri_library_name = dri_library_name, | 74 | .dri_library_name = dri_library_name, |
75 | .irq_preinstall = radeon_driver_irq_preinstall, | 75 | .irq_preinstall = radeon_driver_irq_preinstall, |
76 | .irq_postinstall = radeon_driver_irq_postinstall, | 76 | .irq_postinstall = radeon_driver_irq_postinstall, |
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 173ae620223a..b791420bd3d9 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h | |||
@@ -304,6 +304,9 @@ typedef struct drm_radeon_private { | |||
304 | 304 | ||
305 | u32 scratch_ages[5]; | 305 | u32 scratch_ages[5]; |
306 | 306 | ||
307 | unsigned int crtc_last_cnt; | ||
308 | unsigned int crtc2_last_cnt; | ||
309 | |||
307 | /* starting from here on, data is preserved accross an open */ | 310 | /* starting from here on, data is preserved accross an open */ |
308 | uint32_t flags; /* see radeon_chip_flags */ | 311 | uint32_t flags; /* see radeon_chip_flags */ |
309 | unsigned long fb_aper_offset; | 312 | unsigned long fb_aper_offset; |
@@ -374,13 +377,13 @@ extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file * | |||
374 | extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); | 377 | extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); |
375 | 378 | ||
376 | extern void radeon_do_release(struct drm_device * dev); | 379 | extern void radeon_do_release(struct drm_device * dev); |
377 | extern int radeon_driver_vblank_wait(struct drm_device * dev, | 380 | extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc); |
378 | unsigned int *sequence); | 381 | extern int radeon_enable_vblank(struct drm_device *dev, int crtc); |
379 | extern int radeon_driver_vblank_wait2(struct drm_device * dev, | 382 | extern void radeon_disable_vblank(struct drm_device *dev, int crtc); |
380 | unsigned int *sequence); | 383 | extern void radeon_do_release(struct drm_device * dev); |
381 | extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); | 384 | extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); |
382 | extern void radeon_driver_irq_preinstall(struct drm_device * dev); | 385 | extern void radeon_driver_irq_preinstall(struct drm_device * dev); |
383 | extern void radeon_driver_irq_postinstall(struct drm_device * dev); | 386 | extern int radeon_driver_irq_postinstall(struct drm_device * dev); |
384 | extern void radeon_driver_irq_uninstall(struct drm_device * dev); | 387 | extern void radeon_driver_irq_uninstall(struct drm_device * dev); |
385 | extern int radeon_vblank_crtc_get(struct drm_device *dev); | 388 | extern int radeon_vblank_crtc_get(struct drm_device *dev); |
386 | extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value); | 389 | extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value); |
@@ -558,6 +561,12 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev, | |||
558 | ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \ | 561 | ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \ |
559 | : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) | 562 | : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) |
560 | 563 | ||
564 | #define RADEON_CRTC_CRNT_FRAME 0x0214 | ||
565 | #define RADEON_CRTC2_CRNT_FRAME 0x0314 | ||
566 | |||
567 | #define RADEON_CRTC_STATUS 0x005c | ||
568 | #define RADEON_CRTC2_STATUS 0x03fc | ||
569 | |||
561 | #define RADEON_GEN_INT_CNTL 0x0040 | 570 | #define RADEON_GEN_INT_CNTL 0x0040 |
562 | # define RADEON_CRTC_VBLANK_MASK (1 << 0) | 571 | # define RADEON_CRTC_VBLANK_MASK (1 << 0) |
563 | # define RADEON_CRTC2_VBLANK_MASK (1 << 9) | 572 | # define RADEON_CRTC2_VBLANK_MASK (1 << 9) |
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index 009af3814b6f..507d6b747a13 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c | |||
@@ -35,12 +35,61 @@ | |||
35 | #include "radeon_drm.h" | 35 | #include "radeon_drm.h" |
36 | #include "radeon_drv.h" | 36 | #include "radeon_drv.h" |
37 | 37 | ||
38 | static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv, | 38 | static void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state) |
39 | u32 mask) | ||
40 | { | 39 | { |
41 | u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask; | 40 | drm_radeon_private_t *dev_priv = dev->dev_private; |
41 | |||
42 | if (state) | ||
43 | dev_priv->irq_enable_reg |= mask; | ||
44 | else | ||
45 | dev_priv->irq_enable_reg &= ~mask; | ||
46 | |||
47 | RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); | ||
48 | } | ||
49 | |||
50 | int radeon_enable_vblank(struct drm_device *dev, int crtc) | ||
51 | { | ||
52 | switch (crtc) { | ||
53 | case 0: | ||
54 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1); | ||
55 | break; | ||
56 | case 1: | ||
57 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1); | ||
58 | break; | ||
59 | default: | ||
60 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | ||
61 | crtc); | ||
62 | return EINVAL; | ||
63 | } | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | void radeon_disable_vblank(struct drm_device *dev, int crtc) | ||
69 | { | ||
70 | switch (crtc) { | ||
71 | case 0: | ||
72 | radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0); | ||
73 | break; | ||
74 | case 1: | ||
75 | radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0); | ||
76 | break; | ||
77 | default: | ||
78 | DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", | ||
79 | crtc); | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv) | ||
85 | { | ||
86 | u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & | ||
87 | (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT | | ||
88 | RADEON_CRTC2_VBLANK_STAT); | ||
89 | |||
42 | if (irqs) | 90 | if (irqs) |
43 | RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); | 91 | RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); |
92 | |||
44 | return irqs; | 93 | return irqs; |
45 | } | 94 | } |
46 | 95 | ||
@@ -72,39 +121,21 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) | |||
72 | /* Only consider the bits we're interested in - others could be used | 121 | /* Only consider the bits we're interested in - others could be used |
73 | * outside the DRM | 122 | * outside the DRM |
74 | */ | 123 | */ |
75 | stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | | 124 | stat = radeon_acknowledge_irqs(dev_priv); |
76 | RADEON_CRTC_VBLANK_STAT | | ||
77 | RADEON_CRTC2_VBLANK_STAT)); | ||
78 | if (!stat) | 125 | if (!stat) |
79 | return IRQ_NONE; | 126 | return IRQ_NONE; |
80 | 127 | ||
81 | stat &= dev_priv->irq_enable_reg; | 128 | stat &= dev_priv->irq_enable_reg; |
82 | 129 | ||
83 | /* SW interrupt */ | 130 | /* SW interrupt */ |
84 | if (stat & RADEON_SW_INT_TEST) { | 131 | if (stat & RADEON_SW_INT_TEST) |
85 | DRM_WAKEUP(&dev_priv->swi_queue); | 132 | DRM_WAKEUP(&dev_priv->swi_queue); |
86 | } | ||
87 | 133 | ||
88 | /* VBLANK interrupt */ | 134 | /* VBLANK interrupt */ |
89 | if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) { | 135 | if (stat & RADEON_CRTC_VBLANK_STAT) |
90 | int vblank_crtc = dev_priv->vblank_crtc; | 136 | drm_handle_vblank(dev, 0); |
91 | 137 | if (stat & RADEON_CRTC2_VBLANK_STAT) | |
92 | if ((vblank_crtc & | 138 | drm_handle_vblank(dev, 1); |
93 | (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) == | ||
94 | (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) { | ||
95 | if (stat & RADEON_CRTC_VBLANK_STAT) | ||
96 | atomic_inc(&dev->vbl_received); | ||
97 | if (stat & RADEON_CRTC2_VBLANK_STAT) | ||
98 | atomic_inc(&dev->vbl_received2); | ||
99 | } else if (((stat & RADEON_CRTC_VBLANK_STAT) && | ||
100 | (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) || | ||
101 | ((stat & RADEON_CRTC2_VBLANK_STAT) && | ||
102 | (vblank_crtc & DRM_RADEON_VBLANK_CRTC2))) | ||
103 | atomic_inc(&dev->vbl_received); | ||
104 | |||
105 | DRM_WAKEUP(&dev->vbl_queue); | ||
106 | drm_vbl_send_signals(dev); | ||
107 | } | ||
108 | 139 | ||
109 | return IRQ_HANDLED; | 140 | return IRQ_HANDLED; |
110 | } | 141 | } |
@@ -144,54 +175,27 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) | |||
144 | return ret; | 175 | return ret; |
145 | } | 176 | } |
146 | 177 | ||
147 | static int radeon_driver_vblank_do_wait(struct drm_device * dev, | 178 | u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) |
148 | unsigned int *sequence, int crtc) | ||
149 | { | 179 | { |
150 | drm_radeon_private_t *dev_priv = | 180 | drm_radeon_private_t *dev_priv = dev->dev_private; |
151 | (drm_radeon_private_t *) dev->dev_private; | 181 | u32 crtc_cnt_reg, crtc_status_reg; |
152 | unsigned int cur_vblank; | 182 | |
153 | int ret = 0; | ||
154 | int ack = 0; | ||
155 | atomic_t *counter; | ||
156 | if (!dev_priv) { | 183 | if (!dev_priv) { |
157 | DRM_ERROR("called with no initialization\n"); | 184 | DRM_ERROR("called with no initialization\n"); |
158 | return -EINVAL; | 185 | return -EINVAL; |
159 | } | 186 | } |
160 | 187 | ||
161 | if (crtc == DRM_RADEON_VBLANK_CRTC1) { | 188 | if (crtc == 0) { |
162 | counter = &dev->vbl_received; | 189 | crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME; |
163 | ack |= RADEON_CRTC_VBLANK_STAT; | 190 | crtc_status_reg = RADEON_CRTC_STATUS; |
164 | } else if (crtc == DRM_RADEON_VBLANK_CRTC2) { | 191 | } else if (crtc == 1) { |
165 | counter = &dev->vbl_received2; | 192 | crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME; |
166 | ack |= RADEON_CRTC2_VBLANK_STAT; | 193 | crtc_status_reg = RADEON_CRTC2_STATUS; |
167 | } else | 194 | } else { |
168 | return -EINVAL; | 195 | return -EINVAL; |
196 | } | ||
169 | 197 | ||
170 | radeon_acknowledge_irqs(dev_priv, ack); | 198 | return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1); |
171 | |||
172 | dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; | ||
173 | |||
174 | /* Assume that the user has missed the current sequence number | ||
175 | * by about a day rather than she wants to wait for years | ||
176 | * using vertical blanks... | ||
177 | */ | ||
178 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | ||
179 | (((cur_vblank = atomic_read(counter)) | ||
180 | - *sequence) <= (1 << 23))); | ||
181 | |||
182 | *sequence = cur_vblank; | ||
183 | |||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence) | ||
188 | { | ||
189 | return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1); | ||
190 | } | ||
191 | |||
192 | int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence) | ||
193 | { | ||
194 | return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2); | ||
195 | } | 199 | } |
196 | 200 | ||
197 | /* Needs the lock as it touches the ring. | 201 | /* Needs the lock as it touches the ring. |
@@ -234,21 +238,6 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr | |||
234 | return radeon_wait_irq(dev, irqwait->irq_seq); | 238 | return radeon_wait_irq(dev, irqwait->irq_seq); |
235 | } | 239 | } |
236 | 240 | ||
237 | static void radeon_enable_interrupt(struct drm_device *dev) | ||
238 | { | ||
239 | drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; | ||
240 | |||
241 | dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE; | ||
242 | if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1) | ||
243 | dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK; | ||
244 | |||
245 | if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2) | ||
246 | dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK; | ||
247 | |||
248 | RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); | ||
249 | dev_priv->irq_enabled = 1; | ||
250 | } | ||
251 | |||
252 | /* drm_dma.h hooks | 241 | /* drm_dma.h hooks |
253 | */ | 242 | */ |
254 | void radeon_driver_irq_preinstall(struct drm_device * dev) | 243 | void radeon_driver_irq_preinstall(struct drm_device * dev) |
@@ -260,20 +249,27 @@ void radeon_driver_irq_preinstall(struct drm_device * dev) | |||
260 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); | 249 | RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); |
261 | 250 | ||
262 | /* Clear bits if they're already high */ | 251 | /* Clear bits if they're already high */ |
263 | radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | | 252 | radeon_acknowledge_irqs(dev_priv); |
264 | RADEON_CRTC_VBLANK_STAT | | ||
265 | RADEON_CRTC2_VBLANK_STAT)); | ||
266 | } | 253 | } |
267 | 254 | ||
268 | void radeon_driver_irq_postinstall(struct drm_device * dev) | 255 | int radeon_driver_irq_postinstall(struct drm_device * dev) |
269 | { | 256 | { |
270 | drm_radeon_private_t *dev_priv = | 257 | drm_radeon_private_t *dev_priv = |
271 | (drm_radeon_private_t *) dev->dev_private; | 258 | (drm_radeon_private_t *) dev->dev_private; |
259 | int ret; | ||
272 | 260 | ||
273 | atomic_set(&dev_priv->swi_emitted, 0); | 261 | atomic_set(&dev_priv->swi_emitted, 0); |
274 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); | 262 | DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); |
275 | 263 | ||
276 | radeon_enable_interrupt(dev); | 264 | ret = drm_vblank_init(dev, 2); |
265 | if (ret) | ||
266 | return ret; | ||
267 | |||
268 | dev->max_vblank_count = 0x001fffff; | ||
269 | |||
270 | radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); | ||
271 | |||
272 | return 0; | ||
277 | } | 273 | } |
278 | 274 | ||
279 | void radeon_driver_irq_uninstall(struct drm_device * dev) | 275 | void radeon_driver_irq_uninstall(struct drm_device * dev) |
@@ -315,6 +311,5 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) | |||
315 | return -EINVAL; | 311 | return -EINVAL; |
316 | } | 312 | } |
317 | dev_priv->vblank_crtc = (unsigned int)value; | 313 | dev_priv->vblank_crtc = (unsigned int)value; |
318 | radeon_enable_interrupt(dev); | ||
319 | return 0; | 314 | return 0; |
320 | } | 315 | } |
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c index 80c01cdfa37d..37870a4a3dc7 100644 --- a/drivers/char/drm/via_drv.c +++ b/drivers/char/drm/via_drv.c | |||
@@ -40,11 +40,13 @@ static struct pci_device_id pciidlist[] = { | |||
40 | static struct drm_driver driver = { | 40 | static struct drm_driver driver = { |
41 | .driver_features = | 41 | .driver_features = |
42 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | | 42 | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | |
43 | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, | 43 | DRIVER_IRQ_SHARED, |
44 | .load = via_driver_load, | 44 | .load = via_driver_load, |
45 | .unload = via_driver_unload, | 45 | .unload = via_driver_unload, |
46 | .context_dtor = via_final_context, | 46 | .context_dtor = via_final_context, |
47 | .vblank_wait = via_driver_vblank_wait, | 47 | .get_vblank_counter = via_get_vblank_counter, |
48 | .enable_vblank = via_enable_vblank, | ||
49 | .disable_vblank = via_disable_vblank, | ||
48 | .irq_preinstall = via_driver_irq_preinstall, | 50 | .irq_preinstall = via_driver_irq_preinstall, |
49 | .irq_postinstall = via_driver_irq_postinstall, | 51 | .irq_postinstall = via_driver_irq_postinstall, |
50 | .irq_uninstall = via_driver_irq_uninstall, | 52 | .irq_uninstall = via_driver_irq_uninstall, |
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index 2daae81874cd..fe67030e39ac 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h | |||
@@ -75,6 +75,7 @@ typedef struct drm_via_private { | |||
75 | struct timeval last_vblank; | 75 | struct timeval last_vblank; |
76 | int last_vblank_valid; | 76 | int last_vblank_valid; |
77 | unsigned usec_per_vblank; | 77 | unsigned usec_per_vblank; |
78 | atomic_t vbl_received; | ||
78 | drm_via_state_t hc_state; | 79 | drm_via_state_t hc_state; |
79 | char pci_buf[VIA_PCI_BUF_SIZE]; | 80 | char pci_buf[VIA_PCI_BUF_SIZE]; |
80 | const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; | 81 | const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; |
@@ -130,11 +131,13 @@ extern int via_init_context(struct drm_device * dev, int context); | |||
130 | extern int via_final_context(struct drm_device * dev, int context); | 131 | extern int via_final_context(struct drm_device * dev, int context); |
131 | 132 | ||
132 | extern int via_do_cleanup_map(struct drm_device * dev); | 133 | extern int via_do_cleanup_map(struct drm_device * dev); |
133 | extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); | 134 | extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc); |
135 | extern int via_enable_vblank(struct drm_device *dev, int crtc); | ||
136 | extern void via_disable_vblank(struct drm_device *dev, int crtc); | ||
134 | 137 | ||
135 | extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); | 138 | extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); |
136 | extern void via_driver_irq_preinstall(struct drm_device * dev); | 139 | extern void via_driver_irq_preinstall(struct drm_device * dev); |
137 | extern void via_driver_irq_postinstall(struct drm_device * dev); | 140 | extern int via_driver_irq_postinstall(struct drm_device * dev); |
138 | extern void via_driver_irq_uninstall(struct drm_device * dev); | 141 | extern void via_driver_irq_uninstall(struct drm_device * dev); |
139 | 142 | ||
140 | extern int via_dma_cleanup(struct drm_device * dev); | 143 | extern int via_dma_cleanup(struct drm_device * dev); |
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index c6bb978a1106..f1ab6fc7c07e 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c | |||
@@ -92,8 +92,17 @@ static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; | |||
92 | static unsigned time_diff(struct timeval *now, struct timeval *then) | 92 | static unsigned time_diff(struct timeval *now, struct timeval *then) |
93 | { | 93 | { |
94 | return (now->tv_usec >= then->tv_usec) ? | 94 | return (now->tv_usec >= then->tv_usec) ? |
95 | now->tv_usec - then->tv_usec : | 95 | now->tv_usec - then->tv_usec : |
96 | 1000000 - (then->tv_usec - now->tv_usec); | 96 | 1000000 - (then->tv_usec - now->tv_usec); |
97 | } | ||
98 | |||
99 | u32 via_get_vblank_counter(struct drm_device *dev, int crtc) | ||
100 | { | ||
101 | drm_via_private_t *dev_priv = dev->dev_private; | ||
102 | if (crtc != 0) | ||
103 | return 0; | ||
104 | |||
105 | return atomic_read(&dev_priv->vbl_received); | ||
97 | } | 106 | } |
98 | 107 | ||
99 | irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | 108 | irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) |
@@ -108,8 +117,8 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | |||
108 | 117 | ||
109 | status = VIA_READ(VIA_REG_INTERRUPT); | 118 | status = VIA_READ(VIA_REG_INTERRUPT); |
110 | if (status & VIA_IRQ_VBLANK_PENDING) { | 119 | if (status & VIA_IRQ_VBLANK_PENDING) { |
111 | atomic_inc(&dev->vbl_received); | 120 | atomic_inc(&dev_priv->vbl_received); |
112 | if (!(atomic_read(&dev->vbl_received) & 0x0F)) { | 121 | if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { |
113 | do_gettimeofday(&cur_vblank); | 122 | do_gettimeofday(&cur_vblank); |
114 | if (dev_priv->last_vblank_valid) { | 123 | if (dev_priv->last_vblank_valid) { |
115 | dev_priv->usec_per_vblank = | 124 | dev_priv->usec_per_vblank = |
@@ -119,12 +128,11 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | |||
119 | dev_priv->last_vblank = cur_vblank; | 128 | dev_priv->last_vblank = cur_vblank; |
120 | dev_priv->last_vblank_valid = 1; | 129 | dev_priv->last_vblank_valid = 1; |
121 | } | 130 | } |
122 | if (!(atomic_read(&dev->vbl_received) & 0xFF)) { | 131 | if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { |
123 | DRM_DEBUG("US per vblank is: %u\n", | 132 | DRM_DEBUG("US per vblank is: %u\n", |
124 | dev_priv->usec_per_vblank); | 133 | dev_priv->usec_per_vblank); |
125 | } | 134 | } |
126 | DRM_WAKEUP(&dev->vbl_queue); | 135 | drm_handle_vblank(dev, 0); |
127 | drm_vbl_send_signals(dev); | ||
128 | handled = 1; | 136 | handled = 1; |
129 | } | 137 | } |
130 | 138 | ||
@@ -163,31 +171,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv) | |||
163 | } | 171 | } |
164 | } | 172 | } |
165 | 173 | ||
166 | int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) | 174 | int via_enable_vblank(struct drm_device *dev, int crtc) |
167 | { | 175 | { |
168 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | 176 | drm_via_private_t *dev_priv = dev->dev_private; |
169 | unsigned int cur_vblank; | 177 | u32 status; |
170 | int ret = 0; | ||
171 | 178 | ||
172 | DRM_DEBUG("\n"); | 179 | if (crtc != 0) { |
173 | if (!dev_priv) { | 180 | DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); |
174 | DRM_ERROR("called with no initialization\n"); | ||
175 | return -EINVAL; | 181 | return -EINVAL; |
176 | } | 182 | } |
177 | 183 | ||
178 | viadrv_acknowledge_irqs(dev_priv); | 184 | status = VIA_READ(VIA_REG_INTERRUPT); |
185 | VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE); | ||
179 | 186 | ||
180 | /* Assume that the user has missed the current sequence number | 187 | VIA_WRITE8(0x83d4, 0x11); |
181 | * by about a day rather than she wants to wait for years | 188 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); |
182 | * using vertical blanks... | ||
183 | */ | ||
184 | 189 | ||
185 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | 190 | return 0; |
186 | (((cur_vblank = atomic_read(&dev->vbl_received)) - | 191 | } |
187 | *sequence) <= (1 << 23))); | ||
188 | 192 | ||
189 | *sequence = cur_vblank; | 193 | void via_disable_vblank(struct drm_device *dev, int crtc) |
190 | return ret; | 194 | { |
195 | drm_via_private_t *dev_priv = dev->dev_private; | ||
196 | |||
197 | VIA_WRITE8(0x83d4, 0x11); | ||
198 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30); | ||
199 | |||
200 | if (crtc != 0) | ||
201 | DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc); | ||
191 | } | 202 | } |
192 | 203 | ||
193 | static int | 204 | static int |
@@ -292,23 +303,25 @@ void via_driver_irq_preinstall(struct drm_device * dev) | |||
292 | } | 303 | } |
293 | } | 304 | } |
294 | 305 | ||
295 | void via_driver_irq_postinstall(struct drm_device * dev) | 306 | int via_driver_irq_postinstall(struct drm_device * dev) |
296 | { | 307 | { |
297 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | 308 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; |
298 | u32 status; | 309 | u32 status; |
299 | 310 | ||
300 | DRM_DEBUG("\n"); | 311 | DRM_DEBUG("via_driver_irq_postinstall\n"); |
301 | if (dev_priv) { | 312 | if (!dev_priv) |
302 | status = VIA_READ(VIA_REG_INTERRUPT); | 313 | return -EINVAL; |
303 | VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL | ||
304 | | dev_priv->irq_enable_mask); | ||
305 | 314 | ||
306 | /* Some magic, oh for some data sheets ! */ | 315 | drm_vblank_init(dev, 1); |
316 | status = VIA_READ(VIA_REG_INTERRUPT); | ||
317 | VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL | ||
318 | | dev_priv->irq_enable_mask); | ||
307 | 319 | ||
308 | VIA_WRITE8(0x83d4, 0x11); | 320 | /* Some magic, oh for some data sheets ! */ |
309 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | 321 | VIA_WRITE8(0x83d4, 0x11); |
322 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | ||
310 | 323 | ||
311 | } | 324 | return 0; |
312 | } | 325 | } |
313 | 326 | ||
314 | void via_driver_irq_uninstall(struct drm_device * dev) | 327 | void via_driver_irq_uninstall(struct drm_device * dev) |
diff --git a/kernel/fork.c b/kernel/fork.c index efb618fc8ffe..cb46befdd3a0 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1787,7 +1787,7 @@ bad_unshare_out: | |||
1787 | int unshare_files(struct files_struct **displaced) | 1787 | int unshare_files(struct files_struct **displaced) |
1788 | { | 1788 | { |
1789 | struct task_struct *task = current; | 1789 | struct task_struct *task = current; |
1790 | struct files_struct *copy; | 1790 | struct files_struct *copy = NULL; |
1791 | int error; | 1791 | int error; |
1792 | 1792 | ||
1793 | error = unshare_fd(CLONE_FILES, ©); | 1793 | error = unshare_fd(CLONE_FILES, ©); |