1 #!/usr/bin/env bash 2 3 set -e 4 5 rootdir=$(readlink -f $(dirname $0))/.. 6 source "$rootdir/scripts/common.sh" 7 8 function 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). 66 function 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 80 function 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 88 function 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 119 function 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 133 function linux_hugetlbfs_mounts() { 134 mount | grep ' type hugetlbfs ' | awk '{ print $3 }' 135 } 136 137 function 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 157 function 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 170 function 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 while IFS= read -r dev_id 237 do 238 for bdf in $(iter_all_pci_dev_id 8086 $dev_id); do 239 if ! pci_can_use $bdf; then 240 pci_dev_echo "$bdf" "Skipping un-whitelisted I/OAT device" 241 continue 242 fi 243 244 linux_bind_driver "$bdf" "$driver_name" 245 done 246 done < $TMP 247 rm $TMP 248 249 # virtio 250 TMP=$(mktemp) 251 #collect all the device_id info of virtio devices. 252 grep "PCI_DEVICE_ID_VIRTIO" $rootdir/include/spdk/pci_ids.h \ 253 | awk -F"x" '{print $2}' > $TMP 254 255 while IFS= read -r dev_id 256 do 257 for bdf in $(iter_all_pci_dev_id 1af4 $dev_id); do 258 if ! pci_can_use $bdf; then 259 pci_dev_echo "$bdf" "Skipping un-whitelisted Virtio device at $bdf" 260 continue 261 fi 262 blknames=() 263 get_virtio_names_from_bdf "$bdf" blknames 264 for blkname in $blknames; do 265 if [ "$(lsblk /dev/$blkname --output MOUNTPOINT -n | wc -w)" != "0" ]; then 266 pci_dev_echo "$bdf" "Active mountpoints on /dev/$blkname, so not binding" 267 continue 2 268 fi 269 done 270 271 linux_bind_driver "$bdf" "$driver_name" 272 done 273 done < $TMP 274 rm $TMP 275 276 # VMD 277 TMP=$(mktemp) 278 #collect all the device_id info of vmd devices. 279 grep "PCI_DEVICE_ID_INTEL_VMD" $rootdir/include/spdk/pci_ids.h \ 280 | awk -F"x" '{print $2}' > $TMP 281 282 while IFS= read -r dev_id 283 do 284 for bdf in $(iter_pci_dev_id 8086 $dev_id); do 285 if [[ -z "$PCI_WHITELIST" ]] || ! pci_can_use $bdf; then 286 echo "Skipping un-whitelisted VMD device at $bdf" 287 continue 288 fi 289 290 linux_bind_driver "$bdf" "$driver_name" 291 echo " VMD generic kdrv: " "$bdf" "$driver_name" 292 done 293 done < $TMP 294 rm $TMP 295 296 echo "1" > "/sys/bus/pci/rescan" 297 } 298 299 function cleanup_linux { 300 shopt -s extglob nullglob 301 dirs_to_clean="" 302 dirs_to_clean="$(echo {/var/run,/tmp}/dpdk/spdk{,_pid}+([0-9])) " 303 if [[ -d $XDG_RUNTIME_DIR && $XDG_RUNTIME_DIR != *" "* ]]; then 304 dirs_to_clean+="$(readlink -e assert_not_empty $XDG_RUNTIME_DIR/dpdk/spdk{,_pid}+([0-9]) || true) " 305 fi 306 307 files_to_clean="" 308 for dir in $dirs_to_clean; do 309 files_to_clean+="$(echo $dir/*) " 310 done 311 shopt -u extglob nullglob 312 313 files_to_clean+="$(ls -1 /dev/shm/* | \ 314 grep -E '(spdk_tgt|iscsi|vhost|nvmf|rocksdb|bdevio|bdevperf|vhost_fuzz|nvme_fuzz)_trace|spdk_iscsi_conns' || true) " 315 files_to_clean="$(readlink -e assert_not_empty $files_to_clean || true)" 316 if [[ -z "$files_to_clean" ]]; then 317 echo "Clean" 318 return 0; 319 fi 320 321 shopt -s extglob 322 for fd_dir in $(echo /proc/+([0-9])); do 323 opened_files+="$(readlink -e assert_not_empty $fd_dir/fd/* || true)" 324 done 325 shopt -u extglob 326 327 if [[ -z "$opened_files" ]]; then 328 echo "Can't get list of opened files!" 329 exit 1 330 fi 331 332 echo 'Cleaning' 333 for f in $files_to_clean; do 334 if ! echo "$opened_files" | grep -E -q "^$f\$"; then 335 echo "Removing: $f" 336 rm $f 337 else 338 echo "Still open: $f" 339 fi 340 done 341 342 for dir in $dirs_to_clean; do 343 if ! echo "$opened_files" | grep -E -q "^$dir\$"; then 344 echo "Removing: $dir" 345 rmdir $dir 346 else 347 echo "Still open: $dir" 348 fi 349 done 350 echo "Clean" 351 352 unset dirs_to_clean files_to_clean opened_files 353 } 354 355 function configure_linux { 356 configure_linux_pci 357 hugetlbfs_mounts=$(linux_hugetlbfs_mounts) 358 359 if [ -z "$hugetlbfs_mounts" ]; then 360 hugetlbfs_mounts=/mnt/huge 361 echo "Mounting hugetlbfs at $hugetlbfs_mounts" 362 mkdir -p "$hugetlbfs_mounts" 363 mount -t hugetlbfs nodev "$hugetlbfs_mounts" 364 fi 365 366 if [ -z "$HUGENODE" ]; then 367 hugepages_target="/proc/sys/vm/nr_hugepages" 368 else 369 hugepages_target="/sys/devices/system/node/node${HUGENODE}/hugepages/hugepages-${HUGEPGSZ}kB/nr_hugepages" 370 fi 371 372 echo "$NRHUGE" > "$hugepages_target" 373 allocated_hugepages=$(cat $hugepages_target) 374 if [ "$allocated_hugepages" -lt "$NRHUGE" ]; then 375 echo "" 376 echo "## ERROR: requested $NRHUGE hugepages but only $allocated_hugepages could be allocated." 377 echo "## Memory might be heavily fragmented. Please try flushing the system cache, or reboot the machine." 378 exit 1 379 fi 380 381 if [ "$driver_name" = "vfio-pci" ]; then 382 if [ -n "$TARGET_USER" ]; then 383 for mount in $hugetlbfs_mounts; do 384 chown "$TARGET_USER" "$mount" 385 chmod g+w "$mount" 386 done 387 fi 388 389 MEMLOCK_AMNT=$(ulimit -l) 390 if [ "$MEMLOCK_AMNT" != "unlimited" ] ; then 391 MEMLOCK_MB=$(( $MEMLOCK_AMNT / 1024 )) 392 echo "" 393 echo "Current user memlock limit: ${MEMLOCK_MB} MB" 394 echo "" 395 echo "This is the maximum amount of memory you will be" 396 echo "able to use with DPDK and VFIO if run as current user." 397 echo -n "To change this, please adjust limits.conf memlock " 398 echo "limit for current user." 399 400 if [ $MEMLOCK_AMNT -lt 65536 ] ; then 401 echo "" 402 echo "## WARNING: memlock limit is less than 64MB" 403 echo -n "## DPDK with VFIO may not be able to initialize " 404 echo "if run as current user." 405 fi 406 fi 407 fi 408 409 if [ ! -f /dev/cpu/0/msr ]; then 410 # Some distros build msr as a module. Make sure it's loaded to ensure 411 # DPDK can easily figure out the TSC rate rather than relying on 100ms 412 # sleeps. 413 modprobe msr || true 414 fi 415 } 416 417 function reset_linux_pci { 418 # NVMe 419 set +e 420 check_for_driver nvme 421 driver_loaded=$? 422 set -e 423 for bdf in $(iter_all_pci_class_code 01 08 02); do 424 if ! pci_can_use $bdf; then 425 pci_dev_echo "$bdf" "Skipping un-whitelisted NVMe controller $blkname" 426 continue 427 fi 428 if [ $driver_loaded -ne 0 ]; then 429 linux_bind_driver "$bdf" nvme 430 else 431 linux_unbind_driver "$bdf" 432 fi 433 done 434 435 # IOAT 436 TMP=$(mktemp) 437 #collect all the device_id info of ioat devices. 438 grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \ 439 | awk -F"x" '{print $2}' > $TMP 440 441 set +e 442 check_for_driver ioatdma 443 driver_loaded=$? 444 set -e 445 while IFS= read -r dev_id 446 do 447 for bdf in $(iter_all_pci_dev_id 8086 $dev_id); do 448 if ! pci_can_use $bdf; then 449 pci_dev_echo "$bdf" "Skipping un-whitelisted I/OAT device" 450 continue 451 fi 452 if [ $driver_loaded -ne 0 ]; then 453 linux_bind_driver "$bdf" ioatdma 454 else 455 linux_unbind_driver "$bdf" 456 fi 457 done 458 done < $TMP 459 rm $TMP 460 461 # virtio 462 TMP=$(mktemp) 463 #collect all the device_id info of virtio devices. 464 grep "PCI_DEVICE_ID_VIRTIO" $rootdir/include/spdk/pci_ids.h \ 465 | awk -F"x" '{print $2}' > $TMP 466 467 # TODO: check if virtio-pci is loaded first and just unbind if it is not loaded 468 # Requires some more investigation - for example, some kernels do not seem to have 469 # virtio-pci but just virtio_scsi instead. Also need to make sure we get the 470 # underscore vs. dash right in the virtio_scsi name. 471 modprobe virtio-pci || true 472 while IFS= read -r dev_id 473 do 474 for bdf in $(iter_all_pci_dev_id 1af4 $dev_id); do 475 if ! pci_can_use $bdf; then 476 pci_dev_echo "$bdf" "Skipping un-whitelisted Virtio device at" 477 continue 478 fi 479 linux_bind_driver "$bdf" virtio-pci 480 done 481 done < $TMP 482 rm $TMP 483 484 # VMD 485 TMP=$(mktemp) 486 #collect all the device_id info of vmd devices. 487 grep "PCI_DEVICE_ID_INTEL_VMD" $rootdir/include/spdk/pci_ids.h \ 488 | awk -F"x" '{print $2}' > $TMP 489 490 set +e 491 check_for_driver vmd 492 driver_loaded=$? 493 set -e 494 while IFS= read -r dev_id 495 do 496 for bdf in $(iter_pci_dev_id 8086 $dev_id); do 497 if ! pci_can_use $bdf; then 498 echo "Skipping un-whitelisted VMD device at $bdf" 499 continue 500 fi 501 if [ $driver_loaded -ne 0 ]; then 502 linux_bind_driver "$bdf" vmd 503 else 504 linux_unbind_driver "$bdf" 505 fi 506 done 507 done < $TMP 508 rm $TMP 509 510 echo "1" > "/sys/bus/pci/rescan" 511 } 512 513 function reset_linux { 514 reset_linux_pci 515 for mount in $(linux_hugetlbfs_mounts); do 516 rm -f "$mount"/spdk*map_* 517 done 518 rm -f /run/.spdk* 519 } 520 521 function status_linux { 522 echo "Hugepages" 523 printf "%-6s %10s %8s / %6s\n" "node" "hugesize" "free" "total" 524 525 numa_nodes=0 526 shopt -s nullglob 527 for path in /sys/devices/system/node/node?/hugepages/hugepages-*/; do 528 numa_nodes=$((numa_nodes + 1)) 529 free_pages=$(cat $path/free_hugepages) 530 all_pages=$(cat $path/nr_hugepages) 531 532 [[ $path =~ (node[0-9]+)/hugepages/hugepages-([0-9]+kB) ]] 533 534 node=${BASH_REMATCH[1]} 535 huge_size=${BASH_REMATCH[2]} 536 537 printf "%-6s %10s %8s / %6s\n" $node $huge_size $free_pages $all_pages 538 done 539 shopt -u nullglob 540 541 # fall back to system-wide hugepages 542 if [ "$numa_nodes" = "0" ]; then 543 free_pages=$(grep HugePages_Free /proc/meminfo | awk '{ print $2 }') 544 all_pages=$(grep HugePages_Total /proc/meminfo | awk '{ print $2 }') 545 node="-" 546 huge_size="$HUGEPGSZ" 547 548 printf "%-6s %10s %8s / %6s\n" $node $huge_size $free_pages $all_pages 549 fi 550 551 echo "" 552 echo "NVMe devices" 553 554 echo -e "BDF\t\tVendor\tDevice\tNUMA\tDriver\t\tDevice name" 555 for bdf in $(iter_all_pci_class_code 01 08 02); do 556 driver=$(grep DRIVER /sys/bus/pci/devices/$bdf/uevent |awk -F"=" '{print $2}') 557 if [ "$numa_nodes" = "0" ]; then 558 node="-" 559 else 560 node=$(cat /sys/bus/pci/devices/$bdf/numa_node) 561 fi 562 device=$(cat /sys/bus/pci/devices/$bdf/device) 563 vendor=$(cat /sys/bus/pci/devices/$bdf/vendor) 564 if [ "$driver" = "nvme" ] && [ -d /sys/bus/pci/devices/$bdf/nvme ]; then 565 name="\t"$(ls /sys/bus/pci/devices/$bdf/nvme); 566 else 567 name="-"; 568 fi 569 echo -e "$bdf\t${vendor#0x}\t${device#0x}\t$node\t${driver:--}\t\t$name"; 570 done 571 572 echo "" 573 echo "I/OAT DMA" 574 575 #collect all the device_id info of ioat devices. 576 TMP=$(grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \ 577 | awk -F"x" '{print $2}') 578 echo -e "BDF\t\tVendor\tDevice\tNUMA\tDriver" 579 for dev_id in $TMP; do 580 for bdf in $(iter_all_pci_dev_id 8086 $dev_id); do 581 driver=$(grep DRIVER /sys/bus/pci/devices/$bdf/uevent |awk -F"=" '{print $2}') 582 if [ "$numa_nodes" = "0" ]; then 583 node="-" 584 else 585 node=$(cat /sys/bus/pci/devices/$bdf/numa_node) 586 fi 587 device=$(cat /sys/bus/pci/devices/$bdf/device) 588 vendor=$(cat /sys/bus/pci/devices/$bdf/vendor) 589 echo -e "$bdf\t${vendor#0x}\t${device#0x}\t$node\t${driver:--}" 590 done 591 done 592 593 echo "" 594 echo "virtio" 595 596 #collect all the device_id info of virtio devices. 597 TMP=$(grep "PCI_DEVICE_ID_VIRTIO" $rootdir/include/spdk/pci_ids.h \ 598 | awk -F"x" '{print $2}') 599 echo -e "BDF\t\tVendor\tDevice\tNUMA\tDriver\t\tDevice name" 600 for dev_id in $TMP; do 601 for bdf in $(iter_all_pci_dev_id 1af4 $dev_id); do 602 driver=$(grep DRIVER /sys/bus/pci/devices/$bdf/uevent |awk -F"=" '{print $2}') 603 if [ "$numa_nodes" = "0" ]; then 604 node="-" 605 else 606 node=$(cat /sys/bus/pci/devices/$bdf/numa_node) 607 fi 608 device=$(cat /sys/bus/pci/devices/$bdf/device) 609 vendor=$(cat /sys/bus/pci/devices/$bdf/vendor) 610 blknames=() 611 get_virtio_names_from_bdf "$bdf" blknames 612 echo -e "$bdf\t${vendor#0x}\t${device#0x}\t$node\t\t${driver:--}\t\t$blknames" 613 done 614 done 615 616 echo "VMD" 617 618 #collect all the device_id info of vmd devices. 619 TMP=$(grep "PCI_DEVICE_ID_INTEL_VMD" $rootdir/include/spdk/pci_ids.h \ 620 | awk -F"x" '{print $2}') 621 echo -e "BDF\t\tNuma Node\tDriver Name" 622 for dev_id in $TMP; do 623 for bdf in $(iter_pci_dev_id 8086 $dev_id); do 624 driver=$(grep DRIVER /sys/bus/pci/devices/$bdf/uevent |awk -F"=" '{print $2}') 625 node=$(cat /sys/bus/pci/devices/$bdf/numa_node); 626 echo -e "$bdf\t$node\t\t$driver" 627 done 628 done 629 } 630 631 function configure_freebsd_pci { 632 TMP=$(mktemp) 633 634 # NVMe 635 GREP_STR="class=0x010802" 636 637 # IOAT 638 grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \ 639 | awk -F"x" '{print $2}' > $TMP 640 while IFS= read -r dev_id 641 do 642 GREP_STR="${GREP_STR}\|chip=0x${dev_id}8086" 643 done < $TMP 644 645 # VMD 646 grep "PCI_DEVICE_ID_INTEL_VMD" $rootdir/include/spdk/pci_ids.h \ 647 | awk -F"x" '{print $2}' > $TMP 648 while IFS= read -r dev_id 649 do 650 GREP_STR="${GREP_STR}\|chip=0x${dev_id}8086" 651 done < $TMP 652 653 AWK_PROG="{if (count > 0) printf \",\"; printf \"%s:%s:%s\",\$2,\$3,\$4; count++}" 654 echo $AWK_PROG > $TMP 655 656 BDFS=$(pciconf -l | grep "${GREP_STR}" | awk -F: -f $TMP) 657 658 kldunload nic_uio.ko || true 659 kenv hw.nic_uio.bdfs=$BDFS 660 kldload nic_uio.ko 661 rm $TMP 662 } 663 664 function configure_freebsd { 665 configure_freebsd_pci 666 # If contigmem is already loaded but the HUGEMEM specified doesn't match the 667 # previous value, unload contigmem so that we can reload with the new value. 668 if kldstat -q -m contigmem; then 669 if [ $(kenv hw.contigmem.num_buffers) -ne "$((HUGEMEM / 256))" ]; then 670 kldunload contigmem.ko 671 fi 672 fi 673 if ! kldstat -q -m contigmem; then 674 kenv hw.contigmem.num_buffers=$((HUGEMEM / 256)) 675 kenv hw.contigmem.buffer_size=$((256 * 1024 * 1024)) 676 kldload contigmem.ko 677 fi 678 } 679 680 function reset_freebsd { 681 kldunload contigmem.ko || true 682 kldunload nic_uio.ko || true 683 } 684 685 mode=$1 686 687 if [ -z "$mode" ]; then 688 mode="config" 689 fi 690 691 : ${HUGEMEM:=2048} 692 : ${PCI_WHITELIST:=""} 693 : ${PCI_BLACKLIST:=""} 694 695 if [ -n "$NVME_WHITELIST" ]; then 696 PCI_WHITELIST="$PCI_WHITELIST $NVME_WHITELIST" 697 fi 698 699 if [ -n "$SKIP_PCI" ]; then 700 PCI_WHITELIST="none" 701 fi 702 703 if [ -z "$TARGET_USER" ]; then 704 TARGET_USER="$SUDO_USER" 705 if [ -z "$TARGET_USER" ]; then 706 TARGET_USER=$(logname 2>/dev/null) || true 707 fi 708 fi 709 710 if [ $(uname) = Linux ]; then 711 HUGEPGSZ=$(( $(grep Hugepagesize /proc/meminfo | cut -d : -f 2 | tr -dc '0-9') )) 712 HUGEPGSZ_MB=$(( $HUGEPGSZ / 1024 )) 713 : ${NRHUGE=$(( (HUGEMEM + HUGEPGSZ_MB - 1) / HUGEPGSZ_MB ))} 714 715 if [ "$mode" == "config" ]; then 716 configure_linux 717 elif [ "$mode" == "cleanup" ]; then 718 cleanup_linux 719 elif [ "$mode" == "reset" ]; then 720 reset_linux 721 elif [ "$mode" == "status" ]; then 722 status_linux 723 elif [ "$mode" == "help" ]; then 724 usage $0 725 else 726 usage $0 "Invalid argument '$mode'" 727 fi 728 else 729 if [ "$mode" == "config" ]; then 730 configure_freebsd 731 elif [ "$mode" == "reset" ]; then 732 reset_freebsd 733 elif [ "$mode" == "cleanup" ]; then 734 echo "setup.sh cleanup function not yet supported on $(uname)" 735 elif [ "$mode" == "status" ]; then 736 echo "setup.sh status function not yet supported on $(uname)" 737 elif [ "$mode" == "help" ]; then 738 usage $0 739 else 740 usage $0 "Invalid argument '$mode'" 741 fi 742 fi 743