Macbook Pro 5,x with Ubuntu 14.04

if you are looking for an easy way to setup your Macbook Pro 5,x (with an NVIDIA 9400M and 9600M GT) please have a look at my GIT:

https://github.com/hyphone/mbp5ubuntu

you will find everything you need there.

installation instructions:

– boot your favourite ubuntu flavour from DVD or an USB-key

– when choosing to select “try…” or “install…” hit the key “e” to edit the entry and add “nomodeset” to the second last line to prevent nouveau from loading

– install as you wish

– boot your freshly installed operating system

first we want to be sure the apple EFI-loader will see grub:

– open terminal and get root

goto /boot/efi/EFI/

cp -r ubuntu boot && cd boot

mv grubx64.efi bootx64.efi

– update your OS (be sure to have an ethernet cable)
apt-get update && apt-get upgrade

– install the wifi-firmware for the b43 kernel driver (more reliable after suspend)
apt-get install firmware-b43-installer

download the NVIDIA 331 driver manually (this was the only way to get working cuda / opencl and to avoid conflicts with wine)

– download: http://www.nvidia.com/download/driverResults.aspx/80533/en-us

– reboot

– when grub appears again hit “e” to edit your boot parameters

– add “text” to the second last line to boot into a virtual terminal

– login

– get root
sudo -i

– install dkms and git:
apt-get install dkms git

– goto where you downloaded the NVIDIA driver

– make the file executable
chmod +x NVIDIA-Linux-x86_64-331.113.run

– run the installer
   ./NVIDIA-Linux-x86_64-331.113.run

– say “yes” to install with dkms and to install the 32-bit libraries

install my scripts from git

– goto a temporary directory (i.e /tmp) and get root
   sudo -i
   cd /tmp

– clone my ubuntu git:
git clone https://github.com/hyphone/mbp5ubuntu.git && cd mbp5ubuntu

– copy everything inside to your root partition
cp -r ./* /

– update your kernel ramfs to blacklist nouveau as said in my modprobe nvidia-mbp.conf
update-initramfs

reboot and you are done

 

btw: if you are using gnome-shell you can use the following extension to switch the GPU. a reboot is still required though.

https://github.com/hyphone/mbpgpuswitcher-shell-extension

otherwise to change the GPU open a terminal and enter:

gpuchange

Macbook Pro 5,x Display Switching Linux

#include <stdio.h>
#include <sys/io.h>

#define PORT_SWITCH_DISPLAY 0x710
#define PORT_SWITCH_SELECT 0x728
#define PORT_SWITCH_DDC 0x740
#define PORT_DISCRETE_POWER 0x750

static int gmux_switch_to_igd()
{
outb(1, PORT_SWITCH_SELECT);
outb(2, PORT_SWITCH_DISPLAY);
outb(2, PORT_SWITCH_DDC);
return 0;
    }

    static void mbp_gpu_power(int state)
{
    outb(state, PORT_DISCRETE_POWER);
    }

int main(int argc, char **argv)
{
if (iopl(3) < 0) {
perror ("No IO permissions");
return 1;
}
mbp_gpu_power(0);
gmux_switch_to_igd();
return 0;
}

compile with gcc -O2 igd.c -o igd

  • dgd.c
    based on the source above with the correct gmux values for the dedicated chip
#include <stdio.h>
#include <sys/io.h>

#define PORT_SWITCH_DISPLAY 0x710
#define PORT_SWITCH_SELECT 0x728
#define PORT_SWITCH_DDC 0x740
#define PORT_DISCRETE_POWER 0x750

static int gmux_switch_to_dgd()
{
outb(2, PORT_SWITCH_SELECT);
outb(3, PORT_SWITCH_DISPLAY);
outb(3, PORT_SWITCH_DDC);
return 0;
    }

int main(int argc, char **argv)
{
if (iopl(3) < 0) {
perror ("No IO permissions");
return 1;
}
gmux_switch_to_dgd();
return 0;
}

compile with gcc -O2 dgd.c -o dgd

  • copy them into your /bin directory.

 

Now it gets a bit -not so elegant-. I will have a look for a better solution but since it works for me I share my first try.

  • Create 2 boot options in your bootloader
    one with the parameter gpu=i, and one with gpu=d
    – for example, if you use grub, duplicate the file /etc/grub.d/10_linux to /etc/grub.d/10_linux_2 or something
    – search for “${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}”
    – add “gpu=i” in 10_linux inside the string above as a last parameter. do the same with 10_linux_2 but with “gpu=d”
  • create the new grub.cfg (grub2-mkconfig -o path/to/your/grub.cfg)
  • create two xorg.conf files in /etc/X11:
    – use nvidia-xconfig to create an xorg.conf for you
    – delete everything but the Section “Device”
    – edit your xorg.conf and add this Option to your “Device” Section:
    BusID           “PCI:2:0:0″
    – Save the new xorg as xorg.conf_d in the same dir
    – Change the String to:
    BusID           “PCI:3:0:0″
    – And save it as xorg.conf_i
  • Blacklist the nvidia driver
    blacklisting first makes sure the nvidia driver isn’t initialized before we disable the dedicated chip. this helps using opencl applications.
    – you should have blacklisted nouveau before somewhere (/etc/modprobe.d/*).
    – add the line “blacklist nvidia”
  • Create a Shell Script in /bin (like “changegpu.sh”):

#!/bin/sh

gpu=`cat /proc/cmdline|awk '{print match($0,"gpu=i")}'`
if [ $gpu -gt 0 ] ;then
    cp /etc/X11/xorg.conf_i /etc/X11/xorg.conf
    echo "xorg_i"
    /bin/igd
    sleep 1
    /sbin/modprobe nvidia
    echo "igd executed"
fi

gpu=`cat /proc/cmdline|awk '{print match($0,"gpu=d")}'`
if [ $gpu -gt 0 ] ;then
    cp /etc/X11/xorg.conf_d /etc/X11/xorg.conf
    echo "xorg_d"
    /bin/dgd
    sleep 1
    /sbin/modprobe nvidia
    echo "dgd executed"
fi

This captures your bootparameters and searches for your gpu=x string. I don’t know how to create environment variables or something I could work with from the beginning. So it’s unlikely that the string gpu=x will appear somewhere else in the parameters it should do it for now.
The script copies a xorg.conf file as the default one (use symlinks if you prefer) and runs the application that switches the gmux.

  • Make the script executable with “chmod +x /bin/changegpu.sh”

Now we can boot with the GPU we want to be enabled and screened. The last step is to execute the script on resume from sleep/hibernation because if using the integrated chip, the dedicated one will be enabled again when you resume.

  • Create a new file:
[Unit]
Description=Init GPU . . .
After=suspend.target hibernate.target hybrid-sleep.target basic.target

[Service]
User=root
Type=simple
ExecStart=/bin/changegpu.sh

[Install]
WantedBy=suspend.target hibernate.target hybrid-sleep.target basic.target

This Service runs on boot and after every resume event.

  • Save your newly created service to “/etc/systemd/system/setgpu.service” and enable it with “systemctl enable setgpu”
  • Reboot and choose your GPU in your bootloader

There is a way to make this work on with vgaswitcheroo and the nouveau drivers. but the 9400M in this notebook won’t run in accelerated mode so for me it’s useless.

this is tested with arch, fedora and opensuse

with this setup it doesn’t matter which gpu is activated at boot time (os x respectively) because the gmux values are always set at boot time depending on your bootloader choice.