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