diff --git a/PKGBUILD b/PKGBUILD index 155b422..f98d71e 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -3,10 +3,10 @@ # Contributor: Samsagax # Contributor : abbradar -pkgname=bbswitch-dkms-git +pkgname=bbswitch-dkms-g14-git _pkgname='bbswitch' -pkgver=0.8.r0.g0c38f97 -pkgrel=4 +pkgver=0.8.r5.gddbd243 +pkgrel=1 pkgdesc="kernel module allowing to switch dedicated graphics card on Optimus laptops, dkms version" arch=('i686' 'x86_64') url="http://github.com/Bumblebee-Project/bbswitch" @@ -17,8 +17,10 @@ depends=('dkms' 'linux-headers') makedepends=('git') _gitroot='git://github.com/Bumblebee-Project/bbswitch.git' _gitbranch='develop' -source=("${_gitroot}#branch=${_gitbranch}") -sha256sums=("SKIP") +source=("${_gitroot}#branch=${_gitbranch}" + "bbswitch-dkms-git-zephyrus14.patch") +sha256sums=("SKIP" + "SKIP") pkgver() { @@ -35,7 +37,7 @@ prepare() { package() { cd "${srcdir}/${_pkgname}" - + patch -p1 bbswitch.c ${srcdir}/bbswitch-dkms-git-zephyrus14.patch install -dm755 "${pkgdir}/usr/src/${_pkgname}-${pkgver}" install -Dm644 Makefile bbswitch.c dkms/dkms.conf "${pkgdir}/usr/src/${_pkgname}-${pkgver}" diff --git a/bbswitch-dkms-git-zephyrus14.patch b/bbswitch-dkms-git-zephyrus14.patch new file mode 100644 index 0000000..ac2b0d6 --- /dev/null +++ b/bbswitch-dkms-git-zephyrus14.patch @@ -0,0 +1,335 @@ +diff --unified --recursive --text src.orig/bbswitch/bbswitch.c src/bbswitch/bbswitch.c +--- src.orig/bbswitch/bbswitch.c 2020-08-11 17:50:30.348599901 +0000 ++++ src/bbswitch/bbswitch.c 2020-08-12 12:35:48.309972312 +0000 +@@ -28,6 +28,7 @@ + */ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + ++#include + #include + #include + #include +@@ -35,9 +36,11 @@ + #include + #include + #include ++#include + #include + #include + ++ + #define BBSWITCH_VERSION "0.8" + + MODULE_LICENSE("GPL"); +@@ -91,6 +94,12 @@ + static struct pci_dev *dis_dev; + static acpi_handle dis_handle; + ++static char dis_dev_name[16]; ++unsigned int vendor; ++unsigned int device; ++ ++static struct dev_pm_domain pm_domain; ++ + /* whether the card was off before suspend or not; on: 0, off: 1 */ + static int dis_before_suspend_disabled; + +@@ -184,6 +193,18 @@ + return result & 1 && result & (1 << sfnc); + } + ++static int handle_has_dsm_func(acpi_handle handle, const char muid[16], int revid, int sfnc) { ++ u32 result = 0; ++ ++ // fail if the _DSM call failed ++ if (acpi_call_dsm(handle, muid, revid, 0, 0, &result)) ++ return 0; ++ ++ // ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If ++ // the n-th bit is enabled, function n is supported ++ return result & 1 && result & (1 << sfnc); ++} ++ + static int bbswitch_optimus_dsm(void) { + if (dsm_type == DSM_TYPE_OPTIMUS) { + char args[] = {1, 0, 0, 3}; +@@ -200,86 +221,61 @@ + } + + static int bbswitch_acpi_off(void) { +- if (dsm_type == DSM_TYPE_NVIDIA) { +- char args[] = {2, 0, 0, 0}; +- u32 result = 0; ++ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + +- if (acpi_call_dsm(dis_handle, acpi_nvidia_dsm_muid, 0x102, 0x3, args, +- &result)) { +- // failure +- return 1; +- } +- pr_debug("Result of _DSM call for OFF: %08X\n", result); +- } ++ acpi_status err = (acpi_status) 0x0; ++ acpi_handle hnd; ++ err = acpi_get_handle(NULL, (acpi_string) "\\_SB.PCI0.GPP0.PG00", &hnd); ++ err = acpi_evaluate_object(hnd,"_OFF", NULL, &buffer); ++ kfree(buffer.pointer); + return 0; + } + + static int bbswitch_acpi_on(void) { +- if (dsm_type == DSM_TYPE_NVIDIA) { +- char args[] = {1, 0, 0, 0}; +- u32 result = 0; ++ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; ++ ++ acpi_status err = (acpi_status) 0x0000; ++ acpi_handle hnd; ++ err = acpi_get_handle(NULL, (acpi_string) "\\_SB.PCI0.GPP0.PG00", &hnd); ++ err = acpi_evaluate_object(hnd,"_ON", NULL, &buffer); ++ kfree(buffer.pointer); + +- if (acpi_call_dsm(dis_handle, acpi_nvidia_dsm_muid, 0x102, 0x3, args, +- &result)) { +- // failure +- return 1; +- } +- pr_debug("Result of _DSM call for ON: %08X\n", result); +- } + return 0; + } + + // Returns 1 if the card is disabled, 0 if enabled ++ ++// NOTE: With a fully disabling PCI device(disappears from 'lspci'), ++// you must check that this is '0' anytime you're wanting to interact with dis_dev. ++// Otherwise, you will segfault. + static int is_card_disabled(void) { +- u32 cfg_word; +- // read first config word which contains Vendor and Device ID. If all bits +- // are enabled, the device is assumed to be off +- pci_read_config_dword(dis_dev, 0, &cfg_word); +- // if one of the bits is not enabled (the card is enabled), the inverted +- // result will be non-zero and hence logical not will make it 0 ("false") +- return !~cfg_word; ++ // MAYBE: use the SGST power ACPI call here instead? (returns 0x0 if powered off) ++ struct pci_dev *pdev = NULL; ++ ++ while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) { ++ dis_dev = pdev; ++ return 0; ++ } ++ return 1; + } + + static void bbswitch_off(void) { +- if (is_card_disabled()) ++ if (is_card_disabled()){ ++ pr_info("discrete graphics already disabled"); + return; +- +- // to prevent the system from possibly locking up, don't disable the device +- // if it's still in use by a driver (i.e. nouveau or nvidia) ++ } ++ + if (dis_dev->driver) { + pr_warn("device %s is in use by driver '%s', refusing OFF\n", +- dev_name(&dis_dev->dev), dis_dev->driver->name); ++ dis_dev_name, dis_dev->driver->name); + return; + } +- ++ + pr_info("disabling discrete graphics\n"); + +- if (bbswitch_optimus_dsm()) { +- pr_warn("Optimus ACPI call failed, the device is not disabled\n"); +- return; +- } +- +- pci_save_state(dis_dev); +- pci_clear_master(dis_dev); +- pci_disable_device(dis_dev); +- do { +- struct acpi_device *ad = NULL; +- int r; +- +- r = acpi_bus_get_device(dis_handle, &ad); +- if (r || !ad) { +- pr_warn("Cannot get ACPI device for PCI device\n"); +- break; +- } +- if (ad->power.state == ACPI_STATE_UNKNOWN) { +- pr_debug("ACPI power state is unknown, forcing D0\n"); +- ad->power.state = ACPI_STATE_D0; +- } +- } while (0); +- pci_set_power_state(dis_dev, PCI_D3cold); +- + if (bbswitch_acpi_off()) +- pr_warn("The discrete card could not be disabled by a _DSM call\n"); ++ pr_warn("The discrete card could not be disabled by an _OFF call\n"); ++ dis_dev = NULL; + } + + static void bbswitch_on(void) { +@@ -289,22 +285,38 @@ + pr_info("enabling discrete graphics\n"); + + if (bbswitch_acpi_on()) +- pr_warn("The discrete card could not be enabled by a _DSM call\n"); +- +- pci_set_power_state(dis_dev, PCI_D0); +- pci_restore_state(dis_dev); +- if (pci_enable_device(dis_dev)) +- pr_warn("failed to enable %s\n", dev_name(&dis_dev->dev)); +- pci_set_master(dis_dev); ++ pr_warn("The discrete card could not be enabled by an _ON call\n"); ++ ++ int i = 0; ++ while(is_card_disabled()){ ++ i++; ++ msleep(500); ++ if(i > 4){ ++ break; ++ } ++ } + } + + /* power bus so we can read PCI configuration space */ + static void dis_dev_get(void) { +- if (dis_dev->bus && dis_dev->bus->self) +- pm_runtime_get_sync(&dis_dev->bus->self->dev); ++ if(dis_dev == NULL || is_card_disabled()){ ++ struct pci_dev *pdev = NULL; ++ while ((pdev = pci_get_device(vendor, device, pdev)) != NULL){ ++ dis_dev = pdev; ++ if (dis_dev->bus && dis_dev->bus->self) ++ pm_runtime_get_sync(&dis_dev->bus->self->dev); ++ break; ++ } ++ }else{ ++ if (dis_dev->bus && dis_dev->bus->self) ++ pm_runtime_get_sync(&dis_dev->bus->self->dev); ++ } + } + + static void dis_dev_put(void) { ++ if(dis_dev == NULL || is_card_disabled()){ ++ return; ++ } + if (dis_dev->bus && dis_dev->bus->self) + pm_runtime_put_sync(&dis_dev->bus->self->dev); + } +@@ -335,7 +347,7 @@ + static int bbswitch_proc_show(struct seq_file *seqfp, void *p) { + // show the card state. Example output: 0000:01:00:00 ON + dis_dev_get(); +- seq_printf(seqfp, "%s %s\n", dev_name(&dis_dev->dev), ++ seq_printf(seqfp, "%s %s\n", dis_dev_name, + is_card_disabled() ? "OFF" : "ON"); + dis_dev_put(); + return 0; +@@ -349,20 +361,24 @@ + switch (event_type) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: ++ pr_debug("Detected suspend"); + dis_dev_get(); + dis_before_suspend_disabled = is_card_disabled(); + // enable the device before suspend to avoid the PCI config space from + // being saved incorrectly + if (dis_before_suspend_disabled) ++ pr_info("Enabling GPU for suspend"); + bbswitch_on(); + dis_dev_put(); + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + case PM_POST_RESTORE: ++ pr_debug("Detected restore"); + // after suspend, the card is on, but if it was off before suspend, + // disable it again + if (dis_before_suspend_disabled) { ++ pr_info("Restoring GPU to off"); + dis_dev_get(); + bbswitch_off(); + dis_dev_put(); +@@ -415,13 +431,8 @@ + pci_class != PCI_CLASS_DISPLAY_3D) + continue; + +-#ifdef ACPI_HANDLE +- /* since Linux 3.8 */ + handle = ACPI_HANDLE(&pdev->dev); +-#else +- /* removed since Linux 3.13 */ +- handle = DEVICE_ACPI_HANDLE(&pdev->dev); +-#endif ++ + if (!handle) { + pr_warn("cannot find ACPI handle for VGA device %s\n", + dev_name(&pdev->dev)); +@@ -435,10 +446,19 @@ + pr_info("Found integrated VGA device %s: %s\n", + dev_name(&pdev->dev), (char *)buf.pointer); + } else { +- dis_dev = pdev; +- dis_handle = handle; +- pr_info("Found discrete VGA device %s: %s\n", +- dev_name(&pdev->dev), (char *)buf.pointer); ++ if(handle && handle_has_dsm_func(handle,acpi_optimus_dsm_muid, 0x100, 0x1A)){ ++ dis_dev = pdev; ++ strlcpy(dis_dev_name, dev_name(&pdev->dev), sizeof(dis_dev_name)); ++ dis_handle = handle; ++ vendor = pdev->vendor; ++ device = pdev->device; ++ pr_info("Found discrete VGA device %s: %s\n", ++ dis_dev_name, (char *)buf.pointer); ++ }else{ ++ igd_handle = handle; ++ pr_info("Found non-intel integrated VGA device %s: %s\n", ++ dev_name(&pdev->dev), (char *)buf.pointer); ++ } + } + kfree(buf.pointer); + } +@@ -463,6 +483,7 @@ + dsm_type = DSM_TYPE_NVIDIA; + pr_info("detected a nVidia _DSM function on the" + " integrated video card\n"); ++ + } else { + pr_err("No suitable _DSM call found.\n"); + return -ENODEV; +@@ -480,16 +501,17 @@ + if (!is_card_disabled()) { + /* We think the card is enabled, so ensure the kernel does as well */ + if (pci_enable_device(dis_dev)) +- pr_warn("failed to enable %s\n", dev_name(&dis_dev->dev)); ++ pr_warn("failed to enable %s\n", dis_dev_name); + } + +- if (load_state == CARD_ON) ++ if (load_state == CARD_ON){ + bbswitch_on(); +- else if (load_state == CARD_OFF) ++ } else if (load_state == CARD_OFF){ + bbswitch_off(); ++ } + + pr_info("Succesfully loaded. Discrete card %s is %s\n", +- dev_name(&dis_dev->dev), is_card_disabled() ? "off" : "on"); ++ dis_dev_name, is_card_disabled() ? "off" : "on"); + + dis_dev_put(); + +@@ -509,7 +531,7 @@ + bbswitch_off(); + + pr_info("Unloaded. Discrete card %s is %s\n", +- dev_name(&dis_dev->dev), is_card_disabled() ? "off" : "on"); ++ dis_dev_name, is_card_disabled() ? "off" : "on"); + + dis_dev_put(); +