MacBook Pro Retina with Linux (Fedora 18)

I recently purchased a new MacBook Pro 13″ w/Retina (Early 2013, MacBookPro10,2), it’s absolutely stunning and love using it. As I work on a day-to-day basis with Linux, I decided to remove MacOS and deploy Fedora 18 on it. I was pleasantly surprised that almost everything works out of the box. I did have to make some modifications once it was installed, mainly for performance but also to get sound and the wireless working. As the installation is just as easy as installing it on a non-Apple machine, this guide assumes that you have already done so. If you’re having problems installing, I’d be happy to assist.

What currently doesn’t work? Well, Thunderbolt hotplug currently isn’t supported; Mac OSX seems to use some form of magic to enable hotplugging and to control the thunderbolt controllers. Whilst the Linux kernel supports the thunderbolt controllers, it only ever works if the adapter is plugged in before the system is booted, I’ve successfully used a Thunderbolt Ethernet adapter. I wouldn’t expect thunderbolt hotplug anytime soon either, which is a shame. There’s also currently a bug with the mini-displayport -> VGA, although HDMI works out of the box. I’ll work on the VGA adapter problem and will update this post if/when it’s working.

Step One (Wireless): The MacBook Pro ships with a Broadcom BCM4331 wireless adapter, there’s an open-source driver available in the kernel (b43) but it requires additional proprietary firmware from Broadcom to use it successfully. I had no end of trouble with this driver, it didn’t support 5GHz/N networks and constantly dropped connectivity – completely unreliable. 

