vmbus.c (308621) | vmbus.c (309312) |
---|---|
1/*- 2 * Copyright (c) 2009-2012,2016 Microsoft Corp. 3 * Copyright (c) 2012 NetApp Inc. 4 * Copyright (c) 2012 Citrix Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 16 unchanged lines hidden (view full) --- 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * VM Bus Driver Implementation 31 */ 32#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2009-2012,2016 Microsoft Corp. 3 * Copyright (c) 2012 NetApp Inc. 4 * Copyright (c) 2012 Citrix Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 16 unchanged lines hidden (view full) --- 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * VM Bus Driver Implementation 31 */ 32#include <sys/cdefs.h> |
33__FBSDID("$FreeBSD: stable/11/sys/dev/hyperv/vmbus/vmbus.c 308621 2016-11-14 03:04:54Z sephe $"); | 33__FBSDID("$FreeBSD: stable/11/sys/dev/hyperv/vmbus/vmbus.c 309312 2016-11-30 06:20:43Z dexuan $"); |
34 35#include <sys/param.h> 36#include <sys/bus.h> 37#include <sys/kernel.h> 38#include <sys/lock.h> 39#include <sys/malloc.h> 40#include <sys/module.h> 41#include <sys/mutex.h> 42#include <sys/smp.h> 43#include <sys/sysctl.h> 44#include <sys/systm.h> 45#include <sys/taskqueue.h> 46 | 34 35#include <sys/param.h> 36#include <sys/bus.h> 37#include <sys/kernel.h> 38#include <sys/lock.h> 39#include <sys/malloc.h> 40#include <sys/module.h> 41#include <sys/mutex.h> 42#include <sys/smp.h> 43#include <sys/sysctl.h> 44#include <sys/systm.h> 45#include <sys/taskqueue.h> 46 |
47#include <machine/bus.h> |
|
47#include <machine/intr_machdep.h> | 48#include <machine/intr_machdep.h> |
49#include <machine/resource.h> |
|
48#include <x86/include/apicvar.h> 49 50#include <contrib/dev/acpica/include/acpi.h> | 50#include <x86/include/apicvar.h> 51 52#include <contrib/dev/acpica/include/acpi.h> |
53#include <dev/acpica/acpivar.h> |
|
51 52#include <dev/hyperv/include/hyperv.h> 53#include <dev/hyperv/include/vmbus_xact.h> 54#include <dev/hyperv/vmbus/hyperv_reg.h> 55#include <dev/hyperv/vmbus/hyperv_var.h> 56#include <dev/hyperv/vmbus/vmbus_reg.h> 57#include <dev/hyperv/vmbus/vmbus_var.h> 58#include <dev/hyperv/vmbus/vmbus_chanvar.h> 59 60#include "acpi_if.h" | 54 55#include <dev/hyperv/include/hyperv.h> 56#include <dev/hyperv/include/vmbus_xact.h> 57#include <dev/hyperv/vmbus/hyperv_reg.h> 58#include <dev/hyperv/vmbus/hyperv_var.h> 59#include <dev/hyperv/vmbus/vmbus_reg.h> 60#include <dev/hyperv/vmbus/vmbus_var.h> 61#include <dev/hyperv/vmbus/vmbus_chanvar.h> 62 63#include "acpi_if.h" |
64#include "pcib_if.h" |
|
61#include "vmbus_if.h" 62 63#define VMBUS_GPADL_START 0xe1e10 64 65struct vmbus_msghc { 66 struct vmbus_xact *mh_xact; 67 struct hypercall_postmsg_in mh_inprm_save; 68}; 69 70static int vmbus_probe(device_t); 71static int vmbus_attach(device_t); 72static int vmbus_detach(device_t); 73static int vmbus_read_ivar(device_t, device_t, int, 74 uintptr_t *); 75static int vmbus_child_pnpinfo_str(device_t, device_t, 76 char *, size_t); | 65#include "vmbus_if.h" 66 67#define VMBUS_GPADL_START 0xe1e10 68 69struct vmbus_msghc { 70 struct vmbus_xact *mh_xact; 71 struct hypercall_postmsg_in mh_inprm_save; 72}; 73 74static int vmbus_probe(device_t); 75static int vmbus_attach(device_t); 76static int vmbus_detach(device_t); 77static int vmbus_read_ivar(device_t, device_t, int, 78 uintptr_t *); 79static int vmbus_child_pnpinfo_str(device_t, device_t, 80 char *, size_t); |
81static struct resource *vmbus_alloc_resource(device_t dev, 82 device_t child, int type, int *rid, 83 rman_res_t start, rman_res_t end, 84 rman_res_t count, u_int flags); 85static int vmbus_alloc_msi(device_t bus, device_t dev, 86 int count, int maxcount, int *irqs); 87static int vmbus_release_msi(device_t bus, device_t dev, 88 int count, int *irqs); 89static int vmbus_alloc_msix(device_t bus, device_t dev, 90 int *irq); 91static int vmbus_release_msix(device_t bus, device_t dev, 92 int irq); 93static int vmbus_map_msi(device_t bus, device_t dev, 94 int irq, uint64_t *addr, uint32_t *data); |
|
77static uint32_t vmbus_get_version_method(device_t, device_t); 78static int vmbus_probe_guid_method(device_t, device_t, 79 const struct hyperv_guid *); | 95static uint32_t vmbus_get_version_method(device_t, device_t); 96static int vmbus_probe_guid_method(device_t, device_t, 97 const struct hyperv_guid *); |
98static uint32_t vmbus_get_vcpu_id_method(device_t bus, 99 device_t dev, int cpu); |
|
80 81static int vmbus_init(struct vmbus_softc *); 82static int vmbus_connect(struct vmbus_softc *, uint32_t); 83static int vmbus_req_channels(struct vmbus_softc *sc); 84static void vmbus_disconnect(struct vmbus_softc *); 85static int vmbus_scan(struct vmbus_softc *); 86static void vmbus_scan_teardown(struct vmbus_softc *); 87static void vmbus_scan_done(struct vmbus_softc *, --- 38 unchanged lines hidden (view full) --- 126 DEVMETHOD(device_suspend, bus_generic_suspend), 127 DEVMETHOD(device_resume, bus_generic_resume), 128 129 /* Bus interface */ 130 DEVMETHOD(bus_add_child, bus_generic_add_child), 131 DEVMETHOD(bus_print_child, bus_generic_print_child), 132 DEVMETHOD(bus_read_ivar, vmbus_read_ivar), 133 DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str), | 100 101static int vmbus_init(struct vmbus_softc *); 102static int vmbus_connect(struct vmbus_softc *, uint32_t); 103static int vmbus_req_channels(struct vmbus_softc *sc); 104static void vmbus_disconnect(struct vmbus_softc *); 105static int vmbus_scan(struct vmbus_softc *); 106static void vmbus_scan_teardown(struct vmbus_softc *); 107static void vmbus_scan_done(struct vmbus_softc *, --- 38 unchanged lines hidden (view full) --- 146 DEVMETHOD(device_suspend, bus_generic_suspend), 147 DEVMETHOD(device_resume, bus_generic_resume), 148 149 /* Bus interface */ 150 DEVMETHOD(bus_add_child, bus_generic_add_child), 151 DEVMETHOD(bus_print_child, bus_generic_print_child), 152 DEVMETHOD(bus_read_ivar, vmbus_read_ivar), 153 DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str), |
154 DEVMETHOD(bus_alloc_resource, vmbus_alloc_resource), 155 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 156 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 157 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 158 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 159 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 160#if __FreeBSD_version >= 1100000 161 DEVMETHOD(bus_get_cpus, bus_generic_get_cpus), 162#endif |
|
134 | 163 |
164 /* pcib interface */ 165 DEVMETHOD(pcib_alloc_msi, vmbus_alloc_msi), 166 DEVMETHOD(pcib_release_msi, vmbus_release_msi), 167 DEVMETHOD(pcib_alloc_msix, vmbus_alloc_msix), 168 DEVMETHOD(pcib_release_msix, vmbus_release_msix), 169 DEVMETHOD(pcib_map_msi, vmbus_map_msi), 170 |
|
135 /* Vmbus interface */ 136 DEVMETHOD(vmbus_get_version, vmbus_get_version_method), 137 DEVMETHOD(vmbus_probe_guid, vmbus_probe_guid_method), | 171 /* Vmbus interface */ 172 DEVMETHOD(vmbus_get_version, vmbus_get_version_method), 173 DEVMETHOD(vmbus_probe_guid, vmbus_probe_guid_method), |
174 DEVMETHOD(vmbus_get_vcpu_id, vmbus_get_vcpu_id_method), |
|
138 139 DEVMETHOD_END 140}; 141 142static driver_t vmbus_driver = { 143 "vmbus", 144 vmbus_methods, 145 sizeof(struct vmbus_softc) 146}; 147 148static devclass_t vmbus_devclass; 149 150DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL); 151MODULE_DEPEND(vmbus, acpi, 1, 1, 1); | 175 176 DEVMETHOD_END 177}; 178 179static driver_t vmbus_driver = { 180 "vmbus", 181 vmbus_methods, 182 sizeof(struct vmbus_softc) 183}; 184 185static devclass_t vmbus_devclass; 186 187DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL); 188MODULE_DEPEND(vmbus, acpi, 1, 1, 1); |
189MODULE_DEPEND(vmbus, pci, 1, 1, 1); |
|
152MODULE_VERSION(vmbus, 1); 153 154static __inline struct vmbus_softc * 155vmbus_get_softc(void) 156{ 157 return vmbus_sc; 158} 159 --- 807 unchanged lines hidden (view full) --- 967 char verstr[16]; 968 969 snprintf(verstr, sizeof(verstr), "%u.%u", 970 VMBUS_VERSION_MAJOR(sc->vmbus_version), 971 VMBUS_VERSION_MINOR(sc->vmbus_version)); 972 return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 973} 974 | 190MODULE_VERSION(vmbus, 1); 191 192static __inline struct vmbus_softc * 193vmbus_get_softc(void) 194{ 195 return vmbus_sc; 196} 197 --- 807 unchanged lines hidden (view full) --- 1005 char verstr[16]; 1006 1007 snprintf(verstr, sizeof(verstr), "%u.%u", 1008 VMBUS_VERSION_MAJOR(sc->vmbus_version), 1009 VMBUS_VERSION_MINOR(sc->vmbus_version)); 1010 return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 1011} 1012 |
1013/* 1014 * We need the function to make sure the MMIO resource is allocated from the 1015 * ranges found in _CRS. 1016 * 1017 * For the release function, we can use bus_generic_release_resource(). 1018 */ 1019static struct resource * 1020vmbus_alloc_resource(device_t dev, device_t child, int type, int *rid, 1021 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 1022{ 1023 device_t parent = device_get_parent(dev); 1024 struct resource *res; 1025 1026#ifdef NEW_PCIB 1027 if (type == SYS_RES_MEMORY) { 1028 struct vmbus_softc *sc = device_get_softc(dev); 1029 1030 res = pcib_host_res_alloc(&sc->vmbus_mmio_res, child, type, 1031 rid, start, end, count, flags); 1032 } else 1033#endif 1034 { 1035 res = BUS_ALLOC_RESOURCE(parent, child, type, rid, start, 1036 end, count, flags); 1037 } 1038 1039 return (res); 1040} 1041 1042static device_t 1043get_nexus(device_t vmbus) 1044{ 1045 device_t acpi = device_get_parent(vmbus); 1046 device_t nexus = device_get_parent(acpi); 1047 return (nexus); 1048} 1049 1050static int 1051vmbus_alloc_msi(device_t bus, device_t dev, int count, int maxcount, int *irqs) 1052{ 1053 return (PCIB_ALLOC_MSI(get_nexus(bus), dev, count, maxcount, irqs)); 1054} 1055 1056static int 1057vmbus_release_msi(device_t bus, device_t dev, int count, int *irqs) 1058{ 1059 return (PCIB_RELEASE_MSI(get_nexus(bus), dev, count, irqs)); 1060} 1061 1062static int 1063vmbus_alloc_msix(device_t bus, device_t dev, int *irq) 1064{ 1065 return (PCIB_ALLOC_MSIX(get_nexus(bus), dev, irq)); 1066} 1067 1068static int 1069vmbus_release_msix(device_t bus, device_t dev, int irq) 1070{ 1071 return (PCIB_RELEASE_MSIX(get_nexus(bus), dev, irq)); 1072} 1073 1074static int 1075vmbus_map_msi(device_t bus, device_t dev, int irq, uint64_t *addr, 1076 uint32_t *data) 1077{ 1078 return (PCIB_MAP_MSI(get_nexus(bus), dev, irq, addr, data)); 1079} 1080 |
|
975static uint32_t 976vmbus_get_version_method(device_t bus, device_t dev) 977{ 978 struct vmbus_softc *sc = device_get_softc(bus); 979 980 return sc->vmbus_version; 981} 982 983static int 984vmbus_probe_guid_method(device_t bus, device_t dev, 985 const struct hyperv_guid *guid) 986{ 987 const struct vmbus_channel *chan = vmbus_get_channel(dev); 988 989 if (memcmp(&chan->ch_guid_type, guid, sizeof(struct hyperv_guid)) == 0) 990 return 0; 991 return ENXIO; 992} 993 | 1081static uint32_t 1082vmbus_get_version_method(device_t bus, device_t dev) 1083{ 1084 struct vmbus_softc *sc = device_get_softc(bus); 1085 1086 return sc->vmbus_version; 1087} 1088 1089static int 1090vmbus_probe_guid_method(device_t bus, device_t dev, 1091 const struct hyperv_guid *guid) 1092{ 1093 const struct vmbus_channel *chan = vmbus_get_channel(dev); 1094 1095 if (memcmp(&chan->ch_guid_type, guid, sizeof(struct hyperv_guid)) == 0) 1096 return 0; 1097 return ENXIO; 1098} 1099 |
1100static uint32_t 1101vmbus_get_vcpu_id_method(device_t bus, device_t dev, int cpu) 1102{ 1103 const struct vmbus_softc *sc = device_get_softc(bus); 1104 1105 return (VMBUS_PCPU_GET(sc, vcpuid, cpu)); 1106} 1107 1108#ifdef NEW_PCIB 1109#define VTPM_BASE_ADDR 0xfed40000 1110#define FOUR_GB (1ULL << 32) 1111 1112enum parse_pass { parse_64, parse_32 }; 1113 1114struct parse_context { 1115 device_t vmbus_dev; 1116 enum parse_pass pass; 1117}; 1118 1119static ACPI_STATUS 1120parse_crs(ACPI_RESOURCE *res, void *ctx) 1121{ 1122 const struct parse_context *pc = ctx; 1123 device_t vmbus_dev = pc->vmbus_dev; 1124 1125 struct vmbus_softc *sc = device_get_softc(vmbus_dev); 1126 UINT64 start, end; 1127 1128 switch (res->Type) { 1129 case ACPI_RESOURCE_TYPE_ADDRESS32: 1130 start = res->Data.Address32.Address.Minimum; 1131 end = res->Data.Address32.Address.Maximum; 1132 break; 1133 1134 case ACPI_RESOURCE_TYPE_ADDRESS64: 1135 start = res->Data.Address64.Address.Minimum; 1136 end = res->Data.Address64.Address.Maximum; 1137 break; 1138 1139 default: 1140 /* Unused types. */ 1141 return (AE_OK); 1142 } 1143 1144 /* 1145 * We don't use <1MB addresses. 1146 */ 1147 if (end < 0x100000) 1148 return (AE_OK); 1149 1150 /* Don't conflict with vTPM. */ 1151 if (end >= VTPM_BASE_ADDR && start < VTPM_BASE_ADDR) 1152 end = VTPM_BASE_ADDR - 1; 1153 1154 if ((pc->pass == parse_32 && start < FOUR_GB) || 1155 (pc->pass == parse_64 && start >= FOUR_GB)) 1156 pcib_host_res_decodes(&sc->vmbus_mmio_res, SYS_RES_MEMORY, 1157 start, end, 0); 1158 1159 return (AE_OK); 1160} 1161 1162static void 1163vmbus_get_crs(device_t dev, device_t vmbus_dev, enum parse_pass pass) 1164{ 1165 struct parse_context pc; 1166 ACPI_STATUS status; 1167 1168 if (bootverbose) 1169 device_printf(dev, "walking _CRS, pass=%d\n", pass); 1170 1171 pc.vmbus_dev = vmbus_dev; 1172 pc.pass = pass; 1173 status = AcpiWalkResources(acpi_get_handle(dev), "_CRS", 1174 parse_crs, &pc); 1175 1176 if (bootverbose && ACPI_FAILURE(status)) 1177 device_printf(dev, "_CRS: not found, pass=%d\n", pass); 1178} 1179 1180static void 1181vmbus_get_mmio_res_pass(device_t dev, enum parse_pass pass) 1182{ 1183 device_t acpi0, pcib0 = NULL; 1184 device_t *children; 1185 int i, count; 1186 1187 /* Try to find _CRS on VMBus device */ 1188 vmbus_get_crs(dev, dev, pass); 1189 1190 /* Try to find _CRS on VMBus device's parent */ 1191 acpi0 = device_get_parent(dev); 1192 vmbus_get_crs(acpi0, dev, pass); 1193 1194 /* Try to locate pcib0 and find _CRS on it */ 1195 if (device_get_children(acpi0, &children, &count) != 0) 1196 return; 1197 1198 for (i = 0; i < count; i++) { 1199 if (!device_is_attached(children[i])) 1200 continue; 1201 1202 if (strcmp("pcib0", device_get_nameunit(children[i]))) 1203 continue; 1204 1205 pcib0 = children[i]; 1206 break; 1207 } 1208 1209 if (pcib0) 1210 vmbus_get_crs(pcib0, dev, pass); 1211 1212 free(children, M_TEMP); 1213} 1214 1215static void 1216vmbus_get_mmio_res(device_t dev) 1217{ 1218 struct vmbus_softc *sc = device_get_softc(dev); 1219 /* 1220 * We walk the resources twice to make sure that: in the resource 1221 * list, the 32-bit resources appear behind the 64-bit resources. 1222 * NB: resource_list_add() uses INSERT_TAIL. This way, when we 1223 * iterate through the list to find a range for a 64-bit BAR in 1224 * vmbus_alloc_resource(), we can make sure we try to use >4GB 1225 * ranges first. 1226 */ 1227 pcib_host_res_init(dev, &sc->vmbus_mmio_res); 1228 1229 vmbus_get_mmio_res_pass(dev, parse_64); 1230 vmbus_get_mmio_res_pass(dev, parse_32); 1231} 1232 1233static void 1234vmbus_free_mmio_res(device_t dev) 1235{ 1236 struct vmbus_softc *sc = device_get_softc(dev); 1237 1238 pcib_host_res_free(dev, &sc->vmbus_mmio_res); 1239} 1240#endif /* NEW_PCIB */ 1241 |
|
994static int 995vmbus_probe(device_t dev) 996{ 997 char *id[] = { "VMBUS", NULL }; 998 999 if (ACPI_ID_PROBE(device_get_parent(dev), dev, id) == NULL || 1000 device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV || 1001 (hyperv_features & CPUID_HV_MSR_SYNIC) == 0) --- 20 unchanged lines hidden (view full) --- 1022vmbus_doattach(struct vmbus_softc *sc) 1023{ 1024 struct sysctl_oid_list *child; 1025 struct sysctl_ctx_list *ctx; 1026 int ret; 1027 1028 if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) 1029 return (0); | 1242static int 1243vmbus_probe(device_t dev) 1244{ 1245 char *id[] = { "VMBUS", NULL }; 1246 1247 if (ACPI_ID_PROBE(device_get_parent(dev), dev, id) == NULL || 1248 device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV || 1249 (hyperv_features & CPUID_HV_MSR_SYNIC) == 0) --- 20 unchanged lines hidden (view full) --- 1270vmbus_doattach(struct vmbus_softc *sc) 1271{ 1272 struct sysctl_oid_list *child; 1273 struct sysctl_ctx_list *ctx; 1274 int ret; 1275 1276 if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) 1277 return (0); |
1278 1279#ifdef NEW_PCIB 1280 vmbus_get_mmio_res(sc->vmbus_dev); 1281#endif 1282 |
|
1030 sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; 1031 1032 sc->vmbus_gpadl = VMBUS_GPADL_START; 1033 mtx_init(&sc->vmbus_prichan_lock, "vmbus prichan", NULL, MTX_DEF); 1034 TAILQ_INIT(&sc->vmbus_prichans); 1035 mtx_init(&sc->vmbus_chan_lock, "vmbus channel", NULL, MTX_DEF); 1036 TAILQ_INIT(&sc->vmbus_chans); 1037 sc->vmbus_chmap = malloc( --- 130 unchanged lines hidden (view full) --- 1168 vmbus_xact_ctx_destroy(sc->vmbus_xc); 1169 sc->vmbus_xc = NULL; 1170 } 1171 1172 free(sc->vmbus_chmap, M_DEVBUF); 1173 mtx_destroy(&sc->vmbus_prichan_lock); 1174 mtx_destroy(&sc->vmbus_chan_lock); 1175 | 1283 sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; 1284 1285 sc->vmbus_gpadl = VMBUS_GPADL_START; 1286 mtx_init(&sc->vmbus_prichan_lock, "vmbus prichan", NULL, MTX_DEF); 1287 TAILQ_INIT(&sc->vmbus_prichans); 1288 mtx_init(&sc->vmbus_chan_lock, "vmbus channel", NULL, MTX_DEF); 1289 TAILQ_INIT(&sc->vmbus_chans); 1290 sc->vmbus_chmap = malloc( --- 130 unchanged lines hidden (view full) --- 1421 vmbus_xact_ctx_destroy(sc->vmbus_xc); 1422 sc->vmbus_xc = NULL; 1423 } 1424 1425 free(sc->vmbus_chmap, M_DEVBUF); 1426 mtx_destroy(&sc->vmbus_prichan_lock); 1427 mtx_destroy(&sc->vmbus_chan_lock); 1428 |
1429#ifdef NEW_PCIB 1430 vmbus_free_mmio_res(dev); 1431#endif 1432 |
|
1176 return (0); 1177} 1178 1179#ifndef EARLY_AP_STARTUP 1180 1181static void 1182vmbus_sysinit(void *arg __unused) 1183{ --- 22 unchanged lines hidden --- | 1433 return (0); 1434} 1435 1436#ifndef EARLY_AP_STARTUP 1437 1438static void 1439vmbus_sysinit(void *arg __unused) 1440{ --- 22 unchanged lines hidden --- |