• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/gpu/drm/
1/* drm_pci.h -- PCI DMA memory management wrappers for DRM -*- linux-c -*- */
2/**
3 * \file drm_pci.c
4 * \brief Functions and ioctls to manage PCI memory
5 *
6 * \warning These interfaces aren't stable yet.
7 *
8 * \todo Implement the remaining ioctl's for the PCI pools.
9 * \todo The wrappers here are so thin that they would be better off inlined..
10 *
11 * \author Jos�� Fonseca <jrfonseca@tungstengraphics.com>
12 * \author Leif Delgass <ldelgass@retinalburn.net>
13 */
14
15/*
16 * Copyright 2003 Jos�� Fonseca.
17 * Copyright 2003 Leif Delgass.
18 * All Rights Reserved.
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining a
21 * copy of this software and associated documentation files (the "Software"),
22 * to deal in the Software without restriction, including without limitation
23 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
24 * and/or sell copies of the Software, and to permit persons to whom the
25 * Software is furnished to do so, subject to the following conditions:
26 *
27 * The above copyright notice and this permission notice (including the next
28 * paragraph) shall be included in all copies or substantial portions of the
29 * Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
34 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 */
38
39#include <linux/pci.h>
40#include <linux/slab.h>
41#include <linux/dma-mapping.h>
42#include "drmP.h"
43
44/**********************************************************************/
45/** \name PCI memory */
46/*@{*/
47
48/**
49 * \brief Allocate a PCI consistent memory block, for DMA.
50 */
51drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align)
52{
53	drm_dma_handle_t *dmah;
54	unsigned long addr;
55	size_t sz;
56
57	/* pci_alloc_consistent only guarantees alignment to the smallest
58	 * PAGE_SIZE order which is greater than or equal to the requested size.
59	 * Return NULL here for now to make sure nobody tries for larger alignment
60	 */
61	if (align > size)
62		return NULL;
63
64	dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL);
65	if (!dmah)
66		return NULL;
67
68	dmah->size = size;
69	dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP);
70
71	if (dmah->vaddr == NULL) {
72		kfree(dmah);
73		return NULL;
74	}
75
76	memset(dmah->vaddr, 0, size);
77
78	/* Reserve */
79	for (addr = (unsigned long)dmah->vaddr, sz = size;
80	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
81		SetPageReserved(virt_to_page(addr));
82	}
83
84	return dmah;
85}
86
87EXPORT_SYMBOL(drm_pci_alloc);
88
89/**
90 * \brief Free a PCI consistent memory block without freeing its descriptor.
91 *
92 * This function is for internal use in the Linux-specific DRM core code.
93 */
94void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
95{
96	unsigned long addr;
97	size_t sz;
98
99	if (dmah->vaddr) {
100		/* Unreserve */
101		for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
102		     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
103			ClearPageReserved(virt_to_page(addr));
104		}
105		dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
106				  dmah->busaddr);
107	}
108}
109
110/**
111 * \brief Free a PCI consistent memory block
112 */
113void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
114{
115	__drm_pci_free(dev, dmah);
116	kfree(dmah);
117}
118
119EXPORT_SYMBOL(drm_pci_free);
120
121#ifdef CONFIG_PCI
122/**
123 * Register.
124 *
125 * \param pdev - PCI device structure
126 * \param ent entry from the PCI ID table with device type flags
127 * \return zero on success or a negative number on failure.
128 *
129 * Attempt to gets inter module "drm" information. If we are first
130 * then register the character device and inter module information.
131 * Try and register, if we fail to register, backout previous work.
132 */
133int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
134		    struct drm_driver *driver)
135{
136	struct drm_device *dev;
137	int ret;
138
139	DRM_DEBUG("\n");
140
141	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
142	if (!dev)
143		return -ENOMEM;
144
145	ret = pci_enable_device(pdev);
146	if (ret)
147		goto err_g1;
148
149	pci_set_master(pdev);
150
151	dev->pdev = pdev;
152	dev->dev = &pdev->dev;
153
154	dev->pci_device = pdev->device;
155	dev->pci_vendor = pdev->vendor;
156
157#ifdef __alpha__
158	dev->hose = pdev->sysdata;
159#endif
160
161	mutex_lock(&drm_global_mutex);
162
163	if ((ret = drm_fill_in_dev(dev, ent, driver))) {
164		printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
165		goto err_g2;
166	}
167
168	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
169		pci_set_drvdata(pdev, dev);
170		ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
171		if (ret)
172			goto err_g2;
173	}
174
175	if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
176		goto err_g3;
177
178	if (dev->driver->load) {
179		ret = dev->driver->load(dev, ent->driver_data);
180		if (ret)
181			goto err_g4;
182	}
183
184	/* setup the grouping for the legacy output */
185	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
186		ret = drm_mode_group_init_legacy_group(dev,
187						&dev->primary->mode_group);
188		if (ret)
189			goto err_g4;
190	}
191
192	list_add_tail(&dev->driver_item, &driver->device_list);
193
194	DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
195		 driver->name, driver->major, driver->minor, driver->patchlevel,
196		 driver->date, pci_name(pdev), dev->primary->index);
197
198	mutex_unlock(&drm_global_mutex);
199	return 0;
200
201err_g4:
202	drm_put_minor(&dev->primary);
203err_g3:
204	if (drm_core_check_feature(dev, DRIVER_MODESET))
205		drm_put_minor(&dev->control);
206err_g2:
207	pci_disable_device(pdev);
208err_g1:
209	kfree(dev);
210	mutex_unlock(&drm_global_mutex);
211	return ret;
212}
213EXPORT_SYMBOL(drm_get_pci_dev);
214
215/**
216 * PCI device initialization. Called via drm_init at module load time,
217 *
218 * \return zero on success or a negative number on failure.
219 *
220 * Initializes a drm_device structures,registering the
221 * stubs and initializing the AGP device.
222 *
223 * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
224 * after the initialization for driver customization.
225 */
226int drm_pci_init(struct drm_driver *driver)
227{
228	struct pci_dev *pdev = NULL;
229	const struct pci_device_id *pid;
230	int i;
231
232	if (driver->driver_features & DRIVER_MODESET)
233		return pci_register_driver(&driver->pci_driver);
234
235	/* If not using KMS, fall back to stealth mode manual scanning. */
236	for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
237		pid = &driver->pci_driver.id_table[i];
238
239		/* Loop around setting up a DRM device for each PCI device
240		 * matching our ID and device class.  If we had the internal
241		 * function that pci_get_subsys and pci_get_class used, we'd
242		 * be able to just pass pid in instead of doing a two-stage
243		 * thing.
244		 */
245		pdev = NULL;
246		while ((pdev =
247			pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
248				       pid->subdevice, pdev)) != NULL) {
249			if ((pdev->class & pid->class_mask) != pid->class)
250				continue;
251
252			/* stealth mode requires a manual probe */
253			pci_dev_get(pdev);
254			drm_get_pci_dev(pdev, pid, driver);
255		}
256	}
257	return 0;
258}
259
260#else
261
262int drm_pci_init(struct drm_driver *driver)
263{
264	return -1;
265}
266
267#endif
268/*@}*/
269