1235783Skib/*- 2235783Skib * Copyright 2003 Eric Anholt. 3235783Skib * All Rights Reserved. 4235783Skib * 5235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 6235783Skib * copy of this software and associated documentation files (the "Software"), 7235783Skib * to deal in the Software without restriction, including without limitation 8235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9235783Skib * and/or sell copies of the Software, and to permit persons to whom the 10235783Skib * Software is furnished to do so, subject to the following conditions: 11235783Skib * 12235783Skib * The above copyright notice and this permission notice (including the next 13235783Skib * paragraph) shall be included in all copies or substantial portions of the 14235783Skib * Software. 15235783Skib * 16235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19235783Skib * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20235783Skib * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21235783Skib * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22235783Skib */ 23235783Skib 24235783Skib#include <sys/cdefs.h> 25235783Skib__FBSDID("$FreeBSD$"); 26235783Skib 27235783Skib/** 28235783Skib * \file drm_pci.h 29235783Skib * \brief PCI consistent, DMA-accessible memory allocation. 30235783Skib * 31235783Skib * \author Eric Anholt <anholt@FreeBSD.org> 32235783Skib */ 33235783Skib 34235783Skib#include <dev/drm2/drmP.h> 35235783Skib 36235783Skib/**********************************************************************/ 37235783Skib/** \name PCI memory */ 38235783Skib/*@{*/ 39235783Skib 40235783Skibstatic void 41235783Skibdrm_pci_busdma_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 42235783Skib{ 43235783Skib drm_dma_handle_t *dmah = arg; 44235783Skib 45235783Skib if (error != 0) 46235783Skib return; 47235783Skib 48235783Skib KASSERT(nsegs == 1, ("drm_pci_busdma_callback: bad dma segment count")); 49235783Skib dmah->busaddr = segs[0].ds_addr; 50235783Skib} 51235783Skib 52235783Skib/** 53235783Skib * \brief Allocate a physically contiguous DMA-accessible consistent 54235783Skib * memory block. 55235783Skib */ 56235783Skibdrm_dma_handle_t * 57235783Skibdrm_pci_alloc(struct drm_device *dev, size_t size, 58235783Skib size_t align, dma_addr_t maxaddr) 59235783Skib{ 60235783Skib drm_dma_handle_t *dmah; 61235783Skib int ret; 62235783Skib 63235783Skib /* Need power-of-two alignment, so fail the allocation if it isn't. */ 64235783Skib if ((align & (align - 1)) != 0) { 65235783Skib DRM_ERROR("drm_pci_alloc with non-power-of-two alignment %d\n", 66235783Skib (int)align); 67235783Skib return NULL; 68235783Skib } 69235783Skib 70235783Skib dmah = malloc(sizeof(drm_dma_handle_t), DRM_MEM_DMA, M_ZERO | M_NOWAIT); 71235783Skib if (dmah == NULL) 72235783Skib return NULL; 73235783Skib 74235783Skib /* Make sure we aren't holding mutexes here */ 75235783Skib mtx_assert(&dev->dma_lock, MA_NOTOWNED); 76235783Skib if (mtx_owned(&dev->dma_lock)) 77235783Skib DRM_ERROR("called while holding dma_lock\n"); 78235783Skib 79235783Skib ret = bus_dma_tag_create(NULL, align, 0, /* tag, align, boundary */ 80235783Skib maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ 81235783Skib NULL, NULL, /* filtfunc, filtfuncargs */ 82235783Skib size, 1, size, /* maxsize, nsegs, maxsegsize */ 83235783Skib 0, NULL, NULL, /* flags, lockfunc, lockfuncargs */ 84235783Skib &dmah->tag); 85235783Skib if (ret != 0) { 86235783Skib free(dmah, DRM_MEM_DMA); 87235783Skib return NULL; 88235783Skib } 89235783Skib 90235783Skib ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, 91235783Skib BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map); 92235783Skib if (ret != 0) { 93235783Skib bus_dma_tag_destroy(dmah->tag); 94235783Skib free(dmah, DRM_MEM_DMA); 95235783Skib return NULL; 96235783Skib } 97235783Skib 98235783Skib ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size, 99235783Skib drm_pci_busdma_callback, dmah, BUS_DMA_NOWAIT); 100235783Skib if (ret != 0) { 101235783Skib bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); 102235783Skib bus_dma_tag_destroy(dmah->tag); 103235783Skib free(dmah, DRM_MEM_DMA); 104235783Skib return NULL; 105235783Skib } 106235783Skib 107235783Skib return dmah; 108235783Skib} 109235783Skib 110235783Skib/** 111235783Skib * \brief Free a DMA-accessible consistent memory block. 112235783Skib */ 113235783Skibvoid 114235783Skibdrm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah) 115235783Skib{ 116235783Skib if (dmah == NULL) 117235783Skib return; 118235783Skib 119235783Skib bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); 120235783Skib bus_dma_tag_destroy(dmah->tag); 121235783Skib 122235783Skib free(dmah, DRM_MEM_DMA); 123235783Skib} 124235783Skib 125235783Skib/*@}*/ 126254848Sdumbbell 127254848Sdumbbellint drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) 128254848Sdumbbell{ 129254848Sdumbbell device_t root; 130254848Sdumbbell int pos; 131254848Sdumbbell u32 lnkcap = 0, lnkcap2 = 0; 132254848Sdumbbell 133254848Sdumbbell *mask = 0; 134254848Sdumbbell if (!drm_device_is_pcie(dev)) 135254848Sdumbbell return -EINVAL; 136254848Sdumbbell 137259237Sdumbbell root = 138259237Sdumbbell device_get_parent( /* pcib */ 139259237Sdumbbell device_get_parent( /* `-- pci */ 140259237Sdumbbell device_get_parent( /* `-- vgapci */ 141259237Sdumbbell dev->device))); /* `-- drmn */ 142254848Sdumbbell 143254848Sdumbbell pos = 0; 144254848Sdumbbell pci_find_cap(root, PCIY_EXPRESS, &pos); 145254848Sdumbbell if (!pos) 146254848Sdumbbell return -EINVAL; 147254848Sdumbbell 148254848Sdumbbell /* we've been informed via and serverworks don't make the cut */ 149254848Sdumbbell if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA || 150254848Sdumbbell pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS) 151254848Sdumbbell return -EINVAL; 152254848Sdumbbell 153254848Sdumbbell lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4); 154254848Sdumbbell lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4); 155254848Sdumbbell 156254848Sdumbbell lnkcap &= PCIEM_LINK_CAP_MAX_SPEED; 157254848Sdumbbell lnkcap2 &= 0xfe; 158254848Sdumbbell 159254848Sdumbbell#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */ 160254848Sdumbbell#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */ 161254848Sdumbbell#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */ 162254848Sdumbbell 163254848Sdumbbell if (lnkcap2) { /* PCIE GEN 3.0 */ 164254848Sdumbbell if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB) 165254848Sdumbbell *mask |= DRM_PCIE_SPEED_25; 166254848Sdumbbell if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB) 167254848Sdumbbell *mask |= DRM_PCIE_SPEED_50; 168254848Sdumbbell if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) 169254848Sdumbbell *mask |= DRM_PCIE_SPEED_80; 170254848Sdumbbell } else { 171254848Sdumbbell if (lnkcap & 1) 172254848Sdumbbell *mask |= DRM_PCIE_SPEED_25; 173254848Sdumbbell if (lnkcap & 2) 174254848Sdumbbell *mask |= DRM_PCIE_SPEED_50; 175254848Sdumbbell } 176254848Sdumbbell 177254848Sdumbbell DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", pci_get_vendor(root), pci_get_device(root), lnkcap, lnkcap2); 178254848Sdumbbell return 0; 179254848Sdumbbell} 180