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