Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 603359 Details for
Bug 837461
VGASWITCHEROO not available for macbookpro
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
vga_switcheroo.patch
vga_switcheroo.patch (text/plain), 47.41 KB, created by
William Brown
on 2012-08-09 22:09:42 UTC
(
hide
)
Description:
vga_switcheroo.patch
Filename:
MIME Type:
Creator:
William Brown
Created:
2012-08-09 22:09:42 UTC
Size:
47.41 KB
patch
obsolete
>diff -uNrp vanilla-3.5/arch/x86/boot/compressed/eboot.c mbp-f99a29d/arch/x86/boot/compressed/eboot.c >--- vanilla-3.5/arch/x86/boot/compressed/eboot.c 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/arch/x86/boot/compressed/eboot.c 2012-07-30 08:31:43.000000000 +0930 >@@ -8,6 +8,7 @@ > * ----------------------------------------------------------------------- */ > > #include <linux/efi.h> >+#include <linux/pci.h> > #include <asm/efi.h> > #include <asm/setup.h> > #include <asm/desc.h> >@@ -243,6 +244,121 @@ static void find_bits(unsigned long mask > *size = len; > } > >+static efi_status_t setup_efi_pci(struct boot_params *params) >+{ >+ efi_pci_io_protocol *pci; >+ efi_status_t status; >+ void **pci_handle; >+ efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; >+ unsigned long nr_pci, size = 0; >+ int i; >+ struct setup_data *data; >+ >+ data = (struct setup_data *)params->hdr.setup_data; >+ >+ while (data && data->next) >+ data = (struct setup_data *)data->next; >+ >+ status = efi_call_phys5(sys_table->boottime->locate_handle, >+ EFI_LOCATE_BY_PROTOCOL, &pci_proto, >+ NULL, &size, pci_handle); >+ >+ if (status == EFI_BUFFER_TOO_SMALL) { >+ status = efi_call_phys3(sys_table->boottime->allocate_pool, >+ EFI_LOADER_DATA, size, &pci_handle); >+ >+ if (status != EFI_SUCCESS) >+ return status; >+ >+ status = efi_call_phys5(sys_table->boottime->locate_handle, >+ EFI_LOCATE_BY_PROTOCOL, &pci_proto, >+ NULL, &size, pci_handle); >+ } >+ >+ if (status != EFI_SUCCESS) >+ goto free_handle; >+ >+ nr_pci = size / sizeof(void *); >+ for (i = 0; i < nr_pci; i++) { >+ void *h = pci_handle[i]; >+ uint64_t attributes; >+ struct pci_setup_rom *rom; >+ >+ status = efi_call_phys3(sys_table->boottime->handle_protocol, >+ h, &pci_proto, &pci); >+ >+ if (status != EFI_SUCCESS) >+ continue; >+ >+ if (!pci) >+ continue; >+ >+ status = efi_call_phys4(pci->attributes, pci, >+ EfiPciIoAttributeOperationGet, 0, >+ &attributes); >+ >+ if (status != EFI_SUCCESS) >+ continue; >+ >+ if (!attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) >+ continue; >+ >+ if (!pci->romimage || !pci->romsize) >+ continue; >+ >+ size = pci->romsize + sizeof(*rom); >+ >+ status = efi_call_phys3(sys_table->boottime->allocate_pool, >+ EFI_LOADER_DATA, size, &rom); >+ >+ if (status != EFI_SUCCESS) >+ continue; >+ >+ rom->data.type = SETUP_PCI; >+ rom->data.len = size - sizeof(struct setup_data); >+ rom->data.next = NULL; >+ rom->pcilen = pci->romsize; >+ >+ status = efi_call_phys5(pci->pci.read, pci, >+ EfiPciIoWidthUint16, PCI_VENDOR_ID, >+ 1, &(rom->vendor)); >+ >+ if (status != EFI_SUCCESS) >+ goto free_struct; >+ >+ status = efi_call_phys5(pci->pci.read, pci, >+ EfiPciIoWidthUint16, PCI_DEVICE_ID, >+ 1, &(rom->devid)); >+ >+ if (status != EFI_SUCCESS) >+ goto free_struct; >+ >+ status = efi_call_phys5(pci->get_location, pci, >+ &(rom->segment), &(rom->bus), >+ &(rom->device), &(rom->function)); >+ >+ if (status != EFI_SUCCESS) >+ goto free_struct; >+ >+ memcpy(rom->romdata, pci->romimage, pci->romsize); >+ >+ if (data) >+ data->next = (uint64_t)rom; >+ else >+ params->hdr.setup_data = (uint64_t)rom; >+ >+ data = (struct setup_data *)rom; >+ >+ continue; >+ free_struct: >+ efi_call_phys1(sys_table->boottime->free_pool, rom); >+ } >+ >+free_handle: >+ efi_call_phys1(sys_table->boottime->free_pool, pci_handle); >+ return status; >+} >+ > /* > * See if we have Graphics Output Protocol > */ >@@ -276,8 +392,9 @@ static efi_status_t setup_gop(struct scr > nr_gops = size / sizeof(void *); > for (i = 0; i < nr_gops; i++) { > struct efi_graphics_output_mode_info *info; >- efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID; >- void *pciio; >+ efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; >+ bool conout_found = false; >+ void *dummy; > void *h = gop_handle[i]; > > status = efi_call_phys3(sys_table->boottime->handle_protocol, >@@ -285,19 +402,21 @@ static efi_status_t setup_gop(struct scr > if (status != EFI_SUCCESS) > continue; > >- efi_call_phys3(sys_table->boottime->handle_protocol, >- h, &pciio_proto, &pciio); >+ status = efi_call_phys3(sys_table->boottime->handle_protocol, >+ h, &conout_proto, &dummy); >+ >+ if (status == EFI_SUCCESS) >+ conout_found = true; > > status = efi_call_phys4(gop->query_mode, gop, > gop->mode->mode, &size, &info); >- if (status == EFI_SUCCESS && (!first_gop || pciio)) { >+ if (status == EFI_SUCCESS && (!first_gop || conout_found)) { > /* >- * Apple provide GOPs that are not backed by >- * real hardware (they're used to handle >- * multiple displays). The workaround is to >- * search for a GOP implementing the PCIIO >- * protocol, and if one isn't found, to just >- * fallback to the first GOP. >+ * Systems that use the UEFI Console Splitter may >+ * provide multiple GOP devices, not all of which are >+ * backed by real hardware. The workaround is to search >+ * for a GOP implementing the ConOut protocol, and if >+ * one isn't found, to just fall back to the first GOP. > */ > width = info->horizontal_resolution; > height = info->vertical_resolution; >@@ -308,10 +427,10 @@ static efi_status_t setup_gop(struct scr > pixels_per_scan_line = info->pixels_per_scan_line; > > /* >- * Once we've found a GOP supporting PCIIO, >+ * Once we've found a GOP supporting ConOut, > * don't bother looking any further. > */ >- if (pciio) >+ if (conout_found) > break; > > first_gop = gop; >@@ -328,7 +447,6 @@ static efi_status_t setup_gop(struct scr > si->lfb_width = width; > si->lfb_height = height; > si->lfb_base = fb_base; >- si->lfb_size = fb_size; > si->pages = 1; > > if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) { >@@ -376,6 +494,10 @@ static efi_status_t setup_gop(struct scr > si->rsvd_pos = 0; > } > >+ si->lfb_size = si->lfb_linelength * si->lfb_height; >+ >+ si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; >+ > free_handle: > efi_call_phys1(sys_table->boottime->free_pool, gop_handle); > return status; >@@ -729,32 +851,68 @@ fail: > * need to create one ourselves (usually the bootloader would create > * one for us). > */ >-static efi_status_t make_boot_params(struct boot_params *boot_params, >- efi_loaded_image_t *image, >- void *handle) >+struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table) > { >- struct efi_info *efi = &boot_params->efi_info; >- struct apm_bios_info *bi = &boot_params->apm_bios_info; >- struct sys_desc_table *sdt = &boot_params->sys_desc_table; >- struct e820entry *e820_map = &boot_params->e820_map[0]; >- struct e820entry *prev = NULL; >- struct setup_header *hdr = &boot_params->hdr; >- unsigned long size, key, desc_size, _size; >- efi_memory_desc_t *mem_map; >- void *options = image->load_options; >- u32 load_options_size = image->load_options_size / 2; /* ASCII */ >+ struct boot_params *boot_params; >+ struct sys_desc_table *sdt; >+ struct apm_bios_info *bi; >+ struct setup_header *hdr; >+ struct efi_info *efi; >+ efi_loaded_image_t *image; >+ void *options; >+ u32 load_options_size; >+ efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; > int options_size = 0; > efi_status_t status; >- __u32 desc_version; > unsigned long cmdline; >- u8 nr_entries; > u16 *s2; > u8 *s1; > int i; > >+ sys_table = _table; >+ >+ /* Check if we were booted by the EFI firmware */ >+ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) >+ return NULL; >+ >+ status = efi_call_phys3(sys_table->boottime->handle_protocol, >+ handle, &proto, (void *)&image); >+ if (status != EFI_SUCCESS) { >+ efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); >+ return NULL; >+ } >+ >+ status = low_alloc(0x4000, 1, (unsigned long *)&boot_params); >+ if (status != EFI_SUCCESS) { >+ efi_printk("Failed to alloc lowmem for boot params\n"); >+ return NULL; >+ } >+ >+ memset(boot_params, 0x0, 0x4000); >+ >+ hdr = &boot_params->hdr; >+ efi = &boot_params->efi_info; >+ bi = &boot_params->apm_bios_info; >+ sdt = &boot_params->sys_desc_table; >+ >+ /* Copy the second sector to boot_params */ >+ memcpy(&hdr->jump, image->image_base + 512, 512); >+ >+ /* >+ * Fill out some of the header fields ourselves because the >+ * EFI firmware loader doesn't load the first sector. >+ */ >+ hdr->root_flags = 1; >+ hdr->vid_mode = 0xffff; >+ hdr->boot_flag = 0xAA55; >+ >+ hdr->code32_start = (__u64)(unsigned long)image->image_base; >+ > hdr->type_of_loader = 0x21; > > /* Convert unicode cmdline to ascii */ >+ options = image->load_options; >+ load_options_size = image->load_options_size / 2; /* ASCII */ > cmdline = 0; > s2 = (u16 *)options; > >@@ -791,18 +949,36 @@ static efi_status_t make_boot_params(str > hdr->ramdisk_image = 0; > hdr->ramdisk_size = 0; > >- status = handle_ramdisks(image, hdr); >- if (status != EFI_SUCCESS) >- goto free_cmdline; >- >- setup_graphics(boot_params); >- > /* Clear APM BIOS info */ > memset(bi, 0, sizeof(*bi)); > > memset(sdt, 0, sizeof(*sdt)); > >- memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); >+ status = handle_ramdisks(image, hdr); >+ if (status != EFI_SUCCESS) >+ goto fail2; >+ >+ return boot_params; >+fail2: >+ if (options_size) >+ low_free(options_size, hdr->cmd_line_ptr); >+fail: >+ low_free(0x4000, (unsigned long)boot_params); >+ return NULL; >+} >+ >+static efi_status_t exit_boot(struct boot_params *boot_params, >+ void *handle) >+{ >+ struct efi_info *efi = &boot_params->efi_info; >+ struct e820entry *e820_map = &boot_params->e820_map[0]; >+ struct e820entry *prev = NULL; >+ unsigned long size, key, desc_size, _size; >+ efi_memory_desc_t *mem_map; >+ efi_status_t status; >+ __u32 desc_version; >+ u8 nr_entries; >+ int i; > > size = sizeof(*mem_map) * 32; > >@@ -811,7 +987,7 @@ again: > _size = size; > status = low_alloc(size, 1, (unsigned long *)&mem_map); > if (status != EFI_SUCCESS) >- goto free_cmdline; >+ return status; > > status = efi_call_phys5(sys_table->boottime->get_memory_map, &size, > mem_map, &key, &desc_size, &desc_version); >@@ -823,6 +999,7 @@ again: > if (status != EFI_SUCCESS) > goto free_mem_map; > >+ memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); > efi->efi_systab = (unsigned long)sys_table; > efi->efi_memdesc_size = desc_size; > efi->efi_memdesc_version = desc_version; >@@ -906,61 +1083,13 @@ again: > > free_mem_map: > low_free(_size, (unsigned long)mem_map); >-free_cmdline: >- if (options_size) >- low_free(options_size, hdr->cmd_line_ptr); >-fail: > return status; > } > >-/* >- * On success we return a pointer to a boot_params structure, and NULL >- * on failure. >- */ >-struct boot_params *efi_main(void *handle, efi_system_table_t *_table) >+static efi_status_t relocate_kernel(struct setup_header *hdr) > { >- struct boot_params *boot_params; > unsigned long start, nr_pages; >- struct desc_ptr *gdt, *idt; >- efi_loaded_image_t *image; >- struct setup_header *hdr; > efi_status_t status; >- efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; >- struct desc_struct *desc; >- >- sys_table = _table; >- >- /* Check if we were booted by the EFI firmware */ >- if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) >- goto fail; >- >- status = efi_call_phys3(sys_table->boottime->handle_protocol, >- handle, &proto, (void *)&image); >- if (status != EFI_SUCCESS) { >- efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); >- goto fail; >- } >- >- status = low_alloc(0x4000, 1, (unsigned long *)&boot_params); >- if (status != EFI_SUCCESS) { >- efi_printk("Failed to alloc lowmem for boot params\n"); >- goto fail; >- } >- >- memset(boot_params, 0x0, 0x4000); >- >- hdr = &boot_params->hdr; >- >- /* Copy the second sector to boot_params */ >- memcpy(&hdr->jump, image->image_base + 512, 512); >- >- /* >- * Fill out some of the header fields ourselves because the >- * EFI firmware loader doesn't load the first sector. >- */ >- hdr->root_flags = 1; >- hdr->vid_mode = 0xffff; >- hdr->boot_flag = 0xAA55; > > /* > * The EFI firmware loader could have placed the kernel image >@@ -978,16 +1107,42 @@ struct boot_params *efi_main(void *handl > if (status != EFI_SUCCESS) { > status = low_alloc(hdr->init_size, hdr->kernel_alignment, > &start); >- if (status != EFI_SUCCESS) { >+ if (status != EFI_SUCCESS) > efi_printk("Failed to alloc mem for kernel\n"); >- goto fail; >- } > } > >+ if (status == EFI_SUCCESS) >+ memcpy((void *)start, (void *)(unsigned long)hdr->code32_start, >+ hdr->init_size); >+ >+ hdr->pref_address = hdr->code32_start; > hdr->code32_start = (__u32)start; >- hdr->pref_address = (__u64)(unsigned long)image->image_base; > >- memcpy((void *)start, image->image_base, image->image_size); >+ return status; >+} >+ >+/* >+ * On success we return a pointer to a boot_params structure, and NULL >+ * on failure. >+ */ >+struct boot_params *efi_main(void *handle, efi_system_table_t *_table, >+ struct boot_params *boot_params) >+{ >+ struct desc_ptr *gdt, *idt; >+ efi_loaded_image_t *image; >+ struct setup_header *hdr = &boot_params->hdr; >+ efi_status_t status; >+ struct desc_struct *desc; >+ >+ sys_table = _table; >+ >+ /* Check if we were booted by the EFI firmware */ >+ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) >+ goto fail; >+ >+ setup_graphics(boot_params); >+ >+ setup_efi_pci(boot_params); > > status = efi_call_phys3(sys_table->boottime->allocate_pool, > EFI_LOADER_DATA, sizeof(*gdt), >@@ -1015,7 +1170,18 @@ struct boot_params *efi_main(void *handl > idt->size = 0; > idt->address = 0; > >- status = make_boot_params(boot_params, image, handle); >+ /* >+ * If the kernel isn't already loaded at the preferred load >+ * address, relocate it. >+ */ >+ if (hdr->pref_address != hdr->code32_start) { >+ status = relocate_kernel(hdr); >+ >+ if (status != EFI_SUCCESS) >+ goto fail; >+ } >+ >+ status = exit_boot(boot_params, handle); > if (status != EFI_SUCCESS) > goto fail; > >diff -uNrp vanilla-3.5/arch/x86/boot/compressed/eboot.h mbp-f99a29d/arch/x86/boot/compressed/eboot.h >--- vanilla-3.5/arch/x86/boot/compressed/eboot.h 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/arch/x86/boot/compressed/eboot.h 2012-07-30 08:31:43.000000000 +0930 >@@ -14,6 +14,10 @@ > #define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT) > #define EFI_READ_CHUNK_SIZE (1024 * 1024) > >+#define EFI_CONSOLE_OUT_DEVICE_GUID \ >+ EFI_GUID( 0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \ >+ 0x3f, 0xc1, 0x4d ) >+ > #define PIXEL_RGB_RESERVED_8BIT_PER_COLOR 0 > #define PIXEL_BGR_RESERVED_8BIT_PER_COLOR 1 > #define PIXEL_BIT_MASK 2 >diff -uNrp vanilla-3.5/arch/x86/boot/compressed/head_32.S mbp-f99a29d/arch/x86/boot/compressed/head_32.S >--- vanilla-3.5/arch/x86/boot/compressed/head_32.S 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/arch/x86/boot/compressed/head_32.S 2012-07-30 08:31:43.000000000 +0930 >@@ -42,6 +42,16 @@ ENTRY(startup_32) > */ > add $0x4, %esp > >+ call make_boot_params >+ cmpl $0, %eax >+ je 1f >+ movl 0x4(%esp), %esi >+ movl (%esp), %ecx >+ pushl %eax >+ pushl %esi >+ pushl %ecx >+ >+ .org 0x30,0x90 > call efi_main > cmpl $0, %eax > movl %eax, %esi >diff -uNrp vanilla-3.5/arch/x86/boot/compressed/head_64.S mbp-f99a29d/arch/x86/boot/compressed/head_64.S >--- vanilla-3.5/arch/x86/boot/compressed/head_64.S 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/arch/x86/boot/compressed/head_64.S 2012-07-30 08:31:43.000000000 +0930 >@@ -209,6 +209,16 @@ ENTRY(startup_64) > .org 0x210 > mov %rcx, %rdi > mov %rdx, %rsi >+ pushq %rdi >+ pushq %rsi >+ call make_boot_params >+ cmpq $0,%rax >+ je 1f >+ mov %rax, %rdx >+ popq %rsi >+ popq %rdi >+ >+ .org 0x230,0x90 > call efi_main > movq %rax,%rsi > cmpq $0,%rax >diff -uNrp vanilla-3.5/arch/x86/boot/compressed/Makefile mbp-f99a29d/arch/x86/boot/compressed/Makefile >--- vanilla-3.5/arch/x86/boot/compressed/Makefile 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/arch/x86/boot/compressed/Makefile 2012-07-30 08:31:43.000000000 +0930 >@@ -28,6 +28,9 @@ VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj) > $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \ > $(obj)/piggy.o > >+$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone >+$(obj)/efi_stub_$(BITS).o: KBUILD_CLFAGS += -fshort-wchar -mno-red-zone >+ > ifeq ($(CONFIG_EFI_STUB), y) > VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o > endif >diff -uNrp vanilla-3.5/arch/x86/boot/header.S mbp-f99a29d/arch/x86/boot/header.S >--- vanilla-3.5/arch/x86/boot/header.S 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/arch/x86/boot/header.S 2012-07-30 08:31:43.000000000 +0930 >@@ -283,7 +283,7 @@ _start: > # Part 2 of the header, from the old setup.S > > .ascii "HdrS" # header signature >- .word 0x020a # header version number (>= 0x0105) >+ .word 0x020b # header version number (>= 0x0105) > # or else old loadlin-1.5 will fail) > .globl realmode_swtch > realmode_swtch: .word 0, 0 # default_switch, SETUPSEG >@@ -401,6 +401,8 @@ pref_address: .quad LOAD_PHYSICAL_ADDR > #define INIT_SIZE VO_INIT_SIZE > #endif > init_size: .long INIT_SIZE # kernel initialization size >+handover_offset: .long 0x30 # offset to the handover >+ # protocol entry point > > # End of setup header ##################################################### > >diff -uNrp vanilla-3.5/arch/x86/include/asm/bootparam.h mbp-f99a29d/arch/x86/include/asm/bootparam.h >--- vanilla-3.5/arch/x86/include/asm/bootparam.h 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/arch/x86/include/asm/bootparam.h 2012-07-30 08:31:43.000000000 +0930 >@@ -13,6 +13,7 @@ > #define SETUP_NONE 0 > #define SETUP_E820_EXT 1 > #define SETUP_DTB 2 >+#define SETUP_PCI 3 > > /* extensible setup data list node */ > struct setup_data { >@@ -66,6 +67,7 @@ struct setup_header { > __u64 setup_data; > __u64 pref_address; > __u32 init_size; >+ __u32 handover_offset; > } __attribute__((packed)); > > struct sys_desc_table { >diff -uNrp vanilla-3.5/arch/x86/include/asm/pci.h mbp-f99a29d/arch/x86/include/asm/pci.h >--- vanilla-3.5/arch/x86/include/asm/pci.h 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/arch/x86/include/asm/pci.h 2012-07-30 08:31:43.000000000 +0930 >@@ -171,4 +171,16 @@ cpumask_of_pcibus(const struct pci_bus * > } > #endif > >+struct pci_setup_rom { >+ struct setup_data data; >+ uint16_t vendor; >+ uint16_t devid; >+ uint64_t pcilen; >+ unsigned long segment; >+ unsigned long bus; >+ unsigned long device; >+ unsigned long function; >+ uint8_t romdata[0]; >+}; >+ > #endif /* _ASM_X86_PCI_H */ >diff -uNrp vanilla-3.5/arch/x86/pci/common.c mbp-f99a29d/arch/x86/pci/common.c >--- vanilla-3.5/arch/x86/pci/common.c 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/arch/x86/pci/common.c 2012-07-30 08:31:43.000000000 +0930 >@@ -17,6 +17,7 @@ > #include <asm/io.h> > #include <asm/smp.h> > #include <asm/pci_x86.h> >+#include <asm/setup.h> > > unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | > PCI_PROBE_MMCONF; >@@ -608,6 +609,38 @@ unsigned int pcibios_assign_all_busses(v > return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; > } > >+int pcibios_add_device(struct pci_dev *dev) >+{ >+ struct setup_data *data; >+ struct pci_setup_rom *rom; >+ u64 pa_data; >+ >+ if (boot_params.hdr.version < 0x0209) >+ return 0; >+ >+ pa_data = boot_params.hdr.setup_data; >+ while (pa_data) { >+ data = phys_to_virt(pa_data); >+ >+ if (data->type == SETUP_PCI) { >+ rom = (struct pci_setup_rom *)data; >+ >+ if ((pci_domain_nr(dev->bus) == rom->segment) && >+ (dev->bus->number == rom->bus) && >+ (PCI_SLOT(dev->devfn) == rom->device) && >+ (PCI_FUNC(dev->devfn) == rom->function) && >+ (dev->vendor == rom->vendor) && >+ (dev->device == rom->devid)) { >+ dev->rom = (void *)(pa_data + >+ offsetof(struct pci_setup_rom, romdata)); >+ dev->romlen = rom->pcilen; >+ } >+ } >+ pa_data = data->next; >+ } >+ return 0; >+} >+ > int pcibios_enable_device(struct pci_dev *dev, int mask) > { > int err; >diff -uNrp vanilla-3.5/Documentation/x86/boot.txt mbp-f99a29d/Documentation/x86/boot.txt >--- vanilla-3.5/Documentation/x86/boot.txt 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/Documentation/x86/boot.txt 2012-07-30 08:31:43.000000000 +0930 >@@ -54,6 +54,9 @@ Protocol 2.10: (Kernel 2.6.31) Added a p > beyond the kernel_alignment added, new init_size and > pref_address fields. Added extended boot loader IDs. > >+Protocol 2.11: (Kernel 3.6) Added a field for offset of EFI handover >+ protocol entry point. >+ > **** MEMORY LAYOUT > > The traditional memory map for the kernel loader, used for Image or >@@ -189,6 +192,7 @@ Offset Proto Name Meaning > of struct setup_data > 0258/8 2.10+ pref_address Preferred loading address > 0260/4 2.10+ init_size Linear memory required during initialization >+0264/4 2.11+ handover_offset Offset of handover entry point > > (1) For backwards compatibility, if the setup_sects field contains 0, the > real value is 4. >@@ -690,6 +694,16 @@ Offset/size: 0x260/4 > else > runtime_start = pref_address > >+Field name: handover_offset >+Type: read >+Offset/size: 0x264/4 >+ >+ This field is the offset from the beginning of the kernel image to >+ the EFI handover protocol entry point. Boot loaders using the EFI >+ handover protocol to boot the kernel should jump to this offset. >+ >+ See EFI HANDOVER PROTOCOL below for more details. >+ > > **** THE IMAGE CHECKSUM > >@@ -1010,3 +1024,30 @@ segment; __BOOS_CS must have execute/rea > must have read/write permission; CS must be __BOOT_CS and DS, ES, SS > must be __BOOT_DS; interrupt must be disabled; %esi must hold the base > address of the struct boot_params; %ebp, %edi and %ebx must be zero. >+ >+**** EFI HANDOVER PROTOCOL >+ >+This protocol allows boot loaders to defer initialisation to the EFI >+boot stub. The boot loader is required to load the kernel/initrd(s) >+from the boot media and jump to the EFI handover protocol entry point >+which is hdr->handover_offset bytes from the beginning of >+startup_{32,64}. >+ >+The function prototype for the handover entry point looks like this, >+ >+ efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp) >+ >+'handle' is the EFI image handle passed to the boot loader by the EFI >+firmware, 'table' is the EFI system table - these are the first two >+arguments of the "handoff state" as described in section 2.3 of the >+UEFI specification. 'bp' is the boot loader-allocated boot params. >+ >+The boot loader *must* fill out the following fields in bp, >+ >+ o hdr.code32_start >+ o hdr.cmd_line_ptr >+ o hdr.cmdline_size >+ o hdr.ramdisk_image (if applicable) >+ o hdr.ramdisk_size (if applicable) >+ >+All other fields should be zero. >diff -uNrp vanilla-3.5/drivers/gpu/drm/i915/i915_dma.c mbp-f99a29d/drivers/gpu/drm/i915/i915_dma.c >--- vanilla-3.5/drivers/gpu/drm/i915/i915_dma.c 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/drivers/gpu/drm/i915/i915_dma.c 2012-07-30 08:31:43.000000000 +0930 >@@ -1250,6 +1250,7 @@ static void i915_switcheroo_set_state(st > dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; > /* i915 resume handler doesn't set to D0 */ > pci_set_power_state(dev->pdev, PCI_D0); >+ intel_lvds_get_edid(dev); > i915_resume(dev); > dev->switch_power_state = DRM_SWITCH_POWER_ON; > } else { >diff -uNrp vanilla-3.5/drivers/gpu/drm/i915/intel_drv.h mbp-f99a29d/drivers/gpu/drm/i915/intel_drv.h >--- vanilla-3.5/drivers/gpu/drm/i915/intel_drv.h 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/drivers/gpu/drm/i915/intel_drv.h 2012-07-30 08:31:43.000000000 +0930 >@@ -353,6 +353,7 @@ extern void intel_dvo_init(struct drm_de > extern void intel_tv_init(struct drm_device *dev); > extern void intel_mark_busy(struct drm_device *dev, > struct drm_i915_gem_object *obj); >+extern bool intel_lvds_get_edid(struct drm_device *dev); > extern bool intel_lvds_init(struct drm_device *dev); > extern void intel_dp_init(struct drm_device *dev, int dp_reg); > void >diff -uNrp vanilla-3.5/drivers/gpu/drm/i915/intel_lvds.c mbp-f99a29d/drivers/gpu/drm/i915/intel_lvds.c >--- vanilla-3.5/drivers/gpu/drm/i915/intel_lvds.c 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/drivers/gpu/drm/i915/intel_lvds.c 2012-07-30 08:31:43.000000000 +0930 >@@ -894,6 +894,59 @@ static bool intel_lvds_supported(struct > return IS_MOBILE(dev) && !IS_I830(dev); > } > >+bool intel_lvds_get_edid(struct drm_device *dev) >+{ >+ struct drm_i915_private *dev_priv = dev->dev_private; >+ struct drm_connector *connector = dev_priv->int_lvds_connector; >+ struct intel_lvds *intel_lvds; >+ struct drm_display_mode *scan; /* *modes, *bios_mode; */ >+ u8 pin; >+ >+ if (!connector) >+ return false; >+ >+ intel_lvds = intel_attached_lvds(connector); >+ >+ pin = GMBUS_PORT_PANEL; >+ >+ intel_lvds->edid = drm_get_edid(connector, >+ intel_gmbus_get_adapter(dev_priv, >+ pin)); >+ if (intel_lvds->edid) { >+ if (drm_add_edid_modes(connector, >+ intel_lvds->edid)) { >+ drm_mode_connector_update_edid_property(connector, >+ intel_lvds->edid); >+ } else { >+ kfree(intel_lvds->edid); >+ intel_lvds->edid = NULL; >+ } >+ } >+ >+ if (!intel_lvds->edid) { >+ /* Didn't get an EDID, so >+ * Set wide sync ranges so we get all modes >+ * handed to valid_mode for checking >+ */ >+ connector->display_info.min_vfreq = 0; >+ connector->display_info.max_vfreq = 200; >+ connector->display_info.min_hfreq = 0; >+ connector->display_info.max_hfreq = 200; >+ } >+ >+ list_for_each_entry(scan, &connector->probed_modes, head) { >+ if (scan->type & DRM_MODE_TYPE_PREFERRED) { >+ intel_lvds->fixed_mode = >+ drm_mode_duplicate(dev, scan); >+ intel_find_lvds_downclock(dev, >+ intel_lvds->fixed_mode, >+ connector); >+ return true; >+ } >+ } >+ return false; >+} >+ > /** > * intel_lvds_init - setup LVDS connectors on this device > * @dev: drm device >@@ -909,7 +962,6 @@ bool intel_lvds_init(struct drm_device * > struct intel_connector *intel_connector; > struct drm_connector *connector; > struct drm_encoder *encoder; >- struct drm_display_mode *scan; /* *modes, *bios_mode; */ > struct drm_crtc *crtc; > u32 lvds; > int pipe; >@@ -976,6 +1028,8 @@ bool intel_lvds_init(struct drm_device * > connector->interlace_allowed = false; > connector->doublescan_allowed = false; > >+ dev_priv->int_lvds_connector = connector; >+ > /* create the scaling mode property */ > drm_mode_create_scaling_mode_property(dev); > /* >@@ -1000,40 +1054,8 @@ bool intel_lvds_init(struct drm_device * > * Attempt to get the fixed panel mode from DDC. Assume that the > * preferred mode is the right one. > */ >- intel_lvds->edid = drm_get_edid(connector, >- intel_gmbus_get_adapter(dev_priv, >- pin)); >- if (intel_lvds->edid) { >- if (drm_add_edid_modes(connector, >- intel_lvds->edid)) { >- drm_mode_connector_update_edid_property(connector, >- intel_lvds->edid); >- } else { >- kfree(intel_lvds->edid); >- intel_lvds->edid = NULL; >- } >- } >- if (!intel_lvds->edid) { >- /* Didn't get an EDID, so >- * Set wide sync ranges so we get all modes >- * handed to valid_mode for checking >- */ >- connector->display_info.min_vfreq = 0; >- connector->display_info.max_vfreq = 200; >- connector->display_info.min_hfreq = 0; >- connector->display_info.max_hfreq = 200; >- } >- >- list_for_each_entry(scan, &connector->probed_modes, head) { >- if (scan->type & DRM_MODE_TYPE_PREFERRED) { >- intel_lvds->fixed_mode = >- drm_mode_duplicate(dev, scan); >- intel_find_lvds_downclock(dev, >- intel_lvds->fixed_mode, >- connector); >- goto out; >- } >- } >+ if (intel_lvds_get_edid(dev)) >+ goto out; > > /* Failed to get EDID, what about VBT? */ > if (dev_priv->lfp_lvds_vbt_mode) { >@@ -1112,7 +1134,6 @@ out: > dev_priv->lid_notifier.notifier_call = NULL; > } > /* keep the LVDS connector */ >- dev_priv->int_lvds_connector = connector; > drm_sysfs_connector_add(connector); > > intel_panel_setup_backlight(dev); >@@ -1121,6 +1142,7 @@ out: > > failed: > DRM_DEBUG_KMS("No LVDS modes found, disabling.\n"); >+ dev_priv->int_lvds_connector = NULL; > drm_connector_cleanup(connector); > drm_encoder_cleanup(encoder); > kfree(intel_lvds); >diff -uNrp vanilla-3.5/drivers/gpu/vga/vga_switcheroo.c mbp-f99a29d/drivers/gpu/vga/vga_switcheroo.c >--- vanilla-3.5/drivers/gpu/vga/vga_switcheroo.c 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/drivers/gpu/vga/vga_switcheroo.c 2012-07-30 08:31:43.000000000 +0930 >@@ -101,13 +101,31 @@ static void vga_switcheroo_enable(void) > vgasr_priv.handler->init(); > > list_for_each_entry(client, &vgasr_priv.clients, list) { >+ bool active; >+ > if (client->id != -1) > continue; > ret = vgasr_priv.handler->get_client_id(client->pdev); > if (ret < 0) > return; >- > client->id = ret; >+ >+ if (vgasr_priv.handler->client_active) { >+ active = vgasr_priv.handler->client_active(client->id); >+ >+ /* >+ * If the hardware believes this client is active, >+ * but the client itself doesn't, update state >+ */ >+ >+ if (active && !client->active && client->fb_info) { >+ struct fb_event event; >+ event.info = client->fb_info; >+ fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event); >+ } >+ >+ client->active = active; >+ } > } > vga_switcheroo_debugfs_init(&vgasr_priv); > vgasr_priv.active = true; >diff -uNrp vanilla-3.5/drivers/pci/bus.c mbp-f99a29d/drivers/pci/bus.c >--- vanilla-3.5/drivers/pci/bus.c 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/drivers/pci/bus.c 2012-07-30 08:31:43.000000000 +0930 >@@ -164,6 +164,11 @@ pci_bus_alloc_resource(struct pci_bus *b > int pci_bus_add_device(struct pci_dev *dev) > { > int retval; >+ >+ retval = pcibios_add_device(dev); >+ if (retval) >+ return retval; >+ > retval = device_add(&dev->dev); > if (retval) > return retval; >diff -uNrp vanilla-3.5/drivers/pci/pci.c mbp-f99a29d/drivers/pci/pci.c >--- vanilla-3.5/drivers/pci/pci.c 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/drivers/pci/pci.c 2012-07-30 08:31:43.000000000 +0930 >@@ -1341,6 +1341,19 @@ void pcim_pin_device(struct pci_dev *pde > dr->pinned = 1; > } > >+/* >+ * pcibios_add_device - provide arch specific hooks when adding device dev >+ * @dev: the PCI device being added >+ * >+ * Permits the platform to provide architecture specific functionality when >+ * devices are added. This is the default implementation. Architecture >+ * implementations can override this. >+ */ >+int __attribute__ ((weak)) pcibios_add_device (struct pci_dev *dev) >+{ >+ return 0; >+} >+ > /** > * pcibios_disable_device - disable arch specific PCI resources for device dev > * @dev: the PCI device to disable >diff -uNrp vanilla-3.5/drivers/pci/rom.c mbp-f99a29d/drivers/pci/rom.c >--- vanilla-3.5/drivers/pci/rom.c 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/drivers/pci/rom.c 2012-07-30 08:31:43.000000000 +0930 >@@ -118,6 +118,13 @@ void __iomem *pci_map_rom(struct pci_dev > void __iomem *rom; > > /* >+ * Some devices may provide ROMs via a source other than the BAR >+ */ >+ if (pdev->rom && pdev->romlen) { >+ *size = pdev->romlen; >+ return phys_to_virt(pdev->rom); >+ } >+ /* > * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy > * memory map if the VGA enable bit of the Bridge Control register is > * set for embedded VGA. >@@ -219,7 +226,8 @@ void pci_unmap_rom(struct pci_dev *pdev, > if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) > return; > >- iounmap(rom); >+ if (!pdev->rom || !pdev->romlen) >+ iounmap(rom); > > /* Disable again before continuing, leave enabled if pci=rom */ > if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW))) >diff -uNrp vanilla-3.5/drivers/platform/x86/apple-gmux.c mbp-f99a29d/drivers/platform/x86/apple-gmux.c >--- vanilla-3.5/drivers/platform/x86/apple-gmux.c 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/drivers/platform/x86/apple-gmux.c 2012-07-30 08:31:43.000000000 +0930 >@@ -2,6 +2,7 @@ > * Gmux driver for Apple laptops > * > * Copyright (C) Canonical Ltd. <seth.forshee@canonical.com> >+ * Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de> > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License version 2 as >@@ -20,13 +21,22 @@ > #include <linux/slab.h> > #include <acpi/video.h> > #include <asm/io.h> >+#include <linux/pci.h> >+#include <linux/vga_switcheroo.h> >+#include <linux/delay.h> > >-struct apple_gmux_data { >+static struct apple_gmux_data { > unsigned long iostart; > unsigned long iolen; >+ acpi_handle dhandle; >+ enum vga_switcheroo_client_id resume_client_id; > > struct backlight_device *bdev; >-}; >+} gmux_data; >+ >+static struct pci_dev *discrete; >+ >+DECLARE_COMPLETION(powerchange_done); > > /* > * gmux port offsets. Many of these are not yet used, but may be in the >@@ -59,32 +69,29 @@ struct apple_gmux_data { > #define GMUX_BRIGHTNESS_MASK 0x00ffffff > #define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK > >-static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port) >+static inline u8 gmux_read8(int port) > { >- return inb(gmux_data->iostart + port); >+ return inb(gmux_data.iostart + port); > } > >-static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port, >- u8 val) >+static inline void gmux_write8(int port, u8 val) > { >- outb(val, gmux_data->iostart + port); >+ outb(val, gmux_data.iostart + port); > } > >-static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port) >+static inline u32 gmux_read32(int port) > { >- return inl(gmux_data->iostart + port); >+ return inl(gmux_data.iostart + port); > } > > static int gmux_get_brightness(struct backlight_device *bd) > { >- struct apple_gmux_data *gmux_data = bl_get_data(bd); >- return gmux_read32(gmux_data, GMUX_PORT_BRIGHTNESS) & >+ return gmux_read32(GMUX_PORT_BRIGHTNESS) & > GMUX_BRIGHTNESS_MASK; > } > > static int gmux_update_status(struct backlight_device *bd) > { >- struct apple_gmux_data *gmux_data = bl_get_data(bd); > u32 brightness = bd->props.brightness; > > if (bd->props.state & BL_CORE_SUSPENDED) >@@ -96,54 +103,227 @@ static int gmux_update_status(struct bac > * accept a single u32 write, but the old method also works, so we > * just use the old method for all gmux versions. > */ >- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness); >- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8); >- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16); >- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0); >+ gmux_write8(GMUX_PORT_BRIGHTNESS, brightness); >+ gmux_write8(GMUX_PORT_BRIGHTNESS + 1, brightness >> 8); >+ gmux_write8(GMUX_PORT_BRIGHTNESS + 2, brightness >> 16); >+ gmux_write8(GMUX_PORT_BRIGHTNESS + 3, 0); >+ >+ return 0; >+} >+ >+static int gmux_switchto(enum vga_switcheroo_client_id id) >+{ >+ if (id == VGA_SWITCHEROO_IGD) { >+ gmux_write8(GMUX_PORT_SWITCH_DDC, 1); >+ gmux_write8(GMUX_PORT_SWITCH_DISPLAY, 2); >+ gmux_write8(GMUX_PORT_SWITCH_EXTERNAL, 2); >+ } else { >+ gmux_write8(GMUX_PORT_SWITCH_DDC, 2); >+ gmux_write8(GMUX_PORT_SWITCH_DISPLAY, 3); >+ gmux_write8(GMUX_PORT_SWITCH_EXTERNAL, 3); >+ } >+ >+ return 0; >+} >+ >+static int gmux_call_acpi_pwrd(int arg) >+{ >+ acpi_handle gfx_handle = DEVICE_ACPI_HANDLE(&discrete->dev); >+ acpi_handle pwrd_handle = NULL; >+ acpi_status status = AE_OK; >+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; >+ union acpi_object arg0 = { ACPI_TYPE_INTEGER }; >+ struct acpi_object_list arg_list = { 1, &arg0 }; >+ >+ if (!gfx_handle) { >+ pr_err("Cannot find device ACPI handle\n"); >+ return -ENODEV; >+ } >+ >+ status = acpi_get_handle(gfx_handle, "PWRD", &pwrd_handle); >+ if (ACPI_FAILURE(status)) { >+ pr_err("Cannot get PWRD handle: %s\n", acpi_format_exception(status)); >+ return -ENODEV; >+ } >+ >+ arg0.integer.value = arg; >+ >+ status = acpi_evaluate_object(pwrd_handle, NULL, &arg_list, &buffer); >+ if (ACPI_FAILURE(status)) { >+ pr_err("PWRD call failed: %s\n", acpi_format_exception(status)); >+ return -ENODEV; >+ } >+ >+ //acpi_result_to_string(buffer.pointer); >+ kfree(buffer.pointer); >+ >+ pr_info("PWRD call successful\n"); >+ return 0; >+} >+ >+static int gmux_set_discrete_state(enum vga_switcheroo_state state) >+{ >+ /* TODO: locking for completions needed? */ >+ init_completion(&powerchange_done); >+ >+ if (state == VGA_SWITCHEROO_ON) { >+ gmux_call_acpi_pwrd(0); >+ gmux_write8(GMUX_PORT_DISCRETE_POWER, 1); >+ gmux_write8(GMUX_PORT_DISCRETE_POWER, 3); >+ pr_info("discrete card powered up\n"); >+ } else { >+ gmux_write8(GMUX_PORT_DISCRETE_POWER, 1); >+ gmux_write8(GMUX_PORT_DISCRETE_POWER, 0); >+ gmux_call_acpi_pwrd(1); >+ pr_info("discrete card powered down\n"); >+ } >+ >+ if (wait_for_completion_interruptible_timeout(&powerchange_done, msecs_to_jiffies(200))) >+ pr_info("completion timeout\n"); > > return 0; > } > >+static int gmux_set_power_state(enum vga_switcheroo_client_id id, >+ enum vga_switcheroo_state state) >+{ >+ if (id == VGA_SWITCHEROO_IGD) >+ return 0; >+ >+ return gmux_set_discrete_state(state); >+} >+ >+static int gmux_init(void) >+{ >+ return 0; >+} >+ >+static int gmux_get_client_id(struct pci_dev *pdev) >+{ >+ /* early mbps with switchable graphics use nvidia integrated graphics, >+ * hardcode that the 9400M is integrated */ >+ if (pdev->vendor == PCI_VENDOR_ID_INTEL) { >+ return VGA_SWITCHEROO_IGD; >+ } else if (pdev->vendor == PCI_VENDOR_ID_NVIDIA && pdev->device == 0x0863) { >+ return VGA_SWITCHEROO_IGD; >+ } else { >+ discrete = pdev; >+ return VGA_SWITCHEROO_DIS; >+ } >+} >+ >+static bool gmux_client_active(enum vga_switcheroo_client_id id) >+{ >+ u8 state = gmux_read8(GMUX_PORT_SWITCH_DISPLAY); >+ >+ if ((id == VGA_SWITCHEROO_IGD && state == 2) || >+ (id == VGA_SWITCHEROO_DIS && state == 3)) >+ return true; >+ >+ return false; >+} >+ >+static struct vga_switcheroo_handler gmux_handler = { >+ .switchto = gmux_switchto, >+ .power_state = gmux_set_power_state, >+ .init = gmux_init, >+ .get_client_id = gmux_get_client_id, >+ .client_active = gmux_client_active, >+}; >+ >+static void gmux_disable_interrupts(void) >+{ >+ gmux_write8(GMUX_PORT_INTERRUPT_ENABLE, GMUX_INTERRUPT_DISABLE); >+} >+ >+static void gmux_enable_interrupts(void) >+{ >+ gmux_write8(GMUX_PORT_INTERRUPT_ENABLE, GMUX_INTERRUPT_ENABLE); >+} >+ >+static int gmux_interrupt_get_status(void) >+{ >+ return gmux_read8(GMUX_PORT_INTERRUPT_STATUS); >+} >+ >+static void gmux_interrupt_activate_status(void) >+{ >+ int old_status; >+ int new_status; >+ >+ /* to reactivate interrupts write back current status */ >+ old_status = gmux_read8(GMUX_PORT_INTERRUPT_STATUS); >+ gmux_write8(GMUX_PORT_INTERRUPT_STATUS, old_status); >+ new_status = gmux_read8(GMUX_PORT_INTERRUPT_STATUS); >+ >+ /* status = 0 indicates active interrupts */ >+ if (new_status) >+ pr_info("gmux: error: activate_status, old_status %d new_status %d\n", old_status, new_status); >+} >+ >+static void gmux_notify_handler(acpi_handle device, u32 value, void *context) >+{ >+ int status; >+ >+ status = gmux_interrupt_get_status(); >+ gmux_disable_interrupts(); >+ pr_info("gmux: gpe handler called: status %d\n", status); >+ >+ gmux_interrupt_activate_status(); >+ gmux_enable_interrupts(); >+ >+ if (status & GMUX_INTERRUPT_STATUS_POWER) >+ complete(&powerchange_done); >+} >+ > static const struct backlight_ops gmux_bl_ops = { > .options = BL_CORE_SUSPENDRESUME, > .get_brightness = gmux_get_brightness, > .update_status = gmux_update_status, > }; > >+static int gmux_suspend(struct pnp_dev *dev, pm_message_t state) >+{ >+ gmux_data.resume_client_id = gmux_read8(GMUX_PORT_SWITCH_DISPLAY) == 2 ? >+ VGA_SWITCHEROO_IGD : VGA_SWITCHEROO_DIS; >+ return 0; >+} >+ >+static int gmux_resume(struct pnp_dev *dev) >+{ >+ gmux_switchto(gmux_data.resume_client_id); >+ return 0; >+} >+ > static int __devinit gmux_probe(struct pnp_dev *pnp, > const struct pnp_device_id *id) > { >- struct apple_gmux_data *gmux_data; > struct resource *res; > struct backlight_properties props; > struct backlight_device *bdev; > u8 ver_major, ver_minor, ver_release; >+ acpi_status status; > int ret = -ENXIO; > >- gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL); >- if (!gmux_data) >- return -ENOMEM; >- pnp_set_drvdata(pnp, gmux_data); >- > res = pnp_get_resource(pnp, IORESOURCE_IO, 0); > if (!res) { > pr_err("Failed to find gmux I/O resource\n"); >- goto err_free; >+ goto err_begin; > } > >- gmux_data->iostart = res->start; >- gmux_data->iolen = res->end - res->start; >+ gmux_data.iostart = res->start; >+ gmux_data.iolen = res->end - res->start; > >- if (gmux_data->iolen < GMUX_MIN_IO_LEN) { >+ if (gmux_data.iolen < GMUX_MIN_IO_LEN) { > pr_err("gmux I/O region too small (%lu < %u)\n", >- gmux_data->iolen, GMUX_MIN_IO_LEN); >- goto err_free; >+ gmux_data.iolen, GMUX_MIN_IO_LEN); >+ goto err_begin; > } > >- if (!request_region(gmux_data->iostart, gmux_data->iolen, >+ if (!request_region(gmux_data.iostart, gmux_data.iolen, > "Apple gmux")) { > pr_err("gmux I/O already in use\n"); >- goto err_free; >+ goto err_begin; > } > > /* >@@ -151,9 +331,9 @@ static int __devinit gmux_probe(struct p > * doesn't really have a gmux. Check for invalid version information > * to detect this. > */ >- ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR); >- ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR); >- ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE); >+ ver_major = gmux_read8(GMUX_PORT_VERSION_MAJOR); >+ ver_minor = gmux_read8(GMUX_PORT_VERSION_MINOR); >+ ver_release = gmux_read8(GMUX_PORT_VERSION_RELEASE); > if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) { > pr_info("gmux device not present\n"); > ret = -ENODEV; >@@ -165,7 +345,7 @@ static int __devinit gmux_probe(struct p > > memset(&props, 0, sizeof(props)); > props.type = BACKLIGHT_PLATFORM; >- props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); >+ props.max_brightness = gmux_read32(GMUX_PORT_MAX_BRIGHTNESS); > > /* > * Currently it's assumed that the maximum brightness is less than >@@ -177,44 +357,72 @@ static int __devinit gmux_probe(struct p > props.max_brightness = GMUX_MAX_BRIGHTNESS; > > bdev = backlight_device_register("gmux_backlight", &pnp->dev, >- gmux_data, &gmux_bl_ops, &props); >+ NULL, &gmux_bl_ops, &props); > if (IS_ERR(bdev)) { > ret = PTR_ERR(bdev); > goto err_release; > } > >- gmux_data->bdev = bdev; >+ gmux_data.bdev = bdev; > bdev->props.brightness = gmux_get_brightness(bdev); > backlight_update_status(bdev); > >- /* >- * The backlight situation on Macs is complicated. If the gmux is >- * present it's the best choice, because it always works for >- * backlight control and supports more levels than other options. >- * Disable the other backlight choices. >- */ >- acpi_video_unregister(); >- apple_bl_unregister(); >+ gmux_data.dhandle = DEVICE_ACPI_HANDLE(&pnp->dev); >+ if (!gmux_data.dhandle) { >+ pr_err("Cannot find acpi device for pnp device %s\n", dev_name(&pnp->dev)); >+ goto err_release; >+ } else { >+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; >+ acpi_get_name(gmux_data.dhandle, ACPI_SINGLE_NAME, &buf); >+ pr_info("Found acpi handle for pnp device %s: %s\n", >+ dev_name(&pnp->dev), (char *)buf.pointer); >+ kfree(buf.pointer); >+ } >+ >+ status = acpi_install_notify_handler(gmux_data.dhandle, ACPI_DEVICE_NOTIFY, &gmux_notify_handler, pnp); >+ if (ACPI_FAILURE(status)) { >+ printk("Install notify handler failed: %s\n", acpi_format_exception(status)); >+ goto err_notify; >+ } >+ >+ if (vga_switcheroo_register_handler(&gmux_handler)) >+ goto err_register; >+ >+ init_completion(&powerchange_done); >+ gmux_enable_interrupts(); >+ >+ /* TODO: check this out */ >+ /*active_card = gmux_read8(GMUX_PORT_SWITCH_GET_DISPLAY);*/ >+ /*pr_info("active card: %x\n", active_card);*/ >+ /*pr_info("rom shadow: %x %d", pdev->vendor, pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW);*/ > > return 0; > >+err_register: >+ status = acpi_remove_notify_handler(gmux_data.dhandle, ACPI_DEVICE_NOTIFY, &gmux_notify_handler); >+ if (ACPI_FAILURE(status)) { >+ printk("Install notify handler failed: %s\n", acpi_format_exception(status)); >+ } >+err_notify: >+ backlight_device_unregister(bdev); > err_release: >- release_region(gmux_data->iostart, gmux_data->iolen); >-err_free: >- kfree(gmux_data); >+ release_region(gmux_data.iostart, gmux_data.iolen); >+err_begin: > return ret; > } > > static void __devexit gmux_remove(struct pnp_dev *pnp) > { >- struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp); >+ acpi_status status; > >- backlight_device_unregister(gmux_data->bdev); >- release_region(gmux_data->iostart, gmux_data->iolen); >- kfree(gmux_data); >- >- acpi_video_register(); >- apple_bl_register(); >+ vga_switcheroo_unregister_handler(); >+ backlight_device_unregister(gmux_data.bdev); >+ gmux_disable_interrupts(); >+ status = acpi_remove_notify_handler(gmux_data.dhandle, ACPI_DEVICE_NOTIFY, &gmux_notify_handler); >+ if (ACPI_FAILURE(status)) { >+ printk("Install notify handler failed: %s\n", acpi_format_exception(status)); >+ } >+ release_region(gmux_data.iostart, gmux_data.iolen); > } > > static const struct pnp_device_id gmux_device_ids[] = { >@@ -227,6 +435,8 @@ static struct pnp_driver gmux_pnp_driver > .probe = gmux_probe, > .remove = __devexit_p(gmux_remove), > .id_table = gmux_device_ids, >+ .suspend = gmux_suspend, >+ .resume = gmux_resume > }; > > static int __init apple_gmux_init(void) >diff -uNrp vanilla-3.5/include/linux/efi.h mbp-f99a29d/include/linux/efi.h >--- vanilla-3.5/include/linux/efi.h 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/include/linux/efi.h 2012-07-30 08:31:43.000000000 +0930 >@@ -196,6 +196,77 @@ typedef struct { > void *create_event_ex; > } efi_boot_services_t; > >+typedef enum { >+ EfiPciIoWidthUint8, >+ EfiPciIoWidthUint16, >+ EfiPciIoWidthUint32, >+ EfiPciIoWidthUint64, >+ EfiPciIoWidthFifoUint8, >+ EfiPciIoWidthFifoUint16, >+ EfiPciIoWidthFifoUint32, >+ EfiPciIoWidthFifoUint64, >+ EfiPciIoWidthFillUint8, >+ EfiPciIoWidthFillUint16, >+ EfiPciIoWidthFillUint32, >+ EfiPciIoWidthFillUint64, >+ EfiPciIoWidthMaximum >+} EFI_PCI_IO_PROTOCOL_WIDTH; >+ >+typedef enum { >+ EfiPciIoAttributeOperationGet, >+ EfiPciIoAttributeOperationSet, >+ EfiPciIoAttributeOperationEnable, >+ EfiPciIoAttributeOperationDisable, >+ EfiPciIoAttributeOperationSupported, >+ EfiPciIoAttributeOperationMaximum >+} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION; >+ >+ >+typedef struct { >+ void *read; >+ void *write; >+} efi_pci_io_protocol_access_t; >+ >+typedef struct { >+ void *poll_mem; >+ void *poll_io; >+ efi_pci_io_protocol_access_t mem; >+ efi_pci_io_protocol_access_t io; >+ efi_pci_io_protocol_access_t pci; >+ void *copy_mem; >+ void *map; >+ void *unmap; >+ void *allocate_buffer; >+ void *free_buffer; >+ void *flush; >+ void *get_location; >+ void *attributes; >+ void *get_bar_attributes; >+ void *set_bar_attributes; >+ uint64_t romsize; >+ void *romimage; >+} efi_pci_io_protocol; >+ >+#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 >+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 >+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 >+#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 >+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 >+#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 >+#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 >+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 >+#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 >+#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 >+#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 >+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 >+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 >+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 >+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 >+#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 >+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 >+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 >+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000 >+ > /* > * Types and defines for EFI ResetSystem > */ >diff -uNrp vanilla-3.5/include/linux/pci.h mbp-f99a29d/include/linux/pci.h >--- vanilla-3.5/include/linux/pci.h 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/include/linux/pci.h 2012-07-30 08:31:43.000000000 +0930 >@@ -345,6 +345,8 @@ struct pci_dev { > }; > struct pci_ats *ats; /* Address Translation Service */ > #endif >+ void *rom; /* Physical pointer to ROM if it's not from the BAR */ >+ size_t romlen; /* Length of ROM if it's not from the BAR */ > }; > > static inline struct pci_dev *pci_physfn(struct pci_dev *dev) >@@ -1522,6 +1524,7 @@ void pcibios_disable_device(struct pci_d > void pcibios_set_master(struct pci_dev *dev); > int pcibios_set_pcie_reset_state(struct pci_dev *dev, > enum pcie_reset_state state); >+int pcibios_add_device(struct pci_dev *dev); > > #ifdef CONFIG_PCI_MMCONFIG > extern void __init pci_mmcfg_early_init(void); >diff -uNrp vanilla-3.5/include/linux/vga_switcheroo.h mbp-f99a29d/include/linux/vga_switcheroo.h >--- vanilla-3.5/include/linux/vga_switcheroo.h 2012-07-22 06:28:29.000000000 +0930 >+++ mbp-f99a29d/include/linux/vga_switcheroo.h 2012-07-30 08:31:43.000000000 +0930 >@@ -34,6 +34,7 @@ struct vga_switcheroo_handler { > enum vga_switcheroo_state state); > int (*init)(void); > int (*get_client_id)(struct pci_dev *pdev); >+ bool (*client_active)(enum vga_switcheroo_client_id id); > }; > > struct vga_switcheroo_client_ops {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 837461
:
601855
| 603359 |
627318
|
679517
|
692139