summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorCole Deck2020-08-17 23:01:25 -0500
committerCole Deck2020-08-17 23:01:25 -0500
commitfad5d02f3d363eaee279113d9e1e6259d37d8c10 (patch)
tree4050d3f675ed29e4452a1c42918ae14c06712c07
parent9169ff40234ebd56219322471064ad84d8cba2bb (diff)
downloadaur-fad5d02f3d363eaee279113d9e1e6259d37d8c10.tar.gz
Initial G14 patch
-rw-r--r--PKGBUILD14
-rw-r--r--bbswitch-dkms-git-zephyrus14.patch335
2 files changed, 343 insertions, 6 deletions
diff --git a/PKGBUILD b/PKGBUILD
index 155b4221d3f3..f98d71ee0061 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -3,10 +3,10 @@
# Contributor: Samsagax <samsagax at gmail {dot} com>
# Contributor : abbradar <nikoamia at gmail {dot} com>
-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 000000000000..ac2b0d6fcbdc
--- /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 <linux/delay.h>
+ #include <linux/pci.h>
+ #include <linux/acpi.h>
+ #include <linux/module.h>
+@@ -35,9 +36,11 @@
+ #include <linux/suspend.h>
+ #include <linux/seq_file.h>
+ #include <linux/pm_runtime.h>
++#include <linux/pm_domain.h>
+ #include <linux/proc_fs.h>
+ #include <linux/version.h>
+
++
+ #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();
+