1280183Sdumbbell 2280183Sdumbbell#include <sys/cdefs.h> 3280183Sdumbbell__FBSDID("$FreeBSD$"); 4280183Sdumbbell 5280183Sdumbbell#include <dev/drm2/drmP.h> 6280183Sdumbbell 7280183Sdumbbell#include <dev/agp/agpreg.h> 8280183Sdumbbell#include <dev/pci/pcireg.h> 9280183Sdumbbell 10280183Sdumbbelldevclass_t drm_devclass; 11280183Sdumbbell 12280183SdumbbellMALLOC_DEFINE(DRM_MEM_DMA, "drm_dma", "DRM DMA Data Structures"); 13280183SdumbbellMALLOC_DEFINE(DRM_MEM_SAREA, "drm_sarea", "DRM SAREA Data Structures"); 14280183SdumbbellMALLOC_DEFINE(DRM_MEM_DRIVER, "drm_driver", "DRM DRIVER Data Structures"); 15280183SdumbbellMALLOC_DEFINE(DRM_MEM_MAGIC, "drm_magic", "DRM MAGIC Data Structures"); 16280183SdumbbellMALLOC_DEFINE(DRM_MEM_MINOR, "drm_minor", "DRM MINOR Data Structures"); 17280183SdumbbellMALLOC_DEFINE(DRM_MEM_IOCTLS, "drm_ioctls", "DRM IOCTL Data Structures"); 18280183SdumbbellMALLOC_DEFINE(DRM_MEM_MAPS, "drm_maps", "DRM MAP Data Structures"); 19280183SdumbbellMALLOC_DEFINE(DRM_MEM_BUFS, "drm_bufs", "DRM BUFFER Data Structures"); 20280183SdumbbellMALLOC_DEFINE(DRM_MEM_SEGS, "drm_segs", "DRM SEGMENTS Data Structures"); 21280183SdumbbellMALLOC_DEFINE(DRM_MEM_PAGES, "drm_pages", "DRM PAGES Data Structures"); 22280183SdumbbellMALLOC_DEFINE(DRM_MEM_FILES, "drm_files", "DRM FILE Data Structures"); 23280183SdumbbellMALLOC_DEFINE(DRM_MEM_QUEUES, "drm_queues", "DRM QUEUE Data Structures"); 24280183SdumbbellMALLOC_DEFINE(DRM_MEM_CMDS, "drm_cmds", "DRM COMMAND Data Structures"); 25280183SdumbbellMALLOC_DEFINE(DRM_MEM_MAPPINGS, "drm_mapping", "DRM MAPPING Data Structures"); 26280183SdumbbellMALLOC_DEFINE(DRM_MEM_BUFLISTS, "drm_buflists", "DRM BUFLISTS Data Structures"); 27280183SdumbbellMALLOC_DEFINE(DRM_MEM_AGPLISTS, "drm_agplists", "DRM AGPLISTS Data Structures"); 28280183SdumbbellMALLOC_DEFINE(DRM_MEM_CTXBITMAP, "drm_ctxbitmap", 29280183Sdumbbell "DRM CTXBITMAP Data Structures"); 30280183SdumbbellMALLOC_DEFINE(DRM_MEM_SGLISTS, "drm_sglists", "DRM SGLISTS Data Structures"); 31280183SdumbbellMALLOC_DEFINE(DRM_MEM_MM, "drm_sman", "DRM MEMORY MANAGER Data Structures"); 32280183SdumbbellMALLOC_DEFINE(DRM_MEM_HASHTAB, "drm_hashtab", "DRM HASHTABLE Data Structures"); 33280183SdumbbellMALLOC_DEFINE(DRM_MEM_KMS, "drm_kms", "DRM KMS Data Structures"); 34280183SdumbbellMALLOC_DEFINE(DRM_MEM_VBLANK, "drm_vblank", "DRM VBLANK Handling Data"); 35280183Sdumbbell 36280183Sdumbbellconst char *fb_mode_option = NULL; 37280183Sdumbbell 38280183Sdumbbell#define NSEC_PER_USEC 1000L 39280183Sdumbbell#define NSEC_PER_SEC 1000000000L 40280183Sdumbbell 41280183Sdumbbellint64_t 42280183Sdumbbelltimeval_to_ns(const struct timeval *tv) 43280183Sdumbbell{ 44280183Sdumbbell return ((int64_t)tv->tv_sec * NSEC_PER_SEC) + 45280183Sdumbbell tv->tv_usec * NSEC_PER_USEC; 46280183Sdumbbell} 47280183Sdumbbell 48280183Sdumbbellstruct timeval 49280183Sdumbbellns_to_timeval(const int64_t nsec) 50280183Sdumbbell{ 51280183Sdumbbell struct timeval tv; 52280183Sdumbbell long rem; 53280183Sdumbbell 54280183Sdumbbell if (nsec == 0) { 55280183Sdumbbell tv.tv_sec = 0; 56280183Sdumbbell tv.tv_usec = 0; 57280183Sdumbbell return (tv); 58280183Sdumbbell } 59280183Sdumbbell 60280183Sdumbbell tv.tv_sec = nsec / NSEC_PER_SEC; 61280183Sdumbbell rem = nsec % NSEC_PER_SEC; 62280183Sdumbbell if (rem < 0) { 63280183Sdumbbell tv.tv_sec--; 64280183Sdumbbell rem += NSEC_PER_SEC; 65280183Sdumbbell } 66280183Sdumbbell tv.tv_usec = rem / 1000; 67280183Sdumbbell return (tv); 68280183Sdumbbell} 69280183Sdumbbell 70280183Sdumbbellstatic drm_pci_id_list_t * 71280183Sdumbbelldrm_find_description(int vendor, int device, drm_pci_id_list_t *idlist) 72280183Sdumbbell{ 73280183Sdumbbell int i = 0; 74280183Sdumbbell 75280183Sdumbbell for (i = 0; idlist[i].vendor != 0; i++) { 76280183Sdumbbell if ((idlist[i].vendor == vendor) && 77280183Sdumbbell ((idlist[i].device == device) || 78280183Sdumbbell (idlist[i].device == 0))) { 79280183Sdumbbell return (&idlist[i]); 80280183Sdumbbell } 81280183Sdumbbell } 82280183Sdumbbell return (NULL); 83280183Sdumbbell} 84280183Sdumbbell 85280183Sdumbbell/* 86280183Sdumbbell * drm_probe_helper: called by a driver at the end of its probe 87280183Sdumbbell * method. 88280183Sdumbbell */ 89280183Sdumbbellint 90280183Sdumbbelldrm_probe_helper(device_t kdev, drm_pci_id_list_t *idlist) 91280183Sdumbbell{ 92280183Sdumbbell drm_pci_id_list_t *id_entry; 93280183Sdumbbell int vendor, device; 94280183Sdumbbell 95280183Sdumbbell vendor = pci_get_vendor(kdev); 96280183Sdumbbell device = pci_get_device(kdev); 97280183Sdumbbell 98280183Sdumbbell if (pci_get_class(kdev) != PCIC_DISPLAY || 99280183Sdumbbell (pci_get_subclass(kdev) != PCIS_DISPLAY_VGA && 100280183Sdumbbell pci_get_subclass(kdev) != PCIS_DISPLAY_OTHER)) 101280183Sdumbbell return (-ENXIO); 102280183Sdumbbell 103280183Sdumbbell id_entry = drm_find_description(vendor, device, idlist); 104280183Sdumbbell if (id_entry != NULL) { 105280183Sdumbbell if (device_get_desc(kdev) == NULL) { 106280183Sdumbbell DRM_DEBUG("%s desc: %s\n", 107280183Sdumbbell device_get_nameunit(kdev), id_entry->name); 108280183Sdumbbell device_set_desc(kdev, id_entry->name); 109280183Sdumbbell } 110280183Sdumbbell return (0); 111280183Sdumbbell } 112280183Sdumbbell 113280183Sdumbbell return (-ENXIO); 114280183Sdumbbell} 115280183Sdumbbell 116280183Sdumbbell/* 117280183Sdumbbell * drm_attach_helper: called by a driver at the end of its attach 118280183Sdumbbell * method. 119280183Sdumbbell */ 120280183Sdumbbellint 121280183Sdumbbelldrm_attach_helper(device_t kdev, drm_pci_id_list_t *idlist, 122280183Sdumbbell struct drm_driver *driver) 123280183Sdumbbell{ 124280183Sdumbbell struct drm_device *dev; 125280183Sdumbbell int vendor, device; 126280183Sdumbbell int ret; 127280183Sdumbbell 128280183Sdumbbell dev = device_get_softc(kdev); 129280183Sdumbbell 130280183Sdumbbell vendor = pci_get_vendor(kdev); 131280183Sdumbbell device = pci_get_device(kdev); 132280183Sdumbbell dev->id_entry = drm_find_description(vendor, device, idlist); 133280183Sdumbbell 134280183Sdumbbell ret = drm_get_pci_dev(kdev, dev, driver); 135280183Sdumbbell 136280183Sdumbbell return (ret); 137280183Sdumbbell} 138280183Sdumbbell 139280183Sdumbbellint 140280183Sdumbbelldrm_generic_detach(device_t kdev) 141280183Sdumbbell{ 142280183Sdumbbell struct drm_device *dev; 143280183Sdumbbell int i; 144280183Sdumbbell 145280183Sdumbbell dev = device_get_softc(kdev); 146280183Sdumbbell 147280183Sdumbbell drm_put_dev(dev); 148280183Sdumbbell 149280183Sdumbbell /* Clean up PCI resources allocated by drm_bufs.c. We're not really 150280183Sdumbbell * worried about resource consumption while the DRM is inactive (between 151280183Sdumbbell * lastclose and firstopen or unload) because these aren't actually 152280183Sdumbbell * taking up KVA, just keeping the PCI resource allocated. 153280183Sdumbbell */ 154280183Sdumbbell for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) { 155280183Sdumbbell if (dev->pcir[i] == NULL) 156280183Sdumbbell continue; 157280183Sdumbbell bus_release_resource(dev->dev, SYS_RES_MEMORY, 158280183Sdumbbell dev->pcirid[i], dev->pcir[i]); 159280183Sdumbbell dev->pcir[i] = NULL; 160280183Sdumbbell } 161280183Sdumbbell 162280183Sdumbbell if (pci_disable_busmaster(dev->dev)) 163280183Sdumbbell DRM_ERROR("Request to disable bus-master failed.\n"); 164280183Sdumbbell 165280183Sdumbbell return (0); 166280183Sdumbbell} 167280183Sdumbbell 168280183Sdumbbellint 169280183Sdumbbelldrm_add_busid_modesetting(struct drm_device *dev, struct sysctl_ctx_list *ctx, 170280183Sdumbbell struct sysctl_oid *top) 171280183Sdumbbell{ 172280183Sdumbbell struct sysctl_oid *oid; 173280183Sdumbbell 174280183Sdumbbell snprintf(dev->busid_str, sizeof(dev->busid_str), 175280183Sdumbbell "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus, 176280183Sdumbbell dev->pci_slot, dev->pci_func); 177280183Sdumbbell oid = SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "busid", 178280183Sdumbbell CTLFLAG_RD, dev->busid_str, 0, NULL); 179280183Sdumbbell if (oid == NULL) 180280183Sdumbbell return (-ENOMEM); 181280183Sdumbbell dev->modesetting = (dev->driver->driver_features & DRIVER_MODESET) != 0; 182280183Sdumbbell oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO, 183280183Sdumbbell "modesetting", CTLFLAG_RD, &dev->modesetting, 0, NULL); 184280183Sdumbbell if (oid == NULL) 185280183Sdumbbell return (-ENOMEM); 186280183Sdumbbell 187280183Sdumbbell return (0); 188280183Sdumbbell} 189280183Sdumbbell 190280183Sdumbbellstatic int 191280183Sdumbbelldrm_device_find_capability(struct drm_device *dev, int cap) 192280183Sdumbbell{ 193280183Sdumbbell 194280183Sdumbbell return (pci_find_cap(dev->dev, cap, NULL) == 0); 195280183Sdumbbell} 196280183Sdumbbell 197280183Sdumbbellint 198280183Sdumbbelldrm_pci_device_is_agp(struct drm_device *dev) 199280183Sdumbbell{ 200280183Sdumbbell if (dev->driver->device_is_agp != NULL) { 201280183Sdumbbell int ret; 202280183Sdumbbell 203280183Sdumbbell /* device_is_agp returns a tristate, 0 = not AGP, 1 = definitely 204280183Sdumbbell * AGP, 2 = fall back to PCI capability 205280183Sdumbbell */ 206280183Sdumbbell ret = (*dev->driver->device_is_agp)(dev); 207280183Sdumbbell if (ret != DRM_MIGHT_BE_AGP) 208280183Sdumbbell return ret; 209280183Sdumbbell } 210280183Sdumbbell 211280183Sdumbbell return (drm_device_find_capability(dev, PCIY_AGP)); 212280183Sdumbbell} 213280183Sdumbbell 214280183Sdumbbellint 215280183Sdumbbelldrm_pci_device_is_pcie(struct drm_device *dev) 216280183Sdumbbell{ 217280183Sdumbbell 218280183Sdumbbell return (drm_device_find_capability(dev, PCIY_EXPRESS)); 219280183Sdumbbell} 220280183Sdumbbell 221280183Sdumbbellstatic bool 222280183Sdumbbelldmi_found(const struct dmi_system_id *dsi) 223280183Sdumbbell{ 224280183Sdumbbell char *hw_vendor, *hw_prod; 225280183Sdumbbell int i, slot; 226280183Sdumbbell bool res; 227280183Sdumbbell 228282199Sdumbbell hw_vendor = getenv("smbios.planar.maker"); 229282199Sdumbbell hw_prod = getenv("smbios.planar.product"); 230280183Sdumbbell res = true; 231280183Sdumbbell for (i = 0; i < nitems(dsi->matches); i++) { 232280183Sdumbbell slot = dsi->matches[i].slot; 233280183Sdumbbell switch (slot) { 234280183Sdumbbell case DMI_NONE: 235280183Sdumbbell break; 236280183Sdumbbell case DMI_SYS_VENDOR: 237280183Sdumbbell case DMI_BOARD_VENDOR: 238280183Sdumbbell if (hw_vendor != NULL && 239280183Sdumbbell !strcmp(hw_vendor, dsi->matches[i].substr)) { 240280183Sdumbbell break; 241280183Sdumbbell } else { 242280183Sdumbbell res = false; 243280183Sdumbbell goto out; 244280183Sdumbbell } 245280183Sdumbbell case DMI_PRODUCT_NAME: 246280183Sdumbbell case DMI_BOARD_NAME: 247280183Sdumbbell if (hw_prod != NULL && 248280183Sdumbbell !strcmp(hw_prod, dsi->matches[i].substr)) { 249280183Sdumbbell break; 250280183Sdumbbell } else { 251280183Sdumbbell res = false; 252280183Sdumbbell goto out; 253280183Sdumbbell } 254280183Sdumbbell default: 255280183Sdumbbell res = false; 256280183Sdumbbell goto out; 257280183Sdumbbell } 258280183Sdumbbell } 259280183Sdumbbellout: 260280183Sdumbbell freeenv(hw_vendor); 261280183Sdumbbell freeenv(hw_prod); 262280183Sdumbbell 263280183Sdumbbell return (res); 264280183Sdumbbell} 265280183Sdumbbell 266280183Sdumbbellbool 267280183Sdumbbelldmi_check_system(const struct dmi_system_id *sysid) 268280183Sdumbbell{ 269280183Sdumbbell const struct dmi_system_id *dsi; 270280183Sdumbbell bool res; 271280183Sdumbbell 272280183Sdumbbell for (res = false, dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) { 273280183Sdumbbell if (dmi_found(dsi)) { 274280183Sdumbbell res = true; 275280183Sdumbbell if (dsi->callback != NULL && dsi->callback(dsi)) 276280183Sdumbbell break; 277280183Sdumbbell } 278280183Sdumbbell } 279280183Sdumbbell return (res); 280280183Sdumbbell} 281280183Sdumbbell 282280183Sdumbbellint 283280183Sdumbbelldrm_mtrr_add(unsigned long offset, unsigned long size, unsigned int flags) 284280183Sdumbbell{ 285280183Sdumbbell int act; 286280183Sdumbbell struct mem_range_desc mrdesc; 287280183Sdumbbell 288280183Sdumbbell mrdesc.mr_base = offset; 289280183Sdumbbell mrdesc.mr_len = size; 290280183Sdumbbell mrdesc.mr_flags = flags; 291280183Sdumbbell act = MEMRANGE_SET_UPDATE; 292280183Sdumbbell strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner)); 293280183Sdumbbell return (-mem_range_attr_set(&mrdesc, &act)); 294280183Sdumbbell} 295280183Sdumbbell 296280183Sdumbbellint 297280183Sdumbbelldrm_mtrr_del(int handle __unused, unsigned long offset, unsigned long size, 298280183Sdumbbell unsigned int flags) 299280183Sdumbbell{ 300280183Sdumbbell int act; 301280183Sdumbbell struct mem_range_desc mrdesc; 302280183Sdumbbell 303280183Sdumbbell mrdesc.mr_base = offset; 304280183Sdumbbell mrdesc.mr_len = size; 305280183Sdumbbell mrdesc.mr_flags = flags; 306280183Sdumbbell act = MEMRANGE_SET_REMOVE; 307280183Sdumbbell strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner)); 308280183Sdumbbell return (-mem_range_attr_set(&mrdesc, &act)); 309280183Sdumbbell} 310280183Sdumbbell 311280183Sdumbbellvoid 312280183Sdumbbelldrm_clflush_pages(vm_page_t *pages, unsigned long num_pages) 313280183Sdumbbell{ 314280183Sdumbbell 315280183Sdumbbell#if defined(__i386__) || defined(__amd64__) 316280183Sdumbbell pmap_invalidate_cache_pages(pages, num_pages); 317280183Sdumbbell#else 318280183Sdumbbell DRM_ERROR("drm_clflush_pages not implemented on this architecture"); 319280183Sdumbbell#endif 320280183Sdumbbell} 321280183Sdumbbell 322280183Sdumbbellvoid 323280183Sdumbbelldrm_clflush_virt_range(char *addr, unsigned long length) 324280183Sdumbbell{ 325280183Sdumbbell 326280183Sdumbbell#if defined(__i386__) || defined(__amd64__) 327280183Sdumbbell pmap_invalidate_cache_range((vm_offset_t)addr, 328280183Sdumbbell (vm_offset_t)addr + length, TRUE); 329280183Sdumbbell#else 330280183Sdumbbell DRM_ERROR("drm_clflush_virt_range not implemented on this architecture"); 331280183Sdumbbell#endif 332280183Sdumbbell} 333280183Sdumbbell 334280183Sdumbbell#if DRM_LINUX 335280183Sdumbbell 336280183Sdumbbell#include <sys/sysproto.h> 337280183Sdumbbell 338280183SdumbbellMODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1); 339280183Sdumbbell 340280183Sdumbbell#define LINUX_IOCTL_DRM_MIN 0x6400 341280183Sdumbbell#define LINUX_IOCTL_DRM_MAX 0x64ff 342280183Sdumbbell 343280183Sdumbbellstatic linux_ioctl_function_t drm_linux_ioctl; 344280183Sdumbbellstatic struct linux_ioctl_handler drm_handler = {drm_linux_ioctl, 345280183Sdumbbell LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX}; 346280183Sdumbbell 347280183Sdumbbell/* The bits for in/out are switched on Linux */ 348280183Sdumbbell#define LINUX_IOC_IN IOC_OUT 349280183Sdumbbell#define LINUX_IOC_OUT IOC_IN 350280183Sdumbbell 351280183Sdumbbellstatic int 352280183Sdumbbelldrm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args) 353280183Sdumbbell{ 354280183Sdumbbell int error; 355280183Sdumbbell int cmd = args->cmd; 356280183Sdumbbell 357280183Sdumbbell args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT); 358280183Sdumbbell if (cmd & LINUX_IOC_IN) 359280183Sdumbbell args->cmd |= IOC_IN; 360280183Sdumbbell if (cmd & LINUX_IOC_OUT) 361280183Sdumbbell args->cmd |= IOC_OUT; 362280183Sdumbbell 363280183Sdumbbell error = ioctl(p, (struct ioctl_args *)args); 364280183Sdumbbell 365280183Sdumbbell return error; 366280183Sdumbbell} 367280183Sdumbbell#endif /* DRM_LINUX */ 368280183Sdumbbell 369280183Sdumbbellstatic int 370280183Sdumbbelldrm_modevent(module_t mod, int type, void *data) 371280183Sdumbbell{ 372280183Sdumbbell 373280183Sdumbbell switch (type) { 374280183Sdumbbell case MOD_LOAD: 375280183Sdumbbell TUNABLE_INT_FETCH("drm.debug", &drm_debug); 376280183Sdumbbell TUNABLE_INT_FETCH("drm.notyet", &drm_notyet); 377280183Sdumbbell break; 378280183Sdumbbell } 379280183Sdumbbell return (0); 380280183Sdumbbell} 381280183Sdumbbell 382280183Sdumbbellstatic moduledata_t drm_mod = { 383280183Sdumbbell "drmn", 384280183Sdumbbell drm_modevent, 385280183Sdumbbell 0 386280183Sdumbbell}; 387280183Sdumbbell 388280183SdumbbellDECLARE_MODULE(drmn, drm_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 389280183SdumbbellMODULE_VERSION(drmn, 1); 390280183SdumbbellMODULE_DEPEND(drmn, agp, 1, 1, 1); 391280183SdumbbellMODULE_DEPEND(drmn, pci, 1, 1, 1); 392280183SdumbbellMODULE_DEPEND(drmn, mem, 1, 1, 1); 393280183SdumbbellMODULE_DEPEND(drmn, iicbus, 1, 1, 1); 394