2 * Copyright 2003 José Fonseca.
3 * Copyright 2003 Leif Delgass.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #include <linux/export.h>
27 #include "drm_internal.h"
28 #include "drm_legacy.h"
30 /**********************************************************************/
31 /** \name PCI memory */
35 drm_pci_busdma_callback(void *arg
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
37 drm_dma_handle_t
*dmah
= arg
;
42 KASSERT(nsegs
== 1, ("drm_pci_busdma_callback: bad dma segment count"));
43 dmah
->busaddr
= segs
[0].ds_addr
;
47 * \brief Allocate a PCI consistent memory block, for DMA.
49 drm_dma_handle_t
*drm_pci_alloc(struct drm_device
* dev
, size_t size
, size_t align
)
51 drm_dma_handle_t
*dmah
;
54 /* pci_alloc_consistent only guarantees alignment to the smallest
55 * PAGE_SIZE order which is greater than or equal to the requested size.
56 * Return NULL here for now to make sure nobody tries for larger alignment
61 /* Need power-of-two alignment, so fail the allocation if it isn't. */
62 if ((align
& (align
- 1)) != 0) {
63 DRM_ERROR("drm_pci_alloc with non-power-of-two alignment %d\n",
68 dmah
= kmalloc(sizeof(drm_dma_handle_t
), M_DRM
, M_WAITOK
| M_NULLOK
);
74 ret
= bus_dma_tag_create(NULL
, align
, 0, /* tag, align, boundary */
75 ~0, BUS_SPACE_MAXADDR
, /* lowaddr, highaddr */
76 NULL
, NULL
, /* filtfunc, filtfuncargs */
77 size
, 1, size
, /* maxsize, nsegs, maxsegsize */
85 ret
= bus_dmamem_alloc(dmah
->tag
, &dmah
->vaddr
,
86 BUS_DMA_WAITOK
| BUS_DMA_ZERO
| BUS_DMA_NOCACHE
, &dmah
->map
);
88 bus_dma_tag_destroy(dmah
->tag
);
93 ret
= bus_dmamap_load(dmah
->tag
, dmah
->map
, dmah
->vaddr
, size
,
94 drm_pci_busdma_callback
, dmah
, BUS_DMA_NOWAIT
);
96 bus_dmamem_free(dmah
->tag
, dmah
->vaddr
, dmah
->map
);
97 bus_dma_tag_destroy(dmah
->tag
);
102 memset(dmah
->vaddr
, 0, size
);
108 * Free a PCI consistent memory block without freeing its descriptor.
110 * This function is for internal use in the Linux-specific DRM core code.
112 void __drm_legacy_pci_free(struct drm_device
* dev
, drm_dma_handle_t
* dmah
)
117 bus_dmamem_free(dmah
->tag
, dmah
->vaddr
, dmah
->map
);
118 bus_dma_tag_destroy(dmah
->tag
);
122 * drm_pci_free - Free a PCI consistent memory block
124 * @dmah: handle to memory block
126 void drm_pci_free(struct drm_device
* dev
, drm_dma_handle_t
* dmah
)
128 __drm_legacy_pci_free(dev
, dmah
);
132 int drm_pcie_get_speed_cap_mask(struct drm_device
*dev
, u32
*mask
)
136 u32 lnkcap
= 0, lnkcap2
= 0;
140 root
= device_get_parent(dev
->dev
->bsddev
);
142 /* we've been informed via and serverworks don't make the cut */
143 if (pci_get_vendor(root
) == PCI_VENDOR_ID_VIA
||
144 pci_get_vendor(root
) == PCI_VENDOR_ID_SERVERWORKS
)
148 pci_find_extcap(root
, PCIY_EXPRESS
, &pos
);
152 lnkcap
= pci_read_config(root
, pos
+ PCIER_LINKCAP
, 4);
153 lnkcap2
= pci_read_config(root
, pos
+ PCIER_LINK_CAP2
, 4);
155 lnkcap
&= PCIEM_LNKCAP_SPEED_MASK
;
158 #define PCI_EXP_LNKCAP_SLS_2_5GB PCIEM_LNKCAP_SPEED_2_5
159 #define PCI_EXP_LNKCAP_SLS_5_0GB PCIEM_LNKCAP_SPEED_5
160 #define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */
161 #define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */
162 #define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */
164 if (lnkcap2
) { /* PCIe r3.0-compliant */
165 if (lnkcap2
& PCI_EXP_LNKCAP2_SLS_2_5GB
)
166 *mask
|= DRM_PCIE_SPEED_25
;
167 if (lnkcap2
& PCI_EXP_LNKCAP2_SLS_5_0GB
)
168 *mask
|= DRM_PCIE_SPEED_50
;
169 if (lnkcap2
& PCI_EXP_LNKCAP2_SLS_8_0GB
)
170 *mask
|= DRM_PCIE_SPEED_80
;
171 } else { /* pre-r3.0 */
172 if (lnkcap
& PCI_EXP_LNKCAP_SLS_2_5GB
)
173 *mask
|= DRM_PCIE_SPEED_25
;
174 if (lnkcap
& PCI_EXP_LNKCAP_SLS_5_0GB
)
175 *mask
|= DRM_PCIE_SPEED_50
;
178 DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", pci_get_vendor(root
), pci_get_device(root
), lnkcap
, lnkcap2
);
181 EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask
);
184 int drm_pcie_get_max_link_width(struct drm_device
*dev
, u32
*mlw
)
186 struct pci_dev
*root
;
193 root
= dev
->pdev
->bus
->self
;
195 pcie_capability_read_dword(root
, PCI_EXP_LNKCAP
, &lnkcap
);
197 *mlw
= (lnkcap
& PCI_EXP_LNKCAP_MLW
) >> 4;
199 DRM_INFO("probing mlw for device %x:%x = %x\n", root
->vendor
, root
->device
, lnkcap
);
202 EXPORT_SYMBOL(drm_pcie_get_max_link_width
);
206 * Get interrupt from bus id.
208 * \param inode device inode.
209 * \param file_priv DRM file private.
210 * \param cmd command.
211 * \param arg user argument, pointing to a drm_irq_busid structure.
212 * \return zero on success or a negative number on failure.
214 * Finds the PCI device with the specified bus id and gets its IRQ number.
215 * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
216 * to that of the device that this DRM instance attached to.
218 int drm_irq_by_busid(struct drm_device
*dev
, void *data
,
219 struct drm_file
*file_priv
)
221 struct drm_irq_busid
*irq
= data
;
223 if ((irq
->busnum
>> 8) != dev
->pci_domain
||
224 (irq
->busnum
& 0xff) != dev
->pci_bus
||
225 irq
->devnum
!= dev
->pci_slot
||
226 irq
->funcnum
!= dev
->pci_func
)
231 DRM_DEBUG("%d:%d:%d => IRQ %d\n",
232 irq
->busnum
, irq
->devnum
, irq
->funcnum
, irq
->irq
);