Deleted Added
full compact
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 ---