swithcing off dGPU in MBP 2011

I have been running with Ubuntu for a month now and so far it is holding up very well, just a hiccup with wireless driver up kernel update. Reverted back to previous kernel and things are stable all over again.

I have been monitoring temp and power consumption on my MBP 2011 and found that after every boot it runs quite cool, thanks to lmsensors and swithcing off turbo-boost helps. But one thing I noticed is that every time I resume after suspend the laptop starts heating up all over again, confirmed that dGPU was switched on. Now this is all in domain of gmux and seems like it is playing a role somehow.

Previously, I had disabled dGPU during boot time with changes to grub, can we do that again? inb and outb here are the io instructions that can do the magic. Thanks to the guys that hacked around MacBook and Apple drivers/kexts.

1
2
3
4
outb 0x728 1 # Switch select
outb 0x710 2 # Switch display
outb 0x740 2 # Switch DDC
outb 0x750 0 # Power down discrete graphics


Following code is pretty much along what we did during boot (found somewhere on internet, don’t have link):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#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);
}

static void mb_gpu_print()
{
    printf("SELECT:  %hhu\n", inb(PORT_SWITCH_SELECT));
    printf("DISPLAY: %hhu\n", inb(PORT_SWITCH_DISPLAY));
    printf("DDC:     %hhu\n", inb(PORT_SWITCH_DDC));
    printf("POWER:   %hhu\n", inb(PORT_DISCRETE_POWER));
}

int main(int argc, char **argv)
{
    if (iopl(3) < 0) {
        perror ("No IO permissions");
        return 1;
    }
    int state=0;
    if (argc > 1) state = atoi(argv[1]);
    printf("Before:\n");
    mb_gpu_print();
    mbp_gpu_power(state);
    gmux_switch_to_igd();
    printf("After:\n");
    mb_gpu_print();
    return 0;
}


With this I am back to a cool running MBP on linux. This same logic is applicable to MacOS as well. I have some local code changes along with kexts built to forcefully switching off dGPU thru gmux.

/images/dGPU-swithced-off-forcefully-macos.png


Well this works quite well in practice because of gmux being an intermediary. LWN has a great writeup for it. Some of this is documented in patent US 8,687,007 B2, esp fig6 and fig7: delegate act of switching off dGPU to gmux and how it schedules depending on blanking interval overlap.

A few links about gmux: