1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation.
3 */
4
5 #include <sys/queue.h>
6
7 #include <rte_windows.h>
8 #include <rte_errno.h>
9 #include <rte_log.h>
10 #include <rte_eal.h>
11
12 #ifdef __MINGW32__
13 #include <ddk/ndisguid.h>
14 #else
15 #include <ndisguid.h>
16 #endif
17
18 #include "private.h"
19 #include "pci_netuio.h"
20
21 static int
send_ioctl(HANDLE f,DWORD ioctl,void * in_buf,DWORD in_buf_size,void * out_buf,DWORD out_buf_size)22 send_ioctl(HANDLE f, DWORD ioctl,
23 void *in_buf, DWORD in_buf_size, void *out_buf, DWORD out_buf_size)
24 {
25 BOOL res;
26 DWORD bytes_ret = 0;
27
28 res = DeviceIoControl(f, ioctl, in_buf, in_buf_size,
29 out_buf, out_buf_size, &bytes_ret, NULL);
30 if (!res) {
31 RTE_LOG_WIN32_ERR("DeviceIoControl:IOCTL query failed");
32 return -1;
33 }
34
35 return ERROR_SUCCESS;
36 }
37
38 static HDEVINFO
get_netuio_device_information_set(HDEVINFO dev_info,PSP_DEVINFO_DATA dev_info_data)39 get_netuio_device_information_set(HDEVINFO dev_info,
40 PSP_DEVINFO_DATA dev_info_data)
41 {
42 BOOL res;
43 DWORD required_size = 0;
44 TCHAR dev_instance_id[MAX_DEVICENAME_SZ];
45 HDEVINFO di_set = INVALID_HANDLE_VALUE;
46
47 /* obtain the driver interface for this device */
48 res = SetupDiGetDeviceInstanceId(dev_info, dev_info_data,
49 dev_instance_id, sizeof(dev_instance_id), &required_size);
50 if (!res) {
51 RTE_LOG_WIN32_ERR("SetupDiGetDeviceInstanceId");
52 goto end;
53 }
54
55 /* return the device information set for this device */
56 di_set = SetupDiGetClassDevs(&GUID_DEVINTERFACE_NETUIO,
57 dev_instance_id, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
58 if (di_set == INVALID_HANDLE_VALUE) {
59 RTE_LOG_WIN32_ERR("SetupDiGetClassDevs(device information set)");
60 goto end;
61 }
62 end:
63 return di_set;
64 }
65
66 static PSP_DEVICE_INTERFACE_DETAIL_DATA
get_netuio_device_interface_detail(HDEVINFO di_set)67 get_netuio_device_interface_detail(HDEVINFO di_set)
68 {
69 BOOL res;
70 DWORD required_size = 0;
71 SP_DEVICE_INTERFACE_DATA dev_ifx_data = { 0 };
72 PSP_DEVICE_INTERFACE_DETAIL_DATA dev_ifx_detail = NULL;
73
74 dev_ifx_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
75
76 /* enumerate the netUIO interfaces for this device information set */
77 res = SetupDiEnumDeviceInterfaces(di_set, 0, &GUID_DEVINTERFACE_NETUIO,
78 0, &dev_ifx_data);
79 if (!res) {
80 RTE_LOG_WIN32_ERR("SetupDiEnumDeviceInterfaces: no device interface");
81 goto end;
82 }
83
84 /* request and allocate required size for the device interface detail */
85 required_size = 0;
86 res = SetupDiGetDeviceInterfaceDetail(di_set, &dev_ifx_data, NULL, 0,
87 &required_size, NULL);
88 if (!res) {
89 /* ERROR_INSUFFICIENT_BUFFER is expected */
90 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
91 RTE_LOG_WIN32_ERR("SetupDiGetDeviceInterfaceDetail");
92 goto end;
93 }
94 }
95
96 dev_ifx_detail = malloc(required_size);
97 if (!dev_ifx_detail) {
98 RTE_LOG(ERR, EAL, "Could not allocate memory for dev interface.\n");
99 goto end;
100 }
101 dev_ifx_detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
102
103 res = SetupDiGetDeviceInterfaceDetail(di_set, &dev_ifx_data,
104 dev_ifx_detail, required_size, NULL, NULL);
105 if (!res) {
106 RTE_LOG_WIN32_ERR("SetupDiGetDeviceInterfaceDetail");
107 free(dev_ifx_detail);
108 dev_ifx_detail = NULL;
109 goto end;
110 }
111
112 end:
113 return dev_ifx_detail;
114 }
115
116 /*
117 * get device resource information by sending ioctl to netuio driver
118 */
119 int
get_netuio_device_info(HDEVINFO dev_info,PSP_DEVINFO_DATA dev_info_data,struct rte_pci_device * dev)120 get_netuio_device_info(HDEVINFO dev_info, PSP_DEVINFO_DATA dev_info_data,
121 struct rte_pci_device *dev)
122 {
123 int ret = -1;
124 HDEVINFO di_set = INVALID_HANDLE_VALUE;
125 PSP_DEVICE_INTERFACE_DETAIL_DATA dev_ifx_detail = NULL;
126 HANDLE netuio = INVALID_HANDLE_VALUE;
127 struct device_info hw_info = { 0 };
128 unsigned int idx;
129
130 /* obtain the device information set for this device */
131 di_set = get_netuio_device_information_set(dev_info, dev_info_data);
132 if (di_set == INVALID_HANDLE_VALUE)
133 goto end;
134
135 /* obtain the device interface detail for this device */
136 dev_ifx_detail = get_netuio_device_interface_detail(di_set);
137 if (!dev_ifx_detail)
138 goto end;
139
140 /* open the kernel driver */
141 netuio = CreateFile(dev_ifx_detail->DevicePath,
142 GENERIC_READ | GENERIC_WRITE,
143 FILE_SHARE_READ | FILE_SHARE_WRITE,
144 NULL,
145 OPEN_EXISTING,
146 FILE_ATTRIBUTE_NORMAL,
147 NULL);
148 if (netuio == INVALID_HANDLE_VALUE) {
149 RTE_LOG_WIN32_ERR("CreateFile");
150 RTE_LOG(ERR, EAL, "Unable to open driver file \"%s\".\n",
151 dev_ifx_detail->DevicePath);
152 goto end;
153 }
154
155 /* send ioctl to retrieve device information */
156 if (send_ioctl(netuio, IOCTL_NETUIO_MAP_HW_INTO_USERSPACE, NULL, 0,
157 &hw_info, sizeof(hw_info)) != ERROR_SUCCESS) {
158 RTE_LOG(ERR, EAL, "Unable to send ioctl to driver.\n");
159 goto end;
160 }
161
162 /* set relevant values into the dev structure */
163 for (idx = 0; idx < PCI_MAX_RESOURCE; idx++) {
164 dev->mem_resource[idx].phys_addr =
165 hw_info.hw[idx].phys_addr.QuadPart;
166 dev->mem_resource[idx].addr =
167 hw_info.hw[idx].user_mapped_virt_addr;
168 dev->mem_resource[idx].len = hw_info.hw[idx].size;
169 }
170
171 ret = ERROR_SUCCESS;
172 end:
173 if (ret != ERROR_SUCCESS) {
174 /* Only close the handle to the driver in case of an error.
175 * Otherwise, we want to keep the handle open. Closing it
176 * here will cause the driver to unmap all the process-mapped
177 * values resulting in invalid addresses.
178 */
179 if (netuio != INVALID_HANDLE_VALUE)
180 CloseHandle(netuio);
181 }
182
183 free(dev_ifx_detail);
184
185 if (di_set != INVALID_HANDLE_VALUE)
186 SetupDiDestroyDeviceInfoList(di_set);
187
188 return ret;
189 }
190