xref: /spdk/scripts/setup.sh (revision 407e88fd2ab020d753e33014cf759353a9901b51)
1#!/usr/bin/env bash
2
3set -e
4
5rootdir=$(readlink -f $(dirname $0))/..
6source "$rootdir/scripts/common.sh"
7
8function usage()
9{
10	if [ $(uname) = Linux ]; then
11		options="[config|reset|status|cleanup|help]"
12	else
13		options="[config|reset|help]"
14	fi
15
16	[[ -n $2 ]] && ( echo "$2"; echo ""; )
17	echo "Helper script for allocating hugepages and binding NVMe, I/OAT, VMD and Virtio devices"
18	echo "to a generic VFIO kernel driver. If VFIO is not available on the system, this script"
19	echo "will fall back to UIO. NVMe and Virtio devices with active mountpoints will be ignored."
20	echo "All hugepage operations use default hugepage size on the system (hugepagesz)."
21	echo "Usage: $(basename $1) $options"
22	echo
23	echo "$options - as following:"
24	echo "config            Default mode. Allocate hugepages and bind PCI devices."
25	if [ $(uname) = Linux ]; then
26		echo "cleanup            Remove any orphaned files that can be left in the system after SPDK application exit"
27	fi
28	echo "reset             Rebind PCI devices back to their original drivers."
29	echo "                  Also cleanup any leftover spdk files/resources."
30	echo "                  Hugepage memory size will remain unchanged."
31	if [ $(uname) = Linux ]; then
32		echo "status            Print status of all SPDK-compatible devices on the system."
33	fi
34	echo "help              Print this help message."
35	echo
36	echo "The following environment variables can be specified."
37	echo "HUGEMEM           Size of hugepage memory to allocate (in MB). 2048 by default."
38	echo "                  For NUMA systems, the hugepages will be evenly distributed"
39	echo "                  between CPU nodes"
40	echo "NRHUGE            Number of hugepages to allocate. This variable overwrites HUGEMEM."
41	echo "HUGENODE          Specific NUMA node to allocate hugepages on. To allocate"
42	echo "                  hugepages on multiple nodes run this script multiple times -"
43	echo "                  once for each node."
44	echo "PCI_WHITELIST"
45	echo "PCI_BLACKLIST     Whitespace separated list of PCI devices (NVMe, I/OAT, VMD, Virtio)."
46	echo "                  Each device must be specified as a full PCI address."
47	echo "                  E.g. PCI_WHITELIST=\"0000:01:00.0 0000:02:00.0\""
48	echo "                  To blacklist all PCI devices use a non-valid address."
49	echo "                  E.g. PCI_WHITELIST=\"none\""
50	echo "                  If PCI_WHITELIST and PCI_BLACKLIST are empty or unset, all PCI devices"
51	echo "                  will be bound."
52	echo "                  Each device in PCI_BLACKLIST will be ignored (driver won't be changed)."
53	echo "                  PCI_BLACKLIST has precedence over PCI_WHITELIST."
54	echo "TARGET_USER       User that will own hugepage mountpoint directory and vfio groups."
55	echo "                  By default the current user will be used."
56	echo "DRIVER_OVERRIDE   Disable automatic vfio-pci/uio_pci_generic selection and forcefully"
57	echo "                  bind devices to the given driver."
58	echo "                  E.g. DRIVER_OVERRIDE=uio_pci_generic or DRIVER_OVERRIDE=/home/public/dpdk/build/kmod/igb_uio.ko"
59	exit 0
60}
61
62# In monolithic kernels the lsmod won't work. So
63# back that with a /sys/modules. We also check
64# /sys/bus/pci/drivers/ as neither lsmod nor /sys/modules might
65# contain needed info (like in Fedora-like OS).
66function check_for_driver {
67	if lsmod | grep -q ${1//-/_}; then
68		return 1
69	fi
70
71	if [[ -d /sys/module/${1} || \
72			-d /sys/module/${1//-/_} || \
73			-d /sys/bus/pci/drivers/${1} || \
74			-d /sys/bus/pci/drivers/${1//-/_} ]]; then
75		return 2
76	fi
77	return 0
78}
79
80function pci_dev_echo() {
81	local bdf="$1"
82	local vendor="$(cat /sys/bus/pci/devices/$bdf/vendor)"
83	local device="$(cat /sys/bus/pci/devices/$bdf/device)"
84	shift
85	echo "$bdf (${vendor#0x} ${device#0x}): $@"
86}
87
88function linux_bind_driver() {
89	bdf="$1"
90	driver_name="$2"
91	old_driver_name="no driver"
92	ven_dev_id=$(lspci -n -s $bdf | cut -d' ' -f3 | sed 's/:/ /')
93
94	if [ -e "/sys/bus/pci/devices/$bdf/driver" ]; then
95		old_driver_name=$(basename $(readlink /sys/bus/pci/devices/$bdf/driver))
96
97		if [ "$driver_name" = "$old_driver_name" ]; then
98			pci_dev_echo "$bdf" "Already using the $old_driver_name driver"
99			return 0
100		fi
101
102		echo "$ven_dev_id" > "/sys/bus/pci/devices/$bdf/driver/remove_id" 2> /dev/null || true
103		echo "$bdf" > "/sys/bus/pci/devices/$bdf/driver/unbind"
104	fi
105
106	pci_dev_echo "$bdf" "$old_driver_name -> $driver_name"
107
108	echo "$ven_dev_id" > "/sys/bus/pci/drivers/$driver_name/new_id" 2> /dev/null || true
109	echo "$bdf" > "/sys/bus/pci/drivers/$driver_name/bind" 2> /dev/null || true
110
111	iommu_group=$(basename $(readlink -f /sys/bus/pci/devices/$bdf/iommu_group))
112	if [ -e "/dev/vfio/$iommu_group" ]; then
113		if [ -n "$TARGET_USER" ]; then
114			chown "$TARGET_USER" "/dev/vfio/$iommu_group"
115		fi
116	fi
117}
118
119function linux_unbind_driver() {
120	local bdf="$1"
121	local ven_dev_id=$(lspci -n -s $bdf | cut -d' ' -f3 | sed 's/:/ /')
122	local old_driver_name="no driver"
123
124	if [ -e "/sys/bus/pci/devices/$bdf/driver" ]; then
125		old_driver_name=$(basename $(readlink /sys/bus/pci/devices/$bdf/driver))
126		echo "$ven_dev_id" > "/sys/bus/pci/devices/$bdf/driver/remove_id" 2> /dev/null || true
127		echo "$bdf" > "/sys/bus/pci/devices/$bdf/driver/unbind"
128	fi
129
130	pci_dev_echo "$bdf" "$old_driver_name -> no driver"
131}
132
133function linux_hugetlbfs_mounts() {
134	mount | grep ' type hugetlbfs ' | awk '{ print $3 }'
135}
136
137function get_nvme_name_from_bdf {
138	local blknames=()
139
140	set +e
141	nvme_devs=$(lsblk -d --output NAME | grep "^nvme")
142	set -e
143	for dev in $nvme_devs; do
144		link_name=$(readlink /sys/block/$dev/device/device) || true
145		if [ -z "$link_name" ]; then
146			link_name=$(readlink /sys/block/$dev/device)
147		fi
148		link_bdf=$(basename "$link_name")
149		if [ "$link_bdf" = "$1" ]; then
150			blknames+=($dev)
151		fi
152	done
153
154	printf '%s\n' "${blknames[@]}"
155}
156
157function get_virtio_names_from_bdf {
158	blk_devs=$(lsblk --nodeps --output NAME)
159	virtio_names=''
160
161	for dev in $blk_devs; do
162		if readlink "/sys/block/$dev" | grep -q "$1"; then
163			virtio_names="$virtio_names $dev"
164		fi
165	done
166
167	eval "$2='$virtio_names'"
168}
169
170function configure_linux_pci {
171	local driver_path=""
172	driver_name=""
173	if [[ -n "${DRIVER_OVERRIDE}" ]]; then
174		driver_path="${DRIVER_OVERRIDE%/*}"
175		driver_name="${DRIVER_OVERRIDE##*/}"
176		# path = name -> there is no path
177		if [[ "$driver_path" = "$driver_name" ]]; then
178			driver_path=""
179		fi
180	elif [[ -n "$(ls /sys/kernel/iommu_groups)" || \
181	     (-e /sys/module/vfio/parameters/enable_unsafe_noiommu_mode && \
182	     "$(cat /sys/module/vfio/parameters/enable_unsafe_noiommu_mode)" == "Y") ]]; then
183		driver_name=vfio-pci
184	elif modinfo uio_pci_generic >/dev/null 2>&1; then
185		driver_name=uio_pci_generic
186	elif [[ -r "$rootdir/dpdk/build/kmod/igb_uio.ko" ]]; then
187		driver_path="$rootdir/dpdk/build/kmod/igb_uio.ko"
188		driver_name="igb_uio"
189		modprobe uio
190		echo "WARNING: uio_pci_generic not detected - using $driver_name"
191	else
192		echo "No valid drivers found [vfio-pci, uio_pci_generic, igb_uio]. Please either enable the vfio-pci or uio_pci_generic"
193		echo "kernel modules, or have SPDK build the igb_uio driver by running ./configure --with-igb-uio-driver and recompiling."
194		return 1
195	fi
196
197	# modprobe assumes the directory of the module. If the user passes in a path, we should use insmod
198	if [[ -n "$driver_path" ]]; then
199		insmod $driver_path || true
200	else
201		modprobe $driver_name
202	fi
203
204	# NVMe
205	for bdf in $(iter_all_pci_class_code 01 08 02); do
206		blknames=()
207		if ! pci_can_use $bdf; then
208			pci_dev_echo "$bdf" "Skipping un-whitelisted NVMe controller at $bdf"
209			continue
210		fi
211
212		mount=false
213		for blkname in $(get_nvme_name_from_bdf $bdf); do
214			mountpoints=$(lsblk /dev/$blkname --output MOUNTPOINT -n | wc -w)
215			if [ "$mountpoints" != "0" ]; then
216				mount=true
217				blknames+=($blkname)
218			fi
219		done
220
221		if ! $mount; then
222			linux_bind_driver "$bdf" "$driver_name"
223		else
224			for name in ${blknames[@]}; do
225				pci_dev_echo "$bdf" "Active mountpoints on /dev/$name, so not binding PCI dev"
226			done
227		fi
228	done
229
230	# IOAT
231	TMP=$(mktemp)
232	#collect all the device_id info of ioat devices.
233	grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \
234	| awk -F"x" '{print $2}' > $TMP
235
236	for dev_id in $(cat $TMP); do
237		for bdf in $(iter_all_pci_dev_id 8086 $dev_id); do
238			if ! pci_can_use $bdf; then
239				pci_dev_echo "$bdf" "Skipping un-whitelisted I/OAT device"
240				continue
241			fi
242
243			linux_bind_driver "$bdf" "$driver_name"
244		done
245	done
246	rm $TMP
247
248	# virtio
249	TMP=$(mktemp)
250	#collect all the device_id info of virtio devices.
251	grep "PCI_DEVICE_ID_VIRTIO" $rootdir/include/spdk/pci_ids.h \
252	| awk -F"x" '{print $2}' > $TMP
253
254	for dev_id in $(cat $TMP); do
255		for bdf in $(iter_all_pci_dev_id 1af4 $dev_id); do
256			if ! pci_can_use $bdf; then
257				pci_dev_echo "$bdf" "Skipping un-whitelisted Virtio device at $bdf"
258				continue
259			fi
260			blknames=''
261			get_virtio_names_from_bdf "$bdf" blknames
262			for blkname in $blknames; do
263				if [ "$(lsblk /dev/$blkname --output MOUNTPOINT -n | wc -w)" != "0" ]; then
264					pci_dev_echo "$bdf" "Active mountpoints on /dev/$blkname, so not binding"
265					continue 2
266				fi
267			done
268
269			linux_bind_driver "$bdf" "$driver_name"
270		done
271	done
272	rm $TMP
273
274	# VMD
275	TMP=$(mktemp)
276	#collect all the device_id info of vmd devices.
277	grep "PCI_DEVICE_ID_INTEL_VMD" $rootdir/include/spdk/pci_ids.h \
278	| awk -F"x" '{print $2}' > $TMP
279
280	for dev_id in $(cat $TMP); do
281		for bdf in $(iter_pci_dev_id 8086 $dev_id); do
282			if [[ -z "$PCI_WHITELIST" ]] || ! pci_can_use $bdf; then
283				echo "Skipping un-whitelisted VMD device at $bdf"
284				continue
285			fi
286
287			linux_bind_driver "$bdf" "$driver_name"
288                        echo " VMD generic kdrv: " "$bdf" "$driver_name"
289		done
290	done
291	rm $TMP
292
293	echo "1" > "/sys/bus/pci/rescan"
294}
295
296function cleanup_linux {
297	shopt -s extglob nullglob
298	dirs_to_clean=""
299	dirs_to_clean="$(echo {/var/run,/tmp}/dpdk/spdk{,_pid}+([0-9])) "
300	if [[ -d $XDG_RUNTIME_DIR && $XDG_RUNTIME_DIR != *" "* ]]; then
301		dirs_to_clean+="$(readlink -e assert_not_empty $XDG_RUNTIME_DIR/dpdk/spdk{,_pid}+([0-9]) || true) "
302	fi
303
304	files_to_clean=""
305	for dir in $dirs_to_clean; do
306		files_to_clean+="$(echo $dir/*) "
307	done
308	shopt -u extglob nullglob
309
310	files_to_clean+="$(ls -1 /dev/shm/* | \
311	grep -E '(spdk_tgt|iscsi|vhost|nvmf|rocksdb|bdevio|bdevperf|vhost_fuzz|nvme_fuzz)_trace|spdk_iscsi_conns' || true) "
312	files_to_clean="$(readlink -e assert_not_empty $files_to_clean || true)"
313	if [[ -z "$files_to_clean" ]]; then
314		echo "Clean"
315		return 0;
316	fi
317
318	shopt -s extglob
319	for fd_dir in $(echo /proc/+([0-9])); do
320		opened_files+="$(readlink -e assert_not_empty $fd_dir/fd/* || true)"
321	done
322	shopt -u extglob
323
324	if [[ -z "$opened_files" ]]; then
325		echo "Can't get list of opened files!"
326		exit 1
327	fi
328
329	echo 'Cleaning'
330	for f in $files_to_clean; do
331		if ! echo "$opened_files" | grep -E -q "^$f\$"; then
332			echo "Removing:    $f"
333			rm $f
334		else
335			echo "Still open: $f"
336		fi
337	done
338
339	for dir in $dirs_to_clean; do
340	if ! echo "$opened_files" | grep -E -q "^$dir\$"; then
341		echo "Removing:    $dir"
342		rmdir $dir
343	else
344		echo "Still open: $dir"
345	fi
346	done
347	echo "Clean"
348
349	unset dirs_to_clean files_to_clean opened_files
350}
351
352function configure_linux {
353	configure_linux_pci
354	hugetlbfs_mounts=$(linux_hugetlbfs_mounts)
355
356	if [ -z "$hugetlbfs_mounts" ]; then
357		hugetlbfs_mounts=/mnt/huge
358		echo "Mounting hugetlbfs at $hugetlbfs_mounts"
359		mkdir -p "$hugetlbfs_mounts"
360		mount -t hugetlbfs nodev "$hugetlbfs_mounts"
361	fi
362
363	if [ -z "$HUGENODE" ]; then
364		hugepages_target="/proc/sys/vm/nr_hugepages"
365	else
366		hugepages_target="/sys/devices/system/node/node${HUGENODE}/hugepages/hugepages-${HUGEPGSZ}kB/nr_hugepages"
367	fi
368
369	echo "$NRHUGE" > "$hugepages_target"
370	allocated_hugepages=$(cat $hugepages_target)
371	if [ "$allocated_hugepages" -lt "$NRHUGE" ]; then
372		echo ""
373		echo "## ERROR: requested $NRHUGE hugepages but only $allocated_hugepages could be allocated."
374		echo "## Memory might be heavily fragmented. Please try flushing the system cache, or reboot the machine."
375		exit 1
376	fi
377
378	if [ "$driver_name" = "vfio-pci" ]; then
379		if [ -n "$TARGET_USER" ]; then
380			for mount in $hugetlbfs_mounts; do
381				chown "$TARGET_USER" "$mount"
382				chmod g+w "$mount"
383			done
384		fi
385
386		MEMLOCK_AMNT=$(ulimit -l)
387		if [ "$MEMLOCK_AMNT" != "unlimited" ] ; then
388			MEMLOCK_MB=$(( $MEMLOCK_AMNT / 1024 ))
389			echo ""
390			echo "Current user memlock limit: ${MEMLOCK_MB} MB"
391			echo ""
392			echo "This is the maximum amount of memory you will be"
393			echo "able to use with DPDK and VFIO if run as current user."
394			echo -n "To change this, please adjust limits.conf memlock "
395			echo "limit for current user."
396
397			if [ $MEMLOCK_AMNT -lt 65536 ] ; then
398				echo ""
399				echo "## WARNING: memlock limit is less than 64MB"
400				echo -n "## DPDK with VFIO may not be able to initialize "
401				echo "if run as current user."
402			fi
403		fi
404	fi
405
406	if [ ! -f /dev/cpu/0/msr ]; then
407		# Some distros build msr as a module.  Make sure it's loaded to ensure
408		#  DPDK can easily figure out the TSC rate rather than relying on 100ms
409		#  sleeps.
410		modprobe msr || true
411	fi
412}
413
414function reset_linux_pci {
415	# NVMe
416	set +e
417	check_for_driver nvme
418	driver_loaded=$?
419	set -e
420	for bdf in $(iter_all_pci_class_code 01 08 02); do
421		if ! pci_can_use $bdf; then
422			pci_dev_echo "$bdf" "Skipping un-whitelisted NVMe controller $blkname"
423			continue
424		fi
425		if [ $driver_loaded -ne 0 ]; then
426			linux_bind_driver "$bdf" nvme
427		else
428			linux_unbind_driver "$bdf"
429		fi
430	done
431
432	# IOAT
433	TMP=$(mktemp)
434	#collect all the device_id info of ioat devices.
435	grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \
436	| awk -F"x" '{print $2}' > $TMP
437
438	set +e
439	check_for_driver ioatdma
440	driver_loaded=$?
441	set -e
442	for dev_id in $(cat $TMP); do
443		for bdf in $(iter_all_pci_dev_id 8086 $dev_id); do
444			if ! pci_can_use $bdf; then
445				pci_dev_echo "$bdf" "Skipping un-whitelisted I/OAT device"
446				continue
447			fi
448			if [ $driver_loaded -ne 0 ]; then
449				linux_bind_driver "$bdf" ioatdma
450			else
451				linux_unbind_driver "$bdf"
452			fi
453		done
454	done
455	rm $TMP
456
457	# virtio
458	TMP=$(mktemp)
459	#collect all the device_id info of virtio devices.
460	grep "PCI_DEVICE_ID_VIRTIO" $rootdir/include/spdk/pci_ids.h \
461	| awk -F"x" '{print $2}' > $TMP
462
463	# TODO: check if virtio-pci is loaded first and just unbind if it is not loaded
464	# Requires some more investigation - for example, some kernels do not seem to have
465	#  virtio-pci but just virtio_scsi instead.  Also need to make sure we get the
466	#  underscore vs. dash right in the virtio_scsi name.
467	modprobe virtio-pci || true
468	for dev_id in $(cat $TMP); do
469		for bdf in $(iter_all_pci_dev_id 1af4 $dev_id); do
470			if ! pci_can_use $bdf; then
471				pci_dev_echo "$bdf" "Skipping un-whitelisted Virtio device at"
472				continue
473			fi
474			linux_bind_driver "$bdf" virtio-pci
475		done
476	done
477	rm $TMP
478
479	# VMD
480	TMP=$(mktemp)
481	#collect all the device_id info of vmd devices.
482	grep "PCI_DEVICE_ID_INTEL_VMD" $rootdir/include/spdk/pci_ids.h \
483	| awk -F"x" '{print $2}' > $TMP
484
485	set +e
486	check_for_driver vmd
487	driver_loaded=$?
488	set -e
489	for dev_id in $(cat $TMP); do
490		for bdf in $(iter_pci_dev_id 8086 $dev_id); do
491			if ! pci_can_use $bdf; then
492				echo "Skipping un-whitelisted VMD device at $bdf"
493				continue
494			fi
495			if [ $driver_loaded -ne 0 ]; then
496				linux_bind_driver "$bdf" vmd
497			else
498				linux_unbind_driver "$bdf"
499			fi
500		done
501	done
502	rm $TMP
503
504	echo "1" > "/sys/bus/pci/rescan"
505}
506
507function reset_linux {
508	reset_linux_pci
509	for mount in $(linux_hugetlbfs_mounts); do
510		rm -f "$mount"/spdk*map_*
511	done
512	rm -f /run/.spdk*
513}
514
515function status_linux {
516	echo "Hugepages"
517	printf "%-6s %10s %8s / %6s\n" "node" "hugesize"  "free" "total"
518
519	numa_nodes=0
520	shopt -s nullglob
521	for path in /sys/devices/system/node/node?/hugepages/hugepages-*/; do
522		numa_nodes=$((numa_nodes + 1))
523		free_pages=$(cat $path/free_hugepages)
524		all_pages=$(cat $path/nr_hugepages)
525
526		[[ $path =~ (node[0-9]+)/hugepages/hugepages-([0-9]+kB) ]]
527
528		node=${BASH_REMATCH[1]}
529		huge_size=${BASH_REMATCH[2]}
530
531		printf "%-6s %10s %8s / %6s\n" $node $huge_size $free_pages $all_pages
532	done
533	shopt -u nullglob
534
535	# fall back to system-wide hugepages
536	if [ "$numa_nodes" = "0" ]; then
537		free_pages=$(grep HugePages_Free /proc/meminfo | awk '{ print $2 }')
538		all_pages=$(grep HugePages_Total /proc/meminfo | awk '{ print $2 }')
539		node="-"
540		huge_size="$HUGEPGSZ"
541
542		printf "%-6s %10s %8s / %6s\n" $node $huge_size $free_pages $all_pages
543	fi
544
545	echo ""
546	echo "NVMe devices"
547
548	echo -e "BDF\t\tVendor\tDevice\tNUMA\tDriver\t\tDevice name"
549	for bdf in $(iter_all_pci_class_code 01 08 02); do
550		driver=$(grep DRIVER /sys/bus/pci/devices/$bdf/uevent |awk -F"=" '{print $2}')
551		if [ "$numa_nodes" = "0" ]; then
552			node="-"
553		else
554			node=$(cat /sys/bus/pci/devices/$bdf/numa_node)
555		fi
556		device=$(cat /sys/bus/pci/devices/$bdf/device)
557		vendor=$(cat /sys/bus/pci/devices/$bdf/vendor)
558		if [ "$driver" = "nvme" -a -d /sys/bus/pci/devices/$bdf/nvme ]; then
559			name="\t"$(ls /sys/bus/pci/devices/$bdf/nvme);
560		else
561			name="-";
562		fi
563		echo -e "$bdf\t${vendor#0x}\t${device#0x}\t$node\t${driver:--}\t\t$name";
564	done
565
566	echo ""
567	echo "I/OAT DMA"
568
569	#collect all the device_id info of ioat devices.
570	TMP=$(grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \
571	| awk -F"x" '{print $2}')
572	echo -e "BDF\t\tVendor\tDevice\tNUMA\tDriver"
573	for dev_id in $TMP; do
574		for bdf in $(iter_all_pci_dev_id 8086 $dev_id); do
575			driver=$(grep DRIVER /sys/bus/pci/devices/$bdf/uevent |awk -F"=" '{print $2}')
576			if [ "$numa_nodes" = "0" ]; then
577				node="-"
578			else
579				node=$(cat /sys/bus/pci/devices/$bdf/numa_node)
580			fi
581			device=$(cat /sys/bus/pci/devices/$bdf/device)
582			vendor=$(cat /sys/bus/pci/devices/$bdf/vendor)
583			echo -e "$bdf\t${vendor#0x}\t${device#0x}\t$node\t${driver:--}"
584		done
585	done
586
587	echo ""
588	echo "virtio"
589
590	#collect all the device_id info of virtio devices.
591	TMP=$(grep "PCI_DEVICE_ID_VIRTIO" $rootdir/include/spdk/pci_ids.h \
592	| awk -F"x" '{print $2}')
593	echo -e "BDF\t\tVendor\tDevice\tNUMA\tDriver\t\tDevice name"
594	for dev_id in $TMP; do
595		for bdf in $(iter_all_pci_dev_id 1af4 $dev_id); do
596			driver=$(grep DRIVER /sys/bus/pci/devices/$bdf/uevent |awk -F"=" '{print $2}')
597			if [ "$numa_nodes" = "0" ]; then
598				node="-"
599			else
600				node=$(cat /sys/bus/pci/devices/$bdf/numa_node)
601			fi
602			device=$(cat /sys/bus/pci/devices/$bdf/device)
603			vendor=$(cat /sys/bus/pci/devices/$bdf/vendor)
604			blknames=''
605			get_virtio_names_from_bdf "$bdf" blknames
606			echo -e "$bdf\t${vendor#0x}\t${device#0x}\t$node\t\t${driver:--}\t\t$blknames"
607		done
608	done
609
610	echo "VMD"
611
612	#collect all the device_id info of vmd devices.
613	TMP=$(grep "PCI_DEVICE_ID_INTEL_VMD" $rootdir/include/spdk/pci_ids.h \
614	| awk -F"x" '{print $2}')
615	echo -e "BDF\t\tNuma Node\tDriver Name"
616	for dev_id in $TMP; do
617		for bdf in $(iter_pci_dev_id 8086 $dev_id); do
618			driver=$(grep DRIVER /sys/bus/pci/devices/$bdf/uevent |awk -F"=" '{print $2}')
619			node=$(cat /sys/bus/pci/devices/$bdf/numa_node);
620			echo -e "$bdf\t$node\t\t$driver"
621		done
622	done
623}
624
625function configure_freebsd_pci {
626	TMP=$(mktemp)
627
628	# NVMe
629	GREP_STR="class=0x010802"
630
631	# IOAT
632	grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \
633	| awk -F"x" '{print $2}' > $TMP
634	for dev_id in $(cat $TMP); do
635		GREP_STR="${GREP_STR}\|chip=0x${dev_id}8086"
636	done
637
638	# VMD
639	grep "PCI_DEVICE_ID_INTEL_VMD" $rootdir/include/spdk/pci_ids.h \
640	| awk -F"x" '{print $2}' > $TMP
641	for dev_id in $(cat $TMP); do
642		GREP_STR="${GREP_STR}\|chip=0x${dev_id}8086"
643	done
644
645	AWK_PROG="{if (count > 0) printf \",\"; printf \"%s:%s:%s\",\$2,\$3,\$4; count++}"
646	echo $AWK_PROG > $TMP
647
648	BDFS=$(pciconf -l | grep "${GREP_STR}" | awk -F: -f $TMP)
649
650	kldunload nic_uio.ko || true
651	kenv hw.nic_uio.bdfs=$BDFS
652	kldload nic_uio.ko
653	rm $TMP
654}
655
656function configure_freebsd {
657	configure_freebsd_pci
658	# If contigmem is already loaded but the HUGEMEM specified doesn't match the
659	#  previous value, unload contigmem so that we can reload with the new value.
660	if kldstat -q -m contigmem; then
661		if [ $(kenv hw.contigmem.num_buffers) -ne "$((HUGEMEM / 256))" ]; then
662			kldunload contigmem.ko
663		fi
664	fi
665	if ! kldstat -q -m contigmem; then
666		kenv hw.contigmem.num_buffers=$((HUGEMEM / 256))
667		kenv hw.contigmem.buffer_size=$((256 * 1024 * 1024))
668		kldload contigmem.ko
669	fi
670}
671
672function reset_freebsd {
673	kldunload contigmem.ko || true
674	kldunload nic_uio.ko || true
675}
676
677mode=$1
678
679if [ -z "$mode" ]; then
680	mode="config"
681fi
682
683: ${HUGEMEM:=2048}
684: ${PCI_WHITELIST:=""}
685: ${PCI_BLACKLIST:=""}
686
687if [ -n "$NVME_WHITELIST" ]; then
688	PCI_WHITELIST="$PCI_WHITELIST $NVME_WHITELIST"
689fi
690
691if [ -n "$SKIP_PCI" ]; then
692	PCI_WHITELIST="none"
693fi
694
695if [ -z "$TARGET_USER" ]; then
696	TARGET_USER="$SUDO_USER"
697	if [ -z "$TARGET_USER" ]; then
698		TARGET_USER=$(logname 2>/dev/null) || true
699	fi
700fi
701
702if [ $(uname) = Linux ]; then
703	HUGEPGSZ=$(( $(grep Hugepagesize /proc/meminfo | cut -d : -f 2 | tr -dc '0-9') ))
704	HUGEPGSZ_MB=$(( $HUGEPGSZ / 1024 ))
705	: ${NRHUGE=$(( (HUGEMEM + HUGEPGSZ_MB - 1) / HUGEPGSZ_MB ))}
706
707	if [ "$mode" == "config" ]; then
708		configure_linux
709	elif [ "$mode" == "cleanup" ]; then
710		cleanup_linux
711	elif [ "$mode" == "reset" ]; then
712		reset_linux
713	elif [ "$mode" == "status" ]; then
714		status_linux
715	elif [ "$mode" == "help" ]; then
716		usage $0
717	else
718		usage $0 "Invalid argument '$mode'"
719	fi
720else
721	if [ "$mode" == "config" ]; then
722		configure_freebsd
723	elif [ "$mode" == "reset" ]; then
724		reset_freebsd
725	elif [ "$mode" == "cleanup" ]; then
726		echo "setup.sh cleanup function not yet supported on $(uname)"
727	elif [ "$mode" == "status" ]; then
728		echo "setup.sh status function not yet supported on $(uname)"
729	elif [ "$mode" == "help" ]; then
730		usage $0
731	else
732		usage $0 "Invalid argument '$mode'"
733	fi
734fi
735