David Schlachter

FreeBSD WiFi PCI Passthrough: Intel Wireless 8265, bhyve, 13.0-CURRENT

WiFi speeds for the Intel Wireless 8265 chip on FreeBSD are currently limited to 802.11g speeds (54 Mbit/s). However, the chip is capable of 802.11ac on Linux and Windows. To use the wireless card at full speed, I've tested using PCI passthrough to make the card available to a Linux virtual machine, then creating a NAT connection from the Linux VM to the FreeBSD host. This has been tested on FreeBSD 13.0-CURRENT (revision 356244, Dec 31 2019) on a Lenovo T480.

tl;dr: I can't get the VM to use the wireless card after a suspend/resume; otherwise everything works. I used John Baldwin's guide on the same topic as a resource for my configuration.

Update 2021-12-24: The wifibox package automates this approach. May be worth a try if you don't want to set this up manually.
Update 2022-04-07: I tried wifibox, which has a fix for the suspend/resume issue!

Set up bhyve VM

I installed debian-10.2.0-amd64 using the instructions in the handbook. In /boot/loader.conf I load the required kernel modules and set up the bridge/tap interfaces:

vmm_load="YES"
nmdm_load="YES"
if_bridge_load="YES"
if_tap_load="YES"

In /etc/sysctl.conf I set net.link.tap.up_on_open=1 to automatically bring up tap interfaces when they are created.

I bring up the network interfaces for the VM with this one-liner:

sudo ifconfig tap0 create; sudo ifconfig bridge0 create; sudo ifconfig bridge0 addm tap0; sudo ifconfig bridge0 up; sudo ifconfig bridge0 inet 192.168.6.1 netmask 255.255.255.0; sudo ifconfig wlan0 destroy

On my system, the WiFi card is at pci0:3:0:0, as shown by sudo pciconf -lv. Before running the virtual machine, load the PCI passthrough driver for the card using sudo devctl set driver -f pci0:3:0:0 ppt (with the appropriate address). This can also be done at boot time as detailed in John Baldwin's write-up.

I bring up my VM with these commands, somewhat adapted from the handbook. Note the PCI address of the WiFi card passed via the -s flag (7 being the destination address on the Linux guest). PCI passthrough requires direct memory allocation, hence the -S flags. The paths to the guest disk image and device map are relative here; this should be run from the VM's directory:

sudo grub-bhyve -m device.map -r hd0,msdos1 -M 1024M -S linuxguest && sudo bhyve -A -H -P -s 0:0,hostbridge -s 1:0,lpc -s 2:0,virtio-net,tap0 -s 3:0,virtio-blk,./debian-hd.img -l com1,stdio -c 4 -m 1024M -S -s 7,passthru,3/0/0 linuxguest

Within the Debian guest, edit /etc/sysctl.conf to enable packet forwarding (uncomment net.ipv4.ip_forward=1). I used wpa_supplicant to setup the wireless card, with the following in /etc/network/interfaces:

auto lo
iface lo inet loopback

auto enp0s2
iface enp0s2 inet static
address 192.168.6.2
netmask 255.255.255.0
network 192.168.6.0
broadcast 192.168.6.255
pre-up /scripts/nat.zsh

iface wlp0s7 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

The configuration file for wpa_supplicant goes in the path specified. The interface names would be different based on the PCI addresses specified in the bhyve command used to launch the virtual machine. The contents of /scripts/nat.zsh are:

#!/usr/bin/bash

iptables="/sbin/iptables"
${iptables} -t nat -A POSTROUTING -o wlp0s7 -j MASQUERADE
${iptables} -A FORWARD -i enp0s2 -o wlp0s7 -m state --state RELATED,ESTABLISHED -j ACCEPT
${iptables} -A FORWARD -i enp0s2 -o wlp0s7 -j ACCEPT

Interface names in this file must match the actual interface names if different PCI addresses were used.

With this configuration, the virtual machine should be able to connect to WiFi (can be tested with ping from within the VM). If this works, the FreeBSD host can be configured to use the NAT from the VM with the following configuration in /etc/rc.conf:

cloned_interfaces="bridge0 tap0"
ifconfig_bridge0="inet 192.168.6.1 netmask 255.255.255.0 addm tap0 up"
defaultrouter="192.168.6.2"

Conclusion

This all worked well for me. Transfer speed on my LAN went from 2-3 MB/s on the FreeBSD host to 30 MB/s using the bhyve passthrough. However, the WiFi card would not be activated within the virtual machine after suspending/resuming the host. The error given as the VM is starting is:

iwlwifi 0000:01:00.0: Failed to start INIT ucode: -110
iwlwifi 0000:01:00.0: Failed to run INIT ucode: -110

I tried various ideas such as detaching/attaching suspending/resuming the WiFi card or unloading/loading drivers all using pciconf, to no avail. The card works fine on the FreeBSD host if the ppt driver is cleared using pciconf, but never in the Linux guest after one suspend/resume of the host.

It looks like powersave on this card may cause similar difficulties on some native Linux systems, so for the time being I've given up on finding a solution.

If you find a way to make the card work in the bhyve VM after suspend/resume, let me know!