Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/xen/platform-pci-unplug.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
/******************************************************************************
4
* platform-pci-unplug.c
5
*
6
* Xen platform PCI device driver
7
* Copyright (c) 2010, Citrix
8
*/
9
10
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12
#include <linux/init.h>
13
#include <linux/io.h>
14
#include <linux/export.h>
15
16
#include <xen/xen.h>
17
#include <xen/platform_pci.h>
18
#include "xen-ops.h"
19
20
#define XEN_PLATFORM_ERR_MAGIC -1
21
#define XEN_PLATFORM_ERR_PROTOCOL -2
22
#define XEN_PLATFORM_ERR_BLACKLIST -3
23
24
/* store the value of xen_emul_unplug after the unplug is done */
25
static int xen_platform_pci_unplug;
26
static int xen_emul_unplug;
27
28
static int check_platform_magic(void)
29
{
30
short magic;
31
char protocol;
32
33
magic = inw(XEN_IOPORT_MAGIC);
34
if (magic != XEN_IOPORT_MAGIC_VAL) {
35
pr_err("Xen Platform PCI: unrecognised magic value\n");
36
return XEN_PLATFORM_ERR_MAGIC;
37
}
38
39
protocol = inb(XEN_IOPORT_PROTOVER);
40
41
pr_debug("Xen Platform PCI: I/O protocol version %d\n",
42
protocol);
43
44
switch (protocol) {
45
case 1:
46
outw(XEN_IOPORT_LINUX_PRODNUM, XEN_IOPORT_PRODNUM);
47
outl(XEN_IOPORT_LINUX_DRVVER, XEN_IOPORT_DRVVER);
48
if (inw(XEN_IOPORT_MAGIC) != XEN_IOPORT_MAGIC_VAL) {
49
pr_err("Xen Platform: blacklisted by host\n");
50
return XEN_PLATFORM_ERR_BLACKLIST;
51
}
52
break;
53
default:
54
pr_warn("Xen Platform PCI: unknown I/O protocol version\n");
55
return XEN_PLATFORM_ERR_PROTOCOL;
56
}
57
58
return 0;
59
}
60
61
bool xen_has_pv_devices(void)
62
{
63
if (!xen_domain())
64
return false;
65
66
/* PV and PVH domains always have them. */
67
if (xen_pv_domain() || xen_pvh_domain())
68
return true;
69
70
/* And user has xen_platform_pci=0 set in guest config as
71
* driver did not modify the value. */
72
if (xen_platform_pci_unplug == 0)
73
return false;
74
75
if (xen_platform_pci_unplug & XEN_UNPLUG_NEVER)
76
return false;
77
78
if (xen_platform_pci_unplug & XEN_UNPLUG_ALL)
79
return true;
80
81
/* This is an odd one - we are going to run legacy
82
* and PV drivers at the same time. */
83
if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY)
84
return true;
85
86
/* And the caller has to follow with xen_pv_{disk,nic}_devices
87
* to be certain which driver can load. */
88
return false;
89
}
90
EXPORT_SYMBOL_GPL(xen_has_pv_devices);
91
92
static bool __xen_has_pv_device(int state)
93
{
94
/* HVM domains might or might not */
95
if (xen_hvm_domain() && (xen_platform_pci_unplug & state))
96
return true;
97
98
return xen_has_pv_devices();
99
}
100
101
bool xen_has_pv_nic_devices(void)
102
{
103
return __xen_has_pv_device(XEN_UNPLUG_ALL_NICS | XEN_UNPLUG_ALL);
104
}
105
EXPORT_SYMBOL_GPL(xen_has_pv_nic_devices);
106
107
bool xen_has_pv_disk_devices(void)
108
{
109
return __xen_has_pv_device(XEN_UNPLUG_ALL_IDE_DISKS |
110
XEN_UNPLUG_AUX_IDE_DISKS | XEN_UNPLUG_ALL);
111
}
112
EXPORT_SYMBOL_GPL(xen_has_pv_disk_devices);
113
114
/*
115
* This one is odd - it determines whether you want to run PV _and_
116
* legacy (IDE) drivers together. This combination is only possible
117
* under HVM.
118
*/
119
bool xen_has_pv_and_legacy_disk_devices(void)
120
{
121
if (!xen_domain())
122
return false;
123
124
/* N.B. This is only ever used in HVM mode */
125
if (xen_pv_domain())
126
return false;
127
128
if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY)
129
return true;
130
131
return false;
132
}
133
EXPORT_SYMBOL_GPL(xen_has_pv_and_legacy_disk_devices);
134
135
void xen_unplug_emulated_devices(void)
136
{
137
int r;
138
139
/* PVH guests don't have emulated devices. */
140
if (xen_pvh_domain())
141
return;
142
143
/* user explicitly requested no unplug */
144
if (xen_emul_unplug & XEN_UNPLUG_NEVER)
145
return;
146
/* check the version of the xen platform PCI device */
147
r = check_platform_magic();
148
/* If the version matches enable the Xen platform PCI driver.
149
* Also enable the Xen platform PCI driver if the host does
150
* not support the unplug protocol (XEN_PLATFORM_ERR_MAGIC)
151
* but the user told us that unplugging is unnecessary. */
152
if (r && !(r == XEN_PLATFORM_ERR_MAGIC &&
153
(xen_emul_unplug & XEN_UNPLUG_UNNECESSARY)))
154
return;
155
/* Set the default value of xen_emul_unplug depending on whether or
156
* not the Xen PV frontends and the Xen platform PCI driver have
157
* been compiled for this kernel (modules or built-in are both OK). */
158
if (!xen_emul_unplug) {
159
if (xen_must_unplug_nics()) {
160
pr_info("Netfront and the Xen platform PCI driver have "
161
"been compiled for this kernel: unplug emulated NICs.\n");
162
xen_emul_unplug |= XEN_UNPLUG_ALL_NICS;
163
}
164
if (xen_must_unplug_disks()) {
165
pr_info("Blkfront and the Xen platform PCI driver have "
166
"been compiled for this kernel: unplug emulated disks.\n"
167
"You might have to change the root device\n"
168
"from /dev/hd[a-d] to /dev/xvd[a-d]\n"
169
"in your root= kernel command line option\n");
170
xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS;
171
}
172
}
173
/* Now unplug the emulated devices */
174
if (!(xen_emul_unplug & XEN_UNPLUG_UNNECESSARY))
175
outw(xen_emul_unplug, XEN_IOPORT_UNPLUG);
176
xen_platform_pci_unplug = xen_emul_unplug;
177
}
178
179
static int __init parse_xen_emul_unplug(char *arg)
180
{
181
char *p, *q;
182
int l;
183
184
for (p = arg; p; p = q) {
185
q = strchr(p, ',');
186
if (q) {
187
l = q - p;
188
q++;
189
} else {
190
l = strlen(p);
191
}
192
if (!strncmp(p, "all", l))
193
xen_emul_unplug |= XEN_UNPLUG_ALL;
194
else if (!strncmp(p, "ide-disks", l))
195
xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS;
196
else if (!strncmp(p, "aux-ide-disks", l))
197
xen_emul_unplug |= XEN_UNPLUG_AUX_IDE_DISKS;
198
else if (!strncmp(p, "nics", l))
199
xen_emul_unplug |= XEN_UNPLUG_ALL_NICS;
200
else if (!strncmp(p, "unnecessary", l))
201
xen_emul_unplug |= XEN_UNPLUG_UNNECESSARY;
202
else if (!strncmp(p, "never", l))
203
xen_emul_unplug |= XEN_UNPLUG_NEVER;
204
else
205
pr_warn("unrecognised option '%s' "
206
"in parameter 'xen_emul_unplug'\n", p);
207
}
208
return 0;
209
}
210
early_param("xen_emul_unplug", parse_xen_emul_unplug);
211
212