diff options
Diffstat (limited to 'bsd-core')
| -rw-r--r-- | bsd-core/ati_pcigart.c | 127 | ||||
| -rw-r--r-- | bsd-core/drmP.h | 17 | ||||
| -rw-r--r-- | bsd-core/drm_bufs.c | 4 | ||||
| -rw-r--r-- | bsd-core/drm_drv.c | 18 | ||||
| -rw-r--r-- | bsd-core/drm_irq.c | 421 | ||||
| -rw-r--r-- | bsd-core/drm_lock.c | 7 | ||||
| -rw-r--r-- | bsd-core/drm_pci.c | 5 | ||||
| -rw-r--r-- | bsd-core/i915/Makefile | 2 | ||||
| -rw-r--r-- | bsd-core/i915_drv.c | 32 | ||||
| l--------- | bsd-core/i915_suspend.c | 1 | ||||
| l--------- | bsd-core/radeon_microcode.h | 1 | 
11 files changed, 389 insertions, 246 deletions
| diff --git a/bsd-core/ati_pcigart.c b/bsd-core/ati_pcigart.c index 2b511ada..f8d3f18d 100644 --- a/bsd-core/ati_pcigart.c +++ b/bsd-core/ati_pcigart.c @@ -34,76 +34,125 @@  #include "drmP.h"  #define ATI_PCIGART_PAGE_SIZE		4096	/* PCI GART page size */ +#define ATI_PCIGART_PAGE_MASK		(~(ATI_PCIGART_PAGE_SIZE-1)) + +#define ATI_PCIE_WRITE 0x4 +#define ATI_PCIE_READ 0x8 + +static int drm_ati_alloc_pcigart_table(struct drm_device *dev, +				       struct drm_ati_pcigart_info *gart_info) +{ +	dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, +						PAGE_SIZE, +						gart_info->table_mask); +	if (dev->sg->dmah == NULL) +		return ENOMEM; + +	return 0; +} + +static void drm_ati_free_pcigart_table(struct drm_device *dev, +				       struct drm_ati_pcigart_info *gart_info) +{ +	drm_pci_free(dev, dev->sg->dmah); +	dev->sg->dmah = NULL; +} + +int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) +{ +	/* we need to support large memory configurations */ +	if (dev->sg == NULL) { +		DRM_ERROR("no scatter/gather memory!\n"); +		return 0; +	} + +	if (gart_info->bus_addr) { +		if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { +			gart_info->bus_addr = 0; +			if (dev->sg->dmah) +				drm_ati_free_pcigart_table(dev, gart_info); +		} +	} + +	return 1; +}  int drm_ati_pcigart_init(struct drm_device *dev,  			 struct drm_ati_pcigart_info *gart_info)  { + +	void *address = NULL;  	unsigned long pages; -	u32 *pci_gart = NULL, page_base; -	int i, j; +	u32 *pci_gart, page_base; +	dma_addr_t bus_address = 0; +	int i, j, ret = 0; +	int max_pages; +	dma_addr_t entry_addr; +	/* we need to support large memory configurations */  	if (dev->sg == NULL) { -		DRM_ERROR( "no scatter/gather memory!\n" ); -		return 0; +		DRM_ERROR("no scatter/gather memory!\n"); +		goto done;  	}  	if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { -		/* GART table in system memory */ -		dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, 0, -		    0xfffffffful); -		if (dev->sg->dmah == NULL) { -			DRM_ERROR("cannot allocate PCI GART table!\n"); -			return 0; +		DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); + +		ret = drm_ati_alloc_pcigart_table(dev, gart_info); +		if (ret) { +			DRM_ERROR("cannot allocate PCI GART page!\n"); +			goto done;  		} -	 -		gart_info->addr = (void *)dev->sg->dmah->vaddr; -		gart_info->bus_addr = dev->sg->dmah->busaddr; -		pci_gart = (u32 *)dev->sg->dmah->vaddr; + +		address = (void *)dev->sg->dmah->vaddr; +		bus_address = dev->sg->dmah->busaddr;  	} else { -		/* GART table in framebuffer memory */ -		pci_gart = gart_info->addr; +		address = gart_info->addr; +		bus_address = gart_info->bus_addr; +		DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n", +			  (unsigned int)bus_address, (unsigned long)address);  	} -	 -	pages = DRM_MIN(dev->sg->pages, gart_info->table_size / sizeof(u32)); -	bzero(pci_gart, gart_info->table_size); +	pci_gart = (u32 *) address; -	KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small")); +	max_pages = (gart_info->table_size / sizeof(u32)); +	pages = (dev->sg->pages <= max_pages) +	    ? dev->sg->pages : max_pages; + +	memset(pci_gart, 0, max_pages * sizeof(u32)); -	for ( i = 0 ; i < pages ; i++ ) { -		page_base = (u32) dev->sg->busaddr[i]; +	KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small")); +	for (i = 0; i < pages; i++) { +		entry_addr = dev->sg->busaddr[i];  		for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { +			page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK;  			switch(gart_info->gart_reg_if) {  			case DRM_ATI_GART_IGP: -				*pci_gart = cpu_to_le32(page_base | 0xc); +				page_base |= (upper_32_bits(entry_addr) & 0xff) << 4; +				page_base |= 0xc;  				break;  			case DRM_ATI_GART_PCIE: -				*pci_gart = cpu_to_le32((page_base >> 8) | 0xc); +				page_base >>= 8; +				page_base |= (upper_32_bits(entry_addr) & 0xff) << 24; +				page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE;  				break;  			default: -				*pci_gart = cpu_to_le32(page_base); +			case DRM_ATI_GART_PCI:  				break;  			} +			*pci_gart = cpu_to_le32(page_base);  			pci_gart++; -			page_base += ATI_PCIGART_PAGE_SIZE; +			entry_addr += ATI_PCIGART_PAGE_SIZE;  		}  	}  	DRM_MEMORYBARRIER(); -	return 1; -} - -int drm_ati_pcigart_cleanup(struct drm_device *dev, -			    struct drm_ati_pcigart_info *gart_info) -{ -	if (dev->sg == NULL) { -		DRM_ERROR( "no scatter/gather memory!\n" ); -		return 0; -	} - -	drm_pci_free(dev, dev->sg->dmah); +	ret = 1; -	return 1; +    done: +	gart_info->addr = address; +	gart_info->bus_addr = bus_address; +	return ret;  } diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 4c35cdb2..326b2202 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -632,7 +632,7 @@ struct drm_ati_pcigart_info {  #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) - 1)  #endif -#define upper_32_bits(_val) (((u64)(_val)) >> 32) +#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))  struct drm_driver_info {  	int	(*load)(struct drm_device *, unsigned long flags); @@ -733,11 +733,13 @@ struct drm_device {  				/* Locks */  #if defined(__FreeBSD__) && __FreeBSD_version > 500000 +	struct mtx	  vbl_lock;	/* protects vblank operations */  	struct mtx	  dma_lock;	/* protects dev->dma */  	struct mtx	  irq_lock;	/* protects irq condition checks */  	struct mtx	  dev_lock;	/* protects everything else */  #endif  	DRM_SPINTYPE	  drw_lock; +	DRM_SPINTYPE	  tsk_lock;  				/* Usage Counters */  	int		  open_count;	/* Outstanding files open	   */ @@ -785,25 +787,21 @@ struct drm_device {  	atomic_t	  context_flag;	/* Context swapping flag	   */  	int		  last_context;	/* Last current context		   */ +	int		  vblank_disable_allowed;  	wait_queue_head_t *vbl_queue;	/* vblank wait queue */  	atomic_t	  *_vblank_count;	/* number of VBLANK interrupts */  						/* (driver must alloc the right number of counters) */ -	struct mtx	  vbl_lock;  	struct drm_vbl_sig_list *vbl_sigs;	/* signal list to send on VBLANK */  	atomic_t 	  vbl_signal_pending;	/* number of signals pending on all crtcs*/  	atomic_t	  *vblank_refcount;	/* number of users of vblank interrupts per crtc */  	u32		  *last_vblank;		/* protected by dev->vbl_lock, used */  						/* for wraparound handling */ - -	u32		  *vblank_offset;	/* used to track how many vblanks */  	int		  *vblank_enabled;	/* so we don't call enable more than */  						/* once per disable */ -	u32 		  *vblank_premodeset;	/* were lost during modeset */ +	int 		  *vblank_inmodeset;	/* Display driver is setting mode */  	struct callout	  vblank_disable_timer; -	unsigned long	  max_vblank_count;	/* size of vblank counter register */ +	u32		  max_vblank_count;	/* size of vblank counter register */  	int		  num_crtcs; -	atomic_t	  vbl_received; -	atomic_t	  vbl_received2;  #ifdef __FreeBSD__  	struct sigio      *buf_sigio;	/* Processes waiting for SIGIO     */ @@ -933,7 +931,6 @@ void	drm_handle_vblank(struct drm_device *dev, int crtc);  u32	drm_vblank_count(struct drm_device *dev, int crtc);  int	drm_vblank_get(struct drm_device *dev, int crtc);  void	drm_vblank_put(struct drm_device *dev, int crtc); -void	drm_update_vblank_count(struct drm_device *dev, int crtc);  int	drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);  int	drm_vblank_init(struct drm_device *dev, int num_crtcs);  void	drm_vbl_send_signals(struct drm_device *dev, int crtc); @@ -1090,6 +1087,8 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size,  				size_t align, dma_addr_t maxaddr);  void	drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah); +#define drm_core_ioremap_wc drm_core_ioremap +  /* Inline replacements for DRM_IOREMAP macros */  static __inline__ void  drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) diff --git a/bsd-core/drm_bufs.c b/bsd-core/drm_bufs.c index 3508331a..c793634b 100644 --- a/bsd-core/drm_bufs.c +++ b/bsd-core/drm_bufs.c @@ -832,12 +832,12 @@ int drm_addbufs_sg(struct drm_device *dev, drm_buf_desc_t *request)  	if (request->count < 0 || request->count > 4096)  		return EINVAL; -	DRM_SPINLOCK(&dev->dma_lock); -  	order = drm_order(request->size);  	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)  		return EINVAL; +	DRM_SPINLOCK(&dev->dma_lock); +  	/* No more allocations after first buffer-using ioctl. */  	if (dev->buf_use != 0) {  		DRM_SPINUNLOCK(&dev->dma_lock); diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 9924ac34..771e5554 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -125,6 +125,7 @@ static drm_ioctl_desc_t		  drm_ioctls[256] = {  	DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),  	DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), +	DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),  	DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),  }; @@ -202,8 +203,11 @@ int drm_attach(device_t nbdev, drm_pci_id_list_t *idlist)  			DRM_DEV_MODE,  			"dri/card%d", unit);  #if __FreeBSD_version >= 500000 -	mtx_init(&dev->dev_lock, "drm device", NULL, MTX_DEF); +	mtx_init(&dev->dev_lock, "drmdev", NULL, MTX_DEF); +	mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF); +	mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF);  	mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF); +	mtx_init(&dev->tsk_lock, "drmtsk", NULL, MTX_DEF);  #endif  	id_entry = drm_find_description(pci_get_vendor(dev->device), @@ -542,6 +546,8 @@ static int drm_load(struct drm_device *dev)  		/* Shared code returns -errno. */  		retcode = -dev->driver.load(dev,  		    dev->id_entry->driver_private); +		if (pci_enable_busmaster(dev->device)) +			DRM_ERROR("Request to enable bus-master failed.\n");  		DRM_UNLOCK();  		if (retcode != 0)  			goto error; @@ -594,6 +600,9 @@ error:  #ifdef __FreeBSD__  	destroy_dev(dev->devnode);  #if __FreeBSD_version >= 500000 +	mtx_destroy(&dev->drw_lock); +	mtx_destroy(&dev->irq_lock); +	mtx_destroy(&dev->vbl_lock);  	mtx_destroy(&dev->dev_lock);  #endif  #endif @@ -649,7 +658,14 @@ static void drm_unload(struct drm_device *dev)  	delete_unrhdr(dev->drw_unrhdr);  	drm_mem_uninit(); + +	if (pci_disable_busmaster(dev->device)) +		DRM_ERROR("Request to disable bus-master failed.\n"); +  #if defined(__FreeBSD__) &&  __FreeBSD_version >= 500000 +	mtx_destroy(&dev->drw_lock); +	mtx_destroy(&dev->irq_lock); +	mtx_destroy(&dev->vbl_lock);  	mtx_destroy(&dev->dev_lock);  #endif  } diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 592e2ea8..6e21d41c 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -66,6 +66,129 @@ drm_irq_handler_wrap(DRM_IRQ_ARGS)  }  #endif +static void vblank_disable_fn(void *arg) +{ +	struct drm_device *dev = (struct drm_device *)arg; +	int i; + +	if (callout_pending(&dev->vblank_disable_timer)) { +		/* callout was reset */ +		return; +	} +	if (!callout_active(&dev->vblank_disable_timer)) { +		/* callout was stopped */ +		return; +	} +	callout_deactivate(&dev->vblank_disable_timer); + +	if (!dev->vblank_disable_allowed) +		return; + +	for (i = 0; i < dev->num_crtcs; i++) { +		if (atomic_read(&dev->vblank_refcount[i]) == 0 && +		    dev->vblank_enabled[i]) { +			DRM_DEBUG("disabling vblank on crtc %d\n", i); +			dev->last_vblank[i] = +			    dev->driver.get_vblank_counter(dev, i); +			dev->driver.disable_vblank(dev, i); +			dev->vblank_enabled[i] = 0; +		} +	} +} + +static void drm_vblank_cleanup(struct drm_device *dev) +{ +	unsigned long irqflags; + +	/* Bail if the driver didn't call drm_vblank_init() */ +	if (dev->num_crtcs == 0) +	    return; + +	DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); +	callout_stop(&dev->vblank_disable_timer); +	DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + +	callout_drain(&dev->vblank_disable_timer); + +	vblank_disable_fn((void *)dev); + +	drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, +	    DRM_MEM_DRIVER); +	drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, +	    DRM_MEM_DRIVER); +	drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * +	    dev->num_crtcs, DRM_MEM_DRIVER); +	drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * +	    dev->num_crtcs, DRM_MEM_DRIVER); +	drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * +	    dev->num_crtcs, DRM_MEM_DRIVER); +	drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, +	    DRM_MEM_DRIVER); +	drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * +	    dev->num_crtcs, DRM_MEM_DRIVER); + +	dev->num_crtcs = 0; +} + +int drm_vblank_init(struct drm_device *dev, int num_crtcs) +{ +	int i, ret = ENOMEM; + +	callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0); +	atomic_set(&dev->vbl_signal_pending, 0); +	dev->num_crtcs = num_crtcs; + +	dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, +	    DRM_MEM_DRIVER); +	if (!dev->vbl_queue) +	    goto err; + +	dev->vbl_sigs = drm_alloc(sizeof(struct drm_vbl_sig) * num_crtcs, +	    DRM_MEM_DRIVER); +	if (!dev->vbl_sigs) +	    goto err; + +	dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, +	    DRM_MEM_DRIVER); +	if (!dev->_vblank_count) +	    goto err; + +	dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, +	    DRM_MEM_DRIVER); +	if (!dev->vblank_refcount) +	    goto err; + +	dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), +	    DRM_MEM_DRIVER); +	if (!dev->vblank_enabled) +	    goto err; + +	dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); +	if (!dev->last_vblank) +	    goto err; + +	dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), +	    DRM_MEM_DRIVER); +	if (!dev->vblank_inmodeset) +	    goto err; + +	/* Zero per-crtc vblank stuff */ +	for (i = 0; i < num_crtcs; i++) { +		DRM_INIT_WAITQUEUE(&dev->vbl_queue[i]); +		TAILQ_INIT(&dev->vbl_sigs[i]); +		atomic_set(&dev->_vblank_count[i], 0); +		atomic_set(&dev->vblank_refcount[i], 0); +	} + +	dev->vblank_disable_allowed = 0; + +	return 0; + +err: +	drm_vblank_cleanup(dev); +	return ret; +} +  int drm_irq_install(struct drm_device *dev)  {  	int retcode; @@ -87,8 +210,6 @@ int drm_irq_install(struct drm_device *dev)  	dev->context_flag = 0; -	DRM_SPININIT(&dev->irq_lock, "DRM IRQ lock"); -  				/* Before installing handler */  	dev->driver.irq_preinstall(dev);  	DRM_UNLOCK(); @@ -143,7 +264,6 @@ err:  		dev->irqrid = 0;  	}  #endif -	DRM_SPINUNINIT(&dev->irq_lock);  	DRM_UNLOCK();  	return retcode;  } @@ -175,7 +295,7 @@ int drm_irq_uninstall(struct drm_device *dev)  #elif defined(__NetBSD__) || defined(__OpenBSD__)  	pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh);  #endif -	DRM_SPINUNINIT(&dev->irq_lock); +	drm_vblank_cleanup(dev);  	return 0;  } @@ -208,27 +328,35 @@ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv)  	}  } -static void vblank_disable_fn(void *arg) +u32 drm_vblank_count(struct drm_device *dev, int crtc)  { -	struct drm_device *dev = (struct drm_device *)arg; -	unsigned long irqflags; -	int i; - -	for (i = 0; i < dev->num_crtcs; i++) { -		DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); -		if (atomic_read(&dev->vblank_refcount[i]) == 0 && -		    dev->vblank_enabled[i]) { -			dev->driver.disable_vblank(dev, i); -			dev->vblank_enabled[i] = 0; -		} -		DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); -	} +	return atomic_read(&dev->_vblank_count[crtc]);  } -u32 drm_vblank_count(struct drm_device *dev, int crtc) +static void drm_update_vblank_count(struct drm_device *dev, int crtc)  { -	return atomic_read(&dev->_vblank_count[crtc]) + -	    dev->vblank_offset[crtc]; +	u32 cur_vblank, diff; + +	/* +	 * Interrupts were disabled prior to this call, so deal with counter +	 * wrap if needed. +	 * NOTE!  It's possible we lost a full dev->max_vblank_count events +	 * here if the register is small or we had vblank interrupts off for +	 * a long time. +	 */ +	cur_vblank = dev->driver.get_vblank_counter(dev, crtc); +	diff = cur_vblank - dev->last_vblank[crtc]; +	if (cur_vblank < dev->last_vblank[crtc]) { +		diff += dev->max_vblank_count; + +		DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", +		    crtc, dev->last_vblank[crtc], cur_vblank, diff); +	} + +	DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", +	    crtc, diff); + +	atomic_add(diff, &dev->_vblank_count[crtc]);  }  int drm_vblank_get(struct drm_device *dev, int crtc) @@ -244,8 +372,10 @@ int drm_vblank_get(struct drm_device *dev, int crtc)  		ret = dev->driver.enable_vblank(dev, crtc);  		if (ret)  			atomic_dec(&dev->vblank_refcount[crtc]); -		else +		else {  			dev->vblank_enabled[crtc] = 1; +			drm_update_vblank_count(dev, crtc); +		}  	}  	DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); @@ -254,71 +384,59 @@ int drm_vblank_get(struct drm_device *dev, int crtc)  void drm_vblank_put(struct drm_device *dev, int crtc)  { +	unsigned long irqflags; + +	DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags);  	/* Last user schedules interrupt disable */  	atomic_subtract_acq_int(&dev->vblank_refcount[crtc], 1);  	if (dev->vblank_refcount[crtc] == 0) -	    callout_reset(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ, +	    callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ,  		(timeout_t *)vblank_disable_fn, (void *)dev); -} - -void drm_handle_vblank(struct drm_device *dev, int crtc) -{ -	drm_update_vblank_count(dev, crtc); -	DRM_WAKEUP(&dev->vbl_queue[crtc]); -	drm_vbl_send_signals(dev, crtc); -} - -void drm_update_vblank_count(struct drm_device *dev, int crtc) -{ -	unsigned long irqflags; -	u32 cur_vblank, diff; - -	/* -	 * Interrupts were disabled prior to this call, so deal with counter -	 * wrap if needed. -	 * NOTE!  It's possible we lost a full dev->max_vblank_count events -	 * here if the register is small or we had vblank interrupts off for -	 * a long time. -	 */ -	cur_vblank = dev->driver.get_vblank_counter(dev, crtc); -	DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); -	if (cur_vblank < dev->last_vblank[crtc]) { -		diff = dev->max_vblank_count - -			dev->last_vblank[crtc]; -		diff += cur_vblank; -	} else { -		diff = cur_vblank - dev->last_vblank[crtc]; -	} -	dev->last_vblank[crtc] = cur_vblank;  	DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); - -	atomic_add(diff, &dev->_vblank_count[crtc]);  }  int drm_modeset_ctl(struct drm_device *dev, void *data,  		    struct drm_file *file_priv)  {  	struct drm_modeset_ctl *modeset = data; +	unsigned long irqflags;  	int crtc, ret = 0; -	u32 new; + +	/* If drm_vblank_init() hasn't been called yet, just no-op */ +	if (!dev->num_crtcs) +	    goto out;  	crtc = modeset->crtc;  	if (crtc >= dev->num_crtcs) { -		ret = -EINVAL; +		ret = EINVAL;  		goto out;  	} +	/* +	 * To avoid all the problems that might happen if interrupts +	 * were enabled/disabled around or between these calls, we just +	 * have the kernel take a reference on the CRTC (just once though +	 * to avoid corrupting the count if multiple, mismatch calls occur), +	 * so that interrupts remain enabled in the interim. +	 */  	switch (modeset->cmd) {  	case _DRM_PRE_MODESET: -		dev->vblank_premodeset[crtc] = -		    dev->driver.get_vblank_counter(dev, crtc); +		if (!dev->vblank_inmodeset[crtc]) { +			dev->vblank_inmodeset[crtc] = 1; +			drm_vblank_get(dev, crtc); +		}  		break;  	case _DRM_POST_MODESET: -		new = dev->driver.get_vblank_counter(dev, crtc); -		dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new; +		if (dev->vblank_inmodeset[crtc]) { +			DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); +			dev->vblank_disable_allowed = 1; +			dev->vblank_inmodeset[crtc] = 0; +			DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); +			drm_vblank_put(dev, crtc); +		}  		break;  	default: -		ret = -EINVAL; +		ret = EINVAL;  		break;  	} @@ -329,7 +447,6 @@ out:  int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)  {  	drm_wait_vblank_t *vblwait = data; -	struct timeval now;  	int ret = 0;  	int flags, seq, crtc; @@ -350,7 +467,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr  	if (crtc >= dev->num_crtcs)  		return EINVAL; -	drm_update_vblank_count(dev, crtc); +	ret = drm_vblank_get(dev, crtc); +	if (ret) +	    return ret;  	seq = drm_vblank_count(dev, crtc);  	switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { @@ -360,7 +479,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr  	case _DRM_VBLANK_ABSOLUTE:  		break;  	default: -		return EINVAL; +		ret = EINVAL; +		goto done;  	}  	if ((flags & _DRM_VBLANK_NEXTONMISS) && @@ -381,124 +501,33 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr  		vblwait->reply.sequence = atomic_read(&dev->vbl_received); -		DRM_SPINLOCK(&dev->irq_lock); +		DRM_SPINLOCK(&dev->vbl_lock);  		TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link); -		DRM_SPINUNLOCK(&dev->irq_lock); +		DRM_SPINUNLOCK(&dev->vbl_lock);  		ret = 0;  #endif  		ret = EINVAL;  	} else { -		unsigned long cur_vblank; -  		DRM_LOCK();  		/* shared code returns -errno */ -		ret = drm_vblank_get(dev, crtc); -		if (ret) -		    return ret;  		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, -			    (((cur_vblank = drm_vblank_count(dev, crtc)) -			      - vblwait->request.sequence) <= (1 << 23))); -		drm_vblank_put(dev, crtc); +		    ((drm_vblank_count(dev, crtc) +		      - vblwait->request.sequence) <= (1 << 23)));  		DRM_UNLOCK(); -		microtime(&now); -		vblwait->reply.tval_sec = now.tv_sec; -		vblwait->reply.tval_usec = now.tv_usec; -	} - -	return ret; -} - -static void drm_vblank_cleanup(struct drm_device *dev) -{ -	/* Bail if the driver didn't call drm_vblank_init() */ -	if (dev->num_crtcs == 0) -	    return; - -	callout_stop(&dev->vblank_disable_timer); - -	vblank_disable_fn((void *)dev); +		if (ret != EINTR) { +			struct timeval now; -	drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, -	    DRM_MEM_DRIVER); -	drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, -	    DRM_MEM_DRIVER); -	drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * -	    dev->num_crtcs, DRM_MEM_DRIVER); -	drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * -	    dev->num_crtcs, DRM_MEM_DRIVER); -	drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * -	    dev->num_crtcs, DRM_MEM_DRIVER); -	drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, -	    DRM_MEM_DRIVER); -	drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * -	    dev->num_crtcs, DRM_MEM_DRIVER); -	drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, -	    DRM_MEM_DRIVER); - -	dev->num_crtcs = 0; -} - -int drm_vblank_init(struct drm_device *dev, int num_crtcs) -{ -	int i, ret = -ENOMEM; - -	callout_init(&dev->vblank_disable_timer, 0); -	DRM_SPININIT(&dev->vbl_lock, "drm_vblk"); -	atomic_set(&dev->vbl_signal_pending, 0); -	dev->num_crtcs = num_crtcs; - -	dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, -	    DRM_MEM_DRIVER); -	if (!dev->vbl_queue) -	    goto err; - -	dev->vbl_sigs = drm_alloc(sizeof(struct drm_vbl_sig) * num_crtcs, -	    DRM_MEM_DRIVER); -	if (!dev->vbl_sigs) -	    goto err; - -	dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, -	    DRM_MEM_DRIVER); -	if (!dev->_vblank_count) -	    goto err; - -	dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, -	    DRM_MEM_DRIVER); -	if (!dev->vblank_refcount) -	    goto err; - -	dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), -	    DRM_MEM_DRIVER); -	if (!dev->vblank_enabled) -	    goto err; - -	dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); -	if (!dev->last_vblank) -	    goto err; - -	dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), -	    DRM_MEM_DRIVER); -	if (!dev->vblank_premodeset) -	    goto err; - -	dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); -	if (!dev->vblank_offset) -	    goto err; - -	/* Zero per-crtc vblank stuff */ -	for (i = 0; i < num_crtcs; i++) { -		DRM_INIT_WAITQUEUE(&dev->vbl_queue[i]); -		TAILQ_INIT(&dev->vbl_sigs[i]); -		atomic_set(&dev->_vblank_count[i], 0); -		atomic_set(&dev->vblank_refcount[i], 0); +			microtime(&now); +			vblwait->reply.tval_sec = now.tv_sec; +			vblwait->reply.tval_usec = now.tv_usec; +			vblwait->reply.sequence = drm_vblank_count(dev, crtc); +		}  	} -	return 0; - -err: -	drm_vblank_cleanup(dev); +done: +	drm_vblank_put(dev, crtc);  	return ret;  } @@ -530,45 +559,53 @@ void drm_vbl_send_signals(struct drm_device *dev, int crtc )  }  #endif +void drm_handle_vblank(struct drm_device *dev, int crtc) +{ +	atomic_inc(&dev->_vblank_count[crtc]); +	DRM_WAKEUP(&dev->vbl_queue[crtc]); +	drm_vbl_send_signals(dev, crtc); +} +  static void drm_locked_task(void *context, int pending __unused)  {  	struct drm_device *dev = context; -	DRM_LOCK(); -	for (;;) { -		int ret; - -		if (drm_lock_take(&dev->lock.hw_lock->lock, -		    DRM_KERNEL_CONTEXT)) -		{ -			dev->lock.file_priv = NULL; /* kernel owned */ -			dev->lock.lock_time = jiffies; -			atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); -			break;  /* Got lock */ -		} +	DRM_SPINLOCK(&dev->tsk_lock); -		/* Contention */ -#if defined(__FreeBSD__) && __FreeBSD_version > 500000 -		ret = mtx_sleep((void *)&dev->lock.lock_queue, &dev->dev_lock, -		    PZERO | PCATCH, "drmlk2", 0); -#else -		ret = tsleep((void *)&dev->lock.lock_queue, PZERO | PCATCH, -		    "drmlk2", 0); -#endif -		if (ret != 0) -			return; +	DRM_LOCK(); /* XXX drm_lock_take() should do it's own locking */ +	if (dev->locked_task_call == NULL || +	    drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT) == 0) { +		DRM_UNLOCK(); +		DRM_SPINUNLOCK(&dev->tsk_lock); +		return;  	} + +	dev->lock.file_priv = NULL; /* kernel owned */ +	dev->lock.lock_time = jiffies; +	atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); +  	DRM_UNLOCK();  	dev->locked_task_call(dev);  	drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); + +	dev->locked_task_call = NULL; + +	DRM_SPINUNLOCK(&dev->tsk_lock);  }  void  drm_locked_tasklet(struct drm_device *dev,  		   void (*tasklet)(struct drm_device *dev))  { +	DRM_SPINLOCK(&dev->tsk_lock); +	if (dev->locked_task_call != NULL) { +		DRM_SPINUNLOCK(&dev->tsk_lock); +		return; +	} +  	dev->locked_task_call = tasklet; +	DRM_SPINUNLOCK(&dev->tsk_lock);  	taskqueue_enqueue(taskqueue_swi, &dev->locked_task);  } diff --git a/bsd-core/drm_lock.c b/bsd-core/drm_lock.c index 9101dec8..80ebb71d 100644 --- a/bsd-core/drm_lock.c +++ b/bsd-core/drm_lock.c @@ -180,6 +180,13 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)  	    _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) != lock->context)  		return EINVAL; +	DRM_SPINLOCK(&dev->tsk_lock); +	if (dev->locked_task_call != NULL) { +		dev->locked_task_call(dev); +		dev->locked_task_call = NULL; +	} +	DRM_SPINUNLOCK(&dev->tsk_lock); +  	atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);  	DRM_LOCK(); diff --git a/bsd-core/drm_pci.c b/bsd-core/drm_pci.c index 6b411abb..f23b2a5b 100644 --- a/bsd-core/drm_pci.c +++ b/bsd-core/drm_pci.c @@ -71,6 +71,7 @@ drm_pci_alloc(struct drm_device *dev, size_t size,  		return NULL;  #ifdef __FreeBSD__ +	DRM_UNLOCK();  	ret = bus_dma_tag_create(NULL, align, 0, /* tag, align, boundary */  	    maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */  	    NULL, NULL, /* filtfunc, filtfuncargs */ @@ -79,6 +80,7 @@ drm_pci_alloc(struct drm_device *dev, size_t size,  	    &dmah->tag);  	if (ret != 0) {  		free(dmah, M_DRM); +		DRM_LOCK();  		return NULL;  	} @@ -87,9 +89,10 @@ drm_pci_alloc(struct drm_device *dev, size_t size,  	if (ret != 0) {  		bus_dma_tag_destroy(dmah->tag);  		free(dmah, M_DRM); +		DRM_LOCK();  		return NULL;  	} - +	DRM_LOCK();  	ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size,  	    drm_pci_busdma_callback, dmah, 0);  	if (ret != 0) { diff --git a/bsd-core/i915/Makefile b/bsd-core/i915/Makefile index 6fd7d728..f88155a5 100644 --- a/bsd-core/i915/Makefile +++ b/bsd-core/i915/Makefile @@ -3,7 +3,7 @@  .PATH:	${.CURDIR}/..  KMOD	= i915  NO_MAN	= YES -SRCS    = i915_dma.c i915_drv.c i915_irq.c i915_mem.c +SRCS    = i915_dma.c i915_drv.c i915_irq.c i915_mem.c i915_suspend.c  SRCS   += device_if.h bus_if.h pci_if.h opt_drm.h  CFLAGS += ${DEBUG_FLAGS} -I. -I.. diff --git a/bsd-core/i915_drv.c b/bsd-core/i915_drv.c index e6769d17..c19ef5db 100644 --- a/bsd-core/i915_drv.c +++ b/bsd-core/i915_drv.c @@ -40,10 +40,38 @@ static drm_pci_id_list_t i915_pciidlist[] = {  	i915_PCI_IDS  }; +static int i915_suspend(device_t nbdev) +{ +	struct drm_device *dev = device_get_softc(nbdev); +	struct drm_i915_private *dev_priv = dev->dev_private; + +	if (!dev || !dev_priv) { +		DRM_ERROR("dev: 0x%lx, dev_priv: 0x%lx\n", +			(unsigned long) dev, (unsigned long) dev_priv); +		DRM_ERROR("DRM not initialized, aborting suspend.\n"); +		return -ENODEV; +	} + +	i915_save_state(dev); + +	return (bus_generic_suspend(nbdev)); +} + +static int i915_resume(device_t nbdev) +{ +	struct drm_device *dev = device_get_softc(nbdev); + +	i915_restore_state(dev); + +	return (bus_generic_resume(nbdev)); +} +  static void i915_configure(struct drm_device *dev)  { -	dev->driver.buf_priv_size	= 1;	/* No dev_priv */ +	dev->driver.buf_priv_size	= sizeof(drm_i915_private_t);  	dev->driver.load		= i915_driver_load; +	dev->driver.unload		= i915_driver_unload; +	dev->driver.firstopen		= i915_driver_firstopen;  	dev->driver.preclose		= i915_driver_preclose;  	dev->driver.lastclose		= i915_driver_lastclose;  	dev->driver.device_is_agp	= i915_driver_device_is_agp; @@ -94,6 +122,8 @@ static device_method_t i915_methods[] = {  	/* Device interface */  	DEVMETHOD(device_probe,		i915_probe),  	DEVMETHOD(device_attach,	i915_attach), +	DEVMETHOD(device_suspend,	i915_suspend), +	DEVMETHOD(device_resume,	i915_resume),  	DEVMETHOD(device_detach,	drm_detach),  	{ 0, 0 } diff --git a/bsd-core/i915_suspend.c b/bsd-core/i915_suspend.c new file mode 120000 index 00000000..b55754c5 --- /dev/null +++ b/bsd-core/i915_suspend.c @@ -0,0 +1 @@ +../shared-core/i915_suspend.c
\ No newline at end of file diff --git a/bsd-core/radeon_microcode.h b/bsd-core/radeon_microcode.h new file mode 120000 index 00000000..709fff30 --- /dev/null +++ b/bsd-core/radeon_microcode.h @@ -0,0 +1 @@ +../shared-core/radeon_microcode.h
\ No newline at end of file | 
