]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/drm2/drm_os_freebsd.c
Revert drm2 removal.
[FreeBSD/FreeBSD.git] / sys / dev / drm2 / drm_os_freebsd.c
1
2 #include <sys/cdefs.h>
3 __FBSDID("$FreeBSD$");
4
5 #include <dev/drm2/drmP.h>
6
7 #include <dev/agp/agpreg.h>
8 #include <dev/pci/pcireg.h>
9
10 devclass_t drm_devclass;
11
12 MALLOC_DEFINE(DRM_MEM_DMA, "drm_dma", "DRM DMA Data Structures");
13 MALLOC_DEFINE(DRM_MEM_SAREA, "drm_sarea", "DRM SAREA Data Structures");
14 MALLOC_DEFINE(DRM_MEM_DRIVER, "drm_driver", "DRM DRIVER Data Structures");
15 MALLOC_DEFINE(DRM_MEM_MAGIC, "drm_magic", "DRM MAGIC Data Structures");
16 MALLOC_DEFINE(DRM_MEM_MINOR, "drm_minor", "DRM MINOR Data Structures");
17 MALLOC_DEFINE(DRM_MEM_IOCTLS, "drm_ioctls", "DRM IOCTL Data Structures");
18 MALLOC_DEFINE(DRM_MEM_MAPS, "drm_maps", "DRM MAP Data Structures");
19 MALLOC_DEFINE(DRM_MEM_BUFS, "drm_bufs", "DRM BUFFER Data Structures");
20 MALLOC_DEFINE(DRM_MEM_SEGS, "drm_segs", "DRM SEGMENTS Data Structures");
21 MALLOC_DEFINE(DRM_MEM_PAGES, "drm_pages", "DRM PAGES Data Structures");
22 MALLOC_DEFINE(DRM_MEM_FILES, "drm_files", "DRM FILE Data Structures");
23 MALLOC_DEFINE(DRM_MEM_QUEUES, "drm_queues", "DRM QUEUE Data Structures");
24 MALLOC_DEFINE(DRM_MEM_CMDS, "drm_cmds", "DRM COMMAND Data Structures");
25 MALLOC_DEFINE(DRM_MEM_MAPPINGS, "drm_mapping", "DRM MAPPING Data Structures");
26 MALLOC_DEFINE(DRM_MEM_BUFLISTS, "drm_buflists", "DRM BUFLISTS Data Structures");
27 MALLOC_DEFINE(DRM_MEM_AGPLISTS, "drm_agplists", "DRM AGPLISTS Data Structures");
28 MALLOC_DEFINE(DRM_MEM_CTXBITMAP, "drm_ctxbitmap",
29     "DRM CTXBITMAP Data Structures");
30 MALLOC_DEFINE(DRM_MEM_SGLISTS, "drm_sglists", "DRM SGLISTS Data Structures");
31 MALLOC_DEFINE(DRM_MEM_MM, "drm_sman", "DRM MEMORY MANAGER Data Structures");
32 MALLOC_DEFINE(DRM_MEM_HASHTAB, "drm_hashtab", "DRM HASHTABLE Data Structures");
33 MALLOC_DEFINE(DRM_MEM_KMS, "drm_kms", "DRM KMS Data Structures");
34 MALLOC_DEFINE(DRM_MEM_VBLANK, "drm_vblank", "DRM VBLANK Handling Data");
35
36 const char *fb_mode_option = NULL;
37
38 #define NSEC_PER_USEC   1000L
39 #define NSEC_PER_SEC    1000000000L
40
41 int64_t
42 timeval_to_ns(const struct timeval *tv)
43 {
44         return ((int64_t)tv->tv_sec * NSEC_PER_SEC) +
45                 tv->tv_usec * NSEC_PER_USEC;
46 }
47
48 struct timeval
49 ns_to_timeval(const int64_t nsec)
50 {
51         struct timeval tv;
52         long rem;
53
54         if (nsec == 0) {
55                 tv.tv_sec = 0;
56                 tv.tv_usec = 0;
57                 return (tv);
58         }
59
60         tv.tv_sec = nsec / NSEC_PER_SEC;
61         rem = nsec % NSEC_PER_SEC;
62         if (rem < 0) {
63                 tv.tv_sec--;
64                 rem += NSEC_PER_SEC;
65         }
66         tv.tv_usec = rem / 1000;
67         return (tv);
68 }
69
70 /* Copied from OFED. */
71 unsigned long drm_linux_timer_hz_mask;
72
73 static void
74 drm_linux_timer_init(void *arg)
75 {
76
77         /*
78          * Compute an internal HZ value which can divide 2**32 to
79          * avoid timer rounding problems when the tick value wraps
80          * around 2**32:
81          */
82         drm_linux_timer_hz_mask = 1;
83         while (drm_linux_timer_hz_mask < (unsigned long)hz)
84                 drm_linux_timer_hz_mask *= 2;
85         drm_linux_timer_hz_mask--;
86 }
87 SYSINIT(drm_linux_timer, SI_SUB_DRIVERS, SI_ORDER_FIRST, drm_linux_timer_init, NULL);
88
89 static const drm_pci_id_list_t *
90 drm_find_description(int vendor, int device, const drm_pci_id_list_t *idlist)
91 {
92         int i = 0;
93
94         for (i = 0; idlist[i].vendor != 0; i++) {
95                 if ((idlist[i].vendor == vendor) &&
96                     ((idlist[i].device == device) ||
97                     (idlist[i].device == 0))) {
98                         return (&idlist[i]);
99                 }
100         }
101         return (NULL);
102 }
103
104 /*
105  * drm_probe_helper: called by a driver at the end of its probe
106  * method.
107  */
108 int
109 drm_probe_helper(device_t kdev, const drm_pci_id_list_t *idlist)
110 {
111         const drm_pci_id_list_t *id_entry;
112         int vendor, device;
113
114         vendor = pci_get_vendor(kdev);
115         device = pci_get_device(kdev);
116
117         if (pci_get_class(kdev) != PCIC_DISPLAY ||
118             (pci_get_subclass(kdev) != PCIS_DISPLAY_VGA &&
119              pci_get_subclass(kdev) != PCIS_DISPLAY_OTHER))
120                 return (-ENXIO);
121
122         id_entry = drm_find_description(vendor, device, idlist);
123         if (id_entry != NULL) {
124                 if (device_get_desc(kdev) == NULL) {
125                         DRM_DEBUG("%s desc: %s\n",
126                             device_get_nameunit(kdev), id_entry->name);
127                         device_set_desc(kdev, id_entry->name);
128                 }
129                 return (0);
130         }
131
132         return (-ENXIO);
133 }
134
135 /*
136  * drm_attach_helper: called by a driver at the end of its attach
137  * method.
138  */
139 int
140 drm_attach_helper(device_t kdev, const drm_pci_id_list_t *idlist,
141     struct drm_driver *driver)
142 {
143         struct drm_device *dev;
144         int vendor, device;
145         int ret;
146
147         dev = device_get_softc(kdev);
148
149         vendor = pci_get_vendor(kdev);
150         device = pci_get_device(kdev);
151         dev->id_entry = drm_find_description(vendor, device, idlist);
152
153         ret = drm_get_pci_dev(kdev, dev, driver);
154
155         return (ret);
156 }
157
158 int
159 drm_generic_suspend(device_t kdev)
160 {
161         struct drm_device *dev;
162         int error;
163
164         DRM_DEBUG_KMS("Starting suspend\n");
165
166         dev = device_get_softc(kdev);
167         if (dev->driver->suspend) {
168                 pm_message_t state;
169
170                 state.event = PM_EVENT_SUSPEND;
171                 error = -dev->driver->suspend(dev, state);
172                 if (error)
173                         goto out;
174         }
175
176         error = bus_generic_suspend(kdev);
177
178 out:
179         DRM_DEBUG_KMS("Finished suspend: %d\n", error);
180
181         return error;
182 }
183
184 int
185 drm_generic_resume(device_t kdev)
186 {
187         struct drm_device *dev;
188         int error;
189
190         DRM_DEBUG_KMS("Starting resume\n");
191
192         dev = device_get_softc(kdev);
193         if (dev->driver->resume) {
194                 error = -dev->driver->resume(dev);
195                 if (error)
196                         goto out;
197         }
198
199         error = bus_generic_resume(kdev);
200
201 out:
202         DRM_DEBUG_KMS("Finished resume: %d\n", error);
203
204         return error;
205 }
206
207 int
208 drm_generic_detach(device_t kdev)
209 {
210         struct drm_device *dev;
211         int i;
212
213         dev = device_get_softc(kdev);
214
215         drm_put_dev(dev);
216
217         /* Clean up PCI resources allocated by drm_bufs.c.  We're not really
218          * worried about resource consumption while the DRM is inactive (between
219          * lastclose and firstopen or unload) because these aren't actually
220          * taking up KVA, just keeping the PCI resource allocated.
221          */
222         for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) {
223                 if (dev->pcir[i] == NULL)
224                         continue;
225                 bus_release_resource(dev->dev, SYS_RES_MEMORY,
226                     dev->pcirid[i], dev->pcir[i]);
227                 dev->pcir[i] = NULL;
228         }
229
230         if (pci_disable_busmaster(dev->dev))
231                 DRM_ERROR("Request to disable bus-master failed.\n");
232
233         return (0);
234 }
235
236 int
237 drm_add_busid_modesetting(struct drm_device *dev, struct sysctl_ctx_list *ctx,
238     struct sysctl_oid *top)
239 {
240         struct sysctl_oid *oid;
241
242         snprintf(dev->busid_str, sizeof(dev->busid_str),
243              "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus,
244              dev->pci_slot, dev->pci_func);
245         oid = SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "busid",
246             CTLFLAG_RD, dev->busid_str, 0, NULL);
247         if (oid == NULL)
248                 return (-ENOMEM);
249         dev->modesetting = (dev->driver->driver_features & DRIVER_MODESET) != 0;
250         oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO,
251             "modesetting", CTLFLAG_RD, &dev->modesetting, 0, NULL);
252         if (oid == NULL)
253                 return (-ENOMEM);
254
255         return (0);
256 }
257
258 static int
259 drm_device_find_capability(struct drm_device *dev, int cap)
260 {
261
262         return (pci_find_cap(dev->dev, cap, NULL) == 0);
263 }
264
265 int
266 drm_pci_device_is_agp(struct drm_device *dev)
267 {
268         if (dev->driver->device_is_agp != NULL) {
269                 int ret;
270
271                 /* device_is_agp returns a tristate, 0 = not AGP, 1 = definitely
272                  * AGP, 2 = fall back to PCI capability
273                  */
274                 ret = (*dev->driver->device_is_agp)(dev);
275                 if (ret != DRM_MIGHT_BE_AGP)
276                         return ret;
277         }
278
279         return (drm_device_find_capability(dev, PCIY_AGP));
280 }
281
282 int
283 drm_pci_device_is_pcie(struct drm_device *dev)
284 {
285
286         return (drm_device_find_capability(dev, PCIY_EXPRESS));
287 }
288
289 static bool
290 dmi_found(const struct dmi_system_id *dsi)
291 {
292         char *hw_vendor, *hw_prod;
293         int i, slot;
294         bool res;
295
296         hw_vendor = kern_getenv("smbios.planar.maker");
297         hw_prod = kern_getenv("smbios.planar.product");
298         res = true;
299         for (i = 0; i < nitems(dsi->matches); i++) {
300                 slot = dsi->matches[i].slot;
301                 switch (slot) {
302                 case DMI_NONE:
303                         break;
304                 case DMI_SYS_VENDOR:
305                 case DMI_BOARD_VENDOR:
306                         if (hw_vendor != NULL &&
307                             !strcmp(hw_vendor, dsi->matches[i].substr)) {
308                                 break;
309                         } else {
310                                 res = false;
311                                 goto out;
312                         }
313                 case DMI_PRODUCT_NAME:
314                 case DMI_BOARD_NAME:
315                         if (hw_prod != NULL &&
316                             !strcmp(hw_prod, dsi->matches[i].substr)) {
317                                 break;
318                         } else {
319                                 res = false;
320                                 goto out;
321                         }
322                 default:
323                         res = false;
324                         goto out;
325                 }
326         }
327 out:
328         freeenv(hw_vendor);
329         freeenv(hw_prod);
330
331         return (res);
332 }
333
334 bool
335 dmi_check_system(const struct dmi_system_id *sysid)
336 {
337         const struct dmi_system_id *dsi;
338         bool res;
339
340         for (res = false, dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) {
341                 if (dmi_found(dsi)) {
342                         res = true;
343                         if (dsi->callback != NULL && dsi->callback(dsi))
344                                 break;
345                 }
346         }
347         return (res);
348 }
349
350 #if __OS_HAS_MTRR
351 int
352 drm_mtrr_add(unsigned long offset, unsigned long size, unsigned int flags)
353 {
354         int act;
355         struct mem_range_desc mrdesc;
356
357         mrdesc.mr_base = offset;
358         mrdesc.mr_len = size;
359         mrdesc.mr_flags = flags;
360         act = MEMRANGE_SET_UPDATE;
361         strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
362         return (-mem_range_attr_set(&mrdesc, &act));
363 }
364
365 int
366 drm_mtrr_del(int handle __unused, unsigned long offset, unsigned long size,
367     unsigned int flags)
368 {
369         int act;
370         struct mem_range_desc mrdesc;
371
372         mrdesc.mr_base = offset;
373         mrdesc.mr_len = size;
374         mrdesc.mr_flags = flags;
375         act = MEMRANGE_SET_REMOVE;
376         strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
377         return (-mem_range_attr_set(&mrdesc, &act));
378 }
379 #endif
380
381 void
382 drm_clflush_pages(vm_page_t *pages, unsigned long num_pages)
383 {
384
385 #if defined(__i386__) || defined(__amd64__)
386         pmap_invalidate_cache_pages(pages, num_pages);
387 #else
388         DRM_ERROR("drm_clflush_pages not implemented on this architecture");
389 #endif
390 }
391
392 void
393 drm_clflush_virt_range(char *addr, unsigned long length)
394 {
395
396 #if defined(__i386__) || defined(__amd64__)
397         pmap_invalidate_cache_range((vm_offset_t)addr,
398             (vm_offset_t)addr + length, TRUE);
399 #else
400         DRM_ERROR("drm_clflush_virt_range not implemented on this architecture");
401 #endif
402 }
403
404 void
405 hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
406     char *linebuf, size_t linebuflen, bool ascii __unused)
407 {
408         int i, j, c;
409
410         i = j = 0;
411
412         while (i < len && j <= linebuflen) {
413                 c = ((const char *)buf)[i];
414
415                 if (i != 0) {
416                         if (i % rowsize == 0) {
417                                 /* Newline required. */
418                                 sprintf(linebuf + j, "\n");
419                                 ++j;
420                         } else if (i % groupsize == 0) {
421                                 /* Space required. */
422                                 sprintf(linebuf + j, " ");
423                                 ++j;
424                         }
425                 }
426
427                 if (j > linebuflen - 4)
428                         break;
429
430                 sprintf(linebuf + j, "%02X", c);
431                 j += 2;
432
433                 ++i;
434         }
435
436         if (j <= linebuflen)
437                 sprintf(linebuf + j, "\n");
438 }
439
440 #if DRM_LINUX
441
442 #include <sys/sysproto.h>
443
444 MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1);
445
446 #define LINUX_IOCTL_DRM_MIN             0x6400
447 #define LINUX_IOCTL_DRM_MAX             0x64ff
448
449 static linux_ioctl_function_t drm_linux_ioctl;
450 static struct linux_ioctl_handler drm_handler = {drm_linux_ioctl,
451     LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX};
452
453 /* The bits for in/out are switched on Linux */
454 #define LINUX_IOC_IN    IOC_OUT
455 #define LINUX_IOC_OUT   IOC_IN
456
457 static int
458 drm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args)
459 {
460         int error;
461         int cmd = args->cmd;
462
463         args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT);
464         if (cmd & LINUX_IOC_IN)
465                 args->cmd |= IOC_IN;
466         if (cmd & LINUX_IOC_OUT)
467                 args->cmd |= IOC_OUT;
468
469         error = ioctl(p, (struct ioctl_args *)args);
470
471         return error;
472 }
473 #endif /* DRM_LINUX */
474
475 static int
476 drm_modevent(module_t mod, int type, void *data)
477 {
478
479         switch (type) {
480         case MOD_LOAD:
481                 TUNABLE_INT_FETCH("drm.debug", &drm_debug);
482                 TUNABLE_INT_FETCH("drm.notyet", &drm_notyet);
483                 break;
484         }
485         return (0);
486 }
487
488 static moduledata_t drm_mod = {
489         "drmn",
490         drm_modevent,
491         0
492 };
493
494 DECLARE_MODULE(drmn, drm_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
495 MODULE_VERSION(drmn, 1);
496 MODULE_DEPEND(drmn, agp, 1, 1, 1);
497 MODULE_DEPEND(drmn, pci, 1, 1, 1);
498 MODULE_DEPEND(drmn, mem, 1, 1, 1);
499 MODULE_DEPEND(drmn, iicbus, 1, 1, 1);