Merge branch 'upstream'
[nvidia.git] / src / nvidia_sysctl.c
1 /* _NVRM_COPYRIGHT_BEGIN_
2  *
3  * Copyright 2001-2002 by NVIDIA Corporation.  All rights reserved.  All
4  * information contained herein is proprietary and confidential to NVIDIA
5  * Corporation.  Any use, reproduction, or disclosure without the written
6  * permission of NVIDIA Corporation is prohibited.
7  *
8  * _NVRM_COPYRIGHT_END_
9  */
10
11 #include "nv-misc.h"
12 #include "os-interface.h"
13 #include "nv.h"
14 #include "nv-freebsd.h"
15
16 struct sysctl_ctx_list sysctl_ctx;
17
18 struct sysctl_oid *oid_nvidia;
19 struct sysctl_oid *oid_agp;
20 struct sysctl_oid *oid_registry;
21
22 static char *option_string = NULL;
23
24 static void*  nvidia_find_bridge     (void);
25 static U032   nvidia_dev_agp_cmd     (device_t dev);
26 static U032   nvidia_dev_agp_status  (device_t dev);
27 static U032   nvidia_sys_agp_cmd     (device_t dev);
28
29 void nvidia_sysctl_init(void)
30 {
31     device_t dev;
32     struct sysctl_oid *oid;
33     nv_parm_t *entry;
34
35     sysctl_ctx_init(&sysctl_ctx);
36
37     oid_nvidia = SYSCTL_ADD_NODE(&sysctl_ctx,
38             SYSCTL_STATIC_CHILDREN(_hw),
39             OID_AUTO,
40             "nvidia",
41             CTLFLAG_RD | CTLFLAG_DYN,
42             0,
43             "NVIDIA SYSCTL Master Node");
44
45     oid_agp = SYSCTL_ADD_NODE(&sysctl_ctx,
46             SYSCTL_CHILDREN(oid_nvidia),
47             OID_AUTO,
48             "agp",
49             CTLFLAG_RD | CTLFLAG_DYN,
50             0,
51             "NVIDIA SYSCTL AGP Node");
52
53     SYSCTL_ADD_STRING(&sysctl_ctx,
54             SYSCTL_CHILDREN(oid_nvidia),
55             OID_AUTO,
56             "version",
57             CTLFLAG_RD | CTLFLAG_DYN,
58             (char *)(uintptr_t) pNVRM_ID,
59             0,
60             "NVIDIA Resource Manager (NVRM) Version");
61
62     oid_registry = SYSCTL_ADD_NODE(&sysctl_ctx,
63             SYSCTL_CHILDREN(oid_nvidia),
64             OID_AUTO,
65             "registry",
66             CTLFLAG_RD | CTLFLAG_DYN,
67             0,
68             "NVIDIA SYSCTL Registry Node");
69
70     entry = nv_parms;
71     do {
72         SYSCTL_ADD_PROC(&sysctl_ctx,
73             SYSCTL_CHILDREN(oid_registry),
74             OID_AUTO,
75             entry->name,
76             CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_DYN,
77             entry->data, 0,
78             nvidia_sysctl_registry_key,
79             "IU", NULL);
80         entry++;
81     } while(entry->name != NULL);
82
83     option_string = malloc(1, M_NVIDIA, M_WAITOK | M_ZERO);
84
85     SYSCTL_ADD_PROC(&sysctl_ctx,
86             SYSCTL_CHILDREN(oid_registry),
87             OID_AUTO, "dwords",
88             CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_DYN,
89             NULL, 0,
90             nvidia_sysctl_registry_dwords,
91             "A", NULL);
92
93     if ((dev = nvidia_find_bridge()) != NULL) {
94         /*
95          * Assume this is the only AGP capable bridge in the system
96          * and report its capabilities (hw.nvidia.agp.bridge).
97          */
98         oid = SYSCTL_ADD_NODE(&sysctl_ctx,
99                 SYSCTL_CHILDREN(oid_agp),
100                 OID_AUTO,
101                 "host-bridge",
102                 CTLFLAG_RD | CTLFLAG_DYN,
103                 0,
104                 "NVIDIA AGP Bridge Node");
105
106         SYSCTL_ADD_PROC(&sysctl_ctx,
107                 SYSCTL_CHILDREN(oid),
108                 OID_AUTO,
109                 "rates",
110                 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_DYN,
111                 (void *) dev, 0,
112                 nvidia_sysctl_agp_rates,
113                 "A",
114                 "NVIDIA AGP Bridge Rates Info");
115
116         SYSCTL_ADD_PROC(&sysctl_ctx,
117                 SYSCTL_CHILDREN(oid),
118                 OID_AUTO,
119                 "fw",
120                 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_DYN,
121                 (void *) dev, 0,
122                 nvidia_sysctl_agp_fw,
123                 "A",
124                 "NVIDIA AGP Bridge FW Info");
125
126         SYSCTL_ADD_PROC(&sysctl_ctx,
127                 SYSCTL_CHILDREN(oid),
128                 OID_AUTO,
129                 "sba",
130                 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_DYN,
131                 (void *) dev, 0,
132                 nvidia_sysctl_agp_sba,
133                 "A",
134                 "NVIDIA AGP Bridge SBA Info");
135
136         SYSCTL_ADD_PROC(&sysctl_ctx,
137                 SYSCTL_CHILDREN(oid),
138                 OID_AUTO,
139                 "registers",
140                 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_DYN,
141                 (void *) dev, 0,
142                 nvidia_sysctl_agp_registers,
143                 "A",
144                 "NVIDIA AGP Bridge Registers");
145     }
146 }
147
148 void nvidia_sysctl_exit(void)
149 {
150     sysctl_ctx_free(&sysctl_ctx);
151     if (option_string != NULL)
152         free((void *)option_string, M_NVIDIA);
153 }
154
155
156 static U032 nvidia_dev_agp_cmd(device_t dev)
157 {
158     U008 cap_ptr;
159     U032 tmp;
160
161     cap_ptr = nvidia_pci_find_capability(dev, PCIR_CAP_ID_AGP);
162     tmp = pci_read_config(dev, cap_ptr + 8, 4);
163
164     return tmp;
165 }
166
167 static U032 nvidia_dev_agp_status(device_t dev)
168 {
169     U008 cap_ptr;
170     U032 tmp;
171
172     cap_ptr = nvidia_pci_find_capability(dev, PCIR_CAP_ID_AGP);
173     tmp = pci_read_config(dev, cap_ptr + 4, 4);
174
175     return tmp;
176 }
177
178 static U032 nvidia_sys_agp_cmd(device_t dev)
179 {
180     U032 tmp;
181
182     tmp = nvidia_dev_agp_cmd(dev);
183     tmp &= nvidia_dev_agp_cmd(nvidia_find_bridge());
184
185     return tmp;
186 }
187
188 static void* nvidia_find_bridge(void)
189 {
190     U008 hdrtype;
191     U032 bus;
192     U032 device;
193     U032 func;
194
195     device_t dev;
196
197     for (bus = 0; bus < 5; bus++) {
198         for (device = 0; device < 32; device++) {
199             for (func = 0; func < 8; func++) {
200                 /*
201                  * We're not interested in non-bridge PCI devices, nor do
202                  * care for devices with our own or an invalid vendor ID.
203                  */
204                 dev = pci_find_bsf(bus, device, func);
205
206                 if (dev == NULL)
207                 {
208                     if (func == 0)
209                     {
210                         // If a read to function zero of a specified bus/device master aborts, 
211                         // then it is assumed that no such device exists on the bus since 
212                         // devices are required to implement function number zero. 
213                         // In this case reads to the remaining functions are not necessary.
214                         break;
215                     }
216                     else
217                     {
218                         continue;
219                     }
220                 }
221
222                 if (pci_get_class(dev) != PCIC_BRIDGE)
223                     break;
224
225                 if (pci_get_vendor(dev) == 0xffff)
226                     break;
227
228                 if (nvidia_pci_find_capability(dev, PCIR_CAP_ID_AGP) != 0)
229                     return dev;
230
231                 /*
232                  * It also doesn't make sense to to iterate over multiple
233                  * functions if this isn't a multi-function device.
234                  */
235                 hdrtype = pci_read_config(dev, PCIR_HDRTYPE, 1);
236
237                 if ((hdrtype & PCIM_MFDEV) == 0)
238                     break;
239             }
240         }
241     }
242
243     return NULL;
244 }
245
246
247 int nvidia_sysctl_dev_model(SYSCTL_HANDLER_ARGS)
248 {
249     nv_state_t *nv = arg1;
250     nv_stack_t *sp;
251
252     char model_name[NV_DEVICE_NAME_LENGTH+1];
253     U016 id = nv->device_id;
254
255     NV_UMA_ZONE_ALLOC_STACK(sp);
256     if (sp == NULL)
257         return ENOMEM;
258
259     if (rm_get_device_name(sp, nv, id, NV_DEVICE_NAME_LENGTH, model_name)
260             != RM_OK) {
261         strcpy(model_name, "Unknown");
262     }
263
264     NV_UMA_ZONE_FREE_STACK(sp);
265
266     return SYSCTL_OUT(req, model_name, strlen(model_name) + 1);
267 }
268
269 int nvidia_sysctl_dev_vbios(SYSCTL_HANDLER_ARGS)
270 {
271     nv_state_t *nv = arg1;
272     nv_stack_t *sp;
273
274     U032 vbios[5];
275     U008 vbios_version[16];
276
277     NV_UMA_ZONE_ALLOC_STACK(sp);
278     if (sp == NULL)
279         return ENOMEM;
280
281     if (rm_get_vbios_version(sp, nv, &vbios[0], &vbios[1], &vbios[2],
282                 &vbios[3], &vbios[4]) != RM_OK) {
283         /*
284          * The VBIOS version is only accessible after the device has been
285          * initialized with rm_init_adapter. 
286          */
287         sprintf(vbios_version, "??.??.??.??.??");
288     } else {
289         sprintf(vbios_version, "%02x.%02x.%02x.%02x.%02x", vbios[0],
290                 vbios[1], vbios[2], vbios[3], vbios[4]);
291     }
292
293     NV_UMA_ZONE_FREE_STACK(sp);
294
295     return SYSCTL_OUT(req, vbios_version, strlen(vbios_version) + 1);
296 }
297
298 int nvidia_sysctl_bus_type(SYSCTL_HANDLER_ARGS)
299 {
300     struct nvidia_softc *sc = arg1;
301     U008 bus_type[4];
302
303     if (nvidia_pci_find_capability(sc->dev, PCIR_CAP_ID_AGP) != 0)
304         sprintf(bus_type, "AGP");
305     else
306     if (nvidia_pci_find_capability(sc->dev, PCIR_CAP_ID_EXP) != 0)
307         sprintf(bus_type, "PCI-E");
308     else
309         sprintf(bus_type, "PCI");
310
311     return SYSCTL_OUT(req, bus_type, strlen(bus_type) + 1);
312 }
313
314 int nvidia_sysctl_registry_key(SYSCTL_HANDLER_ARGS)
315 {
316     int error;
317
318     error = sysctl_handle_int(oidp, arg1, 0, req);
319
320     if (error || !req->newptr)
321         return error;
322
323     /* refresh the registry with the updated option table */
324     os_registry_init();
325
326     return 0;
327 }
328
329 int nvidia_sysctl_registry_dwords(SYSCTL_HANDLER_ARGS)
330 {
331     int error, len;
332     char *new_option_string;
333
334     len = strlen(option_string) + 1;
335     error = SYSCTL_OUT(req, option_string, len);
336
337     if (error || !req->newptr)
338         return error;
339
340     len = (req->newlen - req->newidx);
341
342     new_option_string = malloc((len + 1), M_NVIDIA, M_WAITOK);
343     if (!new_option_string)
344         return ENOMEM;
345
346     error = SYSCTL_IN(req, new_option_string, len);
347     if (error)
348         return error;
349
350     free(option_string, M_NVIDIA);
351
352     option_string = new_option_string;
353     option_string[len] = '\0';
354
355     nvidia_update_registry(new_option_string);
356
357     return 0;
358 }
359
360 int nvidia_sysctl_agp_rates(SYSCTL_HANDLER_ARGS)
361 {
362     device_t dev = arg1;
363     U008 agp_rates[16];
364
365     U032 tmp = nvidia_dev_agp_status(dev);
366
367     if ((tmp & 0x08) != 0)
368         tmp = (tmp & 0x07) << 2;
369
370     sprintf(agp_rates, "%s%s%s%s",
371             (tmp & 0x0008) ? "8x " : "",
372             (tmp & 0x0004) ? "4x " : "",
373             (tmp & 0x0002) ? "2x " : "",
374             (tmp & 0x0001) ? "1x " : "");
375
376     return SYSCTL_OUT(req, agp_rates, strlen(agp_rates) + 1);
377 }
378
379 int nvidia_sysctl_agp_fw(SYSCTL_HANDLER_ARGS)
380 {
381     device_t dev = arg1;
382     U008 agp_fw[16];
383
384     sprintf(agp_fw, "%ssupported",
385         ((nvidia_dev_agp_status(dev) & 0x10) == 0x10) ? "" : "not ");
386
387     return SYSCTL_OUT(req, agp_fw, strlen(agp_fw) + 1);
388 }
389
390 int nvidia_sysctl_agp_sba(SYSCTL_HANDLER_ARGS)
391 {
392     device_t dev = arg1;
393     U008 agp_sba[16];
394
395     sprintf(agp_sba, "%ssupported",
396         ((nvidia_dev_agp_status(dev) & 0x200) == 0x200) ? "" : "not ");
397
398     return SYSCTL_OUT(req, agp_sba, strlen(agp_sba) + 1);
399 }
400
401 int nvidia_sysctl_agp_registers(SYSCTL_HANDLER_ARGS)
402 {
403     device_t dev = arg1;
404     U008 agp_registers[24];
405
406     sprintf(agp_registers, "0x%08x:0x%08x",
407         nvidia_dev_agp_status(dev), nvidia_dev_agp_cmd(dev));
408
409     return SYSCTL_OUT(req, agp_registers, strlen(agp_registers) + 1);
410 }
411
412 int nvidia_sysctl_agp_driver(SYSCTL_HANDLER_ARGS)
413 {
414     nv_state_t *nv = arg1;
415     U008 agp_driver[24];
416
417     switch (nv->agp_config) {
418         case NVOS_AGP_CONFIG_DISABLE_AGP:
419             sprintf(agp_driver, "n/a (unused)");
420             break;
421         case NVOS_AGP_CONFIG_OSAGP:
422             sprintf(agp_driver, "freebsd (agp.ko)");
423             break;
424         case NVOS_AGP_CONFIG_NVAGP:
425             sprintf(agp_driver, "nvidia");
426             break;
427     }
428
429     return SYSCTL_OUT(req, agp_driver, strlen(agp_driver) + 1);
430 }
431
432 int nvidia_sysctl_agp_rate_status(SYSCTL_HANDLER_ARGS)
433 {
434     device_t dev = arg1;
435     U008 agp_rate[16];
436     
437     U032 tmp = nvidia_sys_agp_cmd(dev);
438
439     if ((tmp & 0x100) && (tmp &= 0x07)) {
440         sprintf(agp_rate, "%1dx",
441             (nvidia_dev_agp_status(dev) & 0x08) ? (tmp << 2) : tmp);
442     } else {
443         sprintf(agp_rate, "n/a (disabled)");
444     }
445
446     return SYSCTL_OUT(req, agp_rate, strlen(agp_rate) + 1);
447 }
448
449 int nvidia_sysctl_agp_fw_status(SYSCTL_HANDLER_ARGS)
450 {
451     device_t dev = arg1;
452     U008 agp_fw[16];
453
454     U032 tmp = nvidia_sys_agp_cmd(dev);
455
456     if ((tmp & 0x100) == 0x100) {
457         sprintf(agp_fw, "%s",
458             ((tmp & 0x10) == 0x10) ? "enabled" : "disabled");
459     } else {
460         sprintf(agp_fw, "n/a (disabled)");
461     }
462
463     return SYSCTL_OUT(req, agp_fw, strlen(agp_fw) + 1);
464 }
465
466 int nvidia_sysctl_agp_sba_status(SYSCTL_HANDLER_ARGS)
467 {
468     device_t dev = arg1;
469     U008 agp_sba[16];
470
471     U032 tmp = nvidia_sys_agp_cmd(dev);
472
473     if ((tmp & 0x100) == 0x100) {
474         sprintf(agp_sba, "%s",
475             ((tmp & 0x200) == 0x200) ? "enabled" : "disabled");
476     } else {
477         sprintf(agp_sba, "n/a (disabled)");
478     }
479
480     return SYSCTL_OUT(req, agp_sba, strlen(agp_sba) + 1);
481 }
482
483 int nvidia_sysctl_agp_status(SYSCTL_HANDLER_ARGS)
484 {
485     device_t dev = arg1;
486     U008 agp_cmd[16];
487
488     sprintf(agp_cmd, "%s",
489         (nvidia_sys_agp_cmd(dev) & 0x100) ? "enabled" : "disabled");
490
491     return SYSCTL_OUT(req, agp_cmd, strlen(agp_cmd) + 1);
492 }
493
494 void nv_sysctl_init(nv_state_t *nv)
495 {
496     struct sysctl_oid *oid;
497     struct nvidia_softc *sc = nv->os_state;
498
499     char name[4];
500     sprintf(name, "%d", device_get_unit(sc->dev));
501
502     sysctl_ctx_init(&sc->sysctl_ctx);
503
504     oid = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
505             SYSCTL_CHILDREN(oid_nvidia),
506             OID_AUTO,
507             "cards",
508             CTLFLAG_RD | CTLFLAG_DYN,
509             0,
510             "NVIDIA SYSCTL Cards Node");
511
512     oid = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
513             SYSCTL_CHILDREN(oid),
514             OID_AUTO,
515             name,
516             CTLFLAG_RD | CTLFLAG_DYN,
517             0,
518             "NVIDIA SYSCTL Device Node");
519
520     SYSCTL_ADD_PROC(&sc->sysctl_ctx,
521             SYSCTL_CHILDREN(oid),
522             OID_AUTO,
523             "model",
524             CTLFLAG_RD | CTLFLAG_DYN,
525             (void *) nv, 0,
526             nvidia_sysctl_dev_model,
527             "A",
528             "NVIDIA Device Model Name");
529
530     SYSCTL_ADD_UINT(&sc->sysctl_ctx,
531             SYSCTL_CHILDREN(oid),
532             OID_AUTO,
533             "irq",
534             CTLFLAG_RD | CTLFLAG_DYN,
535             &nv->interrupt_line,
536             0,
537             "NVIDIA Device IRQ Number");
538
539     SYSCTL_ADD_PROC(&sc->sysctl_ctx,
540             SYSCTL_CHILDREN(oid),
541             OID_AUTO,
542             "vbios",
543             CTLFLAG_RD | CTLFLAG_DYN,
544             (void *) nv, 0,
545             nvidia_sysctl_dev_vbios,
546             "A",
547             "NVIDIA Device VBIOS Version");
548
549     SYSCTL_ADD_PROC(&sc->sysctl_ctx,
550             SYSCTL_CHILDREN(oid),
551             OID_AUTO,
552             "type",
553             CTLFLAG_RD | CTLFLAG_DYN,
554             (void *) sc, 0,
555             nvidia_sysctl_bus_type,
556             "A",
557             "NVIDIA Device Bus Type");
558
559
560     if (nvidia_pci_find_capability(sc->dev, PCIR_CAP_ID_AGP) != 0) {
561         /*
562          * Assume this is the only AGP VGA device in the system
563          * and report its capabilities (hw.nvidia.agp.card).
564          */
565         oid = SYSCTL_ADD_NODE(&sysctl_ctx,
566                 SYSCTL_CHILDREN(oid_agp),
567                 OID_AUTO,
568                 "card",
569                 CTLFLAG_RD | CTLFLAG_DYN,
570                 0,
571                 "NVIDIA AGP Device Node");
572
573         SYSCTL_ADD_PROC(&sysctl_ctx,
574                 SYSCTL_CHILDREN(oid),
575                 OID_AUTO,
576                 "rates",
577                 CTLFLAG_RD | CTLFLAG_DYN,
578                 (void *) sc->dev, 0,
579                 nvidia_sysctl_agp_rates,
580                 "A",
581                 "NVIDIA AGP Device Rates Info");
582
583         SYSCTL_ADD_PROC(&sysctl_ctx,
584                 SYSCTL_CHILDREN(oid),
585                 OID_AUTO,
586                 "fw",
587                 CTLFLAG_RD | CTLFLAG_DYN,
588                 (void *) sc->dev, 0,
589                 nvidia_sysctl_agp_fw,
590                 "A",
591                 "NVIDIA AGP Device FW Info");
592
593         SYSCTL_ADD_PROC(&sysctl_ctx,
594                 SYSCTL_CHILDREN(oid),
595                 OID_AUTO,
596                 "sba",
597                 CTLFLAG_RD | CTLFLAG_DYN,
598                 (void *) sc->dev, 0,
599                 nvidia_sysctl_agp_sba,
600                 "A",
601                 "NVIDIA AGP Device SBA Info");
602
603         SYSCTL_ADD_PROC(&sysctl_ctx,
604                 SYSCTL_CHILDREN(oid),
605                 OID_AUTO,
606                 "registers",
607                 CTLFLAG_RD | CTLFLAG_DYN,
608                 (void *) sc->dev, 0,
609                 nvidia_sysctl_agp_registers,
610                 "A",
611                 "NVIDIA AGP Device Registers");
612
613
614         if (nvidia_find_bridge() != NULL) {
615             /*
616              * If we can find a bridge and what assume to be the
617              * only AGP VGA device, report the AGP status.
618              */
619             oid = SYSCTL_ADD_NODE(&sysctl_ctx,
620                     SYSCTL_CHILDREN(oid_agp),
621                     OID_AUTO,
622                     "status",
623                     CTLFLAG_RD | CTLFLAG_DYN,
624                     0,
625                     "NVIDIA AGP Status Node");
626
627             SYSCTL_ADD_PROC(&sysctl_ctx,
628                     SYSCTL_CHILDREN(oid),
629                     OID_AUTO,
630                     "status",
631                     CTLFLAG_RD | CTLFLAG_DYN,
632                     (void *) sc->dev, 0,
633                     nvidia_sysctl_agp_status,
634                     "A",
635                     "NVIDIA AGP Status Information");
636
637             SYSCTL_ADD_PROC(&sysctl_ctx,
638                     SYSCTL_CHILDREN(oid),
639                     OID_AUTO,
640                     "driver",
641                     CTLFLAG_RD | CTLFLAG_DYN,
642                     (void *) nv, 0,
643                     nvidia_sysctl_agp_driver,
644                     "A",
645                     "NVIDIA AGP Driver Information");
646
647             SYSCTL_ADD_PROC(&sysctl_ctx,
648                     SYSCTL_CHILDREN(oid),
649                     OID_AUTO,
650                     "rate",
651                     CTLFLAG_RD | CTLFLAG_DYN,
652                     (void *) sc->dev, 0,
653                     nvidia_sysctl_agp_rate_status,
654                     "A",
655                     "NVIDIA AGP Rate Status Information");
656
657             SYSCTL_ADD_PROC(&sysctl_ctx,
658                     SYSCTL_CHILDREN(oid),
659                     OID_AUTO,
660                     "fw",
661                     CTLFLAG_RD | CTLFLAG_DYN,
662                     (void *) sc->dev, 0,
663                     nvidia_sysctl_agp_fw_status,
664                     "A",
665                     "NVIDIA AGP FW Status Information");
666
667             SYSCTL_ADD_PROC(&sysctl_ctx,
668                     SYSCTL_CHILDREN(oid),
669                     OID_AUTO,
670                     "sba",
671                     CTLFLAG_RD | CTLFLAG_DYN,
672                     (void *) sc->dev, 0,
673                     nvidia_sysctl_agp_sba_status,
674                     "A",
675                     "NVIDIA AGP SBA Status Information");
676         }
677     }
678 }
679
680 void nv_sysctl_exit(nv_state_t *nv)
681 {
682     struct nvidia_softc *sc = nv->os_state;
683     sysctl_ctx_free(&sc->sysctl_ctx);
684 }
685