1#!/usr/bin/env bash 2 3set -e 4 5rootdir=$(readlink -f $(dirname $0))/.. 6 7function linux_iter_pci { 8 # Argument is the class code 9 # TODO: More specifically match against only class codes in the grep 10 # step. 11 lspci -mm -n | grep $1 | tr -d '"' | awk -F " " '{print "0000:"$1}' 12} 13 14function linux_bind_driver() { 15 bdf="$1" 16 driver_name="$2" 17 old_driver_name="no driver" 18 ven_dev_id=$(lspci -n -s $bdf | cut -d' ' -f3 | sed 's/:/ /') 19 20 if [ -e "/sys/bus/pci/devices/$bdf/driver" ]; then 21 old_driver_name=$(basename $(readlink /sys/bus/pci/devices/$bdf/driver)) 22 23 if [ "$driver_name" = "$old_driver_name" ]; then 24 return 0 25 fi 26 27 echo "$ven_dev_id" > "/sys/bus/pci/devices/$bdf/driver/remove_id" 2> /dev/null || true 28 echo "$bdf" > "/sys/bus/pci/devices/$bdf/driver/unbind" 29 fi 30 31 echo "$bdf ($ven_dev_id): $old_driver_name -> $driver_name" 32 33 echo "$ven_dev_id" > "/sys/bus/pci/drivers/$driver_name/new_id" 2> /dev/null || true 34 echo "$bdf" > "/sys/bus/pci/drivers/$driver_name/bind" 2> /dev/null || true 35 36 iommu_group=$(basename $(readlink -f /sys/bus/pci/devices/$bdf/iommu_group)) 37 if [ -e "/dev/vfio/$iommu_group" ]; then 38 chown "$username" "/dev/vfio/$iommu_group" 39 fi 40} 41 42function configure_linux { 43 driver_name=vfio-pci 44 if [ -z "$(ls /sys/kernel/iommu_groups)" ]; then 45 # No IOMMU. Use uio. 46 driver_name=uio_pci_generic 47 fi 48 49 # NVMe 50 modprobe $driver_name || true 51 for bdf in $(linux_iter_pci 0108); do 52 linux_bind_driver "$bdf" "$driver_name" 53 done 54 55 56 # IOAT 57 TMP=`mktemp` 58 #collect all the device_id info of ioat devices. 59 grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \ 60 | awk -F"x" '{print $2}' > $TMP 61 62 for dev_id in `cat $TMP`; do 63 # Abuse linux_iter_pci by giving it a device ID instead of a class code 64 for bdf in $(linux_iter_pci $dev_id); do 65 linux_bind_driver "$bdf" "$driver_name" 66 done 67 done 68 rm $TMP 69 70 echo "1" > "/sys/bus/pci/rescan" 71 72 if ! mount | grep -q hugetlbfs; then 73 mkdir -p /mnt/huge 74 mount -t hugetlbfs nodev /mnt/huge 75 fi 76 echo "$NRHUGE" > /proc/sys/vm/nr_hugepages 77 78 if [ "$driver_name" = "vfio-pci" ]; then 79 chown "$username" /dev/hugepages 80 81 MEMLOCK_AMNT=`ulimit -l` 82 if [ "$MEMLOCK_AMNT" != "unlimited" ] ; then 83 MEMLOCK_MB=$(( $MEMLOCK_AMNT / 1024 )) 84 echo "" 85 echo "Current user memlock limit: ${MEMLOCK_MB} MB" 86 echo "" 87 echo "This is the maximum amount of memory you will be" 88 echo "able to use with DPDK and VFIO if run as current user." 89 echo -n "To change this, please adjust limits.conf memlock " 90 echo "limit for current user." 91 92 if [ $MEMLOCK_AMNT -lt 65536 ] ; then 93 echo "" 94 echo "## WARNING: memlock limit is less than 64MB" 95 echo -n "## DPDK with VFIO may not be able to initialize " 96 echo "if run as current user." 97 fi 98 fi 99 fi 100} 101 102function reset_linux { 103 # NVMe 104 modprobe nvme || true 105 for bdf in $(linux_iter_pci 0108); do 106 linux_bind_driver "$bdf" nvme 107 done 108 109 110 # IOAT 111 TMP=`mktemp` 112 #collect all the device_id info of ioat devices. 113 grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \ 114 | awk -F"x" '{print $2}' > $TMP 115 116 modprobe ioatdma || true 117 for dev_id in `cat $TMP`; do 118 # Abuse linux_iter_pci by giving it a device ID instead of a class code 119 for bdf in $(linux_iter_pci $dev_id); do 120 linux_bind_driver "$bdf" ioatdma 121 done 122 done 123 rm $TMP 124 125 echo "1" > "/sys/bus/pci/rescan" 126} 127 128function configure_freebsd { 129 TMP=`mktemp` 130 131 # NVMe 132 GREP_STR="class=0x010802" 133 134 # IOAT 135 grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/include/spdk/pci_ids.h \ 136 | awk -F"x" '{print $2}' > $TMP 137 for dev_id in `cat $TMP`; do 138 GREP_STR="${GREP_STR}\|chip=0x${dev_id}8086" 139 done 140 141 AWK_PROG="{if (count > 0) printf \",\"; printf \"%s:%s:%s\",\$2,\$3,\$4; count++}" 142 echo $AWK_PROG > $TMP 143 144 BDFS=`pciconf -l | grep "${GREP_STR}" | awk -F: -f $TMP` 145 146 kldunload nic_uio.ko || true 147 kenv hw.nic_uio.bdfs=$BDFS 148 kldload nic_uio.ko 149 rm $TMP 150 151 kldunload contigmem.ko || true 152 kenv hw.contigmem.num_buffers=$((NRHUGE * 2 / 256)) 153 kenv hw.contigmem.buffer_size=$((256 * 1024 * 1024)) 154 kldload contigmem.ko 155} 156 157function reset_freebsd { 158 kldunload contigmem.ko || true 159 kldunload nic_uio.ko || true 160} 161 162NRHUGE=1024 163 164username=$1 165mode=$2 166 167if [ "$username" = "reset" -o "$username" = "config" ]; then 168 mode="$username" 169 username="" 170fi 171 172if [ "$mode" == "" ]; then 173 mode="config" 174fi 175 176if [ "$username" = "" ]; then 177 username=`logname` 178fi 179 180if [ `uname` = Linux ]; then 181 if [ "$mode" == "config" ]; then 182 configure_linux 183 elif [ "$mode" == "reset" ]; then 184 reset_linux 185 fi 186else 187 if [ "$mode" == "config" ]; then 188 configure_freebsd 189 elif [ "$mode" == "reset" ]; then 190 reset_freebsd 191 fi 192fi 193