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