⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 savage_bci.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 3 页
字号:
/* savage_bci.c -- BCI support for Savage * * Copyright 2004  Felix Kuehling * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */#include "drmP.h"#include "savage_drm.h"#include "savage_drv.h"/* Need a long timeout for shadow status updates can take a while * and so can waiting for events when the queue is full. */#define SAVAGE_DEFAULT_USEC_TIMEOUT	1000000 /* 1s */#define SAVAGE_EVENT_USEC_TIMEOUT	5000000 /* 5s */#define SAVAGE_FREELIST_DEBUG		0static intsavage_bci_wait_fifo_shadow(drm_savage_private_t *dev_priv, unsigned int n){	uint32_t mask = dev_priv->status_used_mask;	uint32_t threshold = dev_priv->bci_threshold_hi;	uint32_t status;	int i;#if SAVAGE_BCI_DEBUG	if (n > dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - threshold)		DRM_ERROR("Trying to emit %d words "			  "(more than guaranteed space in COB)\n", n);#endif	for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {		DRM_MEMORYBARRIER();		status = dev_priv->status_ptr[0];		if ((status & mask) < threshold)			return 0;		DRM_UDELAY(1);	}#if SAVAGE_BCI_DEBUG	DRM_ERROR("failed!\n");	DRM_INFO("   status=0x%08x, threshold=0x%08x\n", status, threshold);#endif	return DRM_ERR(EBUSY);}static intsavage_bci_wait_fifo_s3d(drm_savage_private_t *dev_priv, unsigned int n){	uint32_t maxUsed = dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - n;	uint32_t status;	int i;	for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {		status = SAVAGE_READ(SAVAGE_STATUS_WORD0);		if ((status & SAVAGE_FIFO_USED_MASK_S3D) <= maxUsed)			return 0;		DRM_UDELAY(1);	}#if SAVAGE_BCI_DEBUG	DRM_ERROR("failed!\n");	DRM_INFO("   status=0x%08x\n", status);#endif	return DRM_ERR(EBUSY);}static intsavage_bci_wait_fifo_s4(drm_savage_private_t *dev_priv, unsigned int n){	uint32_t maxUsed = dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - n;	uint32_t status;	int i;	for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {		status = SAVAGE_READ(SAVAGE_ALT_STATUS_WORD0);		if ((status & SAVAGE_FIFO_USED_MASK_S4) <= maxUsed)			return 0;		DRM_UDELAY(1);	}#if SAVAGE_BCI_DEBUG	DRM_ERROR("failed!\n");	DRM_INFO("   status=0x%08x\n", status);#endif	return DRM_ERR(EBUSY);}/* * Waiting for events. * * The BIOSresets the event tag to 0 on mode changes. Therefore we * never emit 0 to the event tag. If we find a 0 event tag we know the * BIOS stomped on it and return success assuming that the BIOS waited * for engine idle. * * Note: if the Xserver uses the event tag it has to follow the same * rule. Otherwise there may be glitches every 2^16 events. */static intsavage_bci_wait_event_shadow(drm_savage_private_t *dev_priv, uint16_t e){	uint32_t status;	int i;	for (i = 0; i < SAVAGE_EVENT_USEC_TIMEOUT; i++) {		DRM_MEMORYBARRIER();		status = dev_priv->status_ptr[1];		if ((((status & 0xffff) - e) & 0xffff) <= 0x7fff ||		    (status & 0xffff) == 0)			return 0;		DRM_UDELAY(1);	}#if SAVAGE_BCI_DEBUG	DRM_ERROR("failed!\n");	DRM_INFO("   status=0x%08x, e=0x%04x\n", status, e);#endif	return DRM_ERR(EBUSY);}static intsavage_bci_wait_event_reg(drm_savage_private_t *dev_priv, uint16_t e){	uint32_t status;	int i;	for (i = 0; i < SAVAGE_EVENT_USEC_TIMEOUT; i++) {		status = SAVAGE_READ(SAVAGE_STATUS_WORD1);		if ((((status & 0xffff) - e) & 0xffff) <= 0x7fff ||		    (status & 0xffff) == 0)			return 0;		DRM_UDELAY(1);	}#if SAVAGE_BCI_DEBUG	DRM_ERROR("failed!\n");	DRM_INFO("   status=0x%08x, e=0x%04x\n", status, e);#endif	return DRM_ERR(EBUSY);}uint16_t savage_bci_emit_event(drm_savage_private_t *dev_priv,			       unsigned int flags){	uint16_t count;	BCI_LOCALS;	if (dev_priv->status_ptr) {		/* coordinate with Xserver */		count = dev_priv->status_ptr[1023];		if (count < dev_priv->event_counter)			dev_priv->event_wrap++;	} else {		count = dev_priv->event_counter;	}	count = (count + 1) & 0xffff;	if (count == 0) {		count++; /* See the comment above savage_wait_event_*. */		dev_priv->event_wrap++;	}	dev_priv->event_counter = count;	if (dev_priv->status_ptr)		dev_priv->status_ptr[1023] = (uint32_t)count;	if ((flags & (SAVAGE_WAIT_2D | SAVAGE_WAIT_3D))) {		unsigned int wait_cmd = BCI_CMD_WAIT;		if ((flags & SAVAGE_WAIT_2D))			wait_cmd |= BCI_CMD_WAIT_2D;		if ((flags & SAVAGE_WAIT_3D))			wait_cmd |= BCI_CMD_WAIT_3D;		BEGIN_BCI(2);		BCI_WRITE(wait_cmd);	} else {		BEGIN_BCI(1);	}	BCI_WRITE(BCI_CMD_UPDATE_EVENT_TAG | (uint32_t)count);	return count;}/* * Freelist management */static int savage_freelist_init(drm_device_t *dev){	drm_savage_private_t *dev_priv = dev->dev_private;	drm_device_dma_t *dma = dev->dma;	drm_buf_t *buf;	drm_savage_buf_priv_t *entry;	int i;	DRM_DEBUG("count=%d\n", dma->buf_count);	dev_priv->head.next = &dev_priv->tail;	dev_priv->head.prev = NULL;	dev_priv->head.buf = NULL;	dev_priv->tail.next = NULL;	dev_priv->tail.prev = &dev_priv->head;	dev_priv->tail.buf = NULL;	for (i = 0; i < dma->buf_count; i++) {		buf = dma->buflist[i];		entry = buf->dev_private;		SET_AGE(&entry->age, 0, 0);		entry->buf = buf;		entry->next = dev_priv->head.next;		entry->prev = &dev_priv->head;		dev_priv->head.next->prev = entry;		dev_priv->head.next = entry;	}	return 0;}static drm_buf_t *savage_freelist_get(drm_device_t *dev){	drm_savage_private_t *dev_priv = dev->dev_private;	drm_savage_buf_priv_t *tail = dev_priv->tail.prev;	uint16_t event;	unsigned int wrap;	DRM_DEBUG("\n");	UPDATE_EVENT_COUNTER();	if (dev_priv->status_ptr)		event = dev_priv->status_ptr[1] & 0xffff;	else		event = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;	wrap = dev_priv->event_wrap;	if (event > dev_priv->event_counter)		wrap--; /* hardware hasn't passed the last wrap yet */	DRM_DEBUG("   tail=0x%04x %d\n", tail->age.event, tail->age.wrap);	DRM_DEBUG("   head=0x%04x %d\n", event, wrap);	if (tail->buf && (TEST_AGE(&tail->age, event, wrap) || event == 0)) {		drm_savage_buf_priv_t *next = tail->next;		drm_savage_buf_priv_t *prev = tail->prev;		prev->next = next;		next->prev = prev;		tail->next = tail->prev = NULL;		return tail->buf;	}	DRM_DEBUG("returning NULL, tail->buf=%p!\n", tail->buf);	return NULL;}void savage_freelist_put(drm_device_t *dev, drm_buf_t *buf){	drm_savage_private_t *dev_priv = dev->dev_private;	drm_savage_buf_priv_t *entry = buf->dev_private, *prev, *next;	DRM_DEBUG("age=0x%04x wrap=%d\n", entry->age.event, entry->age.wrap);	if (entry->next != NULL || entry->prev != NULL) {		DRM_ERROR("entry already on freelist.\n");		return;	}	prev = &dev_priv->head;	next = prev->next;	prev->next = entry;	next->prev = entry;	entry->prev = prev;	entry->next = next;}/* * Command DMA */static int savage_dma_init(drm_savage_private_t *dev_priv){	unsigned int i;	dev_priv->nr_dma_pages = dev_priv->cmd_dma->size /		(SAVAGE_DMA_PAGE_SIZE*4);	dev_priv->dma_pages = drm_alloc(sizeof(drm_savage_dma_page_t) *					dev_priv->nr_dma_pages,					DRM_MEM_DRIVER);	if (dev_priv->dma_pages == NULL)		return DRM_ERR(ENOMEM);	for (i = 0; i < dev_priv->nr_dma_pages; ++i) {		SET_AGE(&dev_priv->dma_pages[i].age, 0, 0);		dev_priv->dma_pages[i].used = 0;		dev_priv->dma_pages[i].flushed = 0;	}	SET_AGE(&dev_priv->last_dma_age, 0, 0);	dev_priv->first_dma_page = 0;	dev_priv->current_dma_page = 0;	return 0;}void savage_dma_reset(drm_savage_private_t *dev_priv){	uint16_t event;	unsigned int wrap, i;	event = savage_bci_emit_event(dev_priv, 0);	wrap = dev_priv->event_wrap;	for (i = 0; i < dev_priv->nr_dma_pages; ++i) {		SET_AGE(&dev_priv->dma_pages[i].age, event, wrap);		dev_priv->dma_pages[i].used = 0;		dev_priv->dma_pages[i].flushed = 0;	}	SET_AGE(&dev_priv->last_dma_age, event, wrap);	dev_priv->first_dma_page = dev_priv->current_dma_page = 0;}void savage_dma_wait(drm_savage_private_t *dev_priv, unsigned int page){	uint16_t event;	unsigned int wrap;	/* Faked DMA buffer pages don't age. */	if (dev_priv->cmd_dma == &dev_priv->fake_dma)		return;	UPDATE_EVENT_COUNTER();	if (dev_priv->status_ptr)		event = dev_priv->status_ptr[1] & 0xffff;	else		event = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;	wrap = dev_priv->event_wrap;	if (event > dev_priv->event_counter)		wrap--; /* hardware hasn't passed the last wrap yet */	if (dev_priv->dma_pages[page].age.wrap > wrap ||	    (dev_priv->dma_pages[page].age.wrap == wrap &&	     dev_priv->dma_pages[page].age.event > event)) {		if (dev_priv->wait_evnt(dev_priv,					dev_priv->dma_pages[page].age.event)		    < 0)			DRM_ERROR("wait_evnt failed!\n");	}}uint32_t *savage_dma_alloc(drm_savage_private_t *dev_priv, unsigned int n){	unsigned int cur = dev_priv->current_dma_page;	unsigned int rest = SAVAGE_DMA_PAGE_SIZE -		dev_priv->dma_pages[cur].used;	unsigned int nr_pages = (n - rest + SAVAGE_DMA_PAGE_SIZE-1) /

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -