Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/amd64/vmm/amd/ivrs_drv.c
39537 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2016, Anish Gupta ([email protected])
5
* Copyright (c) 2021 The FreeBSD Foundation
6
* All rights reserved.
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice unmodified, this list of conditions, and the following
13
* disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
*/
29
30
#include <sys/cdefs.h>
31
#include "opt_acpi.h"
32
#include <sys/param.h>
33
#include <sys/bus.h>
34
#include <sys/kernel.h>
35
#include <sys/module.h>
36
#include <sys/malloc.h>
37
38
#include <machine/vmparam.h>
39
40
#include <vm/vm.h>
41
#include <vm/pmap.h>
42
43
#include <contrib/dev/acpica/include/acpi.h>
44
#include <contrib/dev/acpica/include/accommon.h>
45
#include <dev/acpica/acpivar.h>
46
#include <dev/pci/pcireg.h>
47
#include <dev/pci/pcivar.h>
48
49
#include "io/iommu.h"
50
#include "amdvi_priv.h"
51
52
device_t *ivhd_devs; /* IVHD or AMD-Vi device list. */
53
int ivhd_count; /* Number of IVHD header. */
54
/*
55
* Cached IVHD header list.
56
* Single entry for each IVHD, filtered the legacy one.
57
*/
58
ACPI_IVRS_HARDWARE1 **ivhd_hdrs;
59
60
extern int amdvi_ptp_level; /* Page table levels. */
61
62
typedef int (*ivhd_iter_t)(ACPI_IVRS_HEADER *ptr, void *arg);
63
/*
64
* Iterate IVRS table for IVHD and IVMD device type.
65
*/
66
static void
67
ivrs_hdr_iterate_tbl(ivhd_iter_t iter, void *arg)
68
{
69
ACPI_TABLE_IVRS *ivrs;
70
ACPI_IVRS_HEADER *ivrs_hdr, *end;
71
ACPI_STATUS status;
72
73
status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs);
74
if (ACPI_FAILURE(status))
75
return;
76
77
if (ivrs->Header.Length == 0) {
78
return;
79
}
80
81
ivrs_hdr = (ACPI_IVRS_HEADER *)(ivrs + 1);
82
end = (ACPI_IVRS_HEADER *)((char *)ivrs + ivrs->Header.Length);
83
84
while (ivrs_hdr < end) {
85
if ((uint8_t *)ivrs_hdr + ivrs_hdr->Length > (uint8_t *)end) {
86
printf("AMD-Vi:IVHD/IVMD is corrupted, length : %d\n",
87
ivrs_hdr->Length);
88
break;
89
}
90
91
switch (ivrs_hdr->Type) {
92
case IVRS_TYPE_HARDWARE_LEGACY: /* Legacy */
93
case IVRS_TYPE_HARDWARE_EFR:
94
case IVRS_TYPE_HARDWARE_MIXED:
95
if (!iter(ivrs_hdr, arg))
96
return;
97
break;
98
99
case ACPI_IVRS_TYPE_MEMORY1:
100
case ACPI_IVRS_TYPE_MEMORY2:
101
case ACPI_IVRS_TYPE_MEMORY3:
102
if (!iter(ivrs_hdr, arg))
103
return;
104
105
break;
106
107
default:
108
printf("AMD-Vi:Not IVHD/IVMD type(%d)", ivrs_hdr->Type);
109
}
110
111
ivrs_hdr = (ACPI_IVRS_HEADER *)((uint8_t *)ivrs_hdr +
112
ivrs_hdr->Length);
113
}
114
}
115
116
static bool
117
ivrs_is_ivhd(UINT8 type)
118
{
119
120
switch(type) {
121
case IVRS_TYPE_HARDWARE_LEGACY:
122
case IVRS_TYPE_HARDWARE_EFR:
123
case IVRS_TYPE_HARDWARE_MIXED:
124
return (true);
125
126
default:
127
return (false);
128
}
129
}
130
131
/* Count the number of AMD-Vi devices in the system. */
132
static int
133
ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he, void *arg)
134
{
135
int *count;
136
137
count = (int *)arg;
138
if (ivrs_is_ivhd(ivrs_he->Type))
139
(*count)++;
140
141
return (1);
142
}
143
144
struct find_ivrs_hdr_args {
145
int i;
146
ACPI_IVRS_HEADER *ptr;
147
};
148
149
static int
150
ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr, void *args)
151
{
152
struct find_ivrs_hdr_args *fi;
153
154
fi = (struct find_ivrs_hdr_args *)args;
155
if (ivrs_is_ivhd(ivrs_hdr->Type)) {
156
if (fi->i == 0) {
157
fi->ptr = ivrs_hdr;
158
return (0);
159
}
160
fi->i--;
161
}
162
163
return (1);
164
}
165
166
static ACPI_IVRS_HARDWARE1 *
167
ivhd_find_by_index(int idx)
168
{
169
struct find_ivrs_hdr_args fi;
170
171
fi.i = idx;
172
fi.ptr = NULL;
173
174
ivrs_hdr_iterate_tbl(ivrs_hdr_find_iter, &fi);
175
176
return ((ACPI_IVRS_HARDWARE1 *)fi.ptr);
177
}
178
179
static void
180
ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id,
181
uint32_t end_id, uint8_t cfg, bool ats)
182
{
183
struct ivhd_dev_cfg *dev_cfg;
184
185
KASSERT(softc->dev_cfg_cap >= softc->dev_cfg_cnt,
186
("Impossible case: number of dev_cfg exceeding capacity"));
187
if (softc->dev_cfg_cap == softc->dev_cfg_cnt) {
188
if (softc->dev_cfg_cap == 0)
189
softc->dev_cfg_cap = 1;
190
else
191
softc->dev_cfg_cap <<= 2;
192
softc->dev_cfg = realloc(softc->dev_cfg,
193
sizeof(*softc->dev_cfg) * softc->dev_cfg_cap, M_DEVBUF,
194
M_WAITOK);
195
}
196
197
dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++];
198
dev_cfg->start_id = start_id;
199
dev_cfg->end_id = end_id;
200
dev_cfg->data = cfg;
201
dev_cfg->enable_ats = ats;
202
}
203
204
/*
205
* Record device attributes as suggested by BIOS.
206
*/
207
static int
208
ivhd_dev_parse(ACPI_IVRS_HARDWARE1 *ivhd, struct amdvi_softc *softc)
209
{
210
ACPI_IVRS_DE_HEADER *de;
211
uint8_t *p, *end;
212
int range_start_id = -1, range_end_id = -1, i;
213
uint32_t *extended;
214
uint8_t all_data = 0, range_data = 0;
215
bool range_enable_ats = false, enable_ats;
216
217
switch (ivhd->Header.Type) {
218
case IVRS_TYPE_HARDWARE_LEGACY:
219
p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE1);
220
break;
221
222
case IVRS_TYPE_HARDWARE_EFR:
223
case IVRS_TYPE_HARDWARE_MIXED:
224
p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE2);
225
break;
226
227
default:
228
device_printf(softc->dev,
229
"unknown type: 0x%x\n", ivhd->Header.Type);
230
return (-1);
231
}
232
233
end = (uint8_t *)ivhd + ivhd->Header.Length;
234
235
while (p < end) {
236
de = (ACPI_IVRS_DE_HEADER *)p;
237
switch (de->Type) {
238
case ACPI_IVRS_TYPE_ALL:
239
all_data = de->DataSetting;
240
for (i = 0; i < softc->dev_cfg_cnt; i++)
241
softc->dev_cfg[i].data |= all_data;
242
break;
243
244
case ACPI_IVRS_TYPE_SELECT:
245
case ACPI_IVRS_TYPE_ALIAS_SELECT:
246
case ACPI_IVRS_TYPE_EXT_SELECT:
247
enable_ats = false;
248
if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) {
249
extended = (uint32_t *)(de + 1);
250
enable_ats =
251
(*extended & IVHD_DEV_EXT_ATS_DISABLE) ?
252
false : true;
253
}
254
ivhd_dev_add_entry(softc, de->Id, de->Id,
255
de->DataSetting | all_data, enable_ats);
256
break;
257
258
case ACPI_IVRS_TYPE_START:
259
case ACPI_IVRS_TYPE_ALIAS_START:
260
case ACPI_IVRS_TYPE_EXT_START:
261
if (range_start_id != -1) {
262
device_printf(softc->dev,
263
"Unexpected start-of-range device entry\n");
264
return (EINVAL);
265
}
266
range_start_id = de->Id;
267
range_data = de->DataSetting;
268
if (de->Type == ACPI_IVRS_TYPE_EXT_START) {
269
extended = (uint32_t *)(de + 1);
270
range_enable_ats =
271
(*extended & IVHD_DEV_EXT_ATS_DISABLE) ?
272
false : true;
273
}
274
break;
275
276
case ACPI_IVRS_TYPE_END:
277
if (range_start_id == -1) {
278
device_printf(softc->dev,
279
"Unexpected end-of-range device entry\n");
280
return (EINVAL);
281
}
282
range_end_id = de->Id;
283
if (range_end_id < range_start_id) {
284
device_printf(softc->dev,
285
"Device entry range going backward\n");
286
return (EINVAL);
287
}
288
ivhd_dev_add_entry(softc, range_start_id, range_end_id,
289
range_data | all_data, range_enable_ats);
290
range_start_id = range_end_id = -1;
291
range_data = 0;
292
all_data = 0;
293
break;
294
295
case ACPI_IVRS_TYPE_PAD4:
296
break;
297
298
case ACPI_IVRS_TYPE_SPECIAL:
299
/* HPET or IOAPIC */
300
break;
301
default:
302
if ((de->Type < 5) ||
303
(de->Type >= ACPI_IVRS_TYPE_PAD8))
304
device_printf(softc->dev,
305
"Unknown dev entry:0x%x\n", de->Type);
306
}
307
308
if (de->Type < 0x40)
309
p += sizeof(ACPI_IVRS_DEVICE4);
310
else if (de->Type < 0x80)
311
p += sizeof(ACPI_IVRS_DEVICE8A);
312
else {
313
printf("Variable size IVHD type 0x%x not supported\n",
314
de->Type);
315
break;
316
}
317
}
318
319
return (0);
320
}
321
322
static bool
323
ivhd_is_newer(ACPI_IVRS_HEADER *old, ACPI_IVRS_HEADER *new)
324
{
325
if (old->DeviceId == new->DeviceId) {
326
/*
327
* Newer IVRS header type take precedence.
328
*/
329
if (old->Type == IVRS_TYPE_HARDWARE_LEGACY &&
330
((new->Type == IVRS_TYPE_HARDWARE_EFR) ||
331
(new->Type == IVRS_TYPE_HARDWARE_MIXED)))
332
return (true);
333
334
/*
335
* Mixed format IVHD header type take precedence
336
* over fixed format IVHD header types.
337
*/
338
if (old->Type == IVRS_TYPE_HARDWARE_EFR &&
339
new->Type == IVRS_TYPE_HARDWARE_MIXED)
340
return (true);
341
}
342
343
return (false);
344
}
345
346
static void
347
ivhd_identify(driver_t *driver, device_t parent)
348
{
349
ACPI_TABLE_IVRS *ivrs;
350
ACPI_IVRS_HARDWARE1 *ivhd;
351
ACPI_STATUS status;
352
int i, j, count = 0;
353
uint32_t ivrs_ivinfo;
354
355
if (acpi_disabled("ivhd"))
356
return;
357
358
status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs);
359
if (ACPI_FAILURE(status))
360
return;
361
362
if (ivrs->Header.Length == 0) {
363
return;
364
}
365
366
ivrs_ivinfo = ivrs->Info;
367
printf("AMD-Vi: IVRS Info VAsize = %d PAsize = %d GVAsize = %d"
368
" flags:%b\n",
369
REG_BITS(ivrs_ivinfo, 21, 15), REG_BITS(ivrs_ivinfo, 14, 8),
370
REG_BITS(ivrs_ivinfo, 7, 5), REG_BITS(ivrs_ivinfo, 22, 22),
371
"\020\001EFRSup");
372
373
ivrs_hdr_iterate_tbl(ivhd_count_iter, &count);
374
if (!count)
375
return;
376
377
ivhd_hdrs = malloc(sizeof(void *) * count, M_DEVBUF,
378
M_WAITOK | M_ZERO);
379
for (i = 0; i < count; i++) {
380
ivhd = ivhd_find_by_index(i);
381
KASSERT(ivhd, ("ivhd%d is NULL\n", i));
382
383
/*
384
* Scan for presence of legacy and non-legacy device type
385
* for same IOMMU device and override the old one.
386
*
387
* If there is no existing IVHD to the same IOMMU device,
388
* the IVHD header pointer is appended.
389
*/
390
for (j = 0; j < ivhd_count; j++) {
391
if (ivhd_is_newer(&ivhd_hdrs[j]->Header, &ivhd->Header))
392
break;
393
}
394
ivhd_hdrs[j] = ivhd;
395
if (j == ivhd_count)
396
ivhd_count++;
397
}
398
399
ivhd_devs = malloc(sizeof(device_t) * ivhd_count, M_DEVBUF,
400
M_WAITOK | M_ZERO);
401
for (i = 0, j = 0; i < ivhd_count; i++) {
402
ivhd = ivhd_hdrs[i];
403
KASSERT(ivhd, ("ivhd%d is NULL\n", i));
404
405
/*
406
* Use a high order to ensure that this driver is probed after
407
* the Host-PCI bridge and the root PCI bus.
408
*/
409
ivhd_devs[i] = BUS_ADD_CHILD(parent,
410
ACPI_DEV_BASE_ORDER + 10 * 10, "ivhd", i);
411
412
/*
413
* XXX: In case device was not destroyed before, add will fail.
414
* locate the old device instance.
415
*/
416
if (ivhd_devs[i] == NULL) {
417
ivhd_devs[i] = device_find_child(parent, "ivhd", i);
418
if (ivhd_devs[i] == NULL) {
419
printf("AMD-Vi: can't find ivhd%d\n", i);
420
break;
421
}
422
}
423
j++;
424
}
425
426
/*
427
* Update device count in case failed to attach.
428
*/
429
ivhd_count = j;
430
}
431
432
static int
433
ivhd_probe(device_t dev)
434
{
435
ACPI_IVRS_HARDWARE1 *ivhd;
436
int unit;
437
438
if (acpi_get_handle(dev) != NULL)
439
return (ENXIO);
440
441
unit = device_get_unit(dev);
442
KASSERT((unit < ivhd_count),
443
("ivhd unit %d > count %d", unit, ivhd_count));
444
ivhd = ivhd_hdrs[unit];
445
KASSERT(ivhd, ("ivhd is NULL"));
446
447
switch (ivhd->Header.Type) {
448
case IVRS_TYPE_HARDWARE_EFR:
449
device_set_desc(dev, "AMD-Vi/IOMMU ivhd with EFR");
450
break;
451
452
case IVRS_TYPE_HARDWARE_MIXED:
453
device_set_desc(dev, "AMD-Vi/IOMMU ivhd in mixed format");
454
break;
455
456
case IVRS_TYPE_HARDWARE_LEGACY:
457
default:
458
device_set_desc(dev, "AMD-Vi/IOMMU ivhd");
459
break;
460
}
461
462
return (BUS_PROBE_NOWILDCARD);
463
}
464
465
static void
466
ivhd_print_flag(device_t dev, enum IvrsType ivhd_type, uint8_t flag)
467
{
468
/*
469
* IVHD lgeacy type has two extra high bits in flag which has
470
* been moved to EFR for non-legacy device.
471
*/
472
switch (ivhd_type) {
473
case IVRS_TYPE_HARDWARE_LEGACY:
474
device_printf(dev, "Flag:%b\n", flag,
475
"\020"
476
"\001HtTunEn"
477
"\002PassPW"
478
"\003ResPassPW"
479
"\004Isoc"
480
"\005IotlbSup"
481
"\006Coherent"
482
"\007PreFSup"
483
"\010PPRSup");
484
break;
485
486
case IVRS_TYPE_HARDWARE_EFR:
487
case IVRS_TYPE_HARDWARE_MIXED:
488
device_printf(dev, "Flag:%b\n", flag,
489
"\020"
490
"\001HtTunEn"
491
"\002PassPW"
492
"\003ResPassPW"
493
"\004Isoc"
494
"\005IotlbSup"
495
"\006Coherent");
496
break;
497
498
default:
499
device_printf(dev, "Can't decode flag of ivhd type :0x%x\n",
500
ivhd_type);
501
break;
502
}
503
}
504
505
/*
506
* Feature in legacy IVHD type(0x10) and attribute in newer type(0x11 and 0x40).
507
*/
508
static void
509
ivhd_print_feature(device_t dev, enum IvrsType ivhd_type, uint32_t feature)
510
{
511
switch (ivhd_type) {
512
case IVRS_TYPE_HARDWARE_LEGACY:
513
device_printf(dev, "Features(type:0x%x) HATS = %d GATS = %d"
514
" MsiNumPPR = %d PNBanks= %d PNCounters= %d\n",
515
ivhd_type,
516
REG_BITS(feature, 31, 30),
517
REG_BITS(feature, 29, 28),
518
REG_BITS(feature, 27, 23),
519
REG_BITS(feature, 22, 17),
520
REG_BITS(feature, 16, 13));
521
device_printf(dev, "max PASID = %d GLXSup = %d Feature:%b\n",
522
REG_BITS(feature, 12, 8),
523
REG_BITS(feature, 4, 3),
524
feature,
525
"\020"
526
"\002NXSup"
527
"\003GTSup"
528
"\004<b4>"
529
"\005IASup"
530
"\006GASup"
531
"\007HESup");
532
break;
533
534
/* Fewer features or attributes are reported in non-legacy type. */
535
case IVRS_TYPE_HARDWARE_EFR:
536
case IVRS_TYPE_HARDWARE_MIXED:
537
device_printf(dev, "Features(type:0x%x) MsiNumPPR = %d"
538
" PNBanks= %d PNCounters= %d\n",
539
ivhd_type,
540
REG_BITS(feature, 27, 23),
541
REG_BITS(feature, 22, 17),
542
REG_BITS(feature, 16, 13));
543
break;
544
545
default: /* Other ivhd type features are not decoded. */
546
device_printf(dev, "Can't decode ivhd type :0x%x\n", ivhd_type);
547
}
548
}
549
550
/* Print extended features of IOMMU. */
551
static void
552
ivhd_print_ext_feature(device_t dev, uint64_t ext_feature)
553
{
554
uint32_t ext_low, ext_high;
555
556
if (!ext_feature)
557
return;
558
559
ext_low = ext_feature;
560
device_printf(dev, "Extended features[31:0]:%b "
561
"HATS = 0x%x GATS = 0x%x "
562
"GLXSup = 0x%x SmiFSup = 0x%x SmiFRC = 0x%x "
563
"GAMSup = 0x%x DualPortLogSup = 0x%x DualEventLogSup = 0x%x\n",
564
(int)ext_low,
565
"\020"
566
"\001PreFSup"
567
"\002PPRSup"
568
"\003<b2>"
569
"\004NXSup"
570
"\005GTSup"
571
"\006<b5>"
572
"\007IASup"
573
"\010GASup"
574
"\011HESup"
575
"\012PCSup",
576
REG_BITS(ext_low, 11, 10),
577
REG_BITS(ext_low, 13, 12),
578
REG_BITS(ext_low, 15, 14),
579
REG_BITS(ext_low, 17, 16),
580
REG_BITS(ext_low, 20, 18),
581
REG_BITS(ext_low, 23, 21),
582
REG_BITS(ext_low, 25, 24),
583
REG_BITS(ext_low, 29, 28));
584
585
ext_high = ext_feature >> 32;
586
device_printf(dev, "Extended features[62:32]:%b "
587
"Max PASID: 0x%x DevTblSegSup = 0x%x "
588
"MarcSup = 0x%x\n",
589
(int)(ext_high),
590
"\020"
591
"\006USSup"
592
"\011PprOvrflwEarlySup"
593
"\012PPRAutoRspSup"
594
"\015BlKStopMrkSup"
595
"\016PerfOptSup"
596
"\017MsiCapMmioSup"
597
"\021GIOSup"
598
"\022HASup"
599
"\023EPHSup"
600
"\024AttrFWSup"
601
"\025HDSup"
602
"\027InvIotlbSup",
603
REG_BITS(ext_high, 5, 0),
604
REG_BITS(ext_high, 8, 7),
605
REG_BITS(ext_high, 11, 10));
606
}
607
608
static int
609
ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE1 * ivhd)
610
{
611
device_t dev;
612
int max_ptp_level;
613
614
dev = softc->dev;
615
616
ivhd_print_flag(dev, softc->ivhd_type, softc->ivhd_flag);
617
ivhd_print_feature(dev, softc->ivhd_type, softc->ivhd_feature);
618
ivhd_print_ext_feature(dev, softc->ext_feature);
619
max_ptp_level = 7;
620
/* Make sure device support minimum page level as requested by user. */
621
if (max_ptp_level < amdvi_ptp_level) {
622
device_printf(dev, "insufficient PTP level:%d\n",
623
max_ptp_level);
624
return (EINVAL);
625
} else {
626
device_printf(softc->dev, "supported paging level:%d, will use only: %d\n",
627
max_ptp_level, amdvi_ptp_level);
628
}
629
630
return (0);
631
}
632
633
static int
634
ivhd_attach(device_t dev)
635
{
636
ACPI_IVRS_HARDWARE1 *ivhd;
637
ACPI_IVRS_HARDWARE2 *ivhd_efr;
638
struct amdvi_softc *softc;
639
int status, unit;
640
641
unit = device_get_unit(dev);
642
KASSERT((unit < ivhd_count),
643
("ivhd unit %d > count %d", unit, ivhd_count));
644
/* Make sure its same device for which attach is called. */
645
KASSERT((ivhd_devs[unit] == dev),
646
("Not same device old %p new %p", ivhd_devs[unit], dev));
647
648
softc = device_get_softc(dev);
649
softc->dev = dev;
650
ivhd = ivhd_hdrs[unit];
651
KASSERT(ivhd, ("ivhd is NULL"));
652
softc->pci_dev = pci_find_dbsf(ivhd->PciSegmentGroup,
653
PCI_RID2BUS(ivhd->Header.DeviceId),
654
PCI_RID2SLOT(ivhd->Header.DeviceId),
655
PCI_RID2FUNC(ivhd->Header.DeviceId));
656
657
softc->ivhd_type = ivhd->Header.Type;
658
softc->pci_seg = ivhd->PciSegmentGroup;
659
softc->pci_rid = ivhd->Header.DeviceId;
660
softc->ivhd_flag = ivhd->Header.Flags;
661
/*
662
* On lgeacy IVHD type(0x10), it is documented as feature
663
* but in newer type it is attribute.
664
*/
665
softc->ivhd_feature = ivhd->FeatureReporting;
666
/*
667
* PCI capability has more capabilities that are not part of IVRS.
668
*/
669
softc->cap_off = ivhd->CapabilityOffset;
670
671
#ifdef notyet
672
/* IVHD Info bit[4:0] is event MSI/X number. */
673
softc->event_msix = ivhd->Info & 0x1F;
674
#endif
675
switch (ivhd->Header.Type) {
676
case IVRS_TYPE_HARDWARE_EFR:
677
case IVRS_TYPE_HARDWARE_MIXED:
678
ivhd_efr = (ACPI_IVRS_HARDWARE2 *)ivhd;
679
softc->ext_feature = ivhd_efr->EfrRegisterImage;
680
break;
681
}
682
683
softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress);
684
status = ivhd_dev_parse(ivhd, softc);
685
if (status != 0) {
686
device_printf(dev,
687
"endpoint device parsing error=%d\n", status);
688
goto fail;
689
}
690
691
status = ivhd_print_cap(softc, ivhd);
692
if (status != 0)
693
goto fail;
694
695
status = amdvi_setup_hw(softc);
696
if (status != 0) {
697
device_printf(dev, "couldn't be initialised, error=%d\n",
698
status);
699
goto fail;
700
}
701
702
return (0);
703
704
fail:
705
free(softc->dev_cfg, M_DEVBUF);
706
return (status);
707
}
708
709
static int
710
ivhd_detach(device_t dev)
711
{
712
struct amdvi_softc *softc;
713
714
softc = device_get_softc(dev);
715
716
amdvi_teardown_hw(softc);
717
free(softc->dev_cfg, M_DEVBUF);
718
719
/*
720
* XXX: delete the device.
721
* don't allow detach, return EBUSY.
722
*/
723
return (0);
724
}
725
726
static int
727
ivhd_suspend(device_t dev)
728
{
729
730
return (0);
731
}
732
733
static int
734
ivhd_resume(device_t dev)
735
{
736
737
return (0);
738
}
739
740
static device_method_t ivhd_methods[] = {
741
DEVMETHOD(device_identify, ivhd_identify),
742
DEVMETHOD(device_probe, ivhd_probe),
743
DEVMETHOD(device_attach, ivhd_attach),
744
DEVMETHOD(device_detach, ivhd_detach),
745
DEVMETHOD(device_suspend, ivhd_suspend),
746
DEVMETHOD(device_resume, ivhd_resume),
747
DEVMETHOD_END
748
};
749
750
static driver_t ivhd_driver = {
751
"ivhd",
752
ivhd_methods,
753
sizeof(struct amdvi_softc),
754
};
755
756
/*
757
* Load this module at the end after PCI re-probing to configure interrupt.
758
*/
759
DRIVER_MODULE_ORDERED(ivhd, acpi, ivhd_driver, 0, 0, SI_ORDER_ANY);
760
MODULE_DEPEND(ivhd, acpi, 1, 1, 1);
761
MODULE_DEPEND(ivhd, pci, 1, 1, 1);
762
763