Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/amd64/vmm/amd/amdviiommu.c
39537 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2021 The FreeBSD Foundation
5
*
6
* Portions of this software were developed by Ka Ho Ng
7
* under sponsorship from the FreeBSD Foundation.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice unmodified, this list of conditions, and the following
14
* disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30
31
#include <sys/param.h>
32
#include <sys/bus.h>
33
#include <sys/kernel.h>
34
#include <sys/module.h>
35
#include <sys/rman.h>
36
37
#include <dev/pci/pcireg.h>
38
#include <dev/pci/pcivar.h>
39
40
#include "amdvi_priv.h"
41
#include "ivhd_if.h"
42
43
struct amdviiommu_softc {
44
struct resource *event_res; /* Event interrupt resource. */
45
void *event_tag; /* Event interrupt tag. */
46
int event_rid;
47
};
48
49
static int amdviiommu_probe(device_t);
50
static int amdviiommu_attach(device_t);
51
static int amdviiommu_detach(device_t);
52
static int ivhd_setup_intr(device_t, driver_intr_t, void *,
53
const char *);
54
static int ivhd_teardown_intr(device_t);
55
56
static device_method_t amdviiommu_methods[] = {
57
/* device interface */
58
DEVMETHOD(device_probe, amdviiommu_probe),
59
DEVMETHOD(device_attach, amdviiommu_attach),
60
DEVMETHOD(device_detach, amdviiommu_detach),
61
DEVMETHOD(ivhd_setup_intr, ivhd_setup_intr),
62
DEVMETHOD(ivhd_teardown_intr, ivhd_teardown_intr),
63
DEVMETHOD_END
64
};
65
static driver_t amdviiommu_driver = {
66
"amdviiommu",
67
amdviiommu_methods,
68
sizeof(struct amdviiommu_softc),
69
};
70
71
static int
72
amdviiommu_probe(device_t dev)
73
{
74
int error;
75
int capoff;
76
77
/*
78
* Check base class and sub-class
79
*/
80
if (pci_get_class(dev) != PCIC_BASEPERIPH ||
81
pci_get_subclass(dev) != PCIS_BASEPERIPH_IOMMU)
82
return (ENXIO);
83
84
/*
85
* A IOMMU capability block carries a 0Fh capid.
86
*/
87
error = pci_find_cap(dev, PCIY_SECDEV, &capoff);
88
if (error)
89
return (ENXIO);
90
91
/*
92
* bit [18:16] == 011b indicates the capability block is IOMMU
93
* capability block. If the field is not set to 011b, bail out.
94
*/
95
if ((pci_read_config(dev, capoff + 2, 2) & 0x7) != 0x3)
96
return (ENXIO);
97
98
return (BUS_PROBE_SPECIFIC);
99
}
100
101
static int
102
amdviiommu_attach(device_t dev)
103
{
104
105
device_set_desc(dev, "AMD-Vi/IOMMU PCI function");
106
return (0);
107
}
108
109
static int
110
amdviiommu_detach(device_t dev)
111
{
112
113
return (0);
114
}
115
116
static int
117
ivhd_setup_intr(device_t dev, driver_intr_t handler, void *arg,
118
const char *desc)
119
{
120
struct amdviiommu_softc *sc;
121
int error, msicnt;
122
123
sc = device_get_softc(dev);
124
msicnt = 1;
125
if (sc->event_res != NULL)
126
panic("%s is called without intr teardown", __func__);
127
sc->event_rid = 1;
128
129
error = pci_alloc_msi(dev, &msicnt);
130
if (error) {
131
device_printf(dev, "Couldn't find event MSI IRQ resource.\n");
132
return (ENOENT);
133
}
134
135
sc->event_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
136
&sc->event_rid, RF_ACTIVE);
137
if (sc->event_res == NULL) {
138
device_printf(dev, "Unable to allocate event INTR resource.\n");
139
error = ENOMEM;
140
goto fail;
141
}
142
143
error = bus_setup_intr(dev, sc->event_res, INTR_TYPE_MISC | INTR_MPSAFE,
144
NULL, handler, arg, &sc->event_tag);
145
if (error) {
146
device_printf(dev, "Fail to setup event intr\n");
147
goto fail;
148
}
149
150
bus_describe_intr(dev, sc->event_res, sc->event_tag, "%s", desc);
151
return (0);
152
153
fail:
154
ivhd_teardown_intr(dev);
155
return (error);
156
}
157
158
static int
159
ivhd_teardown_intr(device_t dev)
160
{
161
struct amdviiommu_softc *sc;
162
163
sc = device_get_softc(dev);
164
165
if (sc->event_tag != NULL) {
166
bus_teardown_intr(dev, sc->event_res, sc->event_tag);
167
sc->event_tag = NULL;
168
}
169
if (sc->event_res != NULL) {
170
bus_release_resource(dev, SYS_RES_IRQ, sc->event_rid,
171
sc->event_res);
172
sc->event_res = NULL;
173
}
174
pci_release_msi(dev);
175
return (0);
176
}
177
178
/* This driver has to be loaded before ivhd */
179
DRIVER_MODULE(amdviiommu, pci, amdviiommu_driver, 0, 0);
180
MODULE_DEPEND(amdviiommu, pci, 1, 1, 1);
181
182