The solution that worked for me and has been rock-solid so far is the proprietary driver direct from Broadcom (wl), it has open-source code to support the driver and provide a standard interface to the binary driver. Broadcom ship this package on their website ( but for reasons unknown to me do not ship the latest code, in addition, via the rpmfusion repositories it’s available as a package for Fedora. The guys over at Ubuntu managed to get access to the latest packages and I was able to build it successfully on Fedora (after reading lots of threads!). The downside is that the compiled module is inserted into each kernel manually after its built and therefore it needs to be built each time there’s a kernel update. I would rather do this and have stable WiFi than use the b43 driver though; perhaps in the future either the b43 or wl driver will be stable enough upstream to use without manual compilation.

Below I’ve outlined the necessary steps for getting the driver working on Fedora 18, note that the package comes as a Debian package that we’ll extract:

$ su -
# yum groupinstall "Development Tools" -y
# yum install binutils -y

# mkdir ~/bcm4331 && cd ~/bcm4331
# wget
# ar vx wireless-bcm43142-dkms_6.20.55.19-1_amd64.deb
# tar -zxvf data.tar.gz

# cd usr/src/wireless-bcm43142-
# wget
# mv wl_cfg80211.c src/wl/sys/
# make && make install

# depmod -a
# modprobe -r b43 ssb bcma
# modprobe wl

# echo "blacklist bcma" >> /etc/modprobe.d/blacklist.conf
# echo "blacklist ssb" >> /etc/modprobe.d/blacklist.conf
# echo "blacklist b43" >> /etc/modprobe.d/blacklist.conf

# echo "wl" >> /etc/modules-load.d/wireless.conf
# restorecon -v /etc/modules-load.d/wireless.conf

The above commands basically grab the Ubuntu package, over-write some minor changes required to build it on a 3.8+ kernel, compile the module for the local system and install it for the current kernel. In addition it also updates the module “database” and inserts the module with associated dependencies (cfg80211, lib80211 and lib80211_crypt_tkip). Finally, it blacklists the open-source drivers and enables the ‘wl‘ driver to be started on boot up.

The system should now report that the wireless adapter is available and that it’s using the correct driver:

# lspci -k | grep -n2 4331 | tail -n3
42:03:00.0 Network controller: Broadcom Corporation BCM4331 802.11a/b/g/n (rev 02)
43-	Subsystem: Apple Inc. Device 010f
44-	Kernel driver in use: wl

# lsmod | grep wl
wl                   3074693  0 
cfg80211              495993  1 wl
lib80211               13968  2 wl,lib80211_crypt_tkip

At this point I’d recommend rebooting to ensure that the machine comes up successfully and that the drivers are loaded automatically (confirm using the above steps again). You should also not be able to see the ‘b43‘ driver in the list of modules.

Note: I did have some instabilities when using ‘iwconfig‘, I’d recommend that you avoid this tool if you can, ‘ifconfig’ works without problem.

Step Two (Sound/Audio): As the device is very much like any other manufacturers equipment, it utilises commodity components. The Ivybridge CPU provides the standard Intel HD4000 video card and therefore works right out of the box; upstream support has been there for a long time. This is also the same story for a number of other components, the sound card whilst supported requires a slight module modification to get it to work properly. What you may find is that the modules get automatically loaded by Fedora but no sound card is visible.

The module that we’re using to provide audio is ‘snd_hda_intel‘, we need to pass an additional model identifier to it in order to initialise the card:

$ su -
# echo "options snd_hda_intel model=mbp101" >> /etc/modprobe.d/snd_hda_intel.conf
# restorecon -v /etc/modprobe.d/snd_hda_intel.conf

Note that you will either need to reboot or reload the module in order to get sound working; I recommend the former as it will integrate with the rest of your environment without having to restart all of the required services manually. When the machine has come back up, confirm that the module was loaded correctly with the model identifier:

$ cat /sys/module/snd_hda_intel/parameters/model 

Step Three (Performance): Regardless of the specification you chose to buy, the MacBook Pro is a very capable machine. There are a number of recommendations that I’d like to make in order to maximise the performance of your system. Firstly, any modern machine with plenty of RAM will very rarely need to touch swap space but it certainly still is a requirement, e.g. for hibernation or for various types of workloads. That being said, we should still ask Linux to avoid using the swap space wherever possible:

$ su -
# echo "vm.swappiness=1" >> /etc/sysctl.d/performance.conf
# echo "vm.vfs_cache_pressure=50" >> /etc/sysctl.d/performance.conf
# restorecon -v /etc/sysctl.d/performance.conf

Next, as we’re using non-rotational disks (i.e. SSD/Flash), the ‘noop‘ block scheduler provides a number of performance benefits that we can exploit; it’s essentially no scheduling at all, just basic FIFO (first in, first out), alternatively the ‘deadline‘ scheduler can be used which tries to prioritise reads to enable some sort of read-performance when there is heavy write I/O. My personal preference is ‘noop‘ but your workload may require ‘deadline‘. You can view the current scheduler algorithm by using the following command:

$ cat /sys/block/sda/queue/scheduler
noop deadline [cfq]

In the above example, you can see that I’m currently using the ‘cfq‘ method. It’s easy to make a one-time change to the scheduler by echoing values into that virtual filesystem but to make this persistent we need to add a udev rule:

# echo ACTION=="add|change", KERNEL=="sda", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="noop" >> /etc/udev/rules.d/60-scheduler.rules
# restorecon -v /etc/udev/rules.d/60-scheduler.rules

Note that I have explicity specified the ‘sda’ device here (the internal SSD) and not all sd*, this is because I may want to attach external disks, e.g. via USB, which will be rotational disks and would therefore benefit from the default scheduler. Feel free to adjust the above udev rule to specify ‘deadline‘ if that’s your preference.

Finally, as we’re using a solid state disk it makes sense to implement trim/discard to aid with the wearing of the disk; I’m not going to go into too much detail of why we do this but it will prolong the life of the drive. There are a number of changes to make, firstly your fstab needs to be updated to mount your drives with these options:

$ su -
# vi /etc/fstab

Depending on your partition layout and whether you use encrypted volumes the next steps may be quite different for you. I will, however, assume that you’re using a default partition layout with a separate /home and / mount points. Simply add the parameters ‘discard’ and ‘noatime’ to each mount. For example:

/dev/mapper/vol0-rootVol    /    ext4    defaults    1 1

/dev/mapper/vol0-rootVol    /    ext4    defaults,discard    1 1

(repeat for /home)

('i' to edit and 'Esc -> :wq!' to save and quit)

Once that’s complete we need to test your changes:

# mount -o remount /
# mount -o remount /home
# mount | egrep '(on /|/home)'
/dev/mapper/vol0-rootVol on / type ext4 (rw,relatime,seclabel,discard,data=ordered)
/dev/mapper/cryptoVol on /home type ext4 (rw,relatime,seclabel,discard,data=ordered)

If successful, you should see the discard option listed in your output, yours my vary but ensure it has discard listed.

Please note: If you want to increase the performance further and are willing to accept a bit of risk, you can mount your volumes with the ‘noatime‘ option too; this removes the requirement for file updates for just reads… just bear in mind that applications may break! Fedora by default uses ‘relatime‘ which is a nice compromise.

— Additional tweaks coming tomorrow